summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 14:11:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 14:11:00 +0000
commitaf754e596a8dbb05ed8580c342e7fe02e08b28e0 (patch)
treeb2f334c2b55ede42081aa6710a72da784547d8ea /src
parentInitial commit. (diff)
downloadfreeradius-upstream.tar.xz
freeradius-upstream.zip
Adding upstream version 3.2.3+dfsg.upstream/3.2.3+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore2
-rw-r--r--src/LICENSE.openssl13
-rw-r--r--src/all.mk4
-rw-r--r--src/include/.gitignore21
-rw-r--r--src/include/all.mk168
-rw-r--r--src/include/atomic_queue.h79
-rw-r--r--src/include/autoconf.h.in748
-rw-r--r--src/include/automask.h21
-rw-r--r--src/include/base64.h38
-rw-r--r--src/include/build-radpaths-h.in37
-rw-r--r--src/include/build.h168
-rw-r--r--src/include/channel.h55
-rw-r--r--src/include/clients.h174
-rw-r--r--src/include/conf.h23
-rw-r--r--src/include/conffile.h306
-rw-r--r--src/include/connection.h131
-rw-r--r--src/include/detail.h97
-rw-r--r--src/include/dhcp.h85
-rw-r--r--src/include/event.h67
-rw-r--r--src/include/exfile.h45
-rw-r--r--src/include/features-h97
-rw-r--r--src/include/hash.h75
-rw-r--r--src/include/heap.h46
-rw-r--r--src/include/libradius.h967
-rw-r--r--src/include/listen.h206
-rw-r--r--src/include/log.h390
-rw-r--r--src/include/map.h111
-rw-r--r--src/include/math.h161
-rw-r--r--src/include/md4.h137
-rw-r--r--src/include/md5.h123
-rw-r--r--src/include/missing-h530
-rw-r--r--src/include/modcall.h55
-rw-r--r--src/include/modpriv.h69
-rw-r--r--src/include/modules.h175
-rw-r--r--src/include/net.h140
-rw-r--r--src/include/openssl3.h109
-rw-r--r--src/include/packet.h87
-rw-r--r--src/include/parser.h111
-rw-r--r--src/include/pcap.h101
-rw-r--r--src/include/process.h87
-rw-r--r--src/include/protocol.h63
-rw-r--r--src/include/rad_assert.h50
-rw-r--r--src/include/radclient.h93
-rw-r--r--src/include/radius.h186
-rw-r--r--src/include/radiusd.h631
-rw-r--r--src/include/radsniff.h323
-rw-r--r--src/include/radutmp.h65
-rw-r--r--src/include/realms.h235
-rw-r--r--src/include/regex.h77
-rw-r--r--src/include/sha1.h57
-rw-r--r--src/include/socket.h53
-rw-r--r--src/include/soh.h42
-rw-r--r--src/include/state.h47
-rw-r--r--src/include/stats.h101
-rw-r--r--src/include/stdatomic.h364
-rw-r--r--src/include/sysutmp.h108
-rw-r--r--src/include/talloc.h51
-rw-r--r--src/include/tcp.h31
-rw-r--r--src/include/threads.h119
-rw-r--r--src/include/tls-h453
-rw-r--r--src/include/tmpl.h345
-rw-r--r--src/include/token.h95
-rw-r--r--src/include/udpfromto.h31
-rw-r--r--src/include/xlat.h71
-rw-r--r--src/lib/LICENSE504
-rw-r--r--src/lib/README2
-rw-r--r--src/lib/all.mk53
-rw-r--r--src/lib/atomic_queue.c337
-rw-r--r--src/lib/base64.c315
-rw-r--r--src/lib/cbuff.c145
-rw-r--r--src/lib/cursor.c461
-rw-r--r--src/lib/debug.c1217
-rw-r--r--src/lib/dict.c3506
-rw-r--r--src/lib/event.c843
-rw-r--r--src/lib/fifo.c197
-rw-r--r--src/lib/filters.c1253
-rw-r--r--src/lib/getaddrinfo.c438
-rw-r--r--src/lib/hash.c935
-rw-r--r--src/lib/heap.c356
-rw-r--r--src/lib/hmacmd5.c197
-rw-r--r--src/lib/hmacsha1.c228
-rw-r--r--src/lib/isaac.c133
-rw-r--r--src/lib/log.c343
-rw-r--r--src/lib/md4.c310
-rw-r--r--src/lib/md5.c276
-rw-r--r--src/lib/misc.c2192
-rw-r--r--src/lib/missing.c443
-rw-r--r--src/lib/net.c94
-rw-r--r--src/lib/packet.c1116
-rw-r--r--src/lib/pair.c2520
-rw-r--r--src/lib/pcap.c474
-rw-r--r--src/lib/print.c790
-rw-r--r--src/lib/radius.c5354
-rw-r--r--src/lib/rbtree.c744
-rw-r--r--src/lib/regex.c390
-rw-r--r--src/lib/sha1.c185
-rw-r--r--src/lib/snprintf.c880
-rw-r--r--src/lib/snprintf.h220
-rw-r--r--src/lib/socket.c390
-rw-r--r--src/lib/strlcat.c67
-rw-r--r--src/lib/strlcpy.c63
-rw-r--r--src/lib/talloc.c74
-rw-r--r--src/lib/tcp.c172
-rw-r--r--src/lib/token.c481
-rw-r--r--src/lib/udpfromto.c579
-rw-r--r--src/lib/value.c2013
-rw-r--r--src/lib/version.c58
-rw-r--r--src/main/.gitignore13
-rw-r--r--src/main/acct.c186
-rw-r--r--src/main/all.mk3
-rw-r--r--src/main/auth.c894
-rw-r--r--src/main/cb.c247
-rw-r--r--src/main/channel.c231
-rw-r--r--src/main/checkrad.in1515
-rw-r--r--src/main/checkrad.mk5
-rw-r--r--src/main/client.c1581
-rw-r--r--src/main/collectd.c382
-rw-r--r--src/main/command.c3632
-rw-r--r--src/main/conffile.c3821
-rw-r--r--src/main/connection.c1520
-rw-r--r--src/main/crypt.c97
-rw-r--r--src/main/detail.c1266
-rw-r--r--src/main/evaluate.c1144
-rw-r--r--src/main/exec.c633
-rw-r--r--src/main/exfile.c547
-rw-r--r--src/main/files.c361
-rw-r--r--src/main/libfreeradius-server.mk22
-rw-r--r--src/main/listen.c4486
-rw-r--r--src/main/log.c923
-rw-r--r--src/main/mainconfig.c1420
-rw-r--r--src/main/map.c1717
-rw-r--r--src/main/modcall.c4041
-rw-r--r--src/main/modules.c2302
-rw-r--r--src/main/pair.c911
-rw-r--r--src/main/parser.c1809
-rw-r--r--src/main/process.c6457
-rw-r--r--src/main/radattr.c1123
-rw-r--r--src/main/radattr.mk10
-rw-r--r--src/main/radclient.c1712
-rw-r--r--src/main/radclient.mk8
-rw-r--r--src/main/radiusd.c794
-rw-r--r--src/main/radiusd.mk21
-rwxr-xr-xsrc/main/radlast.in7
-rw-r--r--src/main/radlast.mk5
-rw-r--r--src/main/radmin.c773
-rw-r--r--src/main/radmin.mk7
-rw-r--r--src/main/radsniff.c2683
-rw-r--r--src/main/radsniff.mk.in13
-rw-r--r--src/main/radtest.in135
-rw-r--r--src/main/radtest.mk5
-rw-r--r--src/main/radwho.c565
-rw-r--r--src/main/radwho.mk5
-rwxr-xr-xsrc/main/radzap54
-rw-r--r--src/main/radzap.mk5
-rw-r--r--src/main/realms.c3247
-rw-r--r--src/main/regex.c279
-rw-r--r--src/main/session.c262
-rw-r--r--src/main/soh.c675
-rw-r--r--src/main/state.c713
-rw-r--r--src/main/stats.c1028
-rw-r--r--src/main/threads.c1697
-rw-r--r--src/main/tls.c5420
-rw-r--r--src/main/tls_listen.c1568
-rw-r--r--src/main/tmpl.c2399
-rw-r--r--src/main/unittest.c982
-rw-r--r--src/main/unittest.mk25
-rw-r--r--src/main/util.c1732
-rw-r--r--src/main/version.c625
-rw-r--r--src/main/xlat.c2696
-rwxr-xr-xsrc/mkinstalldirs40
-rw-r--r--src/modules/.gitignore3
-rw-r--r--src/modules/all.mk28
-rw-r--r--src/modules/proto_dhcp/README.md9
-rw-r--r--src/modules/proto_dhcp/all.mk3
-rw-r--r--src/modules/proto_dhcp/dhcp.c2268
-rw-r--r--src/modules/proto_dhcp/dhcpclient.c652
-rw-r--r--src/modules/proto_dhcp/dhcpclient.mk5
-rw-r--r--src/modules/proto_dhcp/dhcpd.c866
-rw-r--r--src/modules/proto_dhcp/libfreeradius-dhcp.mk3
-rw-r--r--src/modules/proto_dhcp/proto_dhcp.mk9
-rw-r--r--src/modules/proto_dhcp/rlm_dhcp.c203
-rw-r--r--src/modules/proto_dhcp/rlm_dhcp.mk4
-rw-r--r--src/modules/proto_vmps/README.md10
-rw-r--r--src/modules/proto_vmps/all.mk8
-rw-r--r--src/modules/proto_vmps/vmps.c124
-rw-r--r--src/modules/proto_vmps/vqp.c721
-rw-r--r--src/modules/proto_vmps/vqp.h44
-rwxr-xr-xsrc/modules/proto_vmps/vqpcli.pl207
-rw-r--r--src/modules/rlm_always/README.md10
-rw-r--r--src/modules/rlm_always/all.mk2
-rw-r--r--src/modules/rlm_always/rlm_always.c234
-rw-r--r--src/modules/rlm_attr_filter/README.md9
-rw-r--r--src/modules/rlm_attr_filter/all.mk2
-rw-r--r--src/modules/rlm_attr_filter/rlm_attr_filter.c374
-rw-r--r--src/modules/rlm_cache/.gitignore1
-rw-r--r--src/modules/rlm_cache/README.md11
-rw-r--r--src/modules/rlm_cache/all.mk.in7
-rwxr-xr-xsrc/modules/rlm_cache/configure3966
-rw-r--r--src/modules/rlm_cache/configure.ac35
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_memcached/.gitignore1
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_memcached/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_cache/drivers/rlm_cache_memcached/configure4593
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_memcached/configure.ac115
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c347
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_rbtree/all.mk3
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c351
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_redis/.gitignore1
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_redis/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_cache/drivers/rlm_cache_redis/configure4202
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_redis/configure.ac102
-rw-r--r--src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c413
-rw-r--r--src/modules/rlm_cache/rlm_cache.c839
-rw-r--r--src/modules/rlm_cache/rlm_cache.h112
-rw-r--r--src/modules/rlm_cache/rlm_cache.mk3
-rw-r--r--src/modules/rlm_cache/serialize.c243
-rw-r--r--src/modules/rlm_cache/serialize.h29
-rw-r--r--src/modules/rlm_cache/stable2
-rw-r--r--src/modules/rlm_chap/README.md9
-rw-r--r--src/modules/rlm_chap/all.mk4
-rw-r--r--src/modules/rlm_chap/rlm_chap.c162
-rw-r--r--src/modules/rlm_couchbase/.gitignore1
-rw-r--r--src/modules/rlm_couchbase/README.md196
-rw-r--r--src/modules/rlm_couchbase/all.mk.in13
-rw-r--r--src/modules/rlm_couchbase/config.h.in25
-rwxr-xr-xsrc/modules/rlm_couchbase/configure5276
-rw-r--r--src/modules/rlm_couchbase/configure.ac220
-rw-r--r--src/modules/rlm_couchbase/couchbase.c412
-rw-r--r--src/modules/rlm_couchbase/couchbase.h94
-rw-r--r--src/modules/rlm_couchbase/jsonc_missing.c82
-rw-r--r--src/modules/rlm_couchbase/jsonc_missing.h89
-rw-r--r--src/modules/rlm_couchbase/mod.c767
-rw-r--r--src/modules/rlm_couchbase/mod.h101
-rw-r--r--src/modules/rlm_couchbase/rlm_couchbase.c874
-rw-r--r--src/modules/rlm_counter/.gitignore2
-rw-r--r--src/modules/rlm_counter/README.md12
-rw-r--r--src/modules/rlm_counter/all.mk.in17
-rw-r--r--src/modules/rlm_counter/config.h.in9
-rwxr-xr-xsrc/modules/rlm_counter/configure4672
-rw-r--r--src/modules/rlm_counter/configure.ac55
-rwxr-xr-xsrc/modules/rlm_counter/rad_counter113
-rw-r--r--src/modules/rlm_counter/rlm_counter.c891
-rw-r--r--src/modules/rlm_date/README.md9
-rw-r--r--src/modules/rlm_date/all.mk2
-rw-r--r--src/modules/rlm_date/rlm_date.c141
-rw-r--r--src/modules/rlm_detail/README.md9
-rw-r--r--src/modules/rlm_detail/all.mk2
-rw-r--r--src/modules/rlm_detail/rlm_detail.c564
-rw-r--r--src/modules/rlm_digest/README.md11
-rw-r--r--src/modules/rlm_digest/all.mk2
-rw-r--r--src/modules/rlm_digest/rlm_digest.c601
-rw-r--r--src/modules/rlm_dynamic_clients/README.md10
-rw-r--r--src/modules/rlm_dynamic_clients/all.mk2
-rw-r--r--src/modules/rlm_dynamic_clients/rlm_dynamic_clients.c119
-rw-r--r--src/modules/rlm_eap/.gitignore1
-rw-r--r--src/modules/rlm_eap/README.md11
-rw-r--r--src/modules/rlm_eap/all.mk1
-rwxr-xr-xsrc/modules/rlm_eap/configure3557
-rw-r--r--src/modules/rlm_eap/configure.ac42
-rw-r--r--src/modules/rlm_eap/eap.c1270
-rw-r--r--src/modules/rlm_eap/eap.h154
-rw-r--r--src/modules/rlm_eap/libeap/all.mk10
-rw-r--r--src/modules/rlm_eap/libeap/comp128.c460
-rw-r--r--src/modules/rlm_eap/libeap/comp128.h11
-rw-r--r--src/modules/rlm_eap/libeap/eap_chbind.c290
-rw-r--r--src/modules/rlm_eap/libeap/eap_chbind.h64
-rw-r--r--src/modules/rlm_eap/libeap/eap_sim.h122
-rw-r--r--src/modules/rlm_eap/libeap/eap_tls.c1206
-rw-r--r--src/modules/rlm_eap/libeap/eap_tls.h109
-rw-r--r--src/modules/rlm_eap/libeap/eap_types.h162
-rw-r--r--src/modules/rlm_eap/libeap/eapclient.h8
-rw-r--r--src/modules/rlm_eap/libeap/eapcommon.c401
-rw-r--r--src/modules/rlm_eap/libeap/eapcrypto.c301
-rw-r--r--src/modules/rlm_eap/libeap/eapsimlib.c508
-rw-r--r--src/modules/rlm_eap/libeap/fips186prf.c270
-rw-r--r--src/modules/rlm_eap/libeap/mppe_keys.c384
-rw-r--r--src/modules/rlm_eap/mem.c503
-rw-r--r--src/modules/rlm_eap/radeapclient.c2315
-rw-r--r--src/modules/rlm_eap/radeapclient.mk29
-rw-r--r--src/modules/rlm_eap/rlm_eap.c859
-rw-r--r--src/modules/rlm_eap/rlm_eap.h116
-rw-r--r--src/modules/rlm_eap/rlm_eap.mk6
-rw-r--r--src/modules/rlm_eap/types/all.mk1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/.gitignore1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/README.md10
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in12
-rwxr-xr-xsrc/modules/rlm_eap/types/rlm_eap_fast/configure4512
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/configure.ac86
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c1315
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h260
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c198
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h39
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c659
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_gtc/README.md12
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_gtc/all.mk12
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c250
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/README.md11
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in13
-rwxr-xr-xsrc/modules/rlm_eap/types/rlm_eap_ikev2/configure4206
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac99
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c420
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h48
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c52
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h35
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c526
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_md5/README.md12
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_md5/all.mk12
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c229
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h52
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c168
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_mschapv2/README.md13
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk12
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h51
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c757
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_peap/README.md13
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_peap/all.mk10
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h76
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_peap/peap.c1316
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c429
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/README.md11
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in16
-rwxr-xr-xsrc/modules/rlm_eap/types/rlm_eap_pwd/configure4271
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac80
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h190
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c933
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h126
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c972
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h51
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_sim/.gitignore1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_sim/README.md9
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in12
-rwxr-xr-xsrc/modules/rlm_eap/types/rlm_eap_sim/configure2929
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_sim/configure.ac18
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c697
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tls/README.md9
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tls/all.mk10
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c303
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h52
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore1
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/README.md9
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in14
-rwxr-xr-xsrc/modules/rlm_eap/types/rlm_eap_tnc/configure4199
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac90
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c357
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ttls/README.md10
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ttls/all.mk10
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h46
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c392
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c1321
-rw-r--r--src/modules/rlm_example/.gitignore1
-rw-r--r--src/modules/rlm_example/Makefile.clean11
-rw-r--r--src/modules/rlm_example/README.md10
-rw-r--r--src/modules/rlm_example/all.mk.in44
-rw-r--r--src/modules/rlm_example/config.h.in1
-rwxr-xr-xsrc/modules/rlm_example/configure4424
-rw-r--r--src/modules/rlm_example/configure.ac32
-rw-r--r--src/modules/rlm_example/rlm_example.c216
-rw-r--r--src/modules/rlm_exec/README.md11
-rw-r--r--src/modules/rlm_exec/all.mk2
-rw-r--r--src/modules/rlm_exec/rlm_exec.c487
-rw-r--r--src/modules/rlm_expiration/README.md11
-rw-r--r--src/modules/rlm_expiration/all.mk2
-rw-r--r--src/modules/rlm_expiration/rlm_expiration.c131
-rw-r--r--src/modules/rlm_expr/README.md12
-rw-r--r--src/modules/rlm_expr/all.mk2
-rw-r--r--src/modules/rlm_expr/paircmp.c231
-rw-r--r--src/modules/rlm_expr/rlm_expr.c1924
-rw-r--r--src/modules/rlm_expr/rlm_expr.h25
-rw-r--r--src/modules/rlm_files/README.md13
-rw-r--r--src/modules/rlm_files/all.mk2
-rw-r--r--src/modules/rlm_files/rlm_files.c550
-rw-r--r--src/modules/rlm_idn/.gitignore1
-rw-r--r--src/modules/rlm_idn/README.md13
-rw-r--r--src/modules/rlm_idn/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_idn/configure4306
-rw-r--r--src/modules/rlm_idn/configure.ac32
-rw-r--r--src/modules/rlm_idn/rlm_idn.c158
-rw-r--r--src/modules/rlm_ippool/.gitignore3
-rw-r--r--src/modules/rlm_ippool/README.md11
-rw-r--r--src/modules/rlm_ippool/all.mk.in12
-rw-r--r--src/modules/rlm_ippool/config.h.in7
-rwxr-xr-xsrc/modules/rlm_ippool/configure4679
-rw-r--r--src/modules/rlm_ippool/configure.ac60
-rw-r--r--src/modules/rlm_ippool/rlm_ippool.c834
-rw-r--r--src/modules/rlm_ippool/rlm_ippool.mk9
-rw-r--r--src/modules/rlm_ippool/rlm_ippool_tool.8122
-rw-r--r--src/modules/rlm_ippool/rlm_ippool_tool.c645
-rw-r--r--src/modules/rlm_ippool/rlm_ippool_tool.mk12
-rw-r--r--src/modules/rlm_json/.gitignore1
-rw-r--r--src/modules/rlm_json/README.md13
-rw-r--r--src/modules/rlm_json/all.mk.in10
-rw-r--r--src/modules/rlm_json/config.h.in34
-rwxr-xr-xsrc/modules/rlm_json/configure4904
-rw-r--r--src/modules/rlm_json/configure.ac139
-rw-r--r--src/modules/rlm_json/json.c829
-rw-r--r--src/modules/rlm_json/json.h99
-rw-r--r--src/modules/rlm_json/rlm_json.c237
-rw-r--r--src/modules/rlm_krb5/.gitignore1
-rw-r--r--src/modules/rlm_krb5/README.md12
-rw-r--r--src/modules/rlm_krb5/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_krb5/configure5603
-rw-r--r--src/modules/rlm_krb5/configure.ac178
-rw-r--r--src/modules/rlm_krb5/krb5.c166
-rw-r--r--src/modules/rlm_krb5/krb5.h93
-rw-r--r--src/modules/rlm_krb5/rlm_krb5.c470
-rw-r--r--src/modules/rlm_ldap/.gitignore1
-rw-r--r--src/modules/rlm_ldap/README.md14
-rw-r--r--src/modules/rlm_ldap/all.mk.in10
-rw-r--r--src/modules/rlm_ldap/attrmap.c389
-rw-r--r--src/modules/rlm_ldap/clients.c263
-rw-r--r--src/modules/rlm_ldap/config.h.in43
-rwxr-xr-xsrc/modules/rlm_ldap/configure4636
-rw-r--r--src/modules/rlm_ldap/configure.ac140
-rw-r--r--src/modules/rlm_ldap/edir.c275
-rw-r--r--src/modules/rlm_ldap/groups.c863
-rw-r--r--src/modules/rlm_ldap/ldap.c1661
-rw-r--r--src/modules/rlm_ldap/ldap.h489
-rw-r--r--src/modules/rlm_ldap/rlm_ldap.c1985
-rw-r--r--src/modules/rlm_ldap/sasl.c194
-rw-r--r--src/modules/rlm_linelog/README.md11
-rw-r--r--src/modules/rlm_linelog/all.mk2
-rw-r--r--src/modules/rlm_linelog/rlm_linelog.c328
-rw-r--r--src/modules/rlm_logintime/README.md14
-rw-r--r--src/modules/rlm_logintime/all.mk2
-rw-r--r--src/modules/rlm_logintime/rlm_logintime.c260
-rw-r--r--src/modules/rlm_logintime/timestr.c269
-rw-r--r--src/modules/rlm_mschap/.gitignore3
-rw-r--r--src/modules/rlm_mschap/README.md10
-rw-r--r--src/modules/rlm_mschap/all.mk5
-rw-r--r--src/modules/rlm_mschap/auth_wbclient.c270
-rw-r--r--src/modules/rlm_mschap/auth_wbclient.h19
-rw-r--r--src/modules/rlm_mschap/config.h.in7
-rwxr-xr-xsrc/modules/rlm_mschap/configure4931
-rw-r--r--src/modules/rlm_mschap/configure.ac128
-rw-r--r--src/modules/rlm_mschap/mschap.c147
-rw-r--r--src/modules/rlm_mschap/mschap.h25
-rw-r--r--src/modules/rlm_mschap/opendir.c418
-rw-r--r--src/modules/rlm_mschap/rlm_mschap.c2150
-rw-r--r--src/modules/rlm_mschap/rlm_mschap.h55
-rw-r--r--src/modules/rlm_mschap/rlm_mschap.mk.in10
-rw-r--r--src/modules/rlm_mschap/smbdes.c349
-rw-r--r--src/modules/rlm_mschap/smbdes.h13
-rw-r--r--src/modules/rlm_mschap/smbencrypt.c147
-rw-r--r--src/modules/rlm_mschap/smbencrypt.mk8
-rw-r--r--src/modules/rlm_opendirectory/.gitignore1
-rw-r--r--src/modules/rlm_opendirectory/README.md13
-rw-r--r--src/modules/rlm_opendirectory/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_opendirectory/configure4211
-rw-r--r--src/modules/rlm_opendirectory/configure.ac32
-rw-r--r--src/modules/rlm_opendirectory/rlm_opendirectory.c483
-rw-r--r--src/modules/rlm_pam/.gitignore2
-rw-r--r--src/modules/rlm_pam/README.md9
-rw-r--r--src/modules/rlm_pam/all.mk.in10
-rw-r--r--src/modules/rlm_pam/config.h.in43
-rwxr-xr-xsrc/modules/rlm_pam/configure4709
-rw-r--r--src/modules/rlm_pam/configure.ac50
-rw-r--r--src/modules/rlm_pam/rlm_pam.c244
-rw-r--r--src/modules/rlm_pap/README.md13
-rw-r--r--src/modules/rlm_pap/all.mk2
-rw-r--r--src/modules/rlm_pap/rlm_pap.c1422
-rw-r--r--src/modules/rlm_passwd/README.md15
-rw-r--r--src/modules/rlm_passwd/all.mk2
-rw-r--r--src/modules/rlm_passwd/rlm_passwd.c624
-rw-r--r--src/modules/rlm_perl/.gitignore2
-rw-r--r--src/modules/rlm_perl/README.md12
-rw-r--r--src/modules/rlm_perl/all.mk.in10
-rw-r--r--src/modules/rlm_perl/config.h.in1
-rwxr-xr-xsrc/modules/rlm_perl/configure4721
-rw-r--r--src/modules/rlm_perl/configure.ac102
-rw-r--r--src/modules/rlm_perl/rlm_perl.c1195
-rw-r--r--src/modules/rlm_preprocess/README.md11
-rw-r--r--src/modules/rlm_preprocess/all.mk2
-rw-r--r--src/modules/rlm_preprocess/rlm_preprocess.c736
-rw-r--r--src/modules/rlm_python/.gitignore1
-rw-r--r--src/modules/rlm_python/README.md12
-rw-r--r--src/modules/rlm_python/all.mk.in26
-rw-r--r--src/modules/rlm_python/config.h.in4
-rwxr-xr-xsrc/modules/rlm_python/configure4806
-rw-r--r--src/modules/rlm_python/configure.ac145
-rw-r--r--src/modules/rlm_python/example.py99
-rw-r--r--src/modules/rlm_python/prepaid.py251
-rw-r--r--src/modules/rlm_python/prepaid.sql41
-rw-r--r--src/modules/rlm_python/radiusd.py47
-rw-r--r--src/modules/rlm_python/radiusd_test.py63
-rw-r--r--src/modules/rlm_python/rlm_python.c1284
-rw-r--r--src/modules/rlm_python3/.gitignore1
-rw-r--r--src/modules/rlm_python3/README.md12
-rw-r--r--src/modules/rlm_python3/all.mk.in26
-rw-r--r--src/modules/rlm_python3/config.h.in4
-rwxr-xr-xsrc/modules/rlm_python3/configure4802
-rw-r--r--src/modules/rlm_python3/configure.ac101
-rw-r--r--src/modules/rlm_python3/example.py99
-rw-r--r--src/modules/rlm_python3/prepaid.py247
-rw-r--r--src/modules/rlm_python3/prepaid.sql41
-rw-r--r--src/modules/rlm_python3/radiusd.py43
-rw-r--r--src/modules/rlm_python3/rlm_python3.c1372
-rw-r--r--src/modules/rlm_python3/rlm_python3.h63
-rw-r--r--src/modules/rlm_radutmp/.gitignore2
-rw-r--r--src/modules/rlm_radutmp/README.md11
-rw-r--r--src/modules/rlm_radutmp/all.mk.in10
-rw-r--r--src/modules/rlm_radutmp/config.h.in34
-rwxr-xr-xsrc/modules/rlm_radutmp/configure4540
-rw-r--r--src/modules/rlm_radutmp/configure.ac18
-rw-r--r--src/modules/rlm_radutmp/rlm_radutmp.c763
-rw-r--r--src/modules/rlm_realm/.gitignore1
-rw-r--r--src/modules/rlm_realm/README.md10
-rw-r--r--src/modules/rlm_realm/all.mk.in17
-rwxr-xr-xsrc/modules/rlm_realm/configure4438
-rw-r--r--src/modules/rlm_realm/configure.ac39
-rw-r--r--src/modules/rlm_realm/rlm_realm.c542
-rw-r--r--src/modules/rlm_realm/trustrouter.c715
-rw-r--r--src/modules/rlm_realm/trustrouter.h38
-rw-r--r--src/modules/rlm_redis/.gitignore2
-rw-r--r--src/modules/rlm_redis/README.md14
-rw-r--r--src/modules/rlm_redis/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_redis/configure4201
-rw-r--r--src/modules/rlm_redis/configure.ac102
-rw-r--r--src/modules/rlm_redis/rlm_redis.c336
-rw-r--r--src/modules/rlm_redis/rlm_redis.h65
-rw-r--r--src/modules/rlm_rediswho/.gitignore1
-rw-r--r--src/modules/rlm_rediswho/README.md11
-rw-r--r--src/modules/rlm_rediswho/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_rediswho/configure4201
-rw-r--r--src/modules/rlm_rediswho/configure.ac102
-rw-r--r--src/modules/rlm_rediswho/rlm_rediswho.c247
-rw-r--r--src/modules/rlm_replicate/README.md10
-rw-r--r--src/modules/rlm_replicate/all.mk2
-rw-r--r--src/modules/rlm_replicate/rlm_replicate.c290
-rw-r--r--src/modules/rlm_rest/.gitignore1
-rw-r--r--src/modules/rlm_rest/README.md11
-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/configure5313
-rw-r--r--src/modules/rlm_rest/configure.ac155
-rwxr-xr-xsrc/modules/rlm_rest/demo.pl59
-rw-r--r--src/modules/rlm_rest/rest.c2689
-rw-r--r--src/modules/rlm_rest/rest.h328
-rw-r--r--src/modules/rlm_rest/rlm_rest.c1011
-rw-r--r--src/modules/rlm_ruby/.gitignore1
-rw-r--r--src/modules/rlm_ruby/README.md10
-rw-r--r--src/modules/rlm_ruby/all.mk.in22
-rwxr-xr-xsrc/modules/rlm_ruby/configure4638
-rw-r--r--src/modules/rlm_ruby/configure.ac40
-rw-r--r--src/modules/rlm_ruby/example.rb25
-rw-r--r--src/modules/rlm_ruby/rlm_ruby.c481
-rw-r--r--src/modules/rlm_securid/.gitignore1
-rw-r--r--src/modules/rlm_securid/README34
-rw-r--r--src/modules/rlm_securid/README.md49
-rw-r--r--src/modules/rlm_securid/all.mk.in18
-rwxr-xr-xsrc/modules/rlm_securid/configure4200
-rw-r--r--src/modules/rlm_securid/configure.ac97
-rw-r--r--src/modules/rlm_securid/mem.c313
-rw-r--r--src/modules/rlm_securid/rlm_securid.c563
-rw-r--r--src/modules/rlm_securid/rlm_securid.h93
-rw-r--r--src/modules/rlm_securid/securid19
-rw-r--r--src/modules/rlm_smsotp/.gitignore1
-rw-r--r--src/modules/rlm_smsotp/README.md11
-rw-r--r--src/modules/rlm_smsotp/all.mk.in10
-rw-r--r--src/modules/rlm_smsotp/config.h.in34
-rwxr-xr-xsrc/modules/rlm_smsotp/configure4552
-rw-r--r--src/modules/rlm_smsotp/configure.ac24
-rw-r--r--src/modules/rlm_smsotp/rlm_smsotp.c344
-rw-r--r--src/modules/rlm_smsotp/smsotpd.pl238
-rw-r--r--src/modules/rlm_soh/README.md10
-rw-r--r--src/modules/rlm_soh/all.mk2
-rw-r--r--src/modules/rlm_soh/rlm_soh.c226
-rw-r--r--src/modules/rlm_sometimes/README.md13
-rw-r--r--src/modules/rlm_sometimes/all.mk2
-rw-r--r--src/modules/rlm_sometimes/rlm_sometimes.c191
-rw-r--r--src/modules/rlm_sql/.gitignore1
-rw-r--r--src/modules/rlm_sql/README.md19
-rw-r--r--src/modules/rlm_sql/all.mk.in12
-rwxr-xr-xsrc/modules/rlm_sql/configure3980
-rw-r--r--src/modules/rlm_sql/configure.ac41
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_db2/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_db2/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_db2/configure4191
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_db2/configure.ac83
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c271
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_firebird/configure4192
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/configure.ac83
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c298
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.c578
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.h91
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_freetds/.gitignore1
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_freetds/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_freetds/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_freetds/configure4200
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_freetds/configure.ac97
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c773
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_iodbc/.gitignore1
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_iodbc/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_iodbc/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_iodbc/configure4191
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure.ac83
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_iodbc/rlm_sql_iodbc.c295
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mongo/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mongo/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_mongo/configure4075
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mongo/configure.ac118
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mongo/rlm_sql_mongo.c884
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/.gitignore2
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/all.mk.in11
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/config.h.in7
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_mysql/configure4789
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/configure.ac265
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c858
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_null/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_null/all.mk4
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c120
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_oracle/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_oracle/all.mk.in14
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_oracle/configure4160
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_oracle/configure.ac153
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c482
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/.gitignore1
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/all.mk.in11
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/config.h.in16
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_postgresql/configure4473
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure.ac119
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c610
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_postgresql/sql_postgresql.h250
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_sqlite/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_sqlite/all.mk.in11
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_sqlite/config.h.in19
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_sqlite/configure4474
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure.ac117
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c800
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_unixodbc/.gitignore1
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_unixodbc/README.md8
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_unixodbc/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure4192
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure.ac83
-rw-r--r--src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c364
-rw-r--r--src/modules/rlm_sql/rlm_sql.c1847
-rw-r--r--src/modules/rlm_sql/rlm_sql.h258
-rw-r--r--src/modules/rlm_sql/rlm_sql.mk5
-rw-r--r--src/modules/rlm_sql/sql.c516
-rw-r--r--src/modules/rlm_sql/stable7
-rw-r--r--src/modules/rlm_sql_map/.gitignore1
-rw-r--r--src/modules/rlm_sql_map/README.md9
-rw-r--r--src/modules/rlm_sql_map/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sql_map/configure2924
-rw-r--r--src/modules/rlm_sql_map/configure.ac21
-rw-r--r--src/modules/rlm_sql_map/rlm_sql_map.c426
-rw-r--r--src/modules/rlm_sqlcounter/.gitignore1
-rw-r--r--src/modules/rlm_sqlcounter/README.md10
-rw-r--r--src/modules/rlm_sqlcounter/all.mk.in10
-rwxr-xr-xsrc/modules/rlm_sqlcounter/configure3959
-rw-r--r--src/modules/rlm_sqlcounter/configure.ac21
-rw-r--r--src/modules/rlm_sqlcounter/rlm_sqlcounter.c707
-rw-r--r--src/modules/rlm_sqlippool/.gitignore1
-rw-r--r--src/modules/rlm_sqlippool/README.md10
-rw-r--r--src/modules/rlm_sqlippool/all.mk.in11
-rwxr-xr-xsrc/modules/rlm_sqlippool/configure2924
-rw-r--r--src/modules/rlm_sqlippool/configure.ac21
-rw-r--r--src/modules/rlm_sqlippool/rlm_sqlippool.c900
-rw-r--r--src/modules/rlm_test/README.md10
-rw-r--r--src/modules/rlm_test/all.mk2
-rw-r--r--src/modules/rlm_test/rlm_test.c227
-rw-r--r--src/modules/rlm_totp/.gitignore3
-rw-r--r--src/modules/rlm_totp/Makefile33
-rw-r--r--src/modules/rlm_totp/README.md9
-rw-r--r--src/modules/rlm_totp/all.mk2
-rw-r--r--src/modules/rlm_totp/rlm_totp.c320
-rw-r--r--src/modules/rlm_totp/sha1.txt6
-rw-r--r--src/modules/rlm_unbound/.gitignore1
-rw-r--r--src/modules/rlm_unbound/README.md10
-rw-r--r--src/modules/rlm_unbound/all.mk.in12
-rw-r--r--src/modules/rlm_unbound/config.h.in1
-rwxr-xr-xsrc/modules/rlm_unbound/configure4288
-rw-r--r--src/modules/rlm_unbound/configure.ac66
-rw-r--r--src/modules/rlm_unbound/rlm_unbound.c758
-rw-r--r--src/modules/rlm_unix/.gitignore2
-rw-r--r--src/modules/rlm_unix/README.md15
-rw-r--r--src/modules/rlm_unix/all.mk.in10
-rw-r--r--src/modules/rlm_unix/config.h.in49
-rwxr-xr-xsrc/modules/rlm_unix/configure4757
-rw-r--r--src/modules/rlm_unix/configure.ac53
-rw-r--r--src/modules/rlm_unix/rlm_unix.c546
-rw-r--r--src/modules/rlm_unpack/README.md9
-rw-r--r--src/modules/rlm_unpack/all.mk2
-rw-r--r--src/modules/rlm_unpack/rlm_unpack.c422
-rw-r--r--src/modules/rlm_utf8/README.md10
-rw-r--r--src/modules/rlm_utf8/all.mk2
-rw-r--r--src/modules/rlm_utf8/rlm_utf8.c73
-rw-r--r--src/modules/rlm_wimax/README.md9
-rw-r--r--src/modules/rlm_wimax/all.mk9
-rw-r--r--src/modules/rlm_wimax/milenage.c642
-rw-r--r--src/modules/rlm_wimax/milenage.h128
-rw-r--r--src/modules/rlm_wimax/rlm_wimax.c842
-rw-r--r--src/modules/rlm_yubikey/.gitignore1
-rw-r--r--src/modules/rlm_yubikey/README.md11
-rw-r--r--src/modules/rlm_yubikey/all.mk.in23
-rw-r--r--src/modules/rlm_yubikey/config.h.in7
-rwxr-xr-xsrc/modules/rlm_yubikey/configure4864
-rw-r--r--src/modules/rlm_yubikey/configure.ac196
-rw-r--r--src/modules/rlm_yubikey/decrypt.c137
-rw-r--r--src/modules/rlm_yubikey/rlm_yubikey.c455
-rw-r--r--src/modules/rlm_yubikey/rlm_yubikey.h54
-rw-r--r--src/modules/rlm_yubikey/validate.c201
-rw-r--r--src/modules/stable46
-rw-r--r--src/tests/.gitignore12
-rw-r--r--src/tests/Makefile328
-rw-r--r--src/tests/README29
-rw-r--r--src/tests/all.mk78
-rw-r--r--src/tests/auth/all.mk119
-rw-r--r--src/tests/auth/chap3
-rw-r--r--src/tests/auth/chap.attrs4
-rw-r--r--src/tests/auth/chap_header7
-rw-r--r--src/tests/auth/chap_header.attrs4
-rw-r--r--src/tests/auth/digest3
-rw-r--r--src/tests/auth/digest.attrs25
-rw-r--r--src/tests/auth/md5_password7
-rw-r--r--src/tests/auth/md5_password.attrs4
-rw-r--r--src/tests/auth/password_with_header7
-rw-r--r--src/tests/auth/password_with_header.attrs4
-rw-r--r--src/tests/auth/password_without_header7
-rw-r--r--src/tests/auth/password_without_header.attrs4
-rw-r--r--src/tests/auth/radiusd.conf50
-rw-r--r--src/tests/auth/user_password3
-rw-r--r--src/tests/auth/user_password.attrs4
-rw-r--r--src/tests/auth/wimax3
-rw-r--r--src/tests/auth/wimax.attrs30
-rw-r--r--src/tests/bob2
-rw-r--r--src/tests/comp128-1vectors1024
-rw-r--r--src/tests/comp128-2vectors1024
-rw-r--r--src/tests/comp128-3vectors1024
-rw-r--r--src/tests/config/test.conf114
-rw-r--r--src/tests/dictionary.test11
-rw-r--r--src/tests/digest-01/digest-auth-MD528
-rw-r--r--src/tests/digest-01/digest-auth-MD5_Sess23
-rw-r--r--src/tests/digest-01/digest-auth-int23
-rw-r--r--src/tests/digest-01/digest-auth-noalgo21
-rw-r--r--src/tests/digest-01/digest-auth_int-MD523
-rw-r--r--src/tests/digest-01/digest-auth_int-MD5_Sess24
-rw-r--r--src/tests/digest-01/digest-auth_int-noalgo22
-rw-r--r--src/tests/digest-01/digest-md5-sess21
-rw-r--r--src/tests/eap-fast.conf15
-rw-r--r--src/tests/eap-md5.conf10
-rw-r--r--src/tests/eap-mschapv2.conf10
-rw-r--r--src/tests/eap-pwd.conf11
-rw-r--r--src/tests/eap-tls.conf19
-rw-r--r--src/tests/eap-ttls-eap-mschapv2.conf17
-rw-r--r--src/tests/eap-ttls-eap-tls.conf15
-rw-r--r--src/tests/eap-ttls-mschapv2.conf12
-rw-r--r--src/tests/eap-ttls-pap.conf12
-rw-r--r--src/tests/eapcrypto-01/eapcrypto-out.txt63
-rw-r--r--src/tests/eapmd5-01/client.gdb5
-rw-r--r--src/tests/eapmd5-01/client.sh14
-rw-r--r--src/tests/eapmd5-01/req.txt8
-rw-r--r--src/tests/eapsim-02/check.gdb3
-rw-r--r--src/tests/eapsim-02/client.sh14
-rw-r--r--src/tests/eapsim-02/eapsim-in.txt59
-rw-r--r--src/tests/eapsim-02/eapsim-out.txt161
-rw-r--r--src/tests/eapsim-02/req.txt8
-rw-r--r--src/tests/eapsim-03/check.gdb2
-rw-r--r--src/tests/eapsim-03/client.sh6
-rw-r--r--src/tests/eapsim-03/eapsim-cooked.txt169
-rw-r--r--src/tests/eapsim-03/eapsim-in.txt17
-rw-r--r--src/tests/eapsim-03/eapsim-out.txt169
-rw-r--r--src/tests/eapsim-03/eapsim-sanitize.sed21
-rw-r--r--src/tests/eapsim-03/radiusd-example.txt1506
-rw-r--r--src/tests/eapsim-03/users-example.txt34
-rw-r--r--src/tests/eapsim-04/client.sh6
-rw-r--r--src/tests/eapsim-04/eapsim-cooked.txt169
-rw-r--r--src/tests/eapsim-04/eapsim-in.txt17
-rw-r--r--src/tests/eapsim-04/myvectors.txt136
-rw-r--r--src/tests/eapsim-04/users.txt17
-rw-r--r--src/tests/eapsim-05/check.gdb2
-rw-r--r--src/tests/eapsim-05/client.sh6
-rw-r--r--src/tests/eapsim-05/description.txt2
-rw-r--r--src/tests/eapsim-05/eapsim-cooked.txt148
-rw-r--r--src/tests/eapsim-05/eapsim-in.txt15
-rw-r--r--src/tests/eapsim-05/eapsim-out.txt148
-rw-r--r--src/tests/eapsim-05/eapsim-raw.txt148
-rw-r--r--src/tests/eapsim-05/eapsim-sanitize.sed10
-rw-r--r--src/tests/eapsim-06/check.gdb2
-rw-r--r--src/tests/eapsim-06/client.sh6
-rw-r--r--src/tests/eapsim-06/description.txt24
-rw-r--r--src/tests/eapsim-06/eapsim-cooked.txt184
-rw-r--r--src/tests/eapsim-06/eapsim-in.txt15
-rw-r--r--src/tests/eapsim-06/eapsim-out.txt184
-rw-r--r--src/tests/eapsim-06/eapsim-raw.txt184
-rw-r--r--src/tests/eapsim-06/simtriplets.dat5
-rw-r--r--src/tests/example.com5
-rw-r--r--src/tests/fips186-02/description.txt5
-rw-r--r--src/tests/fips186-02/fips186-2.txt9
-rw-r--r--src/tests/hmac-md5-01/digest1.txt1
-rw-r--r--src/tests/hmac-sha1-01/digest1.txt1
-rw-r--r--src/tests/keywords/3gpp19
-rw-r--r--src/tests/keywords/README.md43
-rw-r--r--src/tests/keywords/all.mk123
-rw-r--r--src/tests/keywords/array53
-rw-r--r--src/tests/keywords/base64141
-rw-r--r--src/tests/keywords/break-error11
-rw-r--r--src/tests/keywords/cache229
-rw-r--r--src/tests/keywords/case-attr-error20
-rw-r--r--src/tests/keywords/case-empty23
-rw-r--r--src/tests/keywords/case-empty-string25
-rw-r--r--src/tests/keywords/case-list19
-rw-r--r--src/tests/keywords/cast-byte25
-rw-r--r--src/tests/keywords/cast-integer25
-rw-r--r--src/tests/keywords/cast-ipaddr442
-rw-r--r--src/tests/keywords/cast-short25
-rw-r--r--src/tests/keywords/cmp20
-rw-r--r--src/tests/keywords/cmp-ipaddr20
-rw-r--r--src/tests/keywords/comments48
-rw-r--r--src/tests/keywords/count-error11
-rw-r--r--src/tests/keywords/crypt151
-rw-r--r--src/tests/keywords/default-input.attrs11
-rw-r--r--src/tests/keywords/else-error14
-rw-r--r--src/tests/keywords/escape67
-rw-r--r--src/tests/keywords/escape-sequences95
-rw-r--r--src/tests/keywords/expand39
-rw-r--r--src/tests/keywords/expr108
-rw-r--r--src/tests/keywords/foreach5
-rw-r--r--src/tests/keywords/foreach-break73
-rw-r--r--src/tests/keywords/foreach-break-246
-rw-r--r--src/tests/keywords/foreach-break-344
-rw-r--r--src/tests/keywords/foreach-break-444
-rw-r--r--src/tests/keywords/foreach-break.attrs18
-rw-r--r--src/tests/keywords/foreach-error5
-rw-r--r--src/tests/keywords/foreach-isolation38
-rw-r--r--src/tests/keywords/foreach-list5
-rw-r--r--src/tests/keywords/foreach-list.attrs21
-rw-r--r--src/tests/keywords/foreach-nested9
-rw-r--r--src/tests/keywords/foreach-nested.attrs25
-rw-r--r--src/tests/keywords/foreach-regex26
-rw-r--r--src/tests/keywords/foreach-regex.attrs16
-rw-r--r--src/tests/keywords/foreach-return52
-rw-r--r--src/tests/keywords/foreach-varied-depth43
-rw-r--r--src/tests/keywords/foreach.attrs18
-rw-r--r--src/tests/keywords/hex141
-rw-r--r--src/tests/keywords/if10
-rw-r--r--src/tests/keywords/if-bob15
-rw-r--r--src/tests/keywords/if-else15
-rw-r--r--src/tests/keywords/if-elsif19
-rw-r--r--src/tests/keywords/if-multivalue173
-rw-r--r--src/tests/keywords/if-paircmp27
-rw-r--r--src/tests/keywords/if-rcode-error11
-rw-r--r--src/tests/keywords/if-regex-bad-attribute21
-rw-r--r--src/tests/keywords/if-regex-error12
-rw-r--r--src/tests/keywords/if-regex-match183
-rw-r--r--src/tests/keywords/if-regex-match-comp149
-rw-r--r--src/tests/keywords/if-regex-match-comp.attrs7
-rw-r--r--src/tests/keywords/if-regex-match-named117
-rw-r--r--src/tests/keywords/if-regex-match-named.attrs6
-rw-r--r--src/tests/keywords/if-regex-match.attrs7
-rw-r--r--src/tests/keywords/if-regex-multivalue26
-rw-r--r--src/tests/keywords/if-skip42
-rw-r--r--src/tests/keywords/integer209
-rw-r--r--src/tests/keywords/ipaddr51
-rw-r--r--src/tests/keywords/ipaddr-error10
-rw-r--r--src/tests/keywords/ipaddr.attrs12
-rw-r--r--src/tests/keywords/ipprefix52
-rw-r--r--src/tests/keywords/length155
-rw-r--r--src/tests/keywords/load-balance97
-rw-r--r--src/tests/keywords/log7
-rw-r--r--src/tests/keywords/map-xlat25
-rw-r--r--src/tests/keywords/md458
-rw-r--r--src/tests/keywords/md560
-rw-r--r--src/tests/keywords/module-failure-message40
-rw-r--r--src/tests/keywords/ok-return13
-rw-r--r--src/tests/keywords/ok-return.attrs4
-rw-r--r--src/tests/keywords/pad62
-rw-r--r--src/tests/keywords/pairs42
-rw-r--r--src/tests/keywords/pap146
-rw-r--r--src/tests/keywords/pap-ssha2114
-rw-r--r--src/tests/keywords/radiusd.conf127
-rw-r--r--src/tests/keywords/redundant17
-rw-r--r--src/tests/keywords/redundant-error6
-rw-r--r--src/tests/keywords/redundant-load-balance65
-rw-r--r--src/tests/keywords/redundant-redundant73
-rw-r--r--src/tests/keywords/regex-escape29
-rw-r--r--src/tests/keywords/regex-lhs27
-rw-r--r--src/tests/keywords/return33
-rw-r--r--src/tests/keywords/return-group22
-rw-r--r--src/tests/keywords/return-group.attrs4
-rw-r--r--src/tests/keywords/return-section35
-rw-r--r--src/tests/keywords/sha160
-rw-r--r--src/tests/keywords/sha281
-rw-r--r--src/tests/keywords/smash6
-rw-r--r--src/tests/keywords/string19
-rw-r--r--src/tests/keywords/substring418
-rw-r--r--src/tests/keywords/switch19
-rw-r--r--src/tests/keywords/switch-attr-cast34
-rw-r--r--src/tests/keywords/switch-attr-cmp36
-rw-r--r--src/tests/keywords/switch-default22
-rw-r--r--src/tests/keywords/switch-escape43
-rw-r--r--src/tests/keywords/switch-nodefault22
-rw-r--r--src/tests/keywords/switch-value-error29
-rw-r--r--src/tests/keywords/switch-value-error227
-rw-r--r--src/tests/keywords/switch-virtual23
-rw-r--r--src/tests/keywords/switch-xlat-error17
-rw-r--r--src/tests/keywords/truncation109
-rw-r--r--src/tests/keywords/unknown84
-rw-r--r--src/tests/keywords/unknown-if8
-rw-r--r--src/tests/keywords/unknown-name15
-rw-r--r--src/tests/keywords/unknown-update6
-rw-r--r--src/tests/keywords/update7
-rw-r--r--src/tests/keywords/update-add-ref-index118
-rw-r--r--src/tests/keywords/update-add-ref-tag118
-rw-r--r--src/tests/keywords/update-all9
-rw-r--r--src/tests/keywords/update-array63
-rw-r--r--src/tests/keywords/update-delete40
-rw-r--r--src/tests/keywords/update-error9
-rw-r--r--src/tests/keywords/update-error-29
-rw-r--r--src/tests/keywords/update-error-310
-rw-r--r--src/tests/keywords/update-exec94
-rw-r--r--src/tests/keywords/update-filter75
-rw-r--r--src/tests/keywords/update-index52
-rw-r--r--src/tests/keywords/update-list-error19
-rw-r--r--src/tests/keywords/update-operator85
-rw-r--r--src/tests/keywords/update-prepend65
-rw-r--r--src/tests/keywords/update-remove-any50
-rw-r--r--src/tests/keywords/update-remove-index100
-rw-r--r--src/tests/keywords/update-remove-list40
-rw-r--r--src/tests/keywords/update-remove-tag275
-rw-r--r--src/tests/keywords/update-remove-value116
-rw-r--r--src/tests/keywords/update-tag176
-rw-r--r--src/tests/keywords/update-xlat61
-rw-r--r--src/tests/keywords/urlquote50
-rw-r--r--src/tests/keywords/virtual12
-rw-r--r--src/tests/keywords/virtual-exists12
-rw-r--r--src/tests/keywords/virtual-load-balance14
-rw-r--r--src/tests/keywords/virtual-rhs16
-rw-r--r--src/tests/keywords/virtual_policy15
-rw-r--r--src/tests/keywords/wimax31
-rw-r--r--src/tests/keywords/wimax-comboip19
-rw-r--r--src/tests/keywords/with_dots19
-rw-r--r--src/tests/keywords/xlat-attr62
-rw-r--r--src/tests/keywords/xlat-attr-index53
-rw-r--r--src/tests/keywords/xlat-attr-tag225
-rw-r--r--src/tests/keywords/xlat-concat40
-rw-r--r--src/tests/keywords/xlat-error12
-rw-r--r--src/tests/keywords/xlat-explode91
-rw-r--r--src/tests/keywords/xlat-list64
-rw-r--r--src/tests/keywords/xlat-octets36
-rw-r--r--src/tests/keywords/xlat-virtual-attr131
-rw-r--r--src/tests/map/all.mk1
-rw-r--r--src/tests/map/base6
-rw-r--r--src/tests/map/base.out5
-rw-r--r--src/tests/map/count-error6
-rw-r--r--src/tests/map/count-list-error6
-rw-r--r--src/tests/map/map_tests.mk50
-rw-r--r--src/tests/map/map_unit.c219
-rw-r--r--src/tests/map/map_unit.mk5
-rw-r--r--src/tests/modules/README.rst18
-rw-r--r--src/tests/modules/all.mk40
-rw-r--r--src/tests/modules/always/all.mk3
-rw-r--r--src/tests/modules/always/module.conf7
-rw-r--r--src/tests/modules/always/replace.unlang11
-rw-r--r--src/tests/modules/always/set_rcode.unlang44
-rw-r--r--src/tests/modules/always/set_status_dead.unlang18
-rw-r--r--src/tests/modules/always/set_status_revive.unlang28
-rw-r--r--src/tests/modules/cache/rbtree/all.mk2
-rw-r--r--src/tests/modules/default-input.attrs11
-rw-r--r--src/tests/modules/files/addcontrol.attrs13
-rw-r--r--src/tests/modules/files/addcontrol.unlang8
-rw-r--r--src/tests/modules/files/addreply.attrs12
-rw-r--r--src/tests/modules/files/addreply.unlang4
-rw-r--r--src/tests/modules/files/all.mk3
-rw-r--r--src/tests/modules/files/authorize92
-rw-r--r--src/tests/modules/files/bob.attrs11
-rw-r--r--src/tests/modules/files/bob.unlang4
-rw-r--r--src/tests/modules/files/doug.attrs11
-rw-r--r--src/tests/modules/files/doug.unlang4
-rw-r--r--src/tests/modules/files/fall-through.attrs11
-rw-r--r--src/tests/modules/files/fall-through.unlang4
-rw-r--r--src/tests/modules/files/filterreply.attrs10
-rw-r--r--src/tests/modules/files/filterreply.unlang4
-rw-r--r--src/tests/modules/files/module.conf9
-rw-r--r--src/tests/modules/files/subreply.attrs12
-rw-r--r--src/tests/modules/files/subreply.unlang4
-rw-r--r--src/tests/modules/json/all.mk3
-rw-r--r--src/tests/modules/json/encode.attrs13
-rw-r--r--src/tests/modules/json/encode.unlang233
-rw-r--r--src/tests/modules/json/module.conf150
-rw-r--r--src/tests/modules/ldap/acct.attrs35
-rw-r--r--src/tests/modules/ldap/acct.unlang23
-rw-r--r--src/tests/modules/ldap/all.mk8
-rw-r--r--src/tests/modules/ldap/auth.attrs15
-rw-r--r--src/tests/modules/ldap/auth.unlang72
l---------src/tests/modules/ldap/example.com.ldif1
-rw-r--r--src/tests/modules/ldap/groups_rfc2307bis.attrs15
-rw-r--r--src/tests/modules/ldap/groups_rfc2307bis.unlang41
-rw-r--r--src/tests/modules/ldap/module.conf537
-rw-r--r--src/tests/modules/pap/all.mk3
-rw-r--r--src/tests/modules/pap/module.conf1
-rw-r--r--src/tests/modules/pap/pbkfd2_dig_big.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_dig_big.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_dig_small.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_dig_small.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter0.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter0.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter1.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter1.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter1000.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter1000.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter100000.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_iter100000.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_big.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_big.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_miss.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_miss.unlang19
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_small.attrs11
-rw-r--r--src/tests/modules/pap/pbkfd2_iter_small.unlang19
-rw-r--r--src/tests/modules/pap/pbkfd2_passlib.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_passlib.unlang20
-rw-r--r--src/tests/modules/pap/pbkfd2_salt0.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt0.unlang19
-rw-r--r--src/tests/modules/pap/pbkfd2_salt1.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt1.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_salt1024.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt1024.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_salt64.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt64.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_salt_big.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt_big.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_salt_small.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_salt_small.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_sha1.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_sha1.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_224.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_224.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_256.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_256.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_384.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_384.unlang17
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_512.attrs10
-rw-r--r--src/tests/modules/pap/pbkfd2_sha2_512.unlang17
-rw-r--r--src/tests/modules/preprocess/all.mk3
-rw-r--r--src/tests/modules/preprocess/hints2
-rw-r--r--src/tests/modules/preprocess/huntgroups0
-rw-r--r--src/tests/modules/preprocess/module.conf4
-rw-r--r--src/tests/modules/preprocess/xlat.attrs12
-rw-r--r--src/tests/modules/preprocess/xlat.unlang14
-rw-r--r--src/tests/modules/radiusd.conf103
-rw-r--r--src/tests/modules/rest/all.mk6
-rw-r--r--src/tests/modules/rest/module.conf46
-rw-r--r--src/tests/modules/rest/rest_module.attrs14
-rw-r--r--src/tests/modules/rest/rest_module.unlang111
-rw-r--r--src/tests/modules/rest/rest_xlat.attrs18
-rw-r--r--src/tests/modules/rest/rest_xlat.unlang208
-rw-r--r--src/tests/modules/sql/.gitignore1
-rw-r--r--src/tests/modules/sql/acct_0_start.attrs37
-rw-r--r--src/tests/modules/sql/acct_0_start.unlang40
-rw-r--r--src/tests/modules/sql/acct_1_update.attrs37
-rw-r--r--src/tests/modules/sql/acct_1_update.unlang30
-rw-r--r--src/tests/modules/sql/acct_2_stop.attrs38
-rw-r--r--src/tests/modules/sql/acct_2_stop.unlang40
-rw-r--r--src/tests/modules/sql/acct_start_conflict.attrs37
-rw-r--r--src/tests/modules/sql/acct_start_conflict.unlang76
-rw-r--r--src/tests/modules/sql/acct_update_no_start.attrs37
-rw-r--r--src/tests/modules/sql/acct_update_no_start.unlang40
-rw-r--r--src/tests/modules/sql/auth.attrs12
-rw-r--r--src/tests/modules/sql/auth.unlang39
-rw-r--r--src/tests/modules/sql/reject.attrs12
-rw-r--r--src/tests/modules/sql/reject.unlang39
-rw-r--r--src/tests/modules/sql_mysql/.gitignore1
l---------src/tests/modules/sql_mysql/acct_0_start.attrs1
l---------src/tests/modules/sql_mysql/acct_0_start.unlang1
l---------src/tests/modules/sql_mysql/acct_1_update.attrs1
l---------src/tests/modules/sql_mysql/acct_1_update.unlang1
l---------src/tests/modules/sql_mysql/acct_2_stop.attrs1
l---------src/tests/modules/sql_mysql/acct_2_stop.unlang1
l---------src/tests/modules/sql_mysql/acct_start_conflict.attrs1
l---------src/tests/modules/sql_mysql/acct_start_conflict.unlang1
l---------src/tests/modules/sql_mysql/acct_update_no_start.attrs1
l---------src/tests/modules/sql_mysql/acct_update_no_start.unlang1
-rw-r--r--src/tests/modules/sql_mysql/all.mk6
l---------src/tests/modules/sql_mysql/auth.attrs1
l---------src/tests/modules/sql_mysql/auth.unlang1
-rw-r--r--src/tests/modules/sql_mysql/module.conf53
l---------src/tests/modules/sql_mysql/reject.attrs1
l---------src/tests/modules/sql_mysql/reject.unlang1
-rw-r--r--src/tests/modules/sql_postgresql/.gitignore1
l---------src/tests/modules/sql_postgresql/acct_0_start.attrs1
l---------src/tests/modules/sql_postgresql/acct_0_start.unlang1
l---------src/tests/modules/sql_postgresql/acct_1_update.attrs1
l---------src/tests/modules/sql_postgresql/acct_1_update.unlang1
l---------src/tests/modules/sql_postgresql/acct_2_stop.attrs1
l---------src/tests/modules/sql_postgresql/acct_2_stop.unlang1
l---------src/tests/modules/sql_postgresql/acct_start_conflict.attrs1
l---------src/tests/modules/sql_postgresql/acct_start_conflict.unlang1
l---------src/tests/modules/sql_postgresql/acct_update_no_start.attrs1
l---------src/tests/modules/sql_postgresql/acct_update_no_start.unlang1
-rw-r--r--src/tests/modules/sql_postgresql/all.mk6
l---------src/tests/modules/sql_postgresql/auth.attrs1
l---------src/tests/modules/sql_postgresql/auth.unlang1
-rw-r--r--src/tests/modules/sql_postgresql/module.conf52
l---------src/tests/modules/sql_postgresql/reject.attrs1
l---------src/tests/modules/sql_postgresql/reject.unlang1
-rw-r--r--src/tests/modules/sql_sqlite/.gitignore1
l---------src/tests/modules/sql_sqlite/acct_0_start.attrs1
l---------src/tests/modules/sql_sqlite/acct_0_start.unlang1
l---------src/tests/modules/sql_sqlite/acct_1_update.attrs1
l---------src/tests/modules/sql_sqlite/acct_1_update.unlang1
l---------src/tests/modules/sql_sqlite/acct_2_stop.attrs1
l---------src/tests/modules/sql_sqlite/acct_2_stop.unlang1
l---------src/tests/modules/sql_sqlite/acct_start_conflict.attrs1
l---------src/tests/modules/sql_sqlite/acct_start_conflict.unlang1
l---------src/tests/modules/sql_sqlite/acct_update_no_start.attrs1
l---------src/tests/modules/sql_sqlite/acct_update_no_start.unlang1
-rw-r--r--src/tests/modules/sql_sqlite/all.mk3
l---------src/tests/modules/sql_sqlite/auth.attrs1
l---------src/tests/modules/sql_sqlite/auth.unlang1
-rw-r--r--src/tests/modules/sql_sqlite/module.conf52
l---------src/tests/modules/sql_sqlite/reject.attrs1
l---------src/tests/modules/sql_sqlite/reject.unlang1
-rw-r--r--src/tests/modules/test.mk165
-rw-r--r--src/tests/modules/unbound/all.mk3
-rw-r--r--src/tests/modules/unbound/dns.attrs11
-rw-r--r--src/tests/modules/unbound/dns.unlang53
-rw-r--r--src/tests/modules/unbound/module.conf4
-rw-r--r--src/tests/modules/unbound/unbound.conf6
-rw-r--r--src/tests/mschapv116
-rw-r--r--src/tests/panic.gdb4
-rw-r--r--src/tests/peap-client-mschapv2.conf18
-rw-r--r--src/tests/peap-eap-tls.conf14
-rw-r--r--src/tests/peap-mschapv2.conf13
-rw-r--r--src/tests/proxy.conf61
-rw-r--r--src/tests/radiusd.mk115
-rw-r--r--src/tests/radsec/.gitignore6
-rw-r--r--src/tests/radsec/1.basic-auth.reply2
-rw-r--r--src/tests/radsec/1.basic-auth.request3
-rw-r--r--src/tests/radsec/2.ipaddrudp-coa.reply4
-rw-r--r--src/tests/radsec/2.ipaddrudp-coa.request3
-rw-r--r--src/tests/radsec/3.homepooludp-coa.reply4
-rw-r--r--src/tests/radsec/3.homepooludp-coa.request2
-rw-r--r--src/tests/radsec/4.homepooltls-coa.reply4
-rw-r--r--src/tests/radsec/4.homepooltls-coa.request2
-rw-r--r--src/tests/radsec/5.singletunnel_proxy-coa.reply6
-rw-r--r--src/tests/radsec/5.singletunnel_proxy-coa.request2
-rw-r--r--src/tests/radsec/6.singletunnel_originate-coa.reply4
-rw-r--r--src/tests/radsec/6.singletunnel_originate-coa.request2
-rw-r--r--src/tests/radsec/7.coareply-auth.reply4
-rw-r--r--src/tests/radsec/7.coareply-auth.request2
-rw-r--r--src/tests/radsec/Makefile10
-rw-r--r--src/tests/radsec/README.rst103
-rw-r--r--src/tests/radsec/all.mk150
-rw-r--r--src/tests/radsec/config-coa/main.conf.template37
-rw-r--r--src/tests/radsec/config-home/main.conf322
-rw-r--r--src/tests/radsec/config-proxy/main.conf.template207
-rwxr-xr-xsrc/tests/radsec/runtest.sh83
-rw-r--r--src/tests/rbmonkey.c250
-rw-r--r--src/tests/rbmonkey.mk7
-rwxr-xr-xsrc/tests/runtests.sh51
-rw-r--r--src/tests/salt-test-server/.gitignore8
-rw-r--r--src/tests/salt-test-server/README3
-rwxr-xr-xsrc/tests/salt-test-server/build.sh1
-rw-r--r--src/tests/salt-test-server/salt/iptable.sls13
-rw-r--r--src/tests/salt-test-server/salt/iptables15
-rw-r--r--src/tests/salt-test-server/salt/ldap.sls41
-rw-r--r--src/tests/salt-test-server/salt/ldap/base.ldif80
-rw-r--r--src/tests/salt-test-server/salt/ldap/base2.ldif81
-rw-r--r--src/tests/salt-test-server/salt/ldap/schema_freeradius.ldif76
-rw-r--r--src/tests/salt-test-server/salt/mysql.sls74
-rw-r--r--src/tests/salt-test-server/salt/mysql/schema.sql150
-rw-r--r--src/tests/salt-test-server/salt/mysql/setup.sql18
-rw-r--r--src/tests/salt-test-server/salt/ntp.sls22
-rw-r--r--src/tests/salt-test-server/salt/postgres.sls71
-rw-r--r--src/tests/salt-test-server/salt/postgres/schema.sql183
-rw-r--r--src/tests/salt-test-server/salt/postgres/setup.sql21
-rw-r--r--src/tests/salt-test-server/salt/top.sls7
-rw-r--r--src/tests/salt-test-server/salt_config/master12
-rw-r--r--src/tests/salt-test-server/salt_config/roster4
-rw-r--r--src/tests/sql_nas_table/all.mk78
-rw-r--r--src/tests/sql_nas_table/auth.txt2
-rw-r--r--src/tests/sql_nas_table/clients.sql1
-rw-r--r--src/tests/sql_nas_table/config/radiusd.conf143
-rw-r--r--src/tests/stripped.example.com5
-rw-r--r--src/tests/test.example.com7
-rw-r--r--src/tests/tests.gdb9
-rw-r--r--src/tests/tls/README.md40
-rw-r--r--src/tests/tls/acct7
-rwxr-xr-xsrc/tests/tls/block.sh34
-rw-r--r--src/tests/tls/common.sh12
-rw-r--r--src/tests/tls/home/radiusd.conf105
-rw-r--r--src/tests/tls/proxy/proxy.conf59
-rw-r--r--src/tests/tls/proxy/radiusd.conf63
-rwxr-xr-xsrc/tests/tls/radacct.sh7
-rwxr-xr-xsrc/tests/tls/radclient.sh7
-rwxr-xr-xsrc/tests/tls/radiusd-home.sh7
-rwxr-xr-xsrc/tests/tls/radiusd-proxy.sh7
-rw-r--r--src/tests/tls/user_password3
-rw-r--r--src/tests/unit/all.mk53
-rw-r--r--src/tests/unit/ascend.txt5
-rw-r--r--src/tests/unit/condition.txt679
-rw-r--r--src/tests/unit/dhcp.txt44
-rw-r--r--src/tests/unit/eapol_key_msg.txt14
-rw-r--r--src/tests/unit/errors.txt17
-rw-r--r--src/tests/unit/escape.txt74
-rw-r--r--src/tests/unit/extended.txt103
-rw-r--r--src/tests/unit/lucent.txt11
-rw-r--r--src/tests/unit/rfc.txt204
-rw-r--r--src/tests/unit/rfc4849.txt49
-rw-r--r--src/tests/unit/tunnel.txt87
-rw-r--r--src/tests/unit/vendor.txt48
-rw-r--r--src/tests/unit/wimax.txt171
-rw-r--r--src/tests/unit/xlat.txt142
-rw-r--r--src/tests/xlat/all.mk57
-rw-r--r--src/tests/xlat/expr.txt20
-rw-r--r--src/tests/xlat/radiusd.conf37
1210 files changed, 443143 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..d26678b
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,2 @@
+freeradius-devel
+util
diff --git a/src/LICENSE.openssl b/src/LICENSE.openssl
new file mode 100644
index 0000000..2c971e5
--- /dev/null
+++ b/src/LICENSE.openssl
@@ -0,0 +1,13 @@
+This LICENSE file is a modification to the main LICENSE file, which is
+GPLv2. It applies only to the files in the "src" directory.
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of this program with the OpenSSL library,
+and distribute linked combinations including the two.
+You must obey the GNU General Public License in all respects
+for all of the code used other than OpenSSL. If you modify
+file(s) with this exception, you may extend this exception to your
+version of the file(s), but you are not obligated to do so. If you
+do not wish to do so, delete this exception statement from your
+version. If you delete this exception statement from all source
+files in the program, then also delete it here.
diff --git a/src/all.mk b/src/all.mk
new file mode 100644
index 0000000..d7a8a4f
--- /dev/null
+++ b/src/all.mk
@@ -0,0 +1,4 @@
+# add this dependency BEFORE including the other submakefiles.
+all:
+
+SUBMAKEFILES := include/all.mk lib/all.mk modules/all.mk main/all.mk tests/all.mk
diff --git a/src/include/.gitignore b/src/include/.gitignore
new file mode 100644
index 0000000..c140a2c
--- /dev/null
+++ b/src/include/.gitignore
@@ -0,0 +1,21 @@
+# Autoconf headers
+autoconf.h
+autoconf.sed
+
+# Dynamically generated headers
+attributes.h
+rfc*.h
+missing.h
+tls.h
+features.h
+radpaths.h
+vqp.h
+freeradius.h
+
+# Headers from v3.1.x
+freeradius.snmp.h
+util
+
+# Build scripts
+build-radpaths-h
+stamp-h
diff --git a/src/include/all.mk b/src/include/all.mk
new file mode 100644
index 0000000..e666f14
--- /dev/null
+++ b/src/include/all.mk
@@ -0,0 +1,168 @@
+#
+# Version: $Id$
+#
+
+#
+# Build dynamic headers by substituting various values from autoconf.h, these
+# get installed with the library files, so external programs can tell what
+# the server library was built with.
+#
+# The RFC headers are dynamic, too.
+#
+# The rest of the headers are static.
+#
+
+HEADERS_DY = attributes.h features.h missing.h radpaths.h tls.h
+
+HEADERS = \
+ autoconf.h \
+ build.h \
+ conf.h \
+ conffile.h \
+ detail.h \
+ event.h \
+ hash.h \
+ heap.h \
+ libradius.h \
+ md4.h \
+ md5.h \
+ modcall.h \
+ modules.h \
+ packet.h \
+ rad_assert.h \
+ radius.h \
+ radiusd.h \
+ radutmp.h \
+ realms.h \
+ regex.h \
+ sha1.h \
+ stats.h \
+ sysutmp.h \
+ tcp.h \
+ threads.h \
+ token.h \
+ udpfromto.h \
+ base64.h \
+ map.h \
+ $(HEADERS_DY)
+
+#
+# Solaris awk doesn't recognise [[:blank:]] hence [\t ]
+#
+src/include/autoconf.sed: src/include/autoconf.h
+ @grep ^#define $< | sed 's,/\*\*/,1,;' | awk '{print "'\
+ 's,#[\\t ]*ifdef[\\t ]*" $$2 "$$,#if "$$3 ",g;'\
+ 's,#[\\t ]*ifndef[\\t ]*" $$2 "$$,#if !"$$3 ",g;'\
+ 's,defined(" $$2 ")," $$3 ",g;"}' > $@
+ @grep -o '#undef [^ ]*' $< | sed 's,/#undef /,,;' | awk '{print "'\
+ 's,#[\\t ]*ifdef[\\t ]*" $$2 "$$,#if 0,g;'\
+ 's,#[\\t ]*ifndef[\\t ]*" $$2 "$$,#if 1,g;'\
+ 's,defined(" $$2 "),0,g;"}' >> $@
+
+
+######################################################################
+#
+# Create the header files from the dictionaries.
+#
+
+RFC_DICTS := $(filter-out %~,$(wildcard share/dictionary.rfc*)) share/dictionary.vqp share/dictionary.freeradius
+HEADERS_RFC := $(patsubst share/dictionary.%,src/include/%.h,$(RFC_DICTS))
+HEADERS += $(notdir ${HEADERS_RFC})
+
+.PRECIOUS: $(HEADERS_RFC)
+
+src/include/attributes.h: share/dictionary.freeradius.internal
+ @$(ECHO) HEADER $@
+ @echo "/* AUTO-GENERATED HEADER FILE. DO NOT EDIT. */" > $@
+ @grep ^ATTRIBUTE $< | awk '{print "PW_"$$2 " " $$3 }' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
+ @echo " " >> $@
+ @grep -- 'Auth-Type' $< | grep ^VALUE | awk '{print "PW_"$$2 "_" $$3 " " $$4 }' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
+
+src/include/%.h: share/dictionary.% share/dictionary.vqp
+ @$(ECHO) HEADER $@
+ @echo "/* AUTO-GENERATED HEADER FILE. DO NOT EDIT. */" > $@
+ @grep ^ATTRIBUTE $< | awk '{print "PW_"$$2 " " $$3 } ' | tr '[:lower:]' '[:upper:]' | tr -- - _ | sed 's/^/#define /' >> $@
+
+#
+# Build features.h by copying over WITH_* and RADIUSD_VERSION_*
+# preprocessor macros from autoconf.h
+# This means we don't need to include autoconf.h in installed headers.
+#
+# We use simple patterns here to work with the lowest common
+# denominator's grep (Solaris).
+#
+src/include/features.h: src/include/features-h src/include/autoconf.h
+ @$(ECHO) HEADER $@
+ @cp $< $@
+ @grep "^#define[ ]*WITH_" src/include/autoconf.h >> $@
+ @grep "^#define[ ]*RADIUSD_VERSION" src/include/autoconf.h >> $@
+
+#
+# Use the SED script we built earlier to make permanent substitutions
+# of definitions in missing-h to build missing.h
+#
+src/include/missing.h: src/include/missing-h src/include/autoconf.sed
+ @$(ECHO) HEADER $@
+ @sed -f src/include/autoconf.sed < $< > $@
+
+src/include/tls.h: src/include/tls-h src/include/autoconf.sed
+ @$(ECHO) HEADER $@
+ @sed -f src/include/autoconf.sed < $< > $@
+
+src/include/radpaths.h: src/include/build-radpaths-h
+ @$(ECHO) HEADER $@
+ @cd src/include && /bin/sh build-radpaths-h
+
+#
+# Create the soft link for the fake include file path.
+#
+src/freeradius-devel:
+ @[ -e $@ ] || ln -s include $@
+
+#
+# Ensure we set up the build environment
+#
+BOOTSTRAP_BUILD += src/freeradius-devel $(addprefix src/include/,$(HEADERS_DY)) $(HEADERS_RFC)
+scan: $(BOOTSTRAP_BUILD)
+
+######################################################################
+#
+# Installation
+#
+# define the installation directory
+SRC_INCLUDE_DIR := ${R}${includedir}/freeradius
+
+$(SRC_INCLUDE_DIR):
+ @$(INSTALL) -d -m 755 ${SRC_INCLUDE_DIR}
+
+#
+# install the headers by re-writing the local files
+#
+# install-sh function for creating directories gets confused
+# if there's a trailing slash, tries to create a directory
+# it already created, and fails...
+#
+${SRC_INCLUDE_DIR}/%.h: src/include/%.h | $(SRC_INCLUDE_DIR)
+ @echo INSTALL $(notdir $<)
+ @$(INSTALL) -d -m 755 `echo $(dir $@) | sed 's/\/$$//'`
+# Expression must deal with indentation after the hash and copy it to the substitution string.
+# Hash not anchored to allow substitution in function documentation.
+ @sed -e 's/#\([\\t ]*\)include <freeradius-devel\/\([^>]*\)>/#\1include <freeradius\/\2>/g' < $< > $@
+ @chmod 644 $@
+
+install.src.include: $(addprefix ${SRC_INCLUDE_DIR}/,${HEADERS})
+install: install.src.include
+
+#
+# Cleaning
+#
+.PHONY: clean.src.include distclean.src.include
+clean.src.include:
+ @rm -f $(addprefix src/include/,$(HEADERS_DY)) $(HEADERS_RFC)
+
+clean: clean.src.include
+
+distclean.src.include: clean.src.include
+ @rm -f autoconf.sed
+
+distclean: distclean.src.include
diff --git a/src/include/atomic_queue.h b/src/include/atomic_queue.h
new file mode 100644
index 0000000..9fbcfe7
--- /dev/null
+++ b/src/include/atomic_queue.h
@@ -0,0 +1,79 @@
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file atomic_queue.h
+ * @brief Thread-safe queues.
+ *
+ * @copyright 2016 Alan DeKok (aland@freeradius.org)
+ */
+RCSIDH(atomic_queue_h, "$Id$")
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#include <talloc.h>
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+#include <stdbool.h>
+
+#ifdef HAVE_STDATOMIC_H
+# include <stdatomic.h>
+#else
+# include <freeradius-devel/stdatomic.h>
+#endif
+
+/*
+ * Some macros to make our life easier.
+ */
+#define atomic_int64_t _Atomic(int64_t)
+#define atomic_uint32_t _Atomic(uint32_t)
+#define atomic_uint64_t _Atomic(uint64_t)
+
+#define cas_incr(_store, _var) atomic_compare_exchange_strong_explicit(&_store, &_var, _var + 1, memory_order_release, memory_order_relaxed)
+#define cas_decr(_store, _var) atomic_compare_exchange_strong_explicit(&_store, &_var, _var - 1, memory_order_release, memory_order_relaxed)
+#define load(_var) atomic_load_explicit(&_var, memory_order_relaxed)
+#define aquire(_var) atomic_load_explicit(&_var, memory_order_acquire)
+#define store(_store, _var) atomic_store_explicit(&_store, _var, memory_order_release);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_atomic_queue_s fr_atomic_queue_t;
+
+fr_atomic_queue_t *fr_atomic_queue_alloc(TALLOC_CTX *ctx, size_t size);
+void fr_atomic_queue_free(fr_atomic_queue_t **aq);
+bool fr_atomic_queue_push(fr_atomic_queue_t *aq, void *data);
+bool fr_atomic_queue_pop(fr_atomic_queue_t *aq, void **p_data);
+size_t fr_atomic_queue_size(fr_atomic_queue_t *aq);
+
+#ifdef WITH_VERIFY_PTR
+void fr_atomic_queue_verify(fr_atomic_queue_t *aq);
+#endif
+
+#ifndef NDEBUG
+void fr_atomic_queue_debug(fr_atomic_queue_t *aq, FILE *fp);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/include/autoconf.h.in b/src/include/autoconf.h.in
new file mode 100644
index 0000000..4774482
--- /dev/null
+++ b/src/include/autoconf.h.in
@@ -0,0 +1,748 @@
+/* src/include/autoconf.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* BSD-Style get*byaddr_r */
+#undef BSDSTYLE
+
+/* style of ctime_r function */
+#undef CTIMERSTYLE
+
+/* Define to 1 to have OpenSSL version check enabled */
+#undef ENABLE_OPENSSL_VERSION_CHECK
+
+/* Define to ensure each build is the same */
+#undef ENABLE_REPRODUCIBLE_BUILDS
+
+/* Define if your processor stores words with the most significant byte first
+ */
+#undef FR_BIG_ENDIAN
+
+/* Define if your processor stores words with the least significant byte first
+ */
+#undef FR_LITTLE_ENDIAN
+
+/* style of gethostbyaddr_r functions */
+#undef GETHOSTBYADDRRSTYLE
+
+/* style of gethostbyname_r functions */
+#undef GETHOSTBYNAMERSTYLE
+
+/* GNU-Style get*byaddr_r */
+#undef GNUSTYLE
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
+#undef HAVE_ASN1_STRING_GET0_DATA
+
+/* Define if your compiler supports the __bounded__ attribute (usually OpenBSD
+ gcc). */
+#undef HAVE_ATTRIBUTE_BOUNDED
+
+/* Define to 1 if you have the `bindat' function. */
+#undef HAVE_BINDAT
+
+/* Define if we have a binary safe regular expression library */
+#undef HAVE_BINSAFE_REGEX
+
+/* Define if the compiler supports __builtin_bswap64 */
+#undef HAVE_BUILTIN_BSWAP_64
+
+/* Define if the compiler supports __builtin_choose_expr */
+#undef HAVE_BUILTIN_CHOOSE_EXPR
+
+/* Define if the compiler supports __builtin_types_compatible_p */
+#undef HAVE_BUILTIN_TYPES_COMPATIBLE_P
+
+/* Define to 1 if you have the <sys/capability.h> header file. */
+#undef HAVE_CAPABILITY_H
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `closefrom' function. */
+#undef HAVE_CLOSEFROM
+
+/* Define to 1 if you have the `collectdclient' library (-lcollectdclient). */
+#undef HAVE_COLLECTDC_H
+
+/* Define to 1 if you have the `CONF_modules_load_file' function. */
+#undef HAVE_CONF_MODULES_LOAD_FILE
+
+/* Do we have the crypt function */
+#undef HAVE_CRYPT
+
+/* Define to 1 if you have the `CRYPTO_set_id_callback' function. */
+#undef HAVE_CRYPTO_SET_ID_CALLBACK
+
+/* Define to 1 if you have the `CRYPTO_set_locking_callback' function. */
+#undef HAVE_CRYPTO_SET_LOCKING_CALLBACK
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Do we have the crypt_r function */
+#undef HAVE_CRYPT_R
+
+/* Define to 1 if you have the `ctime_r' function. */
+#undef HAVE_CTIME_R
+
+/* Define to 1 if you have the declaration of `gethostbyaddr_r', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETHOSTBYADDR_R
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dladdr' function. */
+#undef HAVE_DLADDR
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* define this if we have <execinfo.h> and symbols */
+#undef HAVE_EXECINFO
+
+/* Define to 1 if you have the `fcntl' function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <features.h> header file. */
+#undef HAVE_FEATURES_H
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Define to 1 if you have the `fopencookie' function. */
+#undef HAVE_FOPENCOOKIE
+
+/* Define to 1 if you have the `funopen' function. */
+#undef HAVE_FUNOPEN
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the getgrnam_r. */
+#undef HAVE_GETGRNAM_R
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define to 1 if you have the `getpeereid' function. */
+#undef HAVE_GETPEEREID
+
+/* Define to 1 if you have the getpwnam_r. */
+#undef HAVE_GETPWNAM_R
+
+/* Define to 1 if you have the `getresuid' function. */
+#undef HAVE_GETRESUID
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `getusershell' function. */
+#undef HAVE_GETUSERSHELL
+
+/* Define to 1 if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#undef HAVE_GMTIME_R
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define to 1 if you have the <history.h> header file. */
+#undef HAVE_HISTORY_H
+
+/* Define to 1 if you have the `HMAC_CTX_free' function. */
+#undef HAVE_HMAC_CTX_FREE
+
+/* Define to 1 if you have the `HMAC_CTX_new' function. */
+#undef HAVE_HMAC_CTX_NEW
+
+/* Define if the function (or macro) htonll exists. */
+#undef HAVE_HTONLL
+
+/* Define if the function (or macro) htonlll exists. */
+#undef HAVE_HTONLLL
+
+/* Define to 1 if you have the `if_indextoname' function. */
+#undef HAVE_IF_INDEXTONAME
+
+/* define if you have IN6_PKTINFO (Linux) */
+#undef HAVE_IN6_PKTINFO
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `inet_pton' function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* define if you have IP_PKTINFO (Linux) */
+#undef HAVE_IP_PKTINFO
+
+/* Define to 1 if you have the `kqueue' function. */
+#undef HAVE_KQUEUE
+
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+#undef HAVE_LIBDL
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `pcap' library (-lpcap) and header file
+ <pcap.h>. */
+#undef HAVE_LIBPCAP
+
+/* Define if you have a readline compatible library */
+#undef HAVE_LIBREADLINE
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define to 1 if you have the `ws2_32' library (-lws2_32). */
+#undef HAVE_LIBWS2_32
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <linux/if_packet.h> header file. */
+#undef HAVE_LINUX_IF_PACKET_H
+
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `mallopt' function. */
+#undef HAVE_MALLOPT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkdirat' function. */
+#undef HAVE_MKDIRAT
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
+/* Define to 1 if you have the <openssl/asn1.h> header file. */
+#undef HAVE_OPENSSL_ASN1_H
+
+/* Define to 1 if you have the <openssl/conf.h> header file. */
+#undef HAVE_OPENSSL_CONF_H
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#undef HAVE_OPENSSL_CRYPTO_H
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#undef HAVE_OPENSSL_ENGINE_H
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H
+
+/* Define to 1 if you have the <openssl/evp.h> header file. */
+#undef HAVE_OPENSSL_EVP_H
+
+/* Define to 1 if you have the <openssl/hmac.h> header file. */
+#undef HAVE_OPENSSL_HMAC_H
+
+/* Define to 1 if you have the <openssl/md4.h> header file. */
+#undef HAVE_OPENSSL_MD4_H
+
+/* Define to 1 if you have the <openssl/md5.h> header file. */
+#undef HAVE_OPENSSL_MD5_H
+
+/* Define to 1 if you have the <openssl/ocsp.h> header file. */
+#undef HAVE_OPENSSL_OCSP_H
+
+/* Define to 1 if you have the <openssl/rand.h> header file. */
+#undef HAVE_OPENSSL_RAND_H
+
+/* Define to 1 if you have the <openssl/sha.h> header file. */
+#undef HAVE_OPENSSL_SHA_H
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define to 1 if you have the `pcap_activate' function. */
+#undef HAVE_PCAP_ACTIVATE
+
+/* Define to 1 if you have the `pcap_create' function. */
+#undef HAVE_PCAP_CREATE
+
+/* Define to 1 if you have the `pcap_dump_fopen' function. */
+#undef HAVE_PCAP_DUMP_FOPEN
+
+/* Define to 1 if you have the `pcap_fopen_offline' function. */
+#undef HAVE_PCAP_FOPEN_OFFLINE
+
+/* define this if we have libpcre */
+#undef HAVE_PCRE
+
+/* Define to 1 if you have the <prot.h> header file. */
+#undef HAVE_PROT_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the `pthread_sigmask' function. */
+#undef HAVE_PTHREAD_SIGMASK
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the <readline.h> header file. */
+#undef HAVE_READLINE_H
+
+/* Define if your readline library has \`add_history' */
+#undef HAVE_READLINE_HISTORY
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+#undef HAVE_READLINE_HISTORY_H
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+#undef HAVE_READLINE_READLINE_H
+
+/* Define if we have any regular expression library */
+#undef HAVE_REGEX
+
+/* Define to 1 if you have the `regncomp' function. */
+#undef HAVE_REGNCOMP
+
+/* Define to 1 if you have the `regnexec' function. */
+#undef HAVE_REGNEXEC
+
+/* define this if we have REG_EXTENDED (from <regex.h>) */
+#undef HAVE_REG_EXTENDED
+
+/* Define to 1 if you have the <resource.h> header file. */
+#undef HAVE_RESOURCE_H
+
+/* Define to 1 if you have the <sanitizer/lsan_interface.h> header file. */
+#undef HAVE_SANITIZER_LSAN_INTERFACE_H
+
+/* Define to 1 if you have the <semaphore.h> header file. */
+#undef HAVE_SEMAPHORE_H
+
+/* Define to 1 if you have the `setlinebuf' function. */
+#undef HAVE_SETLINEBUF
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the `setsid' function. */
+#undef HAVE_SETSID
+
+/* Define to 1 if you have the `setuid' function. */
+#undef HAVE_SETUID
+
+/* Define to 1 if you have the `setvbuf' function. */
+#undef HAVE_SETVBUF
+
+/* Define to 1 if you have the <siad.h> header file. */
+#undef HAVE_SIAD_H
+
+/* Define to 1 if you have the <sia.h> header file. */
+#undef HAVE_SIA_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the `sigprocmask' function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define if the type sig_t is defined by signal.h */
+#undef HAVE_SIG_T
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `SSL_get_client_random' function. */
+#undef HAVE_SSL_GET_CLIENT_RANDOM
+
+/* Define to 1 if you have the `SSL_get_server_random' function. */
+#undef HAVE_SSL_GET_SERVER_RANDOM
+
+/* Define to 1 if you have the `SSL_SESSION_get_master_key' function. */
+#undef HAVE_SSL_SESSION_GET_MASTER_KEY
+
+/* Define to 1 if you have the <stdalign.h> header file. */
+#undef HAVE_STDALIGN_H
+
+/* Define to 1 if you have the <stdatomic.h> header file. */
+#undef HAVE_STDATOMIC_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strsep' function. */
+#undef HAVE_STRSEP
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Generic DNS lookups */
+#undef HAVE_STRUCT_ADDRINFO
+
+/* IPv6 address structure */
+#undef HAVE_STRUCT_IN6_ADDR
+
+/* IPv6 socket addresses */
+#undef HAVE_STRUCT_SOCKADDR_IN6
+
+/* Generic socket addresses */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the `systemd' library (-lsystemd). */
+#undef HAVE_SYSTEMD
+
+/* Define to 1 if you have the <systemd/sd-daemon.h> header file. */
+#undef HAVE_SYSTEMD_SD_DAEMON_H
+
+/* Define to 1 if you have watchdog support in the `systemd' library
+ (-lsystemd). */
+#undef HAVE_SYSTEMD_WATCHDOG
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#undef HAVE_SYS_EVENT_H
+
+/* Define to 1 if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#undef HAVE_SYS_PRCTL_H
+
+/* Define to 1 if you have the <sys/procctl.h> header file. */
+#undef HAVE_SYS_PROCCTL_H
+
+/* Define to 1 if you have the <sys/ptrace.h> header file. */
+#undef HAVE_SYS_PTRACE_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/security.h> header file. */
+#undef HAVE_SYS_SECURITY_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the function talloc_set_memlimit. */
+#undef HAVE_TALLOC_SET_MEMLIMIT
+
+/* 128 bit unsigned integer */
+#undef HAVE_UINT128_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unlinkat' function. */
+#undef HAVE_UNLINKAT
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <utmpx.h> header file. */
+#undef HAVE_UTMPX_H
+
+/* Define to 1 if you have the <utmp.h> header file. */
+#undef HAVE_UTMP_H
+
+/* Define to 1 if you have the `vdprintf' function. */
+#undef HAVE_VDPRINTF
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if the compiler supports -Wdocumentation */
+#undef HAVE_WDOCUMENTATION
+
+/* Define to 1 if you have the <winsock.h> header file. */
+#undef HAVE_WINSOCK_H
+
+/* compiler specific 128 bit unsigned integer */
+#undef HAVE___UINT128_T
+
+/* define if you have OSFC2 authentication */
+#undef OSFC2
+
+/* define if you have OSFSIA authentication */
+#undef OSFSIA
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Posix-Style ctime_r */
+#undef POSIXSTYLE
+
+/* Version integer in format <ma><ma><mi><mi><in><in> */
+#undef RADIUSD_VERSION
+
+/* Commit HEAD at time of configuring */
+#undef RADIUSD_VERSION_COMMIT
+
+/* Raw version string from VERSION file */
+#undef RADIUSD_VERSION_STRING
+
+/* Solaris-Style ctime_r */
+#undef SOLARISSTYLE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* SYSV-Style get*byaddr_r */
+#undef SYSVSTYLE
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if the compiler supports a thread local storage class */
+#undef TLS_STORAGE_CLASS
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* include support for Ascend binary filter attributes */
+#undef WITH_ASCEND_BINARY
+
+/* define if you want DHCP support */
+#undef WITH_DHCP
+
+/* define if the server was built with -DNDEBUG */
+#undef WITH_NDEBUG
+
+/* define if you want RADIUSv11 support (For RADSec et al) */
+#undef WITH_RADIUSV11
+
+/* define if you want TCP support (For RADSec et al) */
+#undef WITH_TCP
+
+/* define if you want thread support */
+#undef WITH_THREADS
+
+/* define if you want udpfromto */
+#undef WITH_UDPFROMTO
+
+/* define if you want VMPS support */
+#undef WITH_VMPS
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Force OSX >= 10.7 Lion to use RFC2292 IPv6 socket options */
+#undef __APPLE_USE_RFC_3542
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* socklen_t is generally 'int' on systems which don't use it */
+#undef socklen_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* uint16_t should be the canonical '2 octets' for network traffic */
+#undef uint16_t
+
+/* uint32_t should be the canonical 'network integer' */
+#undef uint32_t
+
+/* uint64_t is required for larger counters */
+#undef uint64_t
+
+/* uint8_t should be the canonical 'octet' for network traffic */
+#undef uint8_t
+
+/* define to something if you don't have ut_xtime in struct utmpx */
+#undef ut_xtime
+
+#include <freeradius-devel/automask.h>
diff --git a/src/include/automask.h b/src/include/automask.h
new file mode 100644
index 0000000..87ffdfc
--- /dev/null
+++ b/src/include/automask.h
@@ -0,0 +1,21 @@
+/*
+ * C Preprocessor definitions we do *NOT* want to leave defined autoconf.h
+ * Which are dependent on where the header is being used.
+ *
+ * Version: $Id$
+ */
+
+
+/*
+ * If were building a module we may have local PACKAGE_* defines if
+ * AC_INIT() was called with full arguments.
+ */
+#ifdef IS_MODULE
+# undef PACKAGE_BUGREPORT
+# undef PACKAGE_NAME
+# undef PACKAGE_STRING
+# undef PACKAGE_TARNAME
+# undef PACKAGE_URL
+# undef PACKAGE_VERSION
+#endif
+
diff --git a/src/include/base64.h b/src/include/base64.h
new file mode 100644
index 0000000..c83cfc9
--- /dev/null
+++ b/src/include/base64.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ * Written by Simon Josefsson.
+ *
+ * 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, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _FR_BASE64_H
+#define _FR_BASE64_H
+
+RCSIDH(base64_h, "$Id$")
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* This uses that the expression (n+(k-1))/k means the smallest
+ integer >= n/k, i.e., the ceiling of n/k. */
+#define FR_BASE64_ENC_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
+#define FR_BASE64_DEC_LENGTH(inlen) ((3 * (inlen / 4)) + 2)
+
+bool fr_is_base64(char c);
+
+ssize_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen);
+
+ssize_t fr_base64_decode(uint8_t *out, size_t outlen, char const *in, size_t inlen);
+
+#endif /* _FR_BASE64_H */
diff --git a/src/include/build-radpaths-h.in b/src/include/build-radpaths-h.in
new file mode 100644
index 0000000..506a21b
--- /dev/null
+++ b/src/include/build-radpaths-h.in
@@ -0,0 +1,37 @@
+#! /bin/sh
+#
+# build-radpaths-h
+# Script to generate radpaths.h file. This is needed to
+# work around the weird way "autoconf" substitutes things
+# that are generated in anyway from a command line
+# argument having to do with a path (--prefix etc)
+#
+# Version: $Id$
+#
+
+# Location of files.
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sysconfdir=@sysconfdir@
+localstatedir=@localstatedir@
+libdir=@libdir@
+bindir=@bindir@
+sbindir=@sbindir@
+mandir=@mandir@
+logdir=@logdir@
+raddbdir=@raddbdir@
+dictdir=@dictdir@
+radacctdir=@radacctdir@
+datarootdir=@datarootdir@
+
+cat <<EOF > radpaths.h
+/* Automatically generated by "build-radpaths-h" */
+#define LOGDIR "@logdir@"
+#define LIBDIR "@libdir@"
+#define RADDBDIR "@raddbdir@"
+#define RUNDIR "@localstatedir@/run"
+#define SBINDIR "@sbindir@"
+#define RADIR "@radacctdir@"
+#define DICTDIR "@dictdir@"
+EOF
+
diff --git a/src/include/build.h b/src/include/build.h
new file mode 100644
index 0000000..c5eaa45
--- /dev/null
+++ b/src/include/build.h
@@ -0,0 +1,168 @@
+/**
+ * $Id$
+ *
+ * @brief Source control functions
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ */
+#ifndef _BUILD_H
+#define _BUILD_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <freeradius-devel/autoconf.h> /* Needed for endian macros */
+
+/*
+ * The ubiquitous stringify macros
+ */
+#define XSTRINGIFY(x) #x
+#define STRINGIFY(x) XSTRINGIFY(x)
+#define JOINSTR(x,y) XSTRINGIFY(x ## y)
+
+/*
+ * HEX concatenation macros
+ */
+#ifndef HEXIFY
+# define XHEXIFY4(b1,b2,b3,b4) (0x ## b1 ## b2 ## b3 ## b4)
+# define HEXIFY4(b1,b2,b3,b4) XHEXIFY4(b1, b2, b3, b4)
+
+# define XHEXIFY3(b1,b2,b3) (0x ## b1 ## b2 ## b3)
+# define HEXIFY3(b1,b2,b3) XHEXIFY3(b1, b2, b3)
+
+# define XHEXIFY2(b1,b2) (0x ## b1 ## b2)
+# define HEXIFY2(b1,b2) XHEXIFY2(b1, b2)
+
+# define XHEXIFY(b1) (0x ## b1)
+# define HEXIFY(b1) XHEXIFY(b1)
+#endif
+
+/*
+ * struct field size
+ */
+#define SIZEOF_MEMBER(_t, _m) sizeof(((_t *)0)->_m)
+
+/*
+ * Only use GCC __attribute__ if were building with a GCClike
+ * compiler.
+ */
+#ifdef __GNUC__
+# define CC_HINT(...) __attribute__ ((__VA_ARGS__))
+# define likely(_x) __builtin_expect((_x), 1)
+# define unlikely(_x) __builtin_expect((_x), 0)
+#else
+# define CC_HINT(...)
+# define likely(_x) _x
+# define unlikely(_x) _x
+#endif
+
+#ifdef HAVE_ATTRIBUTE_BOUNDED
+# define CC_BOUNDED(_x, ...) CC_HINT(__bounded__(_x, ## __VA_ARGS__))
+#else
+# define CC_BOUNDED(...)
+#endif
+
+/*
+ * GCC uses __SANITIZE_ADDRESS__, clang uses __has_feature, which
+ * GCC complains about.
+ */
+#ifndef __SANITIZE_ADDRESS__
+#ifdef __has_feature
+#if __has_feature(address_sanitizer)
+#define __SANITIZE_ADDRESS__ (1)
+#endif
+#endif
+#endif
+
+/*
+ * Macros to add pragmas
+ */
+#define PRAGMA(_x) _Pragma(#_x)
+
+/*
+ * Macros for controlling warnings in GCC >= 4.2 and clang >= 2.8
+ */
+#if defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
+# define DIAG_UNKNOWN_PRAGMAS pragmas
+# define DIAG_PRAGMA(_x) PRAGMA(GCC diagnostic _x)
+# if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
+# define DIAG_OFF(_x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(pop)
+# else
+# define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(warning JOINSTR(-W,_x))
+# endif
+#elif defined(__clang__) && ((__clang_major__ * 100) + __clang_minor__ >= 208)
+# define DIAG_UNKNOWN_PRAGMAS unknown-pragmas
+# define DIAG_PRAGMA(_x) PRAGMA(clang diagnostic _x)
+# define DIAG_OFF(_x) DIAG_PRAGMA(push) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
+# define DIAG_ON(_x) DIAG_PRAGMA(pop)
+#else
+# define DIAG_UNKNOWN_PRAGMAS
+# define DIAG_OFF(_x)
+# define DIAG_ON(_x)
+#endif
+
+/*
+ * GCC and clang use different macros
+ */
+#ifdef __clang__
+# define DIAG_OPTIONAL DIAG_OFF(unknown-pragmas)
+#else
+# define DIAG_OPTIONAL DIAG_OFF(pragmas)
+#endif
+
+/*
+ * For dealing with APIs which are only deprecated in OSX (like the OpenSSL API)
+ */
+#ifdef __APPLE__
+# define USES_APPLE_DEPRECATED_API DIAG_OFF(deprecated-declarations)
+# define USES_APPLE_RST DIAG_ON(deprecated-declarations)
+#else
+# define USES_APPLE_DEPRECATED_API
+# define USES_APPLE_RST
+#endif
+
+#if defined(__GNUC__)
+/* force inclusion of ident keywords in the face of optimization */
+# define RCSID(id) static char const rcsid[] __attribute__ ((used)) = id;
+# define RCSIDH(h, id) static char const rcsid_ ## h [] __attribute__ ((used)) = id;
+#elif defined(__SUNPRO_C)
+/* put ident keyword into comment section (nicer than gcc way) */
+# define RCSID(id) PRAGMA(sun ident id)
+# define RCSIDH(h, id) PRAGMA(sun ident id)
+#else
+# define RCSID(id)
+# define RCSIDH(h, id)
+#endif
+
+/*
+ * Try and determine endianness of the target system.
+ *
+ * Other projects seem to use endian.h and variants, but these are
+ * in non standard locations, and may mess up cross compiling.
+ *
+ * Here at least the endianness can be set explicitly with
+ * -DLITTLE_ENDIAN or -DBIG_ENDIAN.
+ */
+#if !defined(FR_LITTLE_ENDIAN) && !defined(FR_BIG_ENDIAN)
+# if defined(__LITTLE_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+# define FR_LITTLE_ENDIAN 1
+# elif defined(__BIG_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+# define FR_BIG_ENDIAN 1
+# else
+# error Failed determining endianness of system
+# endif
+#endif
+
+#define PRINTF_LIKE(n) CC_HINT(format(printf, n, n+1))
+#define NEVER_RETURNS CC_HINT(noreturn)
+#define HIDDEN CC_HINT(visibility("hidden"))
+#define UNUSED CC_HINT(unused)
+#define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _BUILD_H */
diff --git a/src/include/channel.h b/src/include/channel.h
new file mode 100644
index 0000000..5b2d7d5
--- /dev/null
+++ b/src/include/channel.h
@@ -0,0 +1,55 @@
+#ifndef CHANNEL_H
+#define CHANNEL_H
+
+/*
+ * channel.h For radmin / server channels.
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2015 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(heap_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum fr_channel_type_t {
+ FR_CHANNEL_STDIN = 0,
+ FR_CHANNEL_STDOUT,
+ FR_CHANNEL_STDERR,
+ FR_CHANNEL_CMD_STATUS,
+ FR_CHANNEL_INIT_ACK,
+ FR_CHANNEL_AUTH_CHALLENGE,
+ FR_CHANNEL_AUTH_RESPONSE,
+ FR_CHANNEL_WANT_MORE
+} fr_channel_type_t;
+
+typedef enum fr_channel_result_t {
+ FR_CHANNEL_FAIL = 0,
+ FR_CHANNEL_SUCCESS
+} fr_channel_result_t;
+
+ssize_t fr_channel_drain(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen, uint8_t **outbuf, size_t have_read);
+ssize_t fr_channel_read(int fd, fr_channel_type_t *pchannel, void *buffer, size_t buflen);
+ssize_t fr_channel_write(int fd, fr_channel_type_t channel, void const *buffer, size_t buflen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CHANNEL_H */
diff --git a/src/include/clients.h b/src/include/clients.h
new file mode 100644
index 0000000..46b5b3b
--- /dev/null
+++ b/src/include/clients.h
@@ -0,0 +1,174 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version. either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef CLIENTS_H
+#define CLIENTS_H
+/*
+ * $Id$
+ *
+ * @file clients.h
+ * @brief Function declarations and structures to manage clients.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2015 The FreeRADIUS server project
+ */
+
+typedef struct radclient_list RADCLIENT_LIST;
+
+
+/** Describes a host allowed to send packets to the server
+ *
+ */
+typedef struct radclient {
+ RADCLIENT_LIST *list; //!< parent list
+ fr_ipaddr_t ipaddr; //!< IPv4/IPv6 address of the host.
+ fr_ipaddr_t src_ipaddr; //!< IPv4/IPv6 address to send responses
+ //!< from (family must match ipaddr).
+
+ char const *longname; //!< Client identifier.
+ char const *shortname; //!< Client nickname.
+
+ char const *secret; //!< Secret PSK.
+
+ bool message_authenticator; //!< Require RADIUS message authenticator in requests.
+
+ char const *nas_type; //!< Type of client (arbitrary).
+
+ char const *login; //!< Username to use for simultaneous use checks.
+ char const *password; //!< Password to use for simultaneous use checks.
+
+ char const *server; //!< Virtual server client is associated with.
+
+ int number; //!< Unique client number.
+
+ CONF_SECTION *cs; //!< CONF_SECTION that was parsed to generate the client.
+
+#ifdef WITH_STATS
+ fr_stats_t auth; //!< Authentication stats.
+# ifdef WITH_ACCOUNTING
+ fr_stats_t acct; //!< Accounting stats.
+# endif
+# ifdef WITH_COA
+ fr_stats_t coa; //!< Change of Authorization stats.
+ fr_stats_t dsc; //!< Disconnect-Request stats.
+# endif
+#endif
+
+ struct timeval response_window; //!< How long the client has to respond.
+
+ int proto; //!< Protocol number.
+#ifdef WITH_TCP
+ fr_socket_limit_t limit; //!< Connections per client (TCP clients only).
+#endif
+#ifdef WITH_TLS
+ bool tls_required; //!< whether TLS encryption is required.
+
+#ifdef WITH_RADIUSV11
+ char const *radiusv11_name;
+ fr_radiusv11_t radiusv11;
+#endif
+#endif
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ uint32_t lifetime; //!< How long before the client is removed.
+ uint32_t dynamic; //!< Whether the client was dynamically defined.
+ time_t created; //!< When the client was created.
+
+ time_t last_new_client; //!< Used for relate limiting addition and deletion of
+ //!< dynamic clients.
+
+ char const *client_server; //!< Virtual server associated with this dynamic client.
+ //!< Only used where client specifies a network of potential
+ //!< clients.
+
+ bool rate_limit; //!< Where addition of clients should be rate limited.
+ fr_event_t *ev; //!< for deleting dynamic clients
+#endif
+
+#ifdef WITH_COA
+ char const *coa_name; //!< Name of the CoA home server or pool.
+ home_server_t *coa_home_server; //!< The CoA home_server_t the client is associated with.
+ //!< Must be used exclusively from coa_pool.
+ home_pool_t *coa_home_pool; //!< The CoA home_pool_t the client is associated with.
+ //!< Must be used exclusively from coa_server.
+ bool defines_coa_server; //!< Client also defines a home_server.
+#endif
+} RADCLIENT;
+
+/** Callback for retrieving values when building client sections
+ *
+ * Example:
+ @code{.c}
+ int _client_value_cb(char **out, CONF_PAIR const *cp, void *data)
+ {
+ my_result *result = data;
+ char *value;
+
+ value = get_attribute_from_result(result, cf_pair_value(cp));
+ if (!value) {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = talloc_strdup(value);
+ free_attribute(value);
+
+ if (!*out) return -1;
+ return 0;
+ }
+ @endcode
+ *
+ * @param[out] out Where to write a pointer to the talloced value buffer.
+ * @param[in] cp The value of the CONF_PAIR specifies the attribute name to retrieve from the result.
+ * @param[in] data Pointer to the result struct to copy values from.
+ * @return 0 on success -1 on failure.
+ */
+typedef int (*client_value_cb_t)(char **out, CONF_PAIR const *cp, void *data);
+
+RADCLIENT_LIST *client_list_init(CONF_SECTION *cs);
+
+void client_list_free(RADCLIENT_LIST *clients);
+
+RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, bool tls_required);
+
+void client_free(RADCLIENT *client);
+
+bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client);
+
+#ifdef WITH_DYNAMIC_CLIENTS
+void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client);
+
+RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request);
+#endif
+
+int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data);
+
+RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa);
+
+RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char const *secret, char const *shortname,
+ char const *type, char const *server, bool require_ma)
+ CC_HINT(nonnull(2, 3));
+
+RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto);
+
+RADCLIENT *client_findbynumber(RADCLIENT_LIST const *clients, int number);
+
+RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr);
+
+bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c);
+
+RADCLIENT *client_read(char const *filename, int in_server, int flag);
+#endif /* CLIENTS_H */
diff --git a/src/include/conf.h b/src/include/conf.h
new file mode 100644
index 0000000..95005d5
--- /dev/null
+++ b/src/include/conf.h
@@ -0,0 +1,23 @@
+/* Default Database File Names */
+
+#define RADIUS_DIR RADDBDIR
+#define RADACCT_DIR RADIR
+#define L_DST_DIR LOGDIR
+
+#define RADIUS_DICTIONARY "dictionary"
+#define RADIUS_CLIENTS "clients"
+#define RADIUS_NASLIST "naslist"
+#define RADIUS_REALMS "realms"
+
+#define RADUTMP LOGDIR "/radutmp"
+#define SRADUTMP LOGDIR "/sradutmp"
+#define RADWTMP LOGDIR "/radwtmp"
+#define SRADWTMP LOGDIR "/sradwtmp"
+
+#ifdef __APPLE__
+# define LT_SHREXT ".dylib"
+#elif defined (WIN32)
+# define LT_SHREXT ".dll"
+#else
+# define LT_SHREXT ".so"
+#endif
diff --git a/src/include/conffile.h b/src/include/conffile.h
new file mode 100644
index 0000000..b996881
--- /dev/null
+++ b/src/include/conffile.h
@@ -0,0 +1,306 @@
+#ifndef _CONFFILE_H
+#define _CONFFILE_H
+
+/*
+ * conffile.h Defines for the conffile parsing routines.
+ *
+ * Version: $Id$
+ *
+ */
+
+RCSIDH(conffile_h, "$Id$")
+
+#include <stddef.h>
+#include <freeradius-devel/token.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Export the minimum amount of information about these structs
+ */
+typedef struct conf_item CONF_ITEM; //!< Generic configuration element, extended to become
+ ///< a #CONF_PAIR, a #CONF_SECTION or #CONF_DATA.
+typedef struct conf_pair CONF_PAIR; //!< #CONF_ITEM with an attribute, an operator and a value.
+typedef struct conf_part CONF_SECTION; //!< #CONF_ITEM used to group multiple #CONF_PAIR and #CONF_SECTION, together.
+typedef struct conf_data CONF_DATA; //!< #CONF_ITEM used to associate arbitrary data
+ ///< with a #CONF_PAIR or #CONF_SECTION.
+
+
+typedef void conf_type_mismatch; //!< Dummy type used to indicate PW_TYPE_*/C type mismatch.
+typedef void conf_type_invalid; //!< Dummy type used to indicate invalid PW_TYPE_*.
+
+#if defined(HAVE_BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN_TYPES_COMPATIBLE_P)
+/*
+ * Dumb hack for GCC which explodes with lots of errors masking the real
+ * error cause, if we don't use typdefs for these structures.
+ */
+typedef struct timeval _timeval_t;
+
+/** Check the type #_t matches the destination data type
+ *
+ * Validation macro to check the type of the pointer or offset #_p passed in
+ * matches the type #_t of the configuration item.
+ *
+ * Uses various magic builtin precompilation functions, so will likely only
+ * work with recent versions of clang and gcc.
+ *
+ * @note The warnings/errors emitted are usually awful.
+ *
+ * @param _t a #PW_TYPE value with optional PW_TYPE_* flags.
+ * @param _ct data type of global or struct field, obtained with ``__typeof__``.
+ * @param _p Pointer or offset.
+ */
+# define FR_CONF_TYPE_CHECK(_t, _ct, _p) \
+ __builtin_choose_expr((_t & PW_TYPE_TMPL),\
+ __builtin_choose_expr(__builtin_types_compatible_p(vp_tmpl_t **, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_STRING),\
+ __builtin_choose_expr(__builtin_types_compatible_p(char const **, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_BOOLEAN),\
+ __builtin_choose_expr(__builtin_types_compatible_p(bool *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SUBSECTION),\
+ _p,\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_INTEGER),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV4_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_DATE),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_ABINARY),\
+ __builtin_choose_expr(__builtin_types_compatible_p(size_t[32/sizeof(size_t)], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_OCTETS),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IFID),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t[8], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV6_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV6_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_BYTE),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SHORT),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint16_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_ETHERNET),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint8_t[6], _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_SIGNED),\
+ __builtin_choose_expr(__builtin_types_compatible_p(int32_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_COMBO_IP_ADDR),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_INTEGER64),\
+ __builtin_choose_expr(__builtin_types_compatible_p(uint64_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_IPV4_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_TIMEVAL),\
+ __builtin_choose_expr(__builtin_types_compatible_p(_timeval_t *, _ct), _p, (conf_type_mismatch) 0),\
+ __builtin_choose_expr((((_t) & 0xff) == PW_TYPE_COMBO_IP_PREFIX),\
+ __builtin_choose_expr(__builtin_types_compatible_p(fr_ipaddr_t *, _ct), _p, (conf_type_mismatch) 0),\
+ (conf_type_invalid) 0\
+ )))))))))))))))))))))
+
+# define FR_CONF_OFFSET(_t, _s, _f) _t, FR_CONF_TYPE_CHECK((_t), __typeof__(&(((_s *)NULL)->_f)), offsetof(_s, _f)), NULL
+# define FR_CONF_POINTER(_t, _p) _t, 0, FR_CONF_TYPE_CHECK((_t), __typeof__(_p), _p)
+# define FR_ITEM_POINTER(_t, _p) _t, FR_CONF_TYPE_CHECK((_t), __typeof__(_p), _p)
+#else
+# define FR_CONF_OFFSET(_t, _s, _f) _t, offsetof(_s, _f), NULL
+# define FR_CONF_POINTER(_t, _p) _t, 0, _p
+# define FR_ITEM_POINTER(_t, _p) _t, _p
+#endif
+
+#define FR_CONF_DEPRECATED(_t, _p, _f) (_t) | PW_TYPE_DEPRECATED, 0, NULL
+
+/*
+ * Instead of putting the information into a configuration structure,
+ * the configuration file routines MAY just parse it directly into
+ * user-supplied variables.
+ */
+#define PW_TYPE_SUBSECTION 102
+
+/** @name #CONF_PARSER type flags
+ *
+ * These flags should be or'd with another PW_TYPE_* value to create validation
+ * rules for the #cf_item_parse function.
+ *
+ * @note File PW_TYPE_FILE_* types have a base type of string, so they're validated
+ * correctly by the config parser.
+ * @{
+ */
+#define PW_TYPE_DEPRECATED (1 << 10) //!< If a matching #CONF_PAIR is found, error out with a deprecated message.
+#define PW_TYPE_REQUIRED (1 << 11) //!< Error out if no matching #CONF_PAIR is found, and no dflt value is set.
+#define PW_TYPE_ATTRIBUTE (1 << 12) //!< Value must resolve to attribute in dict (deprecated, use #PW_TYPE_TMPL).
+#define PW_TYPE_SECRET (1 << 13) //!< Only print value if debug level >= 3.
+
+#define PW_TYPE_FILE_INPUT ((1 << 14) | PW_TYPE_STRING) //!< File matching value must exist, and must be readable.
+#define PW_TYPE_FILE_OUTPUT ((1 << 15) | PW_TYPE_STRING) //!< File matching value must exist, and must be writeable.
+
+#define PW_TYPE_XLAT (1 << 16) //!< string will be dynamically expanded.
+#define PW_TYPE_TMPL (1 << 17) //!< CONF_PAIR should be parsed as a template.
+
+#define PW_TYPE_MULTI (1 << 18) //!< CONF_PAIR can have multiple copies.
+#define PW_TYPE_NOT_EMPTY (1 << 19) //!< CONF_PAIR is required to have a non zero length value.
+#define PW_TYPE_FILE_EXISTS ((1 << 20) | PW_TYPE_STRING) //!< File matching value must exist
+/* @} **/
+
+#define FR_INTEGER_COND_CHECK(_name, _var, _cond, _new)\
+do {\
+ if (!(_cond)) {\
+ WARN("Ignoring \"" _name " = %i\", forcing to \"" _name " = %i\"", _var, _new);\
+ _var = _new;\
+ }\
+} while (0)
+
+#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound) FR_INTEGER_COND_CHECK(_name, _var, (_var _op _bound), _bound)
+
+#define FR_TIMEVAL_BOUND_CHECK(_name, _var, _op, _bound_sec, _bound_usec)\
+do {\
+ struct timeval _bound = {_bound_sec, _bound_usec};\
+ if (!timercmp(_var, &_bound, _op)) {\
+ WARN("Ignoring \"" _name " = %d.%.06d\", forcing to \"" _name " = %d.%06d\"",\
+ (int)(_var)->tv_sec, (int)(_var)->tv_usec,\
+ (int)_bound.tv_sec, (int)_bound.tv_usec);\
+ *_var = _bound;\
+ }\
+} while (0)
+
+#define FR_TIMEVAL_TO_MS(_x) (((_x)->tv_usec * 1000) + ((_x)->tv_sec / 1000))
+extern bool check_config;
+
+/** Defines a #CONF_PAIR to C data type mapping
+ *
+ * Is typically used to define mappings between module sections, and module instance structs.
+ * May also be used to set global configuration options.
+ *
+ * Offset/data values should be set using #FR_CONF_OFFSET or #FR_CONF_POINTER.
+ *
+ * Example with #FR_CONF_OFFSET :
+ @code{.c}
+ static CONF_PARSER module_config[] = {
+ { "example", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, example_instance_t, example), "default_value" },
+ CONF_PARSER_TERMINATOR
+ }
+ @endcode
+ *
+ * Example with #FR_CONF_POINTER :
+ @code{.c}
+ static CONF_PARSER global_config[] = {
+ { "example", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, &my_global), "default_value" },
+ CONF_PARSER_TERMINATOR
+ }
+ @endcode
+ *
+ * @see FR_CONF_OFFSET
+ * @see FR_CONF_POINTER
+ * @see cf_section_parse
+ * @see cf_item_parse
+ */
+typedef struct CONF_PARSER {
+ char const *name; //!< Name of the #CONF_ITEM to parse.
+ int type; //!< A #PW_TYPE value, may be or'd with one or more PW_TYPE_* flags.
+ //!< @see cf_item_parse.
+
+ size_t offset; //!< Relative offset of field or structure to write the parsed value to.
+ //!< When #type is set to #PW_TYPE_SUBSECTION, may be used to specify
+ //!< a base offset to add to all offsets contained within the
+ //!< subsection.
+ //!< @note Must be used exclusively to #data.
+
+ void *data; //!< Pointer to a static variable to write the parsed value to.
+ //!< @note Must be used exclusively to #offset.
+
+ const void *dflt; //!< Default as it would appear in radiusd.conf.
+ //!< When #type is set to #PW_TYPE_SUBSECTION, should be a pointer
+ //!< to the start of another array of #CONF_PARSER structs, forming
+ //!< the subsection.
+} CONF_PARSER;
+
+#define CONF_PARSER_TERMINATOR { NULL, -1, 0, NULL, NULL }
+
+CONF_PAIR *cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
+ FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type);
+CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp);
+void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp);
+
+CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2);
+CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
+ char const *name1, char const *name2, bool copy_meta);
+void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs);
+int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value);
+int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt);
+int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables);
+int cf_section_parse_pass2(CONF_SECTION *, void *base, CONF_PARSER const *variables);
+const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs);
+int cf_file_read(CONF_SECTION *cs, char const *file);
+void cf_file_free(CONF_SECTION *cs);
+
+CONF_PAIR *cf_pair_find(CONF_SECTION const *, char const *name);
+CONF_PAIR *cf_pair_find_next(CONF_SECTION const *, CONF_PAIR const *, char const *name);
+CONF_SECTION *cf_section_find(char const *name);
+CONF_SECTION *cf_section_find_name2(CONF_SECTION const *section,
+ char const *name1, char const *name2);
+CONF_SECTION *cf_section_sub_find(CONF_SECTION const *, char const *name);
+CONF_SECTION *cf_section_sub_find_name2(CONF_SECTION const *, char const *name1, char const *name2);
+char const *cf_section_value_find(CONF_SECTION const *, char const *attr);
+CONF_SECTION *cf_top_section(CONF_SECTION *cs);
+
+void *cf_data_find(CONF_SECTION const *, char const *);
+int cf_data_add(CONF_SECTION *, char const *, void *, void (*)(void *));
+void *cf_data_remove(CONF_SECTION *cs, char const *name);
+
+char const *cf_pair_attr(CONF_PAIR const *pair);
+char const *cf_pair_value(CONF_PAIR const *pair);
+FR_TOKEN cf_pair_operator(CONF_PAIR const *pair);
+FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair);
+FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair);
+VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair);
+char const *cf_section_name1(CONF_SECTION const *cs);
+char const *cf_section_name2(CONF_SECTION const *cs);
+char const *cf_section_name(CONF_SECTION const *cs);
+FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs);
+int dump_config(CONF_SECTION const *cs);
+CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
+ CONF_SECTION const *subsection,
+ char const *name1);
+CONF_SECTION *cf_section_find_next(CONF_SECTION const *section,
+ CONF_SECTION const *subsection,
+ char const *name1);
+int cf_section_lineno(CONF_SECTION const *section);
+int cf_pair_lineno(CONF_PAIR const *pair);
+char const *cf_pair_filename(CONF_PAIR const *pair);
+char const *cf_section_filename(CONF_SECTION const *section);
+CONF_ITEM *cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item);
+int cf_pair_count(CONF_SECTION const *cs);
+CONF_SECTION *cf_item_parent(CONF_ITEM const *ci);
+bool cf_item_is_section(CONF_ITEM const *item);
+bool cf_item_is_pair(CONF_ITEM const *item);
+bool cf_item_is_data(CONF_ITEM const *item);
+CONF_PAIR *cf_item_to_pair(CONF_ITEM const *item);
+CONF_SECTION *cf_item_to_section(CONF_ITEM const *item);
+CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp);
+CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs);
+
+void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+
+void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci);
+CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
+ CONF_SECTION *outercs,
+ char const *ptr);
+
+#define CF_FILE_NONE (0)
+#define CF_FILE_ERROR (1)
+#define CF_FILE_CONFIG (1 << 2)
+#define CF_FILE_MODULE (1 << 3)
+int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback);
+
+extern CONF_SECTION *root_config;
+extern bool cf_new_escape;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONFFILE_H */
diff --git a/src/include/connection.h b/src/include/connection.h
new file mode 100644
index 0000000..1fd4be4
--- /dev/null
+++ b/src/include/connection.h
@@ -0,0 +1,131 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_CONNECTION_H
+#define FR_CONNECTION_H
+/**
+ * $Id$
+ *
+ * @file connection.h
+ * @brief Structures, prototypes and global variables for server connection pools.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ * @copyright 2012 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(connection_h, "$Id$")
+
+#include <freeradius-devel/conffile.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_connection_pool_t fr_connection_pool_t;
+
+/** Create a new connection handle
+ *
+ * This function will be called whenever the connection pool manager needs
+ * to spawn a new connection, and on reconnect.
+ *
+ * Memory should be talloced in the parent context to hold the module's
+ * connection structure. The parent context is allocated in the NULL
+ * context, but will be freed when fr_connection_t is freed.
+ *
+ * There is no delete callback, so operations such as closing sockets and
+ * freeing library connection handles should be done by a destructor attached
+ * to memory allocated beneath ctx.
+ *
+ * @note A function pointer matching this prototype must be passed
+ * to fr_connection_pool_init.
+ *
+ * @param[in,out] ctx to allocate memory in.
+ * @param[in] opaque pointer passed to fr_connection_pool_init.
+ * @return NULL on error, else a connection handle.
+ */
+typedef void *(*fr_connection_create_t)(TALLOC_CTX *ctx, void *opaque);
+
+/** Check a connection handle is still viable
+ *
+ * Should check the state of a connection handle.
+ *
+ * @note NULL may be passed to fr_connection_pool_init, if there is no way to check
+ * the state of a connection handle.
+ * @note Not currently use by connection pool manager.
+ * @param[in] opaque pointer passed to fr_connection_pool_init.
+ * @param[in] connection handle returned by fr_connection_create_t.
+ * @return < 0 on error or if the connection is unusable, else 0.
+ */
+typedef int (*fr_connection_alive_t)(void *opaque, void *connection);
+
+/*
+ * Pool allocation/initialisation
+ */
+fr_connection_pool_t *fr_connection_pool_module_init(CONF_SECTION *module,
+ void *opaque,
+ fr_connection_create_t c,
+ fr_connection_alive_t a,
+ char const *prefix);
+
+/*
+ * Pool getters
+ */
+int fr_connection_pool_get_num(fr_connection_pool_t *pool);
+
+int fr_connection_pool_get_retries(fr_connection_pool_t *pool);
+
+/*
+ * Pool management
+ */
+void fr_connection_pool_free(fr_connection_pool_t *pool);
+
+/*
+ * Connection lifecycle
+ */
+void *fr_connection_get(fr_connection_pool_t *pool);
+
+void fr_connection_release(fr_connection_pool_t *pool, void *conn);
+
+void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn);
+
+int fr_connection_close(fr_connection_pool_t *pool, void *conn, char const *msg);
+
+typedef struct {
+ time_t last_checked; //!< Last time we pruned the connection pool.
+ time_t last_opened; //!< Last time we opened a connection.
+ time_t last_closed; //!< Last time we closed a connection.
+ time_t last_failed; //!< Last time we tried to spawn a connection but failed.
+ time_t last_throttled; //!< Last time we refused to spawn a connection because
+ //!< the last connection failed, or we were already spawning
+ //!< a connection.
+ time_t last_at_max; //!< Last time we hit the maximum number of allowed
+ //!< connections.
+
+ uint64_t opened; //!< Number of connections opened over the lifetime
+ //!< of the pool.
+ uint64_t closed; //!< Number of connections which were closed for this pool
+ uint64_t failed; //!< Number of failed connections for this pool.
+
+ uint32_t num; //!< Number of connections in the pool.
+ uint32_t active; //!< Number of currently reserved connections.
+} fr_connection_pool_stats_t;
+
+fr_connection_pool_stats_t const *fr_connection_pool_stats(CONF_SECTION *cs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_CONNECTION_H*/
diff --git a/src/include/detail.h b/src/include/detail.h
new file mode 100644
index 0000000..5b5539b
--- /dev/null
+++ b/src/include/detail.h
@@ -0,0 +1,97 @@
+#ifndef DETAIL_H
+#define DETAIL_H
+/*
+ * detail.h Routines to handle detail files.
+ *
+ * Version: $Id$
+ *
+ */
+
+RCSIDH(detail_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum detail_state_t {
+ STATE_UNOPENED = 0,
+ STATE_UNLOCKED,
+ STATE_HEADER,
+ STATE_READING,
+ STATE_QUEUED,
+ STATE_RUNNING,
+ STATE_NO_REPLY,
+ STATE_REPLIED
+} detail_state_t;
+
+/*
+ * Allow people to revert to the old behavior if desired.
+ * Also, use the old code if we don't have threads.
+ * FIXME: delete the old (crappy) code, and enable the new
+ * code to work without threads. One thing at a time...
+ */
+#ifndef WITHOUT_DETAIL_THREAD
+# ifdef HAVE_PTHREAD_H
+# define WITH_DETAIL_THREAD (1)
+# endif
+#endif
+
+typedef struct listen_detail_t {
+ fr_event_t *ev; /* has to be first entry (ugh) */
+ char const *name; //!< Identifier used in log messages
+ int delay_time;
+ char const *filename;
+ char const *filename_work;
+
+ TALLOC_CTX *ctx;
+ VALUE_PAIR *vps;
+ int work_fd;
+
+#ifdef WITH_DETAIL_THREAD
+ int master_pipe[2];
+ int child_pipe[2];
+ pthread_t pthread_id;
+#endif
+
+ FILE *fp;
+ off_t offset;
+ detail_state_t state;
+ time_t timestamp;
+ time_t running;
+ fr_ipaddr_t client_ip;
+
+ off_t last_offset;
+ off_t timestamp_offset;
+ bool done_entry; //!< Are we done reading this entry?
+ bool track; //!< Do we track progress through the file?
+
+ uint32_t load_factor; /* 1..100 */
+ uint32_t poll_interval;
+ uint32_t retry_interval;
+
+ int signal;
+ int packets;
+ int tries;
+ bool one_shot;
+ int outstanding;
+ int has_rtt;
+ int srtt;
+ int rttvar;
+ uint32_t counter;
+ struct timeval last_packet;
+ RADCLIENT detail_client;
+} listen_detail_t;
+
+int detail_recv(rad_listen_t *listener);
+int detail_send(rad_listen_t *listener, REQUEST *request);
+void detail_free(rad_listen_t *this);
+int detail_print(rad_listen_t const *this, char *buffer, size_t bufsize);
+int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request);
+int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request);
+int detail_parse(CONF_SECTION *cs, rad_listen_t *this);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DETAIL_H */
diff --git a/src/include/dhcp.h b/src/include/dhcp.h
new file mode 100644
index 0000000..01fa781
--- /dev/null
+++ b/src/include/dhcp.h
@@ -0,0 +1,85 @@
+#ifndef FR_DHCP_H
+#define FR_DHCP_H
+
+/*
+ * dhcp.h Structures and prototypes for DHCP.
+ * Why DHCP in a RADIUS server?
+ * Why not?
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+RCSIDH(dhcp_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Not for production use.
+ */
+RADIUS_PACKET *fr_dhcp_recv(int sockfd);
+int fr_dhcp_send(RADIUS_PACKET *packet);
+
+int fr_dhcp_add_arp_entry(int fd, char const *interface, VALUE_PAIR *hwvp, VALUE_PAIR *clvp);
+
+int8_t fr_dhcp_attr_cmp(void const *a, void const *b);
+ssize_t fr_dhcp_encode_option(TALLOC_CTX *ctx, uint8_t *out, size_t outlen, vp_cursor_t *cursor);
+int fr_dhcp_encode(RADIUS_PACKET *packet);
+ssize_t fr_dhcp_decode_options(TALLOC_CTX *ctx, VALUE_PAIR **out, uint8_t const *data, size_t len);
+int fr_dhcp_decode(RADIUS_PACKET *packet);
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+#include <linux/if_packet.h>
+int fr_socket_packet(int iface_index, struct sockaddr_ll *p_ll);
+int fr_dhcp_send_raw_packet(int sockfd, struct sockaddr_ll *p_ll, RADIUS_PACKET *packet);
+RADIUS_PACKET *fr_dhcp_recv_raw_packet(int sockfd, struct sockaddr_ll *p_ll, RADIUS_PACKET *request);
+#endif
+
+/*
+ * This is a horrible hack.
+ */
+#define PW_DHCP_OFFSET (1024)
+#define PW_DHCP_DISCOVER (1024 + 1)
+#define PW_DHCP_OFFER (1024 + 2)
+#define PW_DHCP_REQUEST (1024 + 3)
+#define PW_DHCP_DECLINE (1024 + 4)
+#define PW_DHCP_ACK (1024 + 5)
+#define PW_DHCP_NAK (1024 + 6)
+#define PW_DHCP_RELEASE (1024 + 7)
+#define PW_DHCP_INFORM (1024 + 8)
+#define PW_DHCP_LEASE_QUERY (1024 + 10)
+
+#define DHCP_MAGIC_VENDOR (54)
+
+#define PW_DHCP_OPTION_82 (82)
+#define DHCP_PACK_OPTION1(x,y) ((x) | ((y) << 8))
+#define DHCP_BASE_ATTR(x) (x & 0xff)
+#define DHCP_UNPACK_OPTION1(x) (((x) & 0xff00) >> 8)
+
+#define PW_DHCP_MESSAGE_TYPE (53)
+#define PW_DHCP_YOUR_IP_ADDRESS (264)
+#define PW_DHCP_SUBNET_MASK (1)
+#define PW_DHCP_IP_ADDRESS_LEASE_TIME (51)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_DHCP_H */
diff --git a/src/include/event.h b/src/include/event.h
new file mode 100644
index 0000000..0409728
--- /dev/null
+++ b/src/include/event.h
@@ -0,0 +1,67 @@
+#ifndef FR_EVENT_H
+#define FR_EVENT_H
+
+/*
+ * event.h Simple event queue
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(event_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_event_list_t fr_event_list_t;
+typedef struct fr_event_t fr_event_t;
+
+typedef void (*fr_event_callback_t)(void *);
+typedef void (*fr_event_status_t)(struct timeval *);
+typedef void (*fr_event_fd_handler_t)(fr_event_list_t *el, int sock, void *ctx);
+
+fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status);
+
+int fr_event_list_num_fds(fr_event_list_t *el);
+int fr_event_list_num_elements(fr_event_list_t *el);
+
+int fr_event_insert(fr_event_list_t *el,
+ fr_event_callback_t callback,
+ void *ctx, struct timeval *when, fr_event_t **parent);
+int fr_event_delete(fr_event_list_t *el, fr_event_t **parent);
+
+int fr_event_run(fr_event_list_t *el, struct timeval *when);
+
+int fr_event_now(fr_event_list_t *el, struct timeval *when);
+
+int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
+ fr_event_fd_handler_t handler, void *ctx);
+int fr_event_fd_write_handler(fr_event_list_t *el, int type, int fd,
+ fr_event_fd_handler_t write_handler, void *ctx);
+int fr_event_fd_delete(fr_event_list_t *el, int type, int fd);
+int fr_event_loop(fr_event_list_t *el);
+void fr_event_loop_exit(fr_event_list_t *el, int code);
+bool fr_event_loop_exiting(fr_event_list_t *el);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_HASH_H */
diff --git a/src/include/exfile.h b/src/include/exfile.h
new file mode 100644
index 0000000..febe2e6
--- /dev/null
+++ b/src/include/exfile.h
@@ -0,0 +1,45 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef EXFILE_H
+#define EXFILE_H
+/*
+ * $Id$
+ *
+ * @file exfile.h
+ * @brief Functions for managing concurrent file access.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSIDH(exfile_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Multiple threads logging to one or more files.
+ */
+typedef struct exfile_t exfile_t;
+
+exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t entries, uint32_t idle, bool locking);
+int exfile_open(exfile_t *lf, char const *filename, mode_t permissions, off_t *offset);
+int exfile_close(exfile_t *lf, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/features-h b/src/include/features-h
new file mode 100644
index 0000000..158541f
--- /dev/null
+++ b/src/include/features-h
@@ -0,0 +1,97 @@
+/*
+ * New defines for minimizing the size of the server, to strip
+ * out functionality.
+ *
+ * This is a hack and should be removed when the protocols are moved
+ * into individual modules.
+ */
+#ifndef WITHOUT_PROXY
+# define WITH_PROXY (1)
+#else
+# define WITHOUT_COA (1)
+#endif
+
+#ifndef WITHOUT_UNLANG
+# define WITH_UNLANG (1)
+#endif
+
+#ifndef WITHOUT_ACCOUNTING
+# define WITH_ACCOUNTING (1)
+#endif
+
+#ifdef WITH_ACCOUNTING
+# ifndef WITHOUT_DETAIL
+# define WITH_DETAIL (1)
+# endif
+#endif
+
+#ifdef WITH_ACCOUNTING
+# ifndef WITHOUT_SESSION_MGMT
+# define WITH_SESSION_MGMT (1)
+# endif
+#endif
+
+#ifndef WITHOUT_DYNAMIC_CLIENTS
+# define WITH_DYNAMIC_CLIENTS (1)
+#endif
+
+#ifndef WITHOUT_STATS
+# define WITH_STATS
+#endif
+
+#ifndef WITHOUT_COMMAND_SOCKET
+# ifdef HAVE_SYS_UN_H
+# define WITH_COMMAND_SOCKET (1)
+# endif
+#endif
+
+#ifndef WITHOUT_COA
+# define WITH_COA (1)
+# ifndef WITH_PROXY
+# error WITH_COA requires WITH_PROXY
+# endif
+#endif
+
+#ifdef WITHOUT_TLS
+# ifndef HAVE_OPENSSL_SSL_H
+# error TLS requires OpenSSL
+# endif
+#else
+# ifdef HAVE_OPENSSL_SSL_H
+# ifndef WITH_TLS
+# ifndef NO_OPENSSL
+# define WITH_TLS (1)
+# endif
+# endif
+# endif
+#endif
+
+#ifdef WITH_TLS
+# ifdef WITH_COA
+# ifndef WITHOUT_COA_TUNNEL
+# define WITH_COA_TUNNEL (1)
+# endif
+# endif
+#endif
+
+#ifdef WITH_COA_TUNNEL
+# ifdef WITHOUT_TLS
+# error Reverse CoA requests requires TLS
+# endif
+#endif
+
+#ifdef WITH_RADIUSV11_ONLY
+# define WITH_RADIUSV11
+#else
+# ifndef WITHOUT_RADIUSV11
+# ifdef WITH_TLS
+//# define WITH_RADIUSV11
+# endif
+# endif
+#endif
+
+#ifdef WITH_RADIUSV11
+# ifndef WITH_TLS
+# error RADIUSv11 requires TLS
+# endif
+#endif
diff --git a/src/include/hash.h b/src/include/hash.h
new file mode 100644
index 0000000..71c8658
--- /dev/null
+++ b/src/include/hash.h
@@ -0,0 +1,75 @@
+#ifndef FR_HASH_H
+#define FR_HASH_H
+
+/*
+ * hash.h Structures and prototypes
+ * for fast hashing.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006 The FreeRADIUS server project
+ */
+
+RCSIDH(hash_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Fast hash, which isn't too bad. Don't use for cryptography,
+ * just for hashing internal data.
+ */
+uint32_t fr_hash(void const *, size_t);
+uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash);
+uint32_t fr_hash_string(char const *p);
+
+typedef struct fr_hash_table_t fr_hash_table_t;
+typedef void (*fr_hash_table_free_t)(void *);
+typedef uint32_t (*fr_hash_table_hash_t)(void const *);
+typedef int (*fr_hash_table_cmp_t)(void const *, void const *);
+typedef int (*fr_hash_table_walk_t)(void * /* ctx */, void * /* data */);
+
+fr_hash_table_t *fr_hash_table_create(fr_hash_table_hash_t hashNode,
+ fr_hash_table_cmp_t cmpNode,
+ fr_hash_table_free_t freeNode);
+void fr_hash_table_free(fr_hash_table_t *ht);
+int fr_hash_table_insert(fr_hash_table_t *ht, void const *data);
+int fr_hash_table_delete(fr_hash_table_t *ht, void const *data);
+void *fr_hash_table_yank(fr_hash_table_t *ht, void const *data);
+int fr_hash_table_replace(fr_hash_table_t *ht, void const *data);
+void *fr_hash_table_finddata(fr_hash_table_t *ht, void const *data);
+int fr_hash_table_num_elements(fr_hash_table_t *ht);
+int fr_hash_table_walk(fr_hash_table_t *ht,
+ fr_hash_table_walk_t callback,
+ void *ctx);
+
+typedef struct fr_hash_entry_s fr_hash_entry_t;
+
+typedef struct fr_hash_iter_s {
+ uint32_t bucket;
+ fr_hash_entry_t *node;
+} fr_hash_iter_t;
+
+void *fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter);
+void *fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_HASH_H */
diff --git a/src/include/heap.h b/src/include/heap.h
new file mode 100644
index 0000000..d980adb
--- /dev/null
+++ b/src/include/heap.h
@@ -0,0 +1,46 @@
+#ifndef LRAD_HEAP_H
+#define LRAD_HEAP_H
+
+/*
+ * heap.h Structures and prototypes for binary heaps.
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 Alan DeKok
+ */
+
+RCSIDH(heap_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*fr_heap_cmp_t)(void const *, void const *);
+
+typedef struct fr_heap_t fr_heap_t;
+fr_heap_t *fr_heap_create(fr_heap_cmp_t cmp, size_t offset);
+void fr_heap_delete(fr_heap_t *hp);
+
+int fr_heap_insert(fr_heap_t *hp, void *data);
+int fr_heap_extract(fr_heap_t *hp, void *data);
+void *fr_heap_peek(fr_heap_t *hp);
+int fr_heap_num_elements(fr_heap_t *hp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LRAD_HEAP_H */
diff --git a/src/include/libradius.h b/src/include/libradius.h
new file mode 100644
index 0000000..777927e
--- /dev/null
+++ b/src/include/libradius.h
@@ -0,0 +1,967 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef LIBRADIUS_H
+#define LIBRADIUS_H
+/*
+ * $Id$
+ *
+ * @file libradius.h
+ * @brief Structures and prototypes for the radius library.
+ *
+ * @copyright 1999-2014 The FreeRADIUS server project
+ */
+RCSIDH(libradius_h, "$Id$")
+
+/*
+ * Compiler hinting macros. Included here for 3rd party consumers
+ * of libradius.h.
+ */
+#include <freeradius-devel/build.h>
+
+/*
+ * Let any external program building against the library know what
+ * features the library was built with.
+ */
+#include <freeradius-devel/features.h>
+
+#ifdef WITHOUT_VERSION_CHECK
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) (0xf4ee4ad3f4ee4ad3))
+# define MAGIC_PREFIX(_x) ((uint8_t) 0x00)
+# define MAGIC_VERSION(_x) ((uint32_t) 0x00000000)
+# define MAGIC_COMMIT(_x) ((uint32_t) 0x00000000)
+#else
+# ifdef RADIUSD_VERSION_COMMIT
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) HEXIFY3(f, RADIUSD_VERSION, RADIUSD_VERSION_COMMIT))
+# else
+# define RADIUSD_MAGIC_NUMBER ((uint64_t) HEXIFY3(f, RADIUSD_VERSION, 00000))
+# endif
+# define MAGIC_PREFIX(_x) ((uint8_t) (_x >> 56))
+# define MAGIC_VERSION(_x) ((uint32_t) ((_x >> 32) & 0x00ffffff))
+# define MAGIC_COMMIT(_x) ((uint32_t) (_x & 0xffffffff))
+#endif
+
+/*
+ * Talloc memory allocation is used in preference to malloc throughout
+ * the libraries and server.
+ */
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#include <talloc.h>
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+/*
+ * Defines signatures for any missing functions.
+ */
+#include <freeradius-devel/missing.h>
+
+/*
+ * Include system headers.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <signal.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <freeradius-devel/threads.h>
+#include <freeradius-devel/radius.h>
+#include <freeradius-devel/token.h>
+#include <freeradius-devel/hash.h>
+#include <freeradius-devel/regex.h>
+
+#ifdef SIZEOF_UNSIGNED_INT
+# if SIZEOF_UNSIGNED_INT != 4
+# error FATAL: sizeof(unsigned int) != 4
+# endif
+#endif
+
+/*
+ * Include for modules.
+ */
+#include <freeradius-devel/sha1.h>
+#include <freeradius-devel/md4.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HAVE_SIG_T
+typedef void (*sig_t)(int);
+#endif
+
+#if defined(WITH_VERIFY_PTR)
+# define FREE_MAGIC (0xF4EEF4EE)
+
+/*
+ * @FIXME
+ * Add if (_x->da) (void) talloc_get_type_abort(_x->da, DICT_ATTR);
+ * to the macro below when dictionaries are talloced.
+ */
+# define VERIFY_VP(_x) fr_pair_verify(__FILE__, __LINE__, _x)
+# define VERIFY_LIST(_x, _name) fr_pair_list_verify(__FILE__, __LINE__, NULL, _x, _name)
+# define VERIFY_PACKET(_x) (void) talloc_get_type_abort(_x, RADIUS_PACKET)
+#else
+/*
+ * Even if were building without WITH_VERIFY_PTR
+ * the pointer must not be NULL when these various macros are used
+ * so we can add some sneaky soft asserts.
+ */
+# define VERIFY_VP(_x) fr_assert(_x)
+# define VERIFY_LIST(_x, _name) fr_assert(_x)
+# define VERIFY_PACKET(_x) fr_assert(_x)
+#endif
+
+#define AUTH_VECTOR_LEN 16
+#define CHAP_VALUE_LENGTH 16
+#define MAX_STRING_LEN 254 /* RFC2138: string 0-253 octets */
+#define FR_MAX_VENDOR (1 << 24) /* RFC limitations */
+
+#ifdef _LIBRADIUS
+# define RADIUS_HDR_LEN 20
+# define VENDORPEC_USR 429
+# define VENDORPEC_LUCENT 4846
+# define VENDORPEC_STARENT 8164
+# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
+#endif
+
+# define debug_pair(vp) do { if (fr_debug_lvl && fr_log_fp) { \
+ vp_print(fr_log_fp, vp); \
+ } \
+ } while(0)
+
+#define TAG_VALID(x) ((x) > 0 && (x) < 0x20)
+#define TAG_VALID_ZERO(x) ((x) < 0x20)
+#define TAG_ANY INT8_MIN
+#define TAG_NONE 0
+/** Check if tags are equal
+ *
+ * @param _x tag were matching on.
+ * @param _y tag belonging to the attribute were checking.
+ */
+#define TAG_EQ(_x, _y) ((_x == _y) || (_x == TAG_ANY) || ((_x == TAG_NONE) && (_y == TAG_ANY)))
+#define ATTRIBUTE_EQ(_x, _y) ((_x && _y) && (_x->da == _y->da) && (!_x->da->flags.has_tag || TAG_EQ(_x->tag, _y->tag)))
+
+#define NUM_ANY INT_MIN
+#define NUM_ALL (INT_MIN + 1)
+#define NUM_COUNT (INT_MIN + 2)
+#define NUM_LAST (INT_MIN + 3)
+
+#define PAD(_x, _y) (_y - ((_x) % _y))
+
+typedef struct attr_flags {
+ unsigned int is_unknown : 1; //!< Attribute number or vendor is unknown.
+ unsigned int is_tlv : 1; //!< Is a sub attribute.
+
+ unsigned int has_tag : 1; //!< Tagged attribute.
+ unsigned int array : 1; //!< Pack multiples into 1 attr.
+ unsigned int has_value : 1; //!< Has a value.
+ unsigned int has_value_alias : 1; //!< Has a value alias.
+ unsigned int has_tlv : 1; //!< Has sub attributes.
+
+ unsigned int extended : 1; //!< Extended attribute.
+ unsigned int long_extended : 1; //!< Long format.
+ unsigned int evs : 1; //!< Extended VSA.
+ unsigned int wimax: 1; //!< WiMAX format=1,1,c.
+
+ unsigned int concat : 1; //!< concatenate multiple instances
+ unsigned int is_pointer : 1; //!< data is a pointer
+
+ unsigned int virtual : 1; //!< for dynamic expansion
+
+ unsigned int compare : 1; //!< has a paircompare registered
+
+ unsigned int is_dup : 1; //!< is a duplicate of another attribute
+
+ unsigned int secret : 1; //!< is a secret thingy
+
+ uint8_t encrypt; //!< Ecryption method.
+ uint8_t length;
+} ATTR_FLAGS;
+
+/*
+ * Values of the encryption flags.
+ */
+#define FLAG_ENCRYPT_NONE (0)
+#define FLAG_ENCRYPT_USER_PASSWORD (1)
+#define FLAG_ENCRYPT_TUNNEL_PASSWORD (2)
+#define FLAG_ENCRYPT_ASCEND_SECRET (3)
+
+extern const FR_NAME_NUMBER dict_attr_types[];
+extern const size_t dict_attr_sizes[PW_TYPE_MAX][2];
+extern const int fr_attr_max_tlv;
+extern const int fr_attr_shift[];
+extern const unsigned int fr_attr_mask[];
+
+/** dictionary attribute
+ *
+ */
+typedef struct dict_attr {
+ unsigned int attr;
+ PW_TYPE type;
+ unsigned int vendor;
+ ATTR_FLAGS flags;
+ char name[1];
+} DICT_ATTR;
+
+/** value of an enumerated attribute
+ *
+ */
+typedef struct dict_value {
+ unsigned int attr;
+ unsigned int vendor;
+ int value;
+ char name[1];
+} DICT_VALUE;
+
+/** dictionary vendor
+ *
+ */
+typedef struct dict_vendor {
+ unsigned int vendorpec;
+ size_t type; //!< Length of type data
+ size_t length; //!< Length of length data
+ size_t flags;
+ char name[1];
+} DICT_VENDOR;
+
+/** Union containing all data types supported by the server
+ *
+ * This union contains all data types that can be represented by VALUE_PAIRs. It may also be used in other parts
+ * of the server where values of different types need to be stored.
+ *
+ * PW_TYPE should be an enumeration of the values in this union.
+ */
+typedef union value_data {
+ char const *strvalue; //!< Pointer to UTF-8 string.
+ uint8_t const *octets; //!< Pointer to binary string.
+ uint32_t integer; //!< 32bit unsigned integer.
+ struct in_addr ipaddr; //!< IPv4 Address.
+ uint32_t date; //!< Date (32bit Unix timestamp).
+ size_t filter[32/sizeof(size_t)]; //!< Ascend binary format a packed data
+ //!< structure.
+
+ uint8_t ifid[8]; //!< IPv6 interface ID (should be struct?).
+ struct in6_addr ipv6addr; //!< IPv6 Address.
+ uint8_t ipv6prefix[18]; //!< IPv6 prefix (should be struct?).
+
+ uint8_t byte; //!< 8bit unsigned integer.
+ uint16_t ushort; //!< 16bit unsigned integer.
+
+ uint8_t ether[6]; //!< Ethernet (MAC) address.
+
+ int32_t sinteger; //!< 32bit signed integer.
+ uint64_t integer64; //!< 64bit unsigned integer.
+
+ uint8_t ipv4prefix[6]; //!< IPv4 prefix (should be struct?).
+
+ void *ptr; //!< generic pointer.
+} value_data_t;
+
+/** The type of value a VALUE_PAIR contains
+ *
+ * This is used to add structure to nested VALUE_PAIRs and specifies what type of node it is (set, list, data).
+ *
+ * xlat is another type of data node which must first be expanded before use.
+ */
+typedef enum value_type {
+ VT_NONE = 0, //!< VALUE_PAIR has no value.
+ VT_SET, //!< VALUE_PAIR has children.
+ VT_LIST, //!< VALUE_PAIR has multiple values.
+ VT_DATA, //!< VALUE_PAIR has a single value.
+ VT_XLAT //!< valuepair value must be xlat expanded when it's
+ //!< added to VALUE_PAIR tree.
+} value_type_t;
+
+/** Stores an attribute, a value and various bits of other data
+ *
+ * VALUE_PAIRs are the main data structure used in the server
+ *
+ * They also specify what behaviour should be used when the attribute is merged into a new list/tree.
+ */
+typedef struct value_pair {
+ DICT_ATTR const *da; //!< Dictionary attribute defines the attribute
+ //!< number, vendor and type of the attribute.
+
+ struct value_pair *next;
+
+ FR_TOKEN op; //!< Operator to use when moving or inserting
+ //!< valuepair into a list.
+
+ int8_t tag; //!< Tag value used to group valuepairs.
+
+ union {
+ // VALUE_SET *set; //!< Set of child attributes.
+ // VALUE_LIST *list; //!< List of values for
+ //!< multivalued attribute.
+ // value_data_t *data; //!< Value data for this attribute.
+
+ char const *xlat; //!< Source string for xlat expansion.
+ } value;
+
+ value_type_t type; //!< Type of pointer in value union.
+
+ size_t length; //!< of Data field.
+ value_data_t data;
+} VALUE_PAIR;
+
+/** Abstraction to allow iterating over different configurations of VALUE_PAIRs
+ *
+ * This allows functions which do not care about the structure of collections of VALUE_PAIRs
+ * to iterate over all members in a collection.
+ *
+ * Field within a vp_cursor should not be accessed directly, and vp_cursors should only be
+ * manipulated with the pair* functions.
+ */
+typedef struct vp_cursor {
+ VALUE_PAIR **first;
+ VALUE_PAIR *found; //!< pairfind marker.
+ VALUE_PAIR *last; //!< Temporary only used for fr_cursor_insert
+ VALUE_PAIR *current; //!< The current attribute.
+ VALUE_PAIR *next; //!< Next attribute to process.
+} vp_cursor_t;
+
+/** A VALUE_PAIR in string format.
+ *
+ * Used to represent pairs in the legacy 'users' file format.
+ */
+typedef struct value_pair_raw {
+ char l_opand[256]; //!< Left hand side of the pair.
+ char r_opand[1024]; //!< Right hand side of the pair.
+
+ FR_TOKEN quote; //!< Type of quoting around the r_opand.
+
+ FR_TOKEN op; //!< Operator.
+} VALUE_PAIR_RAW;
+
+#define vp_strvalue data.strvalue
+#define vp_integer data.integer
+#define vp_ipaddr data.ipaddr.s_addr
+#define vp_date data.date
+#define vp_filter data.filter
+#define vp_octets data.octets
+#define vp_ifid data.ifid
+#define vp_ipv6addr data.ipv6addr
+#define vp_ipv6prefix data.ipv6prefix
+#define vp_byte data.byte
+#define vp_short data.ushort
+#define vp_ether data.ether
+#define vp_signed data.sinteger
+#define vp_integer64 data.integer64
+#define vp_ipv4prefix data.ipv4prefix
+#define vp_length length
+
+typedef struct fr_ipaddr_t {
+ int af; /* address family */
+ union {
+ struct in_addr ip4addr;
+ struct in6_addr ip6addr; /* maybe defined in missing.h */
+ } ipaddr;
+ uint8_t prefix;
+ uint32_t scope; /* for IPv6 */
+} fr_ipaddr_t;
+
+/*
+ * vector: Request authenticator from access-request packet
+ * Put in there by rad_decode, and must be put in the
+ * response RADIUS_PACKET as well before calling rad_send
+ *
+ * verified: Filled in by rad_decode for accounting-request packets
+ *
+ * data,data_len: Used between rad_recv and rad_decode.
+ */
+typedef struct radius_packet {
+ int sockfd;
+ fr_ipaddr_t src_ipaddr;
+ fr_ipaddr_t dst_ipaddr;
+ uint16_t src_port;
+ uint16_t dst_port;
+ int id;
+ unsigned int code;
+ uint8_t vector[AUTH_VECTOR_LEN];
+ struct timeval timestamp;
+ uint8_t *data;
+ size_t data_len;
+ VALUE_PAIR *vps;
+ ssize_t offset;
+#ifdef WITH_TCP
+ size_t partial;
+ int proto;
+#endif
+#ifdef WITH_RADIUSV11
+ bool radiusv11;
+#endif
+} RADIUS_PACKET;
+
+typedef enum {
+ DECODE_FAIL_NONE = 0,
+ DECODE_FAIL_MIN_LENGTH_PACKET,
+ DECODE_FAIL_MIN_LENGTH_FIELD,
+ DECODE_FAIL_MIN_LENGTH_MISMATCH,
+ DECODE_FAIL_HEADER_OVERFLOW,
+ DECODE_FAIL_UNKNOWN_PACKET_CODE,
+ DECODE_FAIL_INVALID_ATTRIBUTE,
+ DECODE_FAIL_ATTRIBUTE_TOO_SHORT,
+ DECODE_FAIL_ATTRIBUTE_OVERFLOW,
+ DECODE_FAIL_MA_INVALID_LENGTH,
+ DECODE_FAIL_ATTRIBUTE_UNDERFLOW,
+ DECODE_FAIL_TOO_MANY_ATTRIBUTES,
+ DECODE_FAIL_MA_MISSING,
+ DECODE_FAIL_TOO_MANY_AUTH,
+ DECODE_FAIL_MAX
+} decode_fail_t;
+
+#ifdef WITH_RADIUSV11
+typedef enum {
+ FR_RADIUSV11_FORBID = 0,
+ FR_RADIUSV11_ALLOW,
+ FR_RADIUSV11_REQUIRE,
+} fr_radiusv11_t;
+
+extern const FR_NAME_NUMBER radiusv11_types[];
+#endif
+
+/*
+ * Version check.
+ */
+int fr_check_lib_magic(uint64_t magic);
+
+/*
+ * Printing functions.
+ */
+int fr_utf8_char(uint8_t const *str, ssize_t inlen);
+char const *fr_utf8_strchr(int *chr_len, char const *str, char const *chr);
+size_t fr_prints(char *out, size_t outlen, char const *in, ssize_t inlen, char quote);
+size_t fr_prints_len(char const *in, ssize_t inlen, char quote);
+char *fr_aprints(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote);
+
+#define is_truncated(_ret, _max) ((_ret) >= (_max))
+#define truncate_len(_ret, _max) (((_ret) >= (_max)) ? ((_max) - 1) : _ret)
+size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, char quote);
+
+
+char *vp_aprints_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote);
+
+size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp, bool raw_value);
+size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp);
+void vp_print(FILE *, VALUE_PAIR const *);
+void vp_printlist(FILE *, VALUE_PAIR const *);
+char *vp_aprints_type(TALLOC_CTX *ctx, PW_TYPE type);
+
+char *vp_aprints(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote);
+#define fprint_attr_val vp_print
+
+/*
+ * Dictionary functions.
+ */
+#define DICT_VALUE_MAX_NAME_LEN (128)
+#define DICT_VENDOR_MAX_NAME_LEN (128)
+#define DICT_ATTR_MAX_NAME_LEN (128)
+
+#define DICT_ATTR_SIZE sizeof(DICT_ATTR) + DICT_ATTR_MAX_NAME_LEN
+
+extern const int dict_attr_allowed_chars[256];
+int dict_valid_name(char const *name);
+int str2argv(char *str, char **argv, int max_argc);
+int dict_str2oid(char const *ptr, unsigned int *pattr,
+ unsigned int *pvendor, int tlv_depth);
+int dict_addvendor(char const *name, unsigned int value);
+int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type, ATTR_FLAGS flags);
+int dict_addvalue(char const *namestr, char const *attrstr, int value);
+int dict_init(char const *dir, char const *fn);
+void dict_free(void);
+int dict_read(char const *dir, char const *filename);
+size_t dict_print_oid(char *buffer, size_t buflen, DICT_ATTR const *da);
+int dict_walk(fr_hash_table_walk_t callback, void *context);
+
+void dict_attr_free(DICT_ATTR const **da);
+int dict_unknown_from_fields(DICT_ATTR *da, unsigned int attr, unsigned int vendor);
+DICT_ATTR const *dict_unknown_afrom_fields(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor);
+int dict_unknown_from_str(DICT_ATTR *da, char const *name);
+int dict_unknown_from_substr(DICT_ATTR *da, char const **name);
+DICT_ATTR const *dict_unknown_afrom_str(TALLOC_CTX *ctx, char const *name);
+DICT_ATTR const *dict_unknown_add(DICT_ATTR const *old);
+
+DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor);
+DICT_ATTR const *dict_attrbyname(char const *attr);
+DICT_ATTR const *dict_attrbyname_substr(char const **name);
+DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
+ PW_TYPE type);
+DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr,
+ unsigned int vendor);
+DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor);
+int dict_attr_child(DICT_ATTR const *parent,
+ unsigned int *pattr, unsigned int *pvendor);
+DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int val);
+DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, char const *val);
+char const *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value);
+int dict_vendorbyname(char const *name);
+DICT_VENDOR *dict_vendorbyvalue(int vendor);
+
+#if 1 /* FIXME: compat */
+#define dict_attrget dict_attrbyvalue
+#define dict_attrfind dict_attrbyname
+#define dict_valfind dict_valbyname
+/*#define dict_valget dict_valbyattr almost but not quite*/
+#endif
+
+/* radius.c */
+int rad_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret);
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason);
+RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags);
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code);
+void rad_recv_discard(int sockfd);
+int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
+ char const *secret);
+int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret);
+int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret);
+int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret);
+
+int rad_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length);
+RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, bool new_vector);
+RADIUS_PACKET *rad_alloc_reply(TALLOC_CTX *ctx, RADIUS_PACKET *);
+RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in);
+
+void rad_free(RADIUS_PACKET **);
+
+#ifndef WITH_RADIUSV11_ONLY
+int rad_pwencode(char *encpw, size_t *len, char const *secret,
+ uint8_t const *vector);
+int rad_pwdecode(char *encpw, size_t len, char const *secret,
+ uint8_t const *vector);
+
+#define FR_TUNNEL_PW_ENC_LENGTH(_x) (2 + 1 + _x + PAD(_x + 1, 16))
+ssize_t rad_tunnel_pwencode(char *encpw, size_t *len, char const *secret,
+ uint8_t const *vector);
+ssize_t rad_tunnel_pwdecode(uint8_t *encpw, size_t *len,
+ char const *secret, uint8_t const *vector);
+int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output,
+ int id, VALUE_PAIR *password);
+#endif
+
+int rad_attr_ok(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ DICT_ATTR *da, uint8_t const *data, size_t length);
+int rad_tlv_ok(uint8_t const *data, size_t length,
+ size_t dv_type, size_t dv_length);
+
+ssize_t data2vp(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_attr2vp(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ uint8_t const *data, size_t length,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_data2vp_tlvs(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret, DICT_ATTR const *da,
+ uint8_t const *start, size_t length,
+ VALUE_PAIR **pvp);
+
+ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp);
+
+int rad_vp2extended(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+int rad_vp2wimax(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+
+int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp, uint8_t *start,
+ size_t room);
+
+int rad_vp2rfc(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room);
+
+int rad_vp2attr(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original, char const *secret,
+ VALUE_PAIR const **pvp, uint8_t *ptr, size_t room);
+
+/* pair.c */
+VALUE_PAIR *fr_pair_alloc(TALLOC_CTX *ctx);
+VALUE_PAIR *fr_pair_afrom_da(TALLOC_CTX *ctx, DICT_ATTR const *da);
+VALUE_PAIR *fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor);
+int fr_pair_to_unknown(VALUE_PAIR *vp);
+void fr_pair_list_free(VALUE_PAIR **);
+VALUE_PAIR *fr_pair_find_by_num(VALUE_PAIR *, unsigned int attr, unsigned int vendor, int8_t tag);
+VALUE_PAIR *fr_pair_find_by_da(VALUE_PAIR *, DICT_ATTR const *da, int8_t tag);
+
+VALUE_PAIR *fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR * const *node);
+void fr_cursor_copy(vp_cursor_t *out, vp_cursor_t *in);
+VALUE_PAIR *fr_cursor_first(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_last(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag);
+
+VALUE_PAIR *fr_cursor_next_by_da(vp_cursor_t *cursor, DICT_ATTR const *da, int8_t tag)
+ CC_HINT(nonnull);
+
+VALUE_PAIR *fr_cursor_next(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_next_peek(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_current(vp_cursor_t *cursor);
+void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp);
+void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp);
+VALUE_PAIR *fr_cursor_remove(vp_cursor_t *cursor);
+VALUE_PAIR *fr_cursor_replace(vp_cursor_t *cursor, VALUE_PAIR *new);
+void fr_pair_delete_by_num(VALUE_PAIR **, unsigned int attr, unsigned int vendor, int8_t tag);
+void fr_pair_delete_by_da(VALUE_PAIR **first, DICT_ATTR const *da);
+void fr_pair_add(VALUE_PAIR **, VALUE_PAIR *);
+void fr_pair_prepend(VALUE_PAIR **, VALUE_PAIR *);
+void fr_pair_replace(VALUE_PAIR **first, VALUE_PAIR *add);
+int fr_pair_cmp(VALUE_PAIR *a, VALUE_PAIR *b);
+int fr_pair_list_cmp(VALUE_PAIR *a, VALUE_PAIR *b);
+
+typedef int8_t (*fr_cmp_t)(void const *a, void const *b);
+int8_t attrcmp(void const *a, void const *b);
+int8_t fr_pair_cmp_by_da_tag(void const *a, void const *b);
+void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp);
+void fr_pair_validate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2]);
+bool fr_pair_validate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list);
+bool fr_pair_validate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list);
+VALUE_PAIR *fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp);
+VALUE_PAIR *fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from);
+VALUE_PAIR *fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int attr, unsigned int vendor, int8_t tag);
+void fr_pair_steal(TALLOC_CTX *ctx, VALUE_PAIR *vp);
+void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const * src, size_t len);
+void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src);
+void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src);
+void fr_pair_value_strcpy(VALUE_PAIR *vp, char const * src);
+void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const * src, size_t len);
+void fr_pair_value_sprintf(VALUE_PAIR *vp, char const * fmt, ...) CC_HINT(format (printf, 2, 3));
+void fr_pair_list_move(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, FR_TOKEN op);
+void fr_pair_list_move_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
+ unsigned int attr, unsigned int vendor, int8_t tag);
+void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
+ unsigned int attr, unsigned int vendor, int8_t tag);
+VALUE_PAIR *fr_pair_afrom_ip_str(TALLOC_CTX *ctx, char const *value,
+ DICT_ATTR *ipv4, DICT_ATTR *ipv6, DICT_ATTR *ipv4_prefix, DICT_ATTR *ipv6_prefix);
+int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t len);
+VALUE_PAIR *fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op);
+int fr_pair_mark_xlat(VALUE_PAIR *vp, char const *value);
+FR_TOKEN fr_pair_raw_from_str(char const **ptr, VALUE_PAIR_RAW *raw);
+FR_TOKEN fr_pair_list_afrom_str(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **head);
+int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone);
+
+
+/** Compare two attributes using and operator.
+ *
+ * @return 1 if equal, 0 if not eaqual, -1 on error.
+ */
+#define fr_pair_cmp_op(_op, _a, _b) value_data_cmp_op(_op, _a->da->type, &_a->data, _a->vp_length, _b->da->type, &_b->data, _b->vp_length)
+
+/* value.c */
+int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
+ PW_TYPE b_type, value_data_t const *b, size_t b_len);
+
+int value_data_cmp_op(FR_TOKEN op,
+ PW_TYPE a_type, value_data_t const *a, size_t a_len,
+ PW_TYPE b_type, value_data_t const *b, size_t b_len);
+
+ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
+ PW_TYPE *src_type, DICT_ATTR const *src_enumv,
+ char const *src, ssize_t src_len, char quote);
+
+ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
+ PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
+ PW_TYPE src_type, DICT_ATTR const *src_enumv,
+ value_data_t const *src, size_t src_len);
+
+ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type,
+ const value_data_t *src, size_t src_len);
+
+size_t value_data_prints(char *out, size_t outlen,
+ PW_TYPE type, DICT_ATTR const *enumv,
+ value_data_t const *data, ssize_t inlen, char quote);
+
+char *value_data_aprints(TALLOC_CTX *ctx,
+ PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
+ size_t inlen, char quote);
+
+/*
+ * Error functions.
+ */
+void fr_strerror_printf(char const *, ...) CC_HINT(format (printf, 1, 2));
+void fr_perror(char const *, ...) CC_HINT(format (printf, 1, 2));
+
+
+char const *fr_strerror(void);
+char const *fr_syserror(int num);
+extern bool fr_dns_lookups; /* do IP -> hostname lookups? */
+extern bool fr_hostname_lookups; /* do hostname -> IP lookups? */
+extern int fr_debug_lvl; /* 0 = no debugging information */
+extern uint32_t fr_max_attributes; /* per incoming packet */
+#define FR_MAX_PACKET_CODE (52)
+extern char const *fr_packet_codes[FR_MAX_PACKET_CODE];
+#define is_radius_code(_x) ((_x > 0) && (_x < FR_MAX_PACKET_CODE))
+extern FILE *fr_log_fp;
+void rad_print_hex(RADIUS_PACKET const *packet);
+void fr_printf_log(char const *, ...) CC_HINT(format (printf, 1, 2));
+
+/*
+ * Several handy miscellaneous functions.
+ */
+int fr_set_signal(int sig, sig_t func);
+int fr_unset_signal(int sig);
+int fr_link_talloc_ctx_free(TALLOC_CTX *parent, TALLOC_CTX *child);
+char const *fr_inet_ntop(int af, void const *src);
+char const *ip_ntoa(char *, uint32_t);
+int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback);
+int fr_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback);
+int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve);
+int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af,
+ bool resolve);
+int fr_ntop(char *out, size_t outlen, fr_ipaddr_t const *addr);
+char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid);
+uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid);
+int rad_lockfd(int fd, int lock_len);
+int rad_lockfd_nonblock(int fd, int lock_len);
+int rad_unlockfd(int fd, int lock_len);
+char *fr_abin2hex(TALLOC_CTX *ctx, uint8_t const *bin, size_t inlen);
+size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen);
+size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen);
+uint32_t fr_strtoul(char const *value, char **end);
+bool is_whitespace(char const *value);
+bool is_printable(void const *value, size_t len);
+bool is_integer(char const *value);
+bool is_zero(char const *value);
+
+int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b);
+
+int ip_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback);
+char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt);
+struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix);
+struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix);
+void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix);
+int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
+ struct sockaddr_storage *sa, socklen_t *salen);
+int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
+ fr_ipaddr_t *ipaddr, uint16_t *port);
+int fr_nonblock(int fd);
+int fr_blocking(int fd);
+ssize_t fr_writev(int fd, struct iovec[], int iovcnt, struct timeval *timeout);
+
+ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen);
+size_t fr_prints_uint128(char *out, size_t outlen, uint128_t const num);
+int fr_get_time(char const *date_str, time_t *date);
+int8_t fr_pointer_cmp(void const *a, void const *b);
+void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp);
+
+void fr_timeval_from_ms(struct timeval *out, uint64_t ms);
+void fr_timeval_from_usec(struct timeval *out, uint64_t usec);
+
+/*
+ * Define TALLOC_DEBUG to check overflows with talloc.
+ * we can't use valgrind, because the memory used by
+ * talloc is valid memory... just not for us.
+ */
+#ifdef TALLOC_DEBUG
+void fr_talloc_verify_cb(const void *ptr, int depth,
+ int max_depth, int is_ref,
+ void *private_data);
+#define VERIFY_ALL_TALLOC talloc_report_depth_cb(NULL, 0, -1, fr_talloc_verify_cb, NULL)
+#else
+#define VERIFY_ALL_TALLOC
+#endif
+
+#ifdef WITH_ASCEND_BINARY
+/* filters.c */
+int ascend_parse_filter(value_data_t *out, char const *value, size_t len);
+void print_abinary(char *out, size_t outlen, uint8_t const *data, size_t len, int8_t quote);
+#endif /*WITH_ASCEND_BINARY*/
+
+/* random numbers in isaac.c */
+/* context of random number generator */
+typedef struct fr_randctx {
+ uint32_t randcnt;
+ uint32_t randrsl[256];
+ uint32_t randmem[256];
+ uint32_t randa;
+ uint32_t randb;
+ uint32_t randc;
+} fr_randctx;
+
+void fr_isaac(fr_randctx *ctx);
+void fr_randinit(fr_randctx *ctx, int flag);
+uint32_t fr_rand(void); /* like rand(), but better. */
+void fr_rand_seed(void const *, size_t ); /* seed the random pool */
+
+
+/* crypt wrapper from crypt.c */
+int fr_crypt_check(char const *key, char const *salt);
+
+/* cbuff.c */
+
+typedef struct fr_cbuff fr_cbuff_t;
+
+fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock);
+void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj);
+void *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx);
+
+/* debug.c */
+typedef enum {
+ DEBUG_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check.
+ DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP = -2, //!< CAP_SYS_PTRACE not set for the process.
+ DEBUG_STATE_UNKNOWN = -1, //!< Unknown, likely fr_get_debug_state() not called yet.
+ DEBUG_STATE_NOT_ATTACHED = 0, //!< We can attach, so a debugger must not be.
+ DEBUG_STATE_ATTACHED = 1 //!< We can't attach, it's likely a debugger is already tracing.
+} fr_debug_state_t;
+
+#define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
+typedef void (*fr_fault_log_t)(char const *msg, ...) CC_HINT(format (printf, 1, 2));
+extern fr_debug_state_t fr_debug_state;
+
+/** Optional callback passed to fr_fault_setup
+ *
+ * Allows optional logic to be run before calling the main fault handler.
+ *
+ * If the callback returns < 0, the main fault handler will not be called.
+ *
+ * @param signum signal raised.
+ * @return 0 on success < 0 on failure.
+ */
+typedef int (*fr_fault_cb_t)(int signum);
+typedef struct fr_bt_marker fr_bt_marker_t;
+
+void fr_store_debug_state(void);
+char const *fr_debug_state_to_msg(fr_debug_state_t state);
+void fr_debug_break(bool always);
+void backtrace_print(fr_cbuff_t *cbuff, void *obj);
+int fr_backtrace_do(fr_bt_marker_t *marker);
+fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj);
+
+void fr_panic_on_free(TALLOC_CTX *ctx);
+int fr_set_dumpable_init(void);
+int fr_set_dumpable(bool allow_core_dumps);
+int fr_reset_dumpable(void);
+int fr_log_talloc_report(TALLOC_CTX *ctx);
+void fr_fault(int sig);
+void fr_talloc_fault_setup(void);
+int fr_fault_setup(char const *cmd, char const *program);
+void fr_fault_set_cb(fr_fault_cb_t func);
+void fr_fault_set_log_fd(int fd);
+void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2));
+
+# ifdef WITH_VERIFY_PTR
+void fr_pair_verify(char const *file, int line, VALUE_PAIR const *vp);
+void fr_pair_list_verify(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps, char const *name);
+# endif
+
+bool fr_assert_cond(char const *file, int line, char const *expr, bool cond);
+# define fr_assert(_x) fr_assert_cond(__FILE__, __LINE__, #_x, (_x))
+
+void NEVER_RETURNS _fr_exit(char const *file, int line, int status);
+# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x))
+
+void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status);
+# define fr_exit_now(_x) _fr_exit_now(__FILE__, __LINE__, (_x))
+
+/* rbtree.c */
+typedef struct rbtree_t rbtree_t;
+typedef struct rbnode_t rbnode_t;
+
+/* callback order for walking */
+typedef enum {
+ RBTREE_PRE_ORDER,
+ RBTREE_IN_ORDER,
+ RBTREE_POST_ORDER,
+ RBTREE_DELETE_ORDER
+} rb_order_t;
+
+#define RBTREE_FLAG_NONE (0)
+#define RBTREE_FLAG_REPLACE (1 << 0)
+#define RBTREE_FLAG_LOCK (1 << 1)
+
+typedef int (*rb_comparator_t)(void const *ctx, void const *data);
+typedef int (*rb_walker_t)(void *ctx, void *data);
+typedef void (*rb_free_t)(void *data);
+
+rbtree_t *rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags);
+void rbtree_free(rbtree_t *tree);
+bool rbtree_insert(rbtree_t *tree, void *data);
+rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data);
+void rbtree_delete(rbtree_t *tree, rbnode_t *z);
+bool rbtree_deletebydata(rbtree_t *tree, void const *data);
+rbnode_t *rbtree_find(rbtree_t *tree, void const *data);
+void *rbtree_finddata(rbtree_t *tree, void const *data);
+uint32_t rbtree_num_elements(rbtree_t *tree);
+void *rbtree_node2data(rbtree_t *tree, rbnode_t *node);
+
+/*
+ * The callback should be declared as:
+ * int callback(void *context, void *data)
+ *
+ * The "context" is some user-defined context.
+ * The "data" is the pointer to the user data in the node,
+ * NOT the node itself.
+ *
+ * It should return 0 if all is OK, and !0 for any error.
+ * The walking will stop on any error.
+ *
+ * Except with RBTREE_DELETE_ORDER, where the callback should return <0 for
+ * errors, and may return 1 to delete the current node and halt,
+ * or 2 to delete the current node and continue. This may be
+ * used to batch-delete select nodes from a locked rbtree.
+ */
+int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context);
+
+/*
+ * FIFOs
+ */
+typedef struct fr_fifo_t fr_fifo_t;
+typedef void (*fr_fifo_free_t)(void *);
+fr_fifo_t *fr_fifo_create(TALLOC_CTX *ctx, int max_entries, fr_fifo_free_t freeNode);
+void fr_fifo_free(fr_fifo_t *fi);
+int fr_fifo_push(fr_fifo_t *fi, void *data);
+void *fr_fifo_pop(fr_fifo_t *fi);
+void *fr_fifo_peek(fr_fifo_t *fi);
+unsigned int fr_fifo_num_elements(fr_fifo_t *fi);
+
+/*
+ * socket.c
+ */
+int fr_socket_client_unix(char const *path, bool async);
+int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async);
+int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async);
+int fr_socket_wait_for_connect(int sockfd, struct timeval *timeout);
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <freeradius-devel/packet.h>
+
+#ifdef WITH_TCP
+# include <freeradius-devel/tcp.h>
+#endif
+
+#endif /*LIBRADIUS_H*/
diff --git a/src/include/listen.h b/src/include/listen.h
new file mode 100644
index 0000000..a82b91d
--- /dev/null
+++ b/src/include/listen.h
@@ -0,0 +1,206 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef LISTEN_H
+#define LISTEN_H
+/**
+ * $Id$
+ *
+ * @file listen.h
+ * @brief The listener API.
+ *
+ * @copyright 2015 The FreeRADIUS server project
+ */
+
+/*
+ * Types of listeners.
+ *
+ * Ordered by priority!
+ */
+typedef enum RAD_LISTEN_TYPE {
+ RAD_LISTEN_NONE = 0,
+ RAD_LISTEN_PROXY,
+ RAD_LISTEN_AUTH,
+ RAD_LISTEN_ACCT,
+ RAD_LISTEN_DETAIL,
+ RAD_LISTEN_VQP,
+ RAD_LISTEN_DHCP,
+ RAD_LISTEN_COMMAND,
+ RAD_LISTEN_COA,
+ RAD_LISTEN_MAX
+} RAD_LISTEN_TYPE;
+
+typedef enum RAD_LISTEN_STATUS {
+ RAD_LISTEN_STATUS_INIT = 0,
+ RAD_LISTEN_STATUS_KNOWN,
+ RAD_LISTEN_STATUS_PAUSE,
+ RAD_LISTEN_STATUS_RESUME,
+ RAD_LISTEN_STATUS_FROZEN,
+ RAD_LISTEN_STATUS_EOL,
+ RAD_LISTEN_STATUS_REMOVE_NOW
+} RAD_LISTEN_STATUS;
+
+typedef struct rad_listen rad_listen_t;
+
+typedef int (*rad_listen_recv_t)(rad_listen_t *);
+typedef int (*rad_listen_send_t)(rad_listen_t *, REQUEST *);
+typedef int (*rad_listen_print_t)(rad_listen_t const *, char *, size_t);
+typedef int (*rad_listen_encode_t)(rad_listen_t *, REQUEST *);
+typedef int (*rad_listen_decode_t)(rad_listen_t *, REQUEST *);
+
+struct rad_listen {
+ rad_listen_t *next; /* should be rbtree stuff */
+
+ /*
+ * For normal sockets.
+ */
+ RAD_LISTEN_TYPE type;
+ int fd;
+ char const *server;
+ int status;
+ int count;
+#ifdef WITH_TCP
+ rbtree_t *children;
+ rad_listen_t *parent;
+
+ bool dual;
+ bool proxy_protocol; //!< haproxy protocol
+#endif
+ bool nodup;
+ bool synchronous;
+ bool dead;
+ uint32_t workers;
+
+#ifdef WITH_TLS
+ fr_tls_server_conf_t *tls;
+ bool check_client_connections;
+ bool nonblock;
+ bool blocked;
+#ifdef WITH_RADIUSV11
+ fr_radiusv11_t radiusv11;
+#endif
+
+#ifdef WITH_COA_TUNNEL
+ char const *key; /* Originating-Realm-Key */
+ bool send_coa; /* to the NAS */
+
+ uint32_t coa_irt;
+ uint32_t coa_mrc;
+ uint32_t coa_mrt;
+ uint32_t coa_mrd;
+
+ int num_ids_used; /* for proxying CoA packets */
+#endif
+#endif
+
+ rad_listen_recv_t recv;
+ rad_listen_send_t send;
+
+ /*
+ * We don't need a proxy_recv, because the main loop in
+ * process.c calls listener->recv(), and we don't know
+ * what kind of packet we're receiving until we receive
+ * it.
+ */
+ rad_listen_send_t proxy_send;
+
+
+ rad_listen_encode_t encode;
+ rad_listen_decode_t decode;
+ rad_listen_encode_t proxy_encode;
+ rad_listen_decode_t proxy_decode;
+ rad_listen_print_t print;
+
+ CONF_SECTION const *cs;
+ void *data;
+
+#ifdef WITH_STATS
+ fr_stats_t stats;
+#endif
+};
+
+/*
+ * This shouldn't really be exposed...
+ */
+typedef struct listen_socket_t {
+ /*
+ * For normal sockets.
+ */
+ fr_ipaddr_t my_ipaddr;
+ uint16_t my_port;
+
+ char const *interface;
+#ifdef SO_BROADCAST
+ int broadcast;
+#endif
+
+ int recv_buff;
+
+ time_t rate_time;
+ uint32_t rate_pps_old;
+ uint32_t rate_pps_now;
+ uint32_t max_rate;
+
+ /* for outgoing sockets */
+ home_server_t *home;
+ fr_ipaddr_t other_ipaddr;
+ uint16_t other_port;
+
+ int proto;
+
+#ifdef WITH_TCP
+ /* for a proxy connecting to home servers */
+ time_t last_packet;
+ time_t opened;
+ fr_event_t *ev;
+
+ fr_socket_limit_t limit;
+
+ struct listen_socket_t *parent;
+ RADCLIENT *client;
+
+ RADIUS_PACKET *packet; /* for reading partial packets */
+
+ fr_ipaddr_t haproxy_src_ipaddr; //!< for proxy_protocol
+ fr_ipaddr_t haproxy_dst_ipaddr;
+ uint16_t haproxy_src_port;
+ uint16_t haproxy_dst_port;
+#endif
+
+#ifdef WITH_TLS
+ tls_session_t *ssn;
+ REQUEST *request; /* horrible hacks */
+ VALUE_PAIR *certs;
+ uint32_t connect_timeout;
+ pthread_mutex_t mutex;
+ uint8_t *data;
+ size_t partial;
+ enum {
+ LISTEN_TLS_INIT = 0,
+ LISTEN_TLS_CHECKING,
+ LISTEN_TLS_SETUP,
+ LISTEN_TLS_RUNNING,
+ } state;
+
+#ifdef WITH_RADIUSV11
+ bool alpn_checked;
+ bool radiusv11; //!< defaults to "no"!
+#endif
+#endif
+
+ RADCLIENT_LIST *clients;
+} listen_socket_t;
+#endif /* LISTEN_H */
+
diff --git a/src/include/log.h b/src/include/log.h
new file mode 100644
index 0000000..2736591
--- /dev/null
+++ b/src/include/log.h
@@ -0,0 +1,390 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_LOG_H
+#define FR_LOG_H
+/**
+ * $Id$
+ *
+ * @file log.h
+ * @brief Macros and function definitions to write log messages, and control the logging system.
+ *
+ * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Alan DeKok <aland@freeradius.org>
+ */
+RCSIDH(log_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum log_type {
+ L_AUTH = 2, //!< Authentication message.
+ L_INFO = 3, //!< Informational message.
+ L_ERR = 4, //!< Error message.
+ L_WARN = 5, //!< Warning.
+ L_PROXY = 6, //!< Proxy messages
+ L_ACCT = 7, //!< Accounting messages
+
+ L_DBG = 16, //!< Only displayed when debugging is enabled.
+ L_DBG_WARN = 17, //!< Warning only displayed when debugging is enabled.
+ L_DBG_ERR = 18, //!< Error only displayed when debugging is enabled.
+ L_DBG_WARN_REQ = 19, //!< Less severe warning only displayed when debugging is enabled.
+ L_DBG_ERR_REQ = 20 //!< Less severe error only displayed when debugging is enabled.
+} log_type_t;
+
+typedef enum log_lvl {
+ L_DBG_LVL_DISABLE = -1, //!< Don't print messages.
+ L_DBG_LVL_OFF = 0, //!< No debug messages.
+ L_DBG_LVL_1, //!< Highest priority debug messages (-x).
+ L_DBG_LVL_2, //!< 2nd highest priority debug messages (-xx | -X).
+ L_DBG_LVL_3, //!< 3rd highest priority debug messages (-xxx | -Xx).
+ L_DBG_LVL_MAX //!< Lowest priority debug messages (-xxxx | -Xxx).
+} log_lvl_t;
+
+typedef enum log_dst {
+ L_DST_STDOUT = 0, //!< Log to stdout.
+ L_DST_FILES, //!< Log to a file on disk.
+ L_DST_SYSLOG, //!< Log to syslog.
+ L_DST_STDERR, //!< Log to stderr.
+ L_DST_NULL, //!< Discard log messages.
+ L_DST_NUM_DEST
+} log_dst_t;
+
+typedef struct fr_log_t {
+ bool colourise; //!< Prefix log messages with VT100 escape codes to change text
+ //!< colour.
+ int fd; //!< File descriptor to write messages to.
+ log_dst_t dst; //!< Log destination.
+ char const *file; //!< Path to log file.
+ char const *debug_file; //!< Path to debug log file.
+} fr_log_t;
+
+typedef void (*radlog_func_t)(log_type_t lvl, log_lvl_t priority, REQUEST *, char const *, va_list ap);
+
+extern FR_NAME_NUMBER const syslog_facility_table[];
+extern FR_NAME_NUMBER const syslog_severity_table[];
+extern FR_NAME_NUMBER const log_str2dst[];
+extern fr_log_t default_log;
+
+int radlog_init(fr_log_t *log, bool daemonize);
+
+int vradlog(log_type_t lvl, char const *fmt, va_list ap)
+ CC_HINT(format (printf, 2, 0)) CC_HINT(nonnull);
+int radlog(log_type_t lvl, char const *fmt, ...)
+ CC_HINT(format (printf, 2, 3)) CC_HINT(nonnull (2));
+
+bool debug_enabled(log_type_t type, log_lvl_t lvl);
+
+bool rate_limit_enabled(void);
+
+bool radlog_debug_enabled(log_type_t type, log_lvl_t lvl, REQUEST *request)
+ CC_HINT(nonnull);
+
+void vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap)
+ CC_HINT(format (printf, 4, 0)) CC_HINT(nonnull (3, 4));
+
+void radlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5)) CC_HINT(nonnull (3, 4));
+
+void radlog_request_error(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5)) CC_HINT(nonnull (3, 4));
+
+void radlog_request_marker(log_type_t type, log_lvl_t lvl, REQUEST *request,
+ char const *fmt, size_t indent, char const *error)
+ CC_HINT(nonnull);
+
+void fr_canonicalize_error(TALLOC_CTX *ctx, char **spaces, char **text, ssize_t slen, char const *msg);
+
+/** @name Log global messages
+ *
+ * Write to the global log.
+ *
+ * Messages will always be written irrespective of the debugging level set with ``-x`` or ``-X``.
+ *
+ * @warning If a REQUEST * is **NOT** available, these macros **MUST** be used.
+ *
+ * @note These macros should only be used for important global events.
+ *
+ * **Debug categories**
+ * Name | Syslog severity | Colour/style | When to use
+ * -------- | ----------------------- | ------------ | -----------
+ * AUTH | LOG_NOTICE | Bold | Never - Deprecated
+ * ACCT | LOG_NOTICE | Bold | Never - Deprecated
+ * PROXY | LOG_NOTICE | Bold | Never - Deprecated
+ * INFO | LOG_INFO | Bold | TBD
+ * WARN | LOG_WARNING | Yellow | Warnings. Impending resource exhaustion, resource exhaustion
+ * ERROR | LOG_ERR | Red | Critical server errors. Malformed queries, failed operations, connection errors, packet processing errors
+ *
+ * @{
+ */
+#define AUTH(fmt, ...) radlog(L_AUTH, fmt, ## __VA_ARGS__)
+#define ACCT(fmt, ...) radlog(L_ACCT, fmt, ## __VA_ARGS__)
+#define PROXY(fmt, ...) radlog(L_PROXY, fmt, ## __VA_ARGS__)
+
+#define INFO(fmt, ...) radlog(L_INFO, fmt, ## __VA_ARGS__)
+#define WARN(fmt, ...) radlog(L_WARN, fmt, ## __VA_ARGS__)
+#define ERROR(fmt, ...) radlog(L_ERR, fmt, ## __VA_ARGS__)
+/** @} */
+
+/** @name Log global debug messages (DEBUG*)
+ *
+ * Write debugging messages to the global log.
+ *
+ * Messages will be written if the debug level is high enough.
+ *
+ * **Debug categories**
+ * Name | Syslog severity | Colour/style | When to use
+ * -------- | ----------------------- | -------------| -----------
+ * DEBUG | LOG_DEBUG | Regular | Normal debug output
+ *
+ * **Debug levels**
+ * Level | Debug arguments | Macro(s) enabled | When to use
+ * -------- | ----------------------- | ----------------------------- | -----------
+ * 1 | ``-x`` | DEBUG | Never - Deprecated
+ * 2 | ``-xx`` or ``-X`` | DEBUG, DEBUG2 | Interactions with external entities. Connection management, control socket, triggers, etc...
+ * 3 | ``-xxx`` or ``-Xx`` | DEBUG, DEBUG2, DEBUG3 | Lower priority events. Polling for detail files, cleanups, etc...
+ * 4 | ``-xxxx`` or ``-Xxx`` | DEBUG, DEBUG2, DEBUG3, DEBUG4 | Internal server state debugging.
+ *
+ * @{
+ */
+#define DEBUG_ENABLED debug_enabled(L_DBG, L_DBG_LVL_1) //!< True if global debug level 1 messages are enabled
+#define DEBUG_ENABLED2 debug_enabled(L_DBG, L_DBG_LVL_2) //!< True if global debug level 1-2 messages are enabled
+#define DEBUG_ENABLED3 debug_enabled(L_DBG, L_DBG_LVL_3) //!< True if global debug level 1-3 messages are enabled
+#define DEBUG_ENABLED4 debug_enabled(L_DBG, L_DBG_LVL_MAX) //!< True if global debug level 1-4 messages are enabled
+
+#define _SL(_l, _p, _f, ...) if (rad_debug_lvl >= _p) radlog(_l, _f, ## __VA_ARGS__)
+#define DEBUG(fmt, ...) _SL(L_DBG, L_DBG_LVL_1, fmt, ## __VA_ARGS__)
+#define DEBUG2(fmt, ...) _SL(L_DBG, L_DBG_LVL_2, fmt, ## __VA_ARGS__)
+#define DEBUG3(fmt, ...) _SL(L_DBG, L_DBG_LVL_3, fmt, ## __VA_ARGS__)
+#define DEBUG4(fmt, ...) _SL(L_DBG, L_DBG_LVL_MAX, fmt, ## __VA_ARGS__)
+/** @} */
+
+/** @name Log request-specific messages (R*)
+ *
+ * Write to the request log, or the global log if a request logging function is not set.
+ *
+ * Messages will always be written irrespective of the debugging level set with ``-x`` or ``-X``.
+ *
+ * @note Automatically prepends date (at lvl >= 3), request number, and module, to the log message.
+ * @note If a REQUEST * is available, these macros should be used.
+ * @note These macros should only be used for important global events.
+ *
+ * **Debug categories**
+ * Name | Syslog severity | Colour/style | When to use
+ * -------- | ----------------------- | -------------| -----------
+ * RAUTH | LOG_NOTICE | Bold | Never - Deprecated
+ * RACCT | LOG_NOTICE | Bold | Never - Deprecated
+ * RPROXY | LOG_NOTICE | Bold | Never - Deprecated
+ * RINFO | LOG_INFO | Bold | TBD
+ * RWARN | LOG_WARNING | Yellow/Bold | Warnings. Impending resource exhaustion, or resource exhaustion.
+ * RERROR | LOG_ERR | Red/Bold | Critical server errors. Malformed queries, failed operations, connection errors, packet processing errors.
+ * @{
+ */
+#define RAUTH(fmt, ...) radlog_request(L_AUTH, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+#define RACCT(fmt, ...) radlog_request(L_ACCT, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+#define RPROXY(fmt, ...) radlog_request(L_PROXY, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+#define RINFO(fmt, ...) radlog_request(L_INFO, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+#define RWARN(fmt, ...) radlog_request(L_DBG_WARN, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+#define RERROR(fmt, ...) radlog_request_error(L_DBG_ERR, L_DBG_LVL_OFF, request, fmt, ## __VA_ARGS__)
+/** @} */
+
+/** @name Log request-specific debug (R*DEBUG*)
+ *
+ * Write debug messages to the request log.
+ *
+ * Messages will only be written if a request log function is set and the request or global
+ * debug level is high enough.
+ *
+ * @note Automatically prepends date (at lvl >= 3), request number, and module, to the log message.
+ *
+ * **Debug categories**
+ * Name | Syslog severity | Colour and style | When to use
+ * -------- | ----------------------- | -----------------| -----------
+ * RDEBUG* | LOG_DEBUG | Regular | Normal debugging messages
+ * RIDEBUG* | LOG_DEBUG | Bold | Informational messages.
+ * RWDEBUG* | LOG_DEBUG | Yellow/Bold | Warnings. Invalid configuration, missing or invalid attributes etc...
+ * REDEBUG* | LOG_DEBUG | Red/Bold | Errors. Reject messages, bad values etc...
+ *
+ * **Debug levels**
+ * Level | Debug arguments | Macro(s) enabled | When to use
+ * -------- | ----------------------- | -------------------------------------- | -----------
+ * 1 | ``-x`` | R*DEBUG | Never - Deprecated
+ * 2 | ``-xx`` or ``-X`` | R*DEBUG, R*DEBUG2 | Normal request flow. Operations, Results of queries, or execs, etc...
+ * 3 | ``-xxx`` or ``-Xx`` | R*DEBUG, R*DEBUG2, R*DEBUG3 | Internal server state or packet input. State machine changes, extra attribute info, etc...
+ * 4 | ``-xxxx`` or ``-Xxx`` | R*DEBUG, R*DEBUG2, R*DEBUG3, R*DEBUG4 | Verbose internal server state messages or packet input. Hex dumps, structure dumps, pointer values.
+ *
+ * @{
+ */
+#define RDEBUG_ENABLED radlog_debug_enabled(L_DBG, L_DBG_LVL_1, request) //!< True if request debug level 1 messages are enabled
+#define RDEBUG_ENABLED2 radlog_debug_enabled(L_DBG, L_DBG_LVL_2, request) //!< True if request debug level 1-2 messages are enabled
+#define RDEBUG_ENABLED3 radlog_debug_enabled(L_DBG, L_DBG_LVL_3, request) //!< True if request debug level 1-3 messages are enabled
+#define RDEBUG_ENABLED4 radlog_debug_enabled(L_DBG, L_DBG_LVL_MAX, request) //!< True if request debug level 1-4 messages are enabled
+
+#define RDEBUGX(_l, fmt, ...) radlog_request(L_DBG, _l, request, fmt, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG, L_DBG_LVL_1, request, fmt, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG, L_DBG_LVL_2, request, fmt, ## __VA_ARGS__)
+#define RDEBUG3(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG, L_DBG_LVL_3, request, fmt, ## __VA_ARGS__)
+#define RDEBUG4(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG, L_DBG_LVL_MAX, request, fmt, ## __VA_ARGS__)
+
+#define RIDEBUG(fmt, ...) radlog_request(L_INFO, L_DBG_LVL_1, request, fmt, ## __VA_ARGS__)
+#define RIDEBUG2(fmt, ...) radlog_request(L_INFO, L_DBG_LVL_2, request, fmt, ## __VA_ARGS__)
+
+#define RWDEBUG(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG_WARN, L_DBG_LVL_1, request, fmt, ## __VA_ARGS__)
+#define RWDEBUG2(fmt, ...) if (rad_debug_lvl || request->log.lvl) radlog_request(L_DBG_WARN, L_DBG_LVL_2, request, fmt, ## __VA_ARGS__)
+
+#define REDEBUG(fmt, ...) radlog_request_error(L_DBG_ERR, L_DBG_LVL_1, request, fmt, ## __VA_ARGS__)
+#define REDEBUG2(fmt, ...) radlog_request_error(L_DBG_ERR, L_DBG_LVL_2, request, fmt, ## __VA_ARGS__)
+#define REDEBUG3(fmt, ...) radlog_request_error(L_DBG_ERR, L_DBG_LVL_3, request, fmt, ## __VA_ARGS__)
+#define REDEBUG4(fmt, ...) radlog_request_error(L_DBG_ERR, L_DBG_LVL_MAX, request, fmt, ## __VA_ARGS__)
+/** @} */
+
+/** Indent R* messages by one level
+ *
+ * @note Has no effect on the indentation of INFO, WARN, ERROR, DEBUG messages,
+ * only RINFO, RWARN, RERROR etc...
+ */
+#define RINDENT() (request->log.indent += 2)
+
+/** Exdent (unindent) R* messages by one level
+ *
+ * @note Has no effect on the indentation of INFO, WARN, ERROR, DEBUG messages,
+ * only RINFO, RWARN, RERROR etc...
+ */
+#define REXDENT() (request->log.indent -= 2)
+
+/** Output string with error marker, showing where format error occurred
+ *
+ @verbatim
+ my pet kitty
+ ^ kitties are not pets, are nature devouring hell beasts
+ @endverbatim
+ *
+ * @warning If a REQUEST * is **NOT** available, or is NULL, this macro must **NOT** be used.
+ *
+ * @param _l log category, a log_type_t value.
+ * @param _p log priority, a log_lvl_t value.
+ * @param _m string to mark e.g. "my pet kitty".
+ * @param _i index e.g. 3 (starts from 0).
+ * @param _e error e.g. "kitties are not pets, are nature devouring hell beasts".
+ */
+#define RMARKER(_l, _p, _m, _i, _e) radlog_request_marker(_l, _p, request, _m, _i, _e)
+
+/** Output string with error marker, showing where format error occurred
+ *
+ * These are logged as RERROR messages.
+ *
+ @verbatim
+ my pet kitty
+ ^ kitties are not pets, are nature devouring hell beasts
+ @endverbatim
+ *
+ * @warning If a REQUEST * is **NOT** available, or is NULL, this macro must **NOT** be used.
+ *
+ * @param _m string to mark e.g. "my pet kitty".
+ * @param _i index e.g. 3 (starts from 0).
+ * @param _e error e.g. "kitties are not pets, are nature devouring hell beasts".
+ */
+#define REMARKER(_m, _i, _e) RMARKER(L_DBG_ERR, L_DBG_LVL_1, _m, _i, _e)
+
+/** Output string with error marker, showing where format error occurred
+ *
+ * These are logged as RDEBUG messages.
+ *
+ @verbatim
+ my pet kitty
+ ^ kitties are not pets, are nature devouring hell beasts
+ @endverbatim
+ *
+ * @warning If a REQUEST * is **NOT** available, or is NULL, this macro must **NOT** be used.
+ *
+ * @param _m string to mark e.g. "my pet kitty".
+ * @param _i index e.g. 3 (starts from 0).
+ * @param _e error e.g. "kitties are not pets, are nature devouring hell beasts".
+ */
+#define RDMARKER(_m, _i, _e) RMARKER(L_DBG, L_DBG_LVL_1, _m, _i, _e)
+
+/** Use different logging functions depending on whether request is NULL or not.
+ *
+ * @note The module must define MOD_PREFIX as its name (do this in the module
+ * header file) e.g. @code{.c}#define MOD_PREFIX "rlm_example"@endcode
+ *
+ * This is useful for areas of code which are run on server startup, and when
+ * processing requests.
+ *
+ * @param _l_request The name of a R* logging macro e.g. RDEBUG3.
+ * @param _l_global The name of a global logging macro e.g. DEBUG3.
+ * @param fmt printf style format string.
+ * @param ... printf arguments.
+ */
+ #define MOD_ROPTIONAL(_l_request, _l_global, fmt, ...) \
+do {\
+ if (request) {\
+ _l_request(fmt, ## __VA_ARGS__);\
+ } else {\
+ _l_global(MOD_PREFIX " (%s): " fmt, inst->name, ## __VA_ARGS__);\
+ }\
+} while (0)
+
+/** Use different logging functions depending on whether request is NULL or not.
+ *
+ * This is useful for areas of code which are run on server startup, and when
+ * processing requests.
+ *
+ * @param _l_request The name of a R* logging macro e.g. RDEBUG3.
+ * @param _l_global The name of a global logging macro e.g. DEBUG3.
+ * @param fmt printf style format string.
+ * @param ... printf arguments.
+ */
+ #define ROPTIONAL(_l_request, _l_global, fmt, ...) \
+do {\
+ if (request) {\
+ _l_request(fmt, ## __VA_ARGS__);\
+ } else {\
+ _l_global(LOG_PREFIX ": " fmt, ## __VA_ARGS__);\
+ }\
+} while (0)
+
+#define RATE_LIMIT_ENABLED rate_limit_enabled() //!< True if rate limiting is enabled.
+/** Rate limit messages
+ *
+ * Rate limit log messages so they're written a maximum of once per second.
+ *
+ @code{.c}
+ RATE_LIMIT(RERROR("Home servers alive in pool %s", pool->name));
+ @endcode
+ * @note Rate limits the macro, not the message. If five different messages are
+ * produced using the same macro in the same second, only the first will
+ * be written to the log.
+ *
+ * @param _x Logging macro to limit.
+ */
+#define RATE_LIMIT(_x) \
+do {\
+ if (RATE_LIMIT_ENABLED) {\
+ static time_t _last_complained = 0;\
+ time_t _now = time(NULL);\
+ if (_now != _last_complained) {\
+ _last_complained = _now;\
+ _x;\
+ }\
+ } else _x;\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_LOG_H */
diff --git a/src/include/map.h b/src/include/map.h
new file mode 100644
index 0000000..584c76b
--- /dev/null
+++ b/src/include/map.h
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef MAP_H
+#define MAP_H
+/**
+ * $Id$
+ *
+ * @file map.h
+ * @brief Structures and prototypes for maps
+ *
+ * @copyright 2015 The FreeRADIUS server project
+ * @copyright 2015 Arran Cudbard-bell <a.cudbardb@freeradius.org>
+ */
+
+RCSIDH(map_h, "$Id$")
+
+#include <freeradius-devel/conffile.h>
+#include <freeradius-devel/tmpl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Value pair map
+ *
+ * Value pair maps contain a pair of templates, that describe a src attribute
+ * or value, and a destination attribute.
+ *
+ * Neither src or dst need to be an FR attribute, and their type can be inferred
+ * from whether map->da is NULL (not FR).
+ *
+ * @see vp_tmpl_t
+ */
+typedef struct vp_map {
+ vp_tmpl_t *lhs; //!< Typically describes the attribute to add, modify or compare.
+ vp_tmpl_t *rhs; //!< Typically describes a literal value or a src attribute to copy or compare.
+
+ FR_TOKEN op; //!< The operator that controls insertion of the dst attribute.
+
+ CONF_ITEM *ci; //!< Config item that the map was created from. Mainly used for
+ //!< logging validation errors.
+
+ struct vp_map *next; //!< The next valuepair map.
+} vp_map_t;
+
+#ifndef WITH_VERIFY_PTR
+# define VERIFY_MAP(_x) rad_assert((_x)->lhs)
+#else
+# define VERIFY_MAP(_x) do { \
+ VERIFY_TMPL((_x)->lhs); \
+ if ((_x)->rhs) VERIFY_TMPL((_x)->rhs); \
+} while (0)
+#endif
+
+typedef int (*map_validate_t)(vp_map_t *map, void *ctx);
+typedef int (*radius_map_getvalue_t)(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request,
+ vp_map_t const *map, void *uctx);
+
+int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def);
+
+int map_afrom_fields(TALLOC_CTX *ctx, vp_map_t **out, char const *lhs, FR_TOKEN lhs_type,
+ FR_TOKEN op, char const *rhs, FR_TOKEN rhs_type,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def);
+
+int map_afrom_cs(vp_map_t **out, CONF_SECTION *cs,
+ pair_lists_t dst_list_def, pair_lists_t src_list_def,
+ map_validate_t validate, void *ctx, unsigned int max) CC_HINT(nonnull(1, 2));
+
+int map_afrom_attr_str(TALLOC_CTX *ctx, vp_map_t **out, char const *raw,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def);
+
+int8_t map_cmp_by_lhs_attr(void const *a, void const *b);
+
+void map_sort(vp_map_t **maps, fr_cmp_t cmp);
+
+int map_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request,
+ vp_map_t const *map, void *uctx) CC_HINT(nonnull (2,3,4));
+
+int map_to_request(REQUEST *request, vp_map_t const *map,
+ radius_map_getvalue_t func, void *ctx);
+
+bool map_dst_valid(REQUEST *request, vp_map_t const *map);
+
+size_t map_prints(char *buffer, size_t bufsize, vp_map_t const *map);
+
+void map_debug_log(REQUEST *request, vp_map_t const *map,
+ VALUE_PAIR const *vp) CC_HINT(nonnull(1, 2));
+
+bool map_cast_from_hex(vp_map_t *map, FR_TOKEN rhs_type, char const *rhs);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MAP_H */
diff --git a/src/include/math.h b/src/include/math.h
new file mode 100644
index 0000000..dc7b197
--- /dev/null
+++ b/src/include/math.h
@@ -0,0 +1,161 @@
+#pragma once
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Various miscellaneous utility functions
+ *
+ * @file src/lib/util/misc.h
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSIDH(math_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/** Find the highest order high bit in an unsigned 64 bit integer
+ *
+ * @return 0-64 indicating the position of the highest bit,
+ * with 0 indicating no high bits, 1 indicating the 1st
+ * bit and 64 indicating the last bit.
+ */
+static inline uint8_t fr_high_bit_pos(uint64_t num)
+{
+ if (num == 0) return 0; /* num being zero is undefined behaviour for __builtin_clzll */
+
+#ifdef HAVE_BUILTIN_CLZLL
+ return (64 - __builtin_clzll(num));
+#else
+ uint8_t ret = 1;
+ while (num >>= 1) ret++;
+ return ret;
+#endif
+}
+
+/** Find the lowest order high bit in an unsigned 64 bit integer
+ *
+ * @return 0-64 indicating the position of the lowest bit,
+ * with 0 indicating no high bits, 1 indicating the 1st
+ * bit and 64 indicating the last bit.
+ */
+static inline uint8_t fr_low_bit_pos(uint64_t num)
+{
+ if (num == 0) return 0;
+
+#ifdef HAVE_BUILTIN_CLZLL
+ return __builtin_ctzll(num) + 1;
+#else
+ uint8_t ret = 1;
+
+ do {
+ if (num & 0x01) break;
+ ret++;
+ } while (num >>= 1);
+
+ return ret;
+#endif
+}
+
+/** Efficient calculation of log10 of a unsigned 64bit integer
+ *
+ * @param[in] num to calculate log10 of.
+ * @return log10 of the integer
+ */
+static inline uint8_t fr_log10(uint64_t num)
+{
+ static uint64_t const pow_of_10[] =
+ {
+ 1ULL,
+ 10ULL,
+ 100ULL,
+ 1000ULL,
+ 10000ULL,
+ 100000ULL,
+ 1000000ULL,
+ 10000000ULL,
+ 100000000ULL,
+ 1000000000ULL,
+ 10000000000ULL,
+ 100000000000ULL,
+ 1000000000000ULL,
+ 10000000000000ULL,
+ 100000000000000ULL,
+ 1000000000000000ULL,
+ 10000000000000000ULL,
+ 100000000000000000ULL,
+ 1000000000000000000ULL,
+ 10000000000000000000ULL
+ };
+ uint64_t tmp;
+
+ tmp = (fr_high_bit_pos(num) * 1233) >> 12;
+ return tmp - (num < pow_of_10[tmp]);
+}
+
+/** Multiplies two integers together
+ *
+ * @param[in] _out Where to store the result.
+ * @param[in] _a first argument to multiply.
+ * @param[in] _b second argument to multiply.
+ * @return
+ * - false on overflow.
+ * - true if there was no overflow.
+ */
+#define fr_multiply(_out, _a, _b) !__builtin_mul_overflow(_a, _b, _out)
+
+/** Adds two integers
+ *
+ * @param[in] _out Where to store the result.
+ * @param[in] _a first argument to add.
+ * @param[in] _b second argument to add.
+ * @return
+ * - false on overflow.
+ * - true if there was no overflow.
+ */
+#define fr_add(_out, _a, _b) !__builtin_add_overflow(_a, _b, _out)
+
+/** Subtracts two integers
+ *
+ * @param[in] _out Where to store the result.
+ * @param[in] _a first argument to subtract.
+ * @param[in] _b second argument to subtract.
+ * @return
+ * - false on overflow.
+ * - true if there was no overflow.
+ */
+#define fr_sub(_out, _a, _b) !__builtin_sub_overflow(_a, _b, _out)
+
+/** Round up - Only works if _mul is a power of 2 but avoids division
+ */
+#define ROUND_UP_POW2(_num, _mul) (((_num) + ((_mul) - 1)) & ~((_mul) - 1))
+
+/** Round up - Works in all cases, but is slower
+ */
+#define ROUND_UP(_num, _mul) (((((_num) + ((_mul) - 1))) / (_mul)) * (_mul))
+
+/** Get the ceiling value of integer division
+ *
+ */
+#define ROUND_UP_DIV(_x, _y) (1 + (((_x) - 1) / (_y)))
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/include/md4.h b/src/include/md4.h
new file mode 100644
index 0000000..1492bd4
--- /dev/null
+++ b/src/include/md4.h
@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ *
+ * @note license is LGPL, but largely derived from a public domain source.
+ *
+ * @file md4.h
+ * @brief Structures and prototypes for md4.
+ */
+
+#ifndef _FR_MD4_H
+#define _FR_MD4_H
+
+RCSIDH(md4_h, "$Id$")
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#include <string.h>
+
+#ifdef WITH_FIPS
+#undef HAVE_OPENSSL_MD4_H
+#endif
+
+#ifdef HAVE_OPENSSL_MD4_H
+# include <openssl/md4.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MD4_DIGEST_LENGTH
+# define MD4_DIGEST_LENGTH 16
+#endif
+
+#ifndef HAVE_OPENSSL_MD4_H
+/*
+ * The MD5 code used here and in md4.c was originally retrieved from:
+ * http://www.openbsd.org/cgi-bin/cvsweb/src/include/md4.h?rev=1.12
+ *
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+# define MD4_BLOCK_LENGTH 64
+# define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1)
+
+typedef struct FR_MD4Context {
+ uint32_t state[4]; //!< State.
+ uint32_t count[2]; //!< Number of bits, mod 2^64.
+ uint8_t buffer[MD4_BLOCK_LENGTH]; //!< Input buffer.
+} FR_MD4_CTX;
+
+void fr_md4_init(FR_MD4_CTX *ctx);
+void fr_md4_update(FR_MD4_CTX *ctx, uint8_t const *in, size_t inlen)
+ CC_BOUNDED(__string__, 2, 3);
+void fr_md4_final(uint8_t out[MD4_DIGEST_LENGTH], FR_MD4_CTX *ctx)
+ CC_BOUNDED(__minbytes__, 1, MD4_DIGEST_LENGTH);
+void fr_md4_transform(uint32_t buf[4], uint8_t const inc[MD4_BLOCK_LENGTH])
+ CC_BOUNDED(__size__, 1, 4, 4)
+ CC_BOUNDED(__minbytes__, 2, MD4_BLOCK_LENGTH);
+# define fr_md4_destroy(_x)
+#else /* HAVE_OPENSSL_MD4_H */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+USES_APPLE_DEPRECATED_API
+# define FR_MD4_CTX MD4_CTX
+# define fr_md4_init MD4_Init
+# define fr_md4_update MD4_Update
+# define fr_md4_final MD4_Final
+# define fr_md4_transform MD4_Transform
+# define fr_md4_destroy(_x)
+#else
+#include <openssl/evp.h>
+
+/*
+ * Wrappers for OpenSSL3, so we don't have to butcher the rest of
+ * the code too much.
+ */
+typedef struct FR_MD4_CTX {
+ EVP_MD_CTX *ctx;
+ EVP_MD const *md;
+ unsigned int len;
+} FR_MD4_CTX;
+
+static inline void fr_md4_init(FR_MD4_CTX *ctx)
+{
+ ctx->ctx = EVP_MD_CTX_new();
+// ctx->md = EVP_MD_fetch(NULL, "MD4", "provider=legacy");
+ ctx->md = EVP_md4();
+ ctx->len = MD4_DIGEST_LENGTH;
+
+ EVP_MD_CTX_set_flags(ctx->ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_DigestInit_ex(ctx->ctx, ctx->md, NULL);
+}
+
+static inline void fr_md4_update(FR_MD4_CTX *ctx, uint8_t const *in, size_t inlen)
+{
+ EVP_DigestUpdate(ctx->ctx, in, inlen);
+}
+
+static inline void fr_md4_final(uint8_t out[MD4_DIGEST_LENGTH], FR_MD4_CTX *ctx)
+{
+ EVP_DigestFinal_ex(ctx->ctx, out, &(ctx->len));
+}
+
+static inline void fr_md4_destroy(FR_MD4_CTX *ctx)
+{
+ EVP_MD_CTX_destroy(ctx->ctx);
+// EVP_MD_free(ctx->md);
+}
+
+#endif /* OPENSSL3 */
+#endif /* HAVE_OPENSSL_MD4_H */
+
+/* md4.c */
+void fr_md4_calc(uint8_t out[MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FR_MD4_H */
diff --git a/src/include/md5.h b/src/include/md5.h
new file mode 100644
index 0000000..b7d571a
--- /dev/null
+++ b/src/include/md5.h
@@ -0,0 +1,123 @@
+/**
+ * $Id$
+ *
+ * @note license is LGPL, but largely derived from a public domain source.
+ *
+ * @file md5.h
+ * @brief Structures and prototypes for md5.
+ */
+
+#ifndef _FR_MD5_H
+#define _FR_MD5_H
+
+RCSIDH(md5_h, "$Id$")
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+# include <string.h>
+
+#ifdef WITH_FIPS
+#undef HAVE_OPENSSL_MD5_H
+#endif
+
+#ifdef HAVE_OPENSSL_MD5_H
+# include <openssl/md5.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MD5_DIGEST_LENGTH
+# define MD5_DIGEST_LENGTH 16
+#endif
+
+#ifndef HAVE_OPENSSL_MD5_H
+/*
+ * The MD5 code used here and in md5.c was originally retrieved from:
+ * http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.h?rev=1.1
+ *
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+# define MD5_BLOCK_LENGTH 64
+typedef struct FR_MD5Context {
+ uint32_t state[4]; //!< State.
+ uint32_t count[2]; //!< Number of bits, mod 2^64.
+ uint8_t buffer[MD5_BLOCK_LENGTH]; //!< Input buffer.
+} FR_MD5_CTX;
+
+void fr_md5_init(FR_MD5_CTX *ctx);
+void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen)
+ CC_BOUNDED(__string__, 2, 3);
+void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx)
+ CC_BOUNDED(__minbytes__, 1, MD5_DIGEST_LENGTH);
+void fr_md5_transform(uint32_t state[4], uint8_t const block[MD5_BLOCK_LENGTH])
+ CC_BOUNDED(__size__, 1, 4, 4)
+ CC_BOUNDED(__minbytes__, 2, MD5_BLOCK_LENGTH);
+# define fr_md5_destroy(_x)
+# define fr_md5_copy(_dst, _src) _dst = _src
+#else /* HAVE_OPENSSL_MD5_H */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+USES_APPLE_DEPRECATED_API
+# define FR_MD5_CTX MD5_CTX
+# define fr_md5_init MD5_Init
+# define fr_md5_update MD5_Update
+# define fr_md5_final MD5_Final
+# define fr_md5_transform MD5_Transform
+# define fr_md5_copy(_dst, _src) _dst = _src
+# define fr_md5_destroy(_x)
+#else
+#include <openssl/evp.h>
+
+/*
+ * Wrappers for OpenSSL3, so we don't have to butcher the rest of
+ * the code too much.
+ */
+typedef EVP_MD_CTX* FR_MD5_CTX;
+
+# define fr_md5_init(_ctx) \
+ do { \
+ *_ctx = EVP_MD_CTX_new(); \
+ EVP_MD_CTX_set_flags(*_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); \
+ EVP_DigestInit_ex(*_ctx, EVP_md5(), NULL); \
+ } while (0)
+# define fr_md5_update(_ctx, _str, _len) \
+ EVP_DigestUpdate(*_ctx, _str, _len)
+# define fr_md5_final(_out, _ctx) \
+ EVP_DigestFinal_ex(*_ctx, _out, NULL)
+# define fr_md5_destroy(_ctx) EVP_MD_CTX_destroy(*_ctx)
+# define fr_md5_copy(_dst, _src) EVP_MD_CTX_copy_ex(_dst, _src)
+#endif /* OPENSSL3 */
+#endif /* HAVE_OPENSSL_MD5_H */
+
+/* hmac.c */
+void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len)
+ CC_BOUNDED(__minbytes__, 1, MD5_DIGEST_LENGTH);
+
+/* md5.c */
+void fr_md5_calc(uint8_t *out, uint8_t const *in, size_t inlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FR_MD5_H */
diff --git a/src/include/missing-h b/src/include/missing-h
new file mode 100644
index 0000000..5698797
--- /dev/null
+++ b/src/include/missing-h
@@ -0,0 +1,530 @@
+#ifndef _FR_MISSING_H
+#define _FR_MISSING_H
+
+/*
+ * missing.h Replacements for functions that are or can be
+ * missing on some platforms.
+ * HAVE_* and WITH_* defines are substituted at
+ * build time by make with values from autoconf.h.
+ *
+ * Version: $Id$
+ *
+ */
+RCSIDH(missing_h, "$Id$")
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef HAVE_VSNPRINTF
+# include <stdarg.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+/*
+ * Check for inclusion of <time.h>, versus <sys/time.h>
+ * Taken verbatim from the autoconf manual.
+ */
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifdef HAVE_OPENSSL_SSL_H
+# include <openssl/ssl.h>
+#endif
+
+#ifdef HAVE_OPENSSL_HMAC_H
+# include <openssl/hmac.h>
+#endif
+
+#ifdef HAVE_OPENSSL_ASN1_H
+# include <openssl/asn1.h>
+#endif
+
+#ifdef HAVE_OPENSSL_CONF_H
+# include <openssl/conf.h>
+#endif
+
+/*
+ * Don't look for winsock.h if we're on cygwin.
+ */
+#if !defined(__CYGWIN__) && defined(HAVE_WINSOCK_H)
+# include <winsock.h>
+#endif
+
+#ifdef __APPLE__
+#undef DARWIN
+#define DARWIN (1)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Functions from missing.c
+ */
+#ifndef HAVE_STRNCASECMP
+int strncasecmp(char *s1, char *s2, int n);
+#endif
+
+#ifndef HAVE_STRCASECMP
+int strcasecmp(char *s1, char *s2);
+#endif
+
+#ifndef HAVE_STRSEP
+char *strsep(char **stringp, char const *delim);
+#endif
+
+#ifndef HAVE_LOCALTIME_R
+struct tm;
+struct tm *localtime_r(time_t const *l_clock, struct tm *result);
+#endif
+
+#ifndef HAVE_CTIME_R
+char *ctime_r(time_t const *l_clock, char *l_buf);
+#endif
+
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, char const *src, void *dst);
+#endif
+#ifndef HAVE_INET_NTOP
+char const *inet_ntop(int af, void const *src, char *dst, size_t cnt);
+#endif
+#ifndef HAVE_CLOSEFROM
+int closefrom(int fd);
+#endif
+
+#ifndef HAVE_SETLINEBUF
+# ifdef HAVE_SETVBUF
+# define setlinebuf(x) setvbuf(x, NULL, _IOLBF, 0)
+# else
+# define setlinebuf(x) 0
+# endif
+#endif
+
+#ifndef INADDR_ANY
+# define INADDR_ANY ((uint32_t) 0x00000000)
+#endif
+
+#ifndef INADDR_LOOPBACK
+# define INADDR_LOOPBACK ((uint32_t) 0x7f000001) /* Inet 127.0.0.1 */
+#endif
+
+#ifndef INADDR_NONE
+# define INADDR_NONE ((uint32_t) 0xffffffff)
+#endif
+
+#ifndef INADDRSZ
+# define INADDRSZ 4
+#endif
+
+#ifndef INET_ADDRSTRLEN
+# define INET_ADDRSTRLEN 16
+#endif
+
+#ifndef AF_UNSPEC
+# define AF_UNSPEC 0
+#endif
+
+#ifndef AF_INET6
+# define AF_INET6 10
+#endif
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr
+{
+ union {
+ uint8_t u6_addr8[16];
+ uint16_t u6_addr16[8];
+ uint32_t u6_addr32[4];
+ } in6_u;
+# define s6_addr in6_u.u6_addr8
+# define s6_addr16 in6_u.u6_addr16
+# define s6_addr32 in6_u.u6_addr32
+};
+
+# ifndef IN6ADDRSZ
+# define IN6ADDRSZ 16
+# endif
+
+# ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 46
+# endif
+
+# ifndef IN6ADDR_ANY_INIT
+# define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}}
+# endif
+
+# ifndef IN6ADDR_LOOPBACK_INIT
+# define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}}
+# endif
+
+# ifndef IN6_IS_ADDR_UNSPECIFIED
+# define IN6_IS_ADDR_UNSPECIFIED(a) \
+ (((__const uint32_t *) (a))[0] == 0 \
+ && ((__const uint32_t *) (a))[1] == 0 \
+ && ((__const uint32_t *) (a))[2] == 0 \
+ && ((__const uint32_t *) (a))[3] == 0)
+# endif
+
+# ifndef IN6_IS_ADDR_LOOPBACK
+# define IN6_IS_ADDR_LOOPBACK(a) \
+ (((__const uint32_t *) (a))[0] == 0 \
+ && ((__const uint32_t *) (a))[1] == 0 \
+ && ((__const uint32_t *) (a))[2] == 0 \
+ && ((__const uint32_t *) (a))[3] == htonl (1))
+# endif
+
+# ifndef IN6_IS_ADDR_MULTICAST
+# define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff)
+# endif
+
+# ifndef IN6_IS_ADDR_LINKLOCAL
+# define IN6_IS_ADDR_LINKLOCAL(a) \
+ ((((__const uint32_t *) (a))[0] & htonl (0xffc00000)) \
+ == htonl (0xfe800000))
+# endif
+
+# ifndef IN6_IS_ADDR_SITELOCAL
+# define IN6_IS_ADDR_SITELOCAL(a) \
+ ((((__const uint32_t *) (a))[0] & htonl (0xffc00000)) \
+ == htonl (0xfec00000))
+# endif
+
+# ifndef IN6_IS_ADDR_V4MAPPED
+# define IN6_IS_ADDR_V4MAPPED(a) \
+ ((((__const uint32_t *) (a))[0] == 0) \
+ && (((__const uint32_t *) (a))[1] == 0) \
+ && (((__const uint32_t *) (a))[2] == htonl (0xffff)))
+# endif
+
+# ifndef IN6_IS_ADDR_V4COMPAT
+# define IN6_IS_ADDR_V4COMPAT(a) \
+ ((((__const uint32_t *) (a))[0] == 0) \
+ && (((__const uint32_t *) (a))[1] == 0) \
+ && (((__const uint32_t *) (a))[2] == 0) \
+ && (ntohl (((__const uint32_t *) (a))[3]) > 1))
+# endif
+
+# ifndef IN6_ARE_ADDR_EQUAL
+# define IN6_ARE_ADDR_EQUAL(a,b) \
+ ((((__const uint32_t *) (a))[0] == ((__const uint32_t *) (b))[0]) \
+ && (((__const uint32_t *) (a))[1] == ((__const uint32_t *) (b))[1]) \
+ && (((__const uint32_t *) (a))[2] == ((__const uint32_t *) (b))[2]) \
+ && (((__const uint32_t *) (a))[3] == ((__const uint32_t *) (b))[3]))
+# endif
+#endif /* HAVE_STRUCT_IN6_ADDR */
+
+/*
+ * Functions from getaddrinfo.c
+ */
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+struct sockaddr_storage
+{
+ uint16_t ss_family; /* Address family, etc. */
+ char ss_padding[128 - (sizeof(uint16_t))];
+};
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+/* for old netdb.h */
+# ifndef EAI_SERVICE
+# define EAI_MEMORY 2
+# define EAI_FAMILY 5 /* ai_family not supported */
+# define EAI_NONAME 8 /* hostname nor servname provided, or not known */
+# define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+# endif
+
+/* dummy value for old netdb.h */
+# ifndef AI_PASSIVE
+# define AI_PASSIVE 1
+# define AI_CANONNAME 2
+# define AI_NUMERICHOST 4
+# define NI_NUMERICHOST 2
+# define NI_NAMEREQD 4
+# define NI_NUMERICSERV 8
+
+struct addrinfo
+{
+ int ai_flags; /* Input flags. */
+ int ai_family; /* Protocol family for socket. */
+ int ai_socktype; /* Socket type. */
+ int ai_protocol; /* Protocol for socket. */
+ socklen_t ai_addrlen; /* Length of socket address. */
+ struct sockaddr *ai_addr; /* Socket address for socket. */
+ char *ai_canonname; /* Canonical name for service location. */
+ struct addrinfo *ai_next; /* Pointer to next in list. */
+};
+
+# endif /* AI_PASSIVE */
+#endif /* HAVE_STRUCT_ADDRINFO */
+
+/* Translate name of a service location and/or a service name to set of
+ socket addresses. */
+#ifndef HAVE_GETADDRINFO
+int getaddrinfo(char const *__name, char const *__service,
+ struct addrinfo const *__req,
+ struct addrinfo **__pai);
+
+/* Free `addrinfo' structure AI including associated storage. */
+void freeaddrinfo (struct addrinfo *__ai);
+
+/* Convert error return from getaddrinfo() to a string. */
+char const *gai_strerror (int __ecode);
+#endif
+
+/* Translate a socket address to a location and service name. */
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(struct sockaddr const *__sa,
+ socklen_t __salen, char *__host,
+ size_t __hostlen, char *__serv,
+ size_t __servlen, unsigned int __flags);
+#endif
+
+/*
+ * Functions from snprintf.c
+ */
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t count, char const *fmt, va_list arg);
+#endif
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t count, char const *fmt, ...);
+#endif
+
+/*
+ * Functions from strl{cat,cpy}.c
+ */
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, char const *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, char const *src, size_t siz);
+#endif
+
+#ifndef INT16SZ
+# define INT16SZ (2)
+#endif
+
+#ifndef HAVE_GMTIME_R
+struct tm *gmtime_r(time_t const *l_clock, struct tm *result);
+#endif
+
+#ifndef HAVE_VDPRINTF
+int vdprintf (int fd, char const *format, va_list args);
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+int gettimeofday (struct timeval *tv, void *tz);
+#endif
+
+/*
+ * Work around different ctime_r styles
+ */
+#if defined(CTIMERSTYLE) && (CTIMERSTYLE == SOLARISSTYLE)
+# define CTIME_R(a,b,c) ctime_r(a,b,c)
+# define ASCTIME_R(a,b,c) asctime_r(a,b,c)
+#else
+# define CTIME_R(a,b,c) ctime_r(a,b)
+# define ASCTIME_R(a,b,c) asctime_r(a,b)
+#endif
+
+#ifdef WIN32
+# undef interface
+# undef mkdir
+# define mkdir(_d, _p) mkdir(_d)
+# define FR_DIR_SEP '\\'
+# define FR_DIR_IS_RELATIVE(p) ((*p && (p[1] != ':')) || ((*p != '\\') && (*p != '\\')))
+#else
+# define FR_DIR_SEP '/'
+# define FR_DIR_IS_RELATIVE(p) ((*p) != '/')
+#endif
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+void timeval2ntp(struct timeval const *tv, uint8_t *ntp);
+void ntp2timeval(struct timeval *tv, char const *ntp);
+
+/*
+ * This is really hacky. Any code needing to perform operations on 128bit integers,
+ * or return 128BIT integers should check for HAVE_128BIT_INTEGERS.
+ */
+#ifndef HAVE_UINT128_T
+# ifdef HAVE___UINT128_T
+# define HAVE_128BIT_INTEGERS
+# define uint128_t __uint128_t
+# define int128_t __int128_t
+# else
+typedef struct uint128_t { uint8_t v[16]; } uint128_t;
+typedef struct int128_t { uint8_t v[16]; } int128_t;
+# endif
+#else
+# define HAVE_128BIT_INTEGERS
+#endif
+
+/* abcd efgh -> dcba hgfe -> hgfe dcba */
+#ifndef HAVE_HTONLL
+# ifdef FR_LITTLE_ENDIAN
+# ifdef HAVE_BUILTIN_BSWAP64
+# define ntohll(x) __builtin_bswap64(x)
+# else
+# define ntohll(x) (((uint64_t)ntohl((uint32_t)(x >> 32))) | (((uint64_t)ntohl(((uint32_t) x)) << 32)))
+# endif
+# else
+# define ntohll(x) (x)
+# endif
+# define htonll(x) ntohll(x)
+#endif
+
+#ifndef HAVE_HTONLLL
+# ifdef FR_LITTLE_ENDIAN
+# ifdef HAVE_128BIT_INTEGERS
+# define ntohlll(x) (((uint128_t)ntohll((uint64_t)(x >> 64))) | (((uint128_t)ntohll(((uint64_t) x)) << 64)))
+# else
+uint128_t ntohlll(uint128_t num);
+# endif
+# else
+# define ntohlll(x) (x)
+# endif
+# define htonlll(x) htohlll(x)
+#endif
+
+#ifndef HAVE_SIG_T
+typedef void(*sig_t)(int);
+#endif
+
+#ifdef HAVE_OPENSSL_HMAC_H
+# ifndef HAVE_HMAC_CTX_NEW
+HMAC_CTX *HMAC_CTX_new(void);
+# endif
+# ifndef HAVE_HMAC_CTX_FREE
+void HMAC_CTX_free(HMAC_CTX *ctx);
+# endif
+#endif
+
+#ifdef HAVE_OPENSSL_ASN1_H
+# ifndef HAVE_ASN1_STRING_GET0_DATA
+static inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ /*
+ * Trick the compiler into not issuing the warning on qualifier stripping.
+ * We know that ASN1_STRING_data doesn't change x, and we're casting
+ * the return value back to const immediately, so it's OK.
+ */
+ union {
+ const ASN1_STRING *c;
+ ASN1_STRING *nc;
+ } const_strip = {.c = x};
+ return ASN1_STRING_data(const_strip.nc);
+}
+# endif
+#endif
+
+#ifdef HAVE_OPENSSL_CONF_H
+# ifndef HAVE_CONF_MODULES_LOAD_FILE
+static inline int CONF_modules_load_file(const char *filename,
+ const char *appname,
+ unsigned long flags)
+{
+ (void)filename;
+ (void)flags;
+ return OPENSSL_config(appname);
+}
+# endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef HAVE_OPENSSL_SSL_H
+# ifndef HAVE_SSL_GET_CLIENT_RANDOM
+size_t SSL_get_client_random(const SSL *s, unsigned char *out, size_t outlen);
+# endif
+# ifndef HAVE_SSL_GET_SERVER_RANDOM
+size_t SSL_get_server_random(const SSL *s, unsigned char *out, size_t outlen);
+# endif
+# ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *s,
+ unsigned char *out, size_t outlen);
+# endif
+#endif
+
+/*
+ * NetBSD doesn't have O_DIRECTORY.
+ */
+#ifndef O_DIRECTORY
+#define O_DIRECTORY 0
+#endif
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
+#endif
+
+/*
+ * Not really missing, but may be submitted as patches
+ * to the talloc project at some point in the future.
+ */
+char *talloc_typed_strdup(const void *t, const char *p);
+char *talloc_typed_asprintf(const void *t, const char *fmt, ...) CC_HINT(format (printf, 2, 3));
+char *talloc_bstrndup(const void *t, char const *in, size_t inlen);
+#endif /* _FR_MISSING_H */
diff --git a/src/include/modcall.h b/src/include/modcall.h
new file mode 100644
index 0000000..7486ef1
--- /dev/null
+++ b/src/include/modcall.h
@@ -0,0 +1,55 @@
+#ifndef FR_MODCALL_H
+#define FR_MODCALL_H
+
+/* modcall.h: the outside interface to the module-calling tree. Includes
+ * functions to build the tree from the config file, and to call it by
+ * feeding it REQUESTs.
+ *
+ * Version: $Id$ */
+
+#include <freeradius-devel/conffile.h> /* Need CONF_* definitions */
+#include <freeradius-devel/modules.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * For each authorize/authtype/etc, we have an ordered
+ * tree of instances to call. This data structure keeps track
+ * of that order.
+ */
+typedef struct modcallable modcallable;
+
+int modcall_fixup_update(vp_map_t *map, void *ctx);
+
+int modcall(rlm_components_t component, modcallable *c, REQUEST *request);
+
+/* Parse a module-method's config section (e.g. authorize{}) into a tree that
+ * may be called with modcall() */
+modcallable *compile_modgroup(modcallable *parent,
+ rlm_components_t component, CONF_SECTION *cs);
+
+/* Create a single modcallable node that references a module instance. This
+ * may be a CONF_SECTION containing action specifiers like "notfound = return"
+ * or a simple CONF_PAIR, in which case the default actions are used. */
+modcallable *compile_modsingle(TALLOC_CTX *ctx, modcallable **parent, rlm_components_t component, CONF_ITEM *ci,
+ char const **modname);
+
+/*
+ * Do the second pass on compiling the modules.
+ */
+bool modcall_pass2(modcallable *mc);
+
+/* Add an entry to the end of a modgroup */
+void add_to_modcallable(modcallable *parent, modcallable *this);
+
+void modcall_debug(modcallable *mc, int depth);
+
+int modcall_pass2_condition(fr_cond_t *c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/modpriv.h b/src/include/modpriv.h
new file mode 100644
index 0000000..f69b47c
--- /dev/null
+++ b/src/include/modpriv.h
@@ -0,0 +1,69 @@
+/* modpriv.h: Stuff needed by both modules.c and modcall.c, but should not be
+ * accessed from anywhere else.
+ *
+ * Version: $Id$ */
+#ifndef FR_MODPRIV_H
+#define FR_MODPRIV_H
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#ifndef HAVE_DLFCN_H
+#error FreeRADIUS needs either libltdl, or a working dlopen()
+#else
+#include <dlfcn.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *fr_dlhandle;
+
+fr_dlhandle fr_dlopenext(char const *name);
+void *fr_dlsym(fr_dlhandle handle, char const *symbol);
+int fr_dlclose(fr_dlhandle handle);
+char const *fr_dlerror(void);
+
+/*
+ * Keep track of which modules we've loaded.
+ */
+typedef struct module_entry_t {
+ char name[MAX_STRING_LEN];
+ module_t const *module;
+ fr_dlhandle handle;
+} module_entry_t;
+
+typedef struct fr_module_hup_t fr_module_hup_t;
+
+/*
+ * Per-instance data structure, to correlate the modules
+ * with the instance names (may NOT be the module names!),
+ * and the per-instance data structures.
+ */
+typedef struct module_instance_t {
+ char name[MAX_STRING_LEN];
+ module_entry_t *entry;
+ void *insthandle;
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t *mutex;
+#endif
+ CONF_SECTION *cs;
+ time_t last_hup;
+ bool instantiated;
+ bool force;
+ rlm_rcode_t code;
+ fr_module_hup_t *mh;
+} module_instance_t;
+
+module_instance_t *module_instantiate(CONF_SECTION *modules, char const *askedname);
+module_instance_t *module_instantiate_method(CONF_SECTION *modules, char const *askedname, rlm_components_t *method);
+module_instance_t *module_find(CONF_SECTION *modules, char const *askedname);
+int find_module_sibling_section(CONF_SECTION **out, CONF_SECTION *module, char const *name);
+int module_hup_module(CONF_SECTION *cs, module_instance_t *node, time_t when);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_MODPRIV_H */
diff --git a/src/include/modules.h b/src/include/modules.h
new file mode 100644
index 0000000..9ba81b3
--- /dev/null
+++ b/src/include/modules.h
@@ -0,0 +1,175 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file modules.h
+ * @brief Interface to the RADIUS module system.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ */
+
+#ifndef RADIUS_MODULES_H
+#define RADIUS_MODULES_H
+
+RCSIDH(modules_h, "$Id$")
+
+#include <freeradius-devel/conffile.h>
+#include <freeradius-devel/features.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The different section components of the server
+ *
+ * Used as indexes in the methods array in the module_t struct.
+ */
+typedef enum rlm_components {
+ MOD_AUTHENTICATE = 0, //!< 0 methods index for authenticate section.
+ MOD_AUTHORIZE, //!< 1 methods index for authorize section.
+ MOD_PREACCT, //!< 2 methods index for preacct section.
+ MOD_ACCOUNTING, //!< 3 methods index for accounting section.
+ MOD_SESSION, //!< 4 methods index for checksimul section.
+ MOD_PRE_PROXY, //!< 5 methods index for preproxy section.
+ MOD_POST_PROXY, //!< 6 methods index for postproxy section.
+ MOD_POST_AUTH, //!< 7 methods index for postauth section.
+#ifdef WITH_COA
+ MOD_RECV_COA, //!< 8 methods index for recvcoa section.
+ MOD_SEND_COA, //!< 9 methods index for sendcoa section.
+#endif
+ MOD_COUNT //!< 10 how many components there are.
+} rlm_components_t;
+
+extern const FR_NAME_NUMBER mod_rcode_table[];
+
+/** Map a section name, to a section typename, to an attribute number
+ *
+ * Used by modules.c to define the mappings between names, types and control
+ * attributes.
+ */
+typedef struct section_type_value_t {
+ char const *section; //!< Section name e.g. "Authorize".
+ char const *typename; //!< Type name e.g. "Auth-Type".
+ int attr; //!< Attribute number.
+} section_type_value_t;
+
+/** Mappings between section names, typenames and control attributes
+ *
+ * Defined in modules.c.
+ */
+extern const section_type_value_t section_type_value[];
+
+#define RLM_TYPE_THREAD_SAFE (0 << 0) //!< Module is threadsafe.
+#define RLM_TYPE_THREAD_UNSAFE (1 << 0) //!< Module is not threadsafe.
+ //!< Server will protect calls
+ //!< with mutex.
+#define RLM_TYPE_HUP_SAFE (1 << 2) //!< Will be restarted on HUP.
+ //!< Server will instantiated
+ //!< new instance, and then
+ //!< destroy old instance.
+
+
+/* Stop people using different module/library/server versions together */
+#define RLM_MODULE_INIT RADIUSD_MAGIC_NUMBER
+
+/** Module section callback
+ *
+ * Is called when the module is listed in a particular section of a virtual
+ * server, and the request has reached the module call.
+ *
+ * @param[in] instance created in instantiated, holds module config.
+ * @param[in,out] request being processed.
+ * @return the appropriate rcode.
+ */
+typedef rlm_rcode_t (*packetmethod)(void *instance, REQUEST *request);
+
+/** Module instantiation callback
+ *
+ * Is called once per module instance. Is not called when new threads are
+ * spawned. Modules that require separate thread contexts should use the
+ * connection pool API.
+ *
+ * @param[in] mod_cs Module instance's configuration section.
+ * @param[out] instance Module instance's configuration structure, should be
+ * alloced by by callback and freed by detach.
+ * @return -1 if instantiation failed, else 0.
+ */
+typedef int (*instantiate_t)(CONF_SECTION *mod_cs, void *instance);
+
+/** Module detach callback
+ *
+ * Is called just before the server exits, and after re-instantiation on HUP,
+ * to free the old module instance.
+ *
+ * Detach should close all handles associated with the module instance, and
+ * free any memory allocated during instantiate.
+ *
+ * @param[in] instance to free.
+ * @return -1 if detach failed, else 0.
+ */
+typedef int (*detach_t)(void *instance);
+
+/** Metadata exported by the module
+ *
+ * This determines the capabilities of the module, and maps internal functions
+ * within the module to different sections.
+ */
+typedef struct module_t {
+ uint64_t magic; //!< Used to validate module struct.
+ char const *name; //!< The name of the module (without rlm_ prefix).
+ int type; //!< One or more of the RLM_TYPE_* constants.
+ size_t inst_size; //!< Size of the instance data
+ CONF_PARSER const *config; //!< Configuration information
+ instantiate_t bootstrap; //!< register dynamic attrs, etc.
+ instantiate_t instantiate; //!< Function to use for instantiation.
+ detach_t detach; //!< Function to use to free module instance.
+ packetmethod methods[MOD_COUNT]; //!< Pointers to the various section functions.
+} module_t;
+
+int modules_init(CONF_SECTION *);
+int modules_free(void);
+int modules_hup(CONF_SECTION *modules);
+rlm_rcode_t process_authorize(int type, REQUEST *request);
+rlm_rcode_t process_authenticate(int type, REQUEST *request);
+rlm_rcode_t module_preacct(REQUEST *request);
+rlm_rcode_t process_accounting(int type, REQUEST *request);
+int process_checksimul(int type, REQUEST *request, int maxsimul);
+rlm_rcode_t process_pre_proxy(int type, REQUEST *request);
+rlm_rcode_t process_post_proxy(int type, REQUEST *request);
+rlm_rcode_t process_post_auth(int type, REQUEST *request);
+#ifdef WITH_COA
+rlm_rcode_t process_recv_coa(int type, REQUEST *request);
+rlm_rcode_t process_send_coa(int type, REQUEST *request);
+#define MODULE_NULL_COA_FUNCS ,NULL,NULL
+#else
+#define MODULE_NULL_COA_FUNCS
+#endif
+
+rlm_rcode_t indexed_modcall(rlm_components_t comp, int idx, REQUEST *request);
+
+/*
+ * For now, these are strongly tied together.
+ */
+int virtual_servers_load(CONF_SECTION *config);
+void virtual_servers_free(time_t when);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RADIUS_MODULES_H */
diff --git a/src/include/net.h b/src/include/net.h
new file mode 100644
index 0000000..2d87b4c
--- /dev/null
+++ b/src/include/net.h
@@ -0,0 +1,140 @@
+#ifndef FR_NET_H
+#define FR_NET_H
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file include/net.h
+ * @brief Structures and functions for parsing raw network packets.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+
+/*
+ * If we don't have libpcap, we still need an enumeration of link layers.
+ */
+#ifdef HAVE_LIBPCAP
+# include <pcap.h>
+#else
+typedef enum {
+ DLT_RAW,
+ DLT_NULL,
+ DLT_LOOP,
+ DLT_EN10MB,
+ DLT_LINUX_SLL,
+ DLT_PFLOG
+} fr_dlt;
+#endif
+
+/*
+ * The number of bytes in an ethernet (MAC) address.
+ */
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Length of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ * Note that some compilers may pad "struct ether_header" to
+ * a multiple of 4 *bytes, for example, so "sizeof (struct
+ * ether_header)" may not give the right answer.
+ *
+ * 6 Byte SRC, 6 Byte DST, 2 Byte Ether type, 4 Byte CVID, 4 Byte SVID
+ */
+#define ETHER_HDR_LEN 22
+#define IP_HDR_LEN 60
+
+/*
+ * The number of bytes in a RADIUS packet header.
+ */
+#define RADIUS_HDR_LEN 20
+
+/*
+ * RADIUS packet length.
+ * RFC 2865, Section 3., subsection 'length' says:
+ * " ... and maximum length is 4096."
+ */
+#define MAX_RADIUS_LEN 4096
+#define MIN_RADIUS_LEN 20
+
+
+#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
+#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
+
+#define IP_VHL(v, hl) ((v & 0x0f) << 4) | (hl & 0x0f)
+
+#define I_DF 0x4000 //!< Dont fragment flag.
+#define IP_MF 0x2000 //!< More fragments flag.
+#define IP_OFFMASK 0x1fff //!< Mask for fragmenting bits.
+
+/*
+ * Structure of a DEC/Intel/Xerox or 802.3 Ethernet header.
+ */
+typedef struct CC_HINT(__packed__) ethernet_header {
+ uint8_t ether_dst[ETHER_ADDR_LEN];
+ uint8_t ether_src[ETHER_ADDR_LEN];
+ uint16_t ether_type;
+} ethernet_header_t;
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+typedef struct CC_HINT(__packed__) ip_header {
+ uint8_t ip_vhl; //!< Header length, version.
+
+ uint8_t ip_tos; //!< Type of service.
+ uint16_t ip_len; //!< Total length.
+ uint16_t ip_id; //!< identification.
+ uint16_t ip_off; //!< Fragment offset field.
+
+ uint8_t ip_ttl; //!< Time To Live.
+ uint8_t ip_p; //!< Protocol.
+ uint16_t ip_sum; //!< Checksum.
+ struct in_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header_t;
+
+typedef struct CC_HINT(__packed__) ip_header6 {
+ uint32_t ip_vtcfl; //!< Version, traffic class, flow label.
+ uint16_t ip_len; //!< Payload length
+
+ uint8_t ip_next; //!< Next header (protocol)
+ uint8_t ip_hopl; //!< IP Hop Limit
+
+ struct in6_addr ip_src, ip_dst; //!< Src and Dst address
+} ip_header6_t;
+
+/*
+ * UDP protocol header.
+ * Per RFC 768, September, 1981.
+ */
+typedef struct CC_HINT(__packed__) udp_header {
+ uint16_t src; //!< Source port.
+ uint16_t dst; //!< Destination port.
+ uint16_t len; //!< UDP length.
+ uint16_t checksum; //!< UDP checksum.
+} udp_header_t;
+
+typedef struct CC_HINT(__packed__) radius_packet_t {
+ uint8_t code;
+ uint8_t id;
+ uint8_t length[2];
+ uint8_t vector[AUTH_VECTOR_LEN];
+ uint8_t data[];
+} radius_packet_t;
+
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr);
+uint16_t fr_iph_checksum(uint8_t const *data, uint8_t ihl);
+#endif /* FR_NET_H */
diff --git a/src/include/openssl3.h b/src/include/openssl3.h
new file mode 100644
index 0000000..4423ee5
--- /dev/null
+++ b/src/include/openssl3.h
@@ -0,0 +1,109 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_OPENSSL3_H
+#define FR_OPENSSL3_H
+/**
+ * $Id$
+ *
+ * @file openssl3.h
+ * @brief Wrappers to shut up OpenSSL3
+ *
+ * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
+ */
+
+RCSIDH(openssl3_h, "$Id$")
+
+/*
+ * The HMAC APIs are deprecated in OpenSSL3. We don't want to
+ * fill the code with ifdef's, so we define some horrific
+ * wrappers here.
+ *
+ * This file should be included AFTER all OpenSSL header files.
+ */
+#ifdef HAVE_OPENSSL_SSL_H
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/core_names.h>
+
+typedef struct {
+ EVP_MAC *mac;
+ EVP_MAC_CTX *ctx;
+} HMAC3_CTX;
+#define HMAC_CTX HMAC3_CTX
+
+#define HMAC_CTX_new HMAC3_CTX_new
+static inline HMAC3_CTX *HMAC3_CTX_new(void)
+{
+ HMAC3_CTX *h = calloc(1, sizeof(*h));
+
+ return h;
+}
+
+#define HMAC_Init_ex(_ctx, _key, _keylen, _md, _engine) HMAC3_Init_ex(_ctx, _key, _keylen, _md, _engine)
+static inline int HMAC3_Init_ex(HMAC3_CTX *ctx, const unsigned char *key, unsigned int keylen, const EVP_MD *md, UNUSED void *engine)
+{
+ OSSL_PARAM params[2], *p = params;
+ char const *name;
+ char *unconst;
+
+ ctx->mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!ctx->mac) return 0;
+
+ ctx->ctx = EVP_MAC_CTX_new(ctx->mac);
+ if (!ctx->ctx) return 0;
+
+ name = EVP_MD_get0_name(md);
+ memcpy(&unconst, &name, sizeof(name)); /* const issues */
+
+ p[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, unconst, 0);
+ p[1] = OSSL_PARAM_construct_end();
+
+ return EVP_MAC_init(ctx->ctx, key, keylen, params);
+}
+
+#define HMAC_Update HMAC3_Update
+static inline int HMAC3_Update(HMAC3_CTX *ctx, const unsigned char *data, unsigned int datalen)
+{
+ return EVP_MAC_update(ctx->ctx, data, datalen);
+}
+
+#define HMAC_Final HMAC3_Final
+static inline int HMAC3_Final(HMAC3_CTX *ctx, unsigned char *out, unsigned int *len)
+{
+ size_t mylen = *len;
+
+ if (!EVP_MAC_final(ctx->ctx, out, &mylen, mylen)) return 0;
+
+ *len = mylen;
+ return 1;
+}
+
+#define HMAC_CTX_free HMAC3_CTX_free
+static inline void HMAC3_CTX_free(HMAC3_CTX *ctx)
+{
+ if (!ctx) return;
+
+ EVP_MAC_free(ctx->mac);
+ EVP_MAC_CTX_free(ctx->ctx);
+ free(ctx);
+}
+
+#define HMAC_CTX_set_flags(_ctx, _flags)
+
+#endif /* OPENSSL_VERSION_NUMBER */
+#endif
+#endif /* FR_OPENSSL3_H */
diff --git a/src/include/packet.h b/src/include/packet.h
new file mode 100644
index 0000000..5b41498
--- /dev/null
+++ b/src/include/packet.h
@@ -0,0 +1,87 @@
+#ifndef FR_PACKET_H
+#define FR_PACKET_H
+
+/*
+ * packet.h Structures and prototypes
+ * for packet manipulation
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001,2002,2003,2004,2005,2006 The FreeRADIUS server project
+ */
+
+RCSIDH(packet_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int fr_packet_cmp(RADIUS_PACKET const *a, RADIUS_PACKET const *b);
+int fr_inaddr_any(fr_ipaddr_t *ipaddr);
+void fr_request_from_reply(RADIUS_PACKET *request,
+ RADIUS_PACKET const *reply);
+int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port);
+
+typedef struct fr_packet_list_t fr_packet_list_t;
+
+fr_packet_list_t *fr_packet_list_create(int alloc_id);
+void fr_packet_list_free(fr_packet_list_t *pl);
+bool fr_packet_list_insert(fr_packet_list_t *pl,
+ RADIUS_PACKET **request_p);
+
+RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,
+ RADIUS_PACKET *request);
+RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
+ RADIUS_PACKET *reply);
+bool fr_packet_list_yank(fr_packet_list_t *pl,
+ RADIUS_PACKET *request);
+uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl);
+bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
+ RADIUS_PACKET **request_p, void **pctx);
+bool fr_packet_list_id_free(fr_packet_list_t *pl,
+ RADIUS_PACKET *request, bool yank);
+bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
+#ifdef WITH_RADIUSV11
+ bool radiusv11,
+#endif
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
+ void *ctx);
+bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd);
+bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd);
+bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd);
+int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback);
+int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set);
+RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set);
+
+uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl);
+uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl);
+void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received);
+
+/*
+ * "find" returns a pointer to the RADIUS_PACKET* member in the
+ * caller's structure. In order to get the pointer to the *top*
+ * of the caller's structure, you have to subtract the offset to
+ * the member from the returned pointer, and cast it to the
+ * required type.
+ */
+# define fr_packet2myptr(TYPE, MEMBER, PTR) (TYPE *) (((char *)PTR) - offsetof(TYPE, MEMBER))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_PACKET_H */
diff --git a/src/include/parser.h b/src/include/parser.h
new file mode 100644
index 0000000..9f3fdeb
--- /dev/null
+++ b/src/include/parser.h
@@ -0,0 +1,111 @@
+#ifndef FR_PARSER_H
+#define FR_PARSER_H
+
+/*
+ * parser.h Structures and prototypes for parsing
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2013 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSIDH(parser_h, "$Id$")
+
+#include <freeradius-devel/map.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef RADIUSD_H
+/*
+ * Also defined in radiusd.h for radius_evalute_cond()
+ */
+typedef struct fr_cond_t fr_cond_t;
+#endif
+
+typedef enum {
+ COND_NONE = 0,
+ COND_AND = '&',
+ COND_OR = '|'
+} fr_cond_op_t;
+
+
+typedef enum {
+ COND_TYPE_INVALID = 0,
+ COND_TYPE_TRUE,
+ COND_TYPE_FALSE,
+ COND_TYPE_EXISTS,
+ COND_TYPE_MAP,
+ COND_TYPE_CHILD
+} fr_cond_type_t;
+
+typedef enum {
+ PASS2_FIXUP_NONE = 0,
+ PASS2_FIXUP_ATTR,
+ PASS2_FIXUP_TYPE,
+ PASS2_PAIRCOMPARE
+} fr_cond_pass2_t;
+
+/*
+ * Allow for the following structures:
+ *
+ * FOO no OP, RHS is NULL
+ * FOO OP BAR
+ * (COND) no LHS/RHS, child is COND, child OP is true
+ * (!(COND)) no LHS/RHS, child is COND, child OP is NOT
+ * (COND1 OP COND2) no LHS/RHS, next is COND2, next OP is OP
+ */
+struct fr_cond_t {
+ fr_cond_type_t type;
+
+ CONF_ITEM const *ci;
+ union {
+ vp_map_t *map;
+ vp_tmpl_t *vpt;
+ fr_cond_t *child;
+ } data;
+
+ bool negate;
+ fr_cond_pass2_t pass2_fixup;
+
+ DICT_ATTR const *cast;
+
+ fr_cond_op_t next_op;
+ fr_cond_t *next;
+};
+
+
+/*
+ * One pass over the conditions means that all references must
+ * exist at parse time.
+ *
+ * Two pass means "soft fail", that some invalid references are
+ * left for pass 2.
+ */
+#define FR_COND_ONE_PASS (0)
+#define FR_COND_TWO_PASS (1)
+
+ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flag);
+size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c);
+
+bool fr_condition_walk(fr_cond_t *head, bool (*callback)(void *, fr_cond_t *), void *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_PARSER_H */
diff --git a/src/include/pcap.h b/src/include/pcap.h
new file mode 100644
index 0000000..1d57d93
--- /dev/null
+++ b/src/include/pcap.h
@@ -0,0 +1,101 @@
+#ifndef FR_PCAP_H
+#define FR_PCAP_H
+#ifdef HAVE_LIBPCAP
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file include/pcap.h
+ * @brief Prototypes and constants for PCAP functions.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/net.h>
+
+#include <sys/types.h>
+#include <pcap.h>
+
+#define SNAPLEN ETHER_HDR_LEN + IP_HDR_LEN + sizeof(struct udp_header) + MAX_RADIUS_LEN
+#define PCAP_BUFFER_DEFAULT (10000)
+/*
+ * It's unclear why this differs between platforms
+ */
+#ifndef __linux__
+# define PCAP_NONBLOCK_TIMEOUT (0)
+#else
+# define PCAP_NONBLOCK_TIMEOUT (-1)
+#endif
+
+#ifndef BIOCIMMEDIATE
+# define BIOCIMMEDIATE (2147762800)
+#endif
+
+/*
+ * Older versions of libpcap don't define this
+ */
+#ifndef PCAP_NETMASK_UNKNOWN
+# define PCAP_NETMASK_UNKNOWN 0
+#endif
+
+typedef enum {
+ PCAP_INVALID = 0,
+ PCAP_INTERFACE_IN,
+ PCAP_FILE_IN,
+ PCAP_STDIO_IN,
+ PCAP_INTERFACE_OUT,
+ PCAP_FILE_OUT,
+ PCAP_STDIO_OUT
+} fr_pcap_type_t;
+
+extern const FR_NAME_NUMBER pcap_types[];
+
+/*
+ * Internal pcap structures
+ */
+typedef struct fr_pcap fr_pcap_t;
+struct fr_pcap {
+ char errbuf[PCAP_ERRBUF_SIZE]; //!< Last error on this interface.
+ fr_pcap_type_t type; //!< What type of handle this is.
+ char *name; //!< Name of file or interface.
+ bool promiscuous; //!< Whether the interface is in promiscuous mode.
+ //!< Only valid for live capture handles.
+ int buffer_pkts; //!< How big to make the PCAP ring buffer.
+ //!< Actual buffer size is SNAPLEN * buffer.
+ //!< Only valid for live capture handles.
+
+ pcap_t *handle; //!< libpcap handle.
+ pcap_dumper_t *dumper; //!< libpcap dumper handle.
+
+ int link_layer; //!< Link layer type.
+
+ int fd; //!< Selectable file descriptor we feed to select.
+ struct pcap_stat pstats; //!< The last set of pcap stats for this handle.
+
+ fr_pcap_t *next; //!< Next handle in collection.
+};
+
+int fr_pcap_if_link_layer(char *errbuff, pcap_if_t *dev);
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type);
+int fr_pcap_open(fr_pcap_t *handle);
+int fr_pcap_apply_filter(fr_pcap_t *handle, char const *expression);
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *handle, char c);
+
+bool fr_pcap_link_layer_supported(int link_layer);
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_layer);
+#endif
+#endif
diff --git a/src/include/process.h b/src/include/process.h
new file mode 100644
index 0000000..35a91bf
--- /dev/null
+++ b/src/include/process.h
@@ -0,0 +1,87 @@
+#ifndef FR_PROCESS_H
+#define FR_PROCESS_H
+
+/*
+ * process.h State machine for a server to process packets.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2012 The FreeRADIUS server project
+ * Copyright 2012 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(process_h, "$Id$")
+
+#include <freeradius-devel/clients.h>
+#include <freeradius-devel/listen.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_SYSTEMD_WATCHDOG
+extern struct timeval sd_watchdog_interval;
+#endif
+
+typedef enum fr_state_action_t { /* server action */
+ FR_ACTION_INVALID = 0,
+ FR_ACTION_RUN,
+ FR_ACTION_DONE,
+ FR_ACTION_DUP,
+ FR_ACTION_TIMER,
+#ifdef WITH_PROXY
+ FR_ACTION_PROXY_REPLY,
+#endif
+ FR_ACTION_CANCELLED,
+ FR_ACTION_CONFLICT,
+ FR_ACTION_MAX_TIME,
+ FR_ACTION_INTERNAL_FAILURE,
+ FR_ACTION_CLEANUP_DELAY,
+ FR_ACTION_COA_CANCELLED,
+} fr_state_action_t;
+
+/*
+ * Function handler for requests.
+ */
+typedef int (*RAD_REQUEST_FUNP)(REQUEST *);
+typedef void (*fr_request_process_t)(REQUEST *, int);
+
+extern time_t fr_start_time;
+
+#ifdef HAVE_PTHREAD_H
+/*
+ * In threads.c
+ */
+int request_enqueue(REQUEST *request);
+#endif
+
+int request_receive(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet,
+ RADCLIENT *client, RAD_REQUEST_FUNP fun);
+void request_inject(REQUEST *request);
+
+#ifdef WITH_PROXY
+int request_proxy_reply(RADIUS_PACKET *packet);
+
+void proxy_listener_freeze(rad_listen_t *listener, fr_event_fd_handler_t write_handler);
+void proxy_listener_thaw(rad_listen_t *listener);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_PROCESS_H */
diff --git a/src/include/protocol.h b/src/include/protocol.h
new file mode 100644
index 0000000..f09ea4a
--- /dev/null
+++ b/src/include/protocol.h
@@ -0,0 +1,63 @@
+#ifndef FR_PROTOCOL_H
+#define FR_PROTOCOL_H
+
+/*
+ * heap.h Structures and prototypes for plug-in protocols
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2013 Alan DeKok
+ */
+
+RCSIDH(protocol_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * We'll use this below.
+ */
+typedef int (*rad_listen_parse_t)(CONF_SECTION *, rad_listen_t *);
+typedef void (*rad_listen_free_t)(rad_listen_t *);
+
+typedef struct fr_protocol_t {
+ uint64_t magic; //!< Used to validate loaded library
+ char const *name; //!< The name of the protocol
+ size_t inst_size;
+ CONF_PARSER *proto_config;
+
+ rad_listen_parse_t parse;
+ rad_listen_free_t free;
+ rad_listen_recv_t recv;
+ rad_listen_send_t send;
+ rad_listen_print_t print;
+ rad_listen_encode_t encode;
+ rad_listen_decode_t decode;
+} fr_protocol_t;
+
+/*
+ * @todo: fix for later
+ */
+int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this);
+int common_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_PROTOCOL_H */
diff --git a/src/include/rad_assert.h b/src/include/rad_assert.h
new file mode 100644
index 0000000..0c16e59
--- /dev/null
+++ b/src/include/rad_assert.h
@@ -0,0 +1,50 @@
+#ifndef RAD_ASSERT_H
+#define RAD_ASSERT_H
+/*
+ * rad_assert.h Debug assertions, with logging.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2001,2006 The FreeRADIUS server project
+ */
+
+RCSIDH(rad_assert_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void rad_assert_fail(char const *file, unsigned int line, char const *expr) CC_HINT(noreturn);
+
+#ifdef NDEBUG
+ #define rad_assert(expr) ((void) (0))
+
+#elif !defined(__clang_analyzer__)
+ #define rad_assert(expr) \
+ ((void) ((expr) ? (void) 0 : \
+ (void) rad_assert_fail (__FILE__, __LINE__, #expr)))
+
+#else
+#include <assert.h>
+#define rad_assert assert
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/radclient.h b/src/include/radclient.h
new file mode 100644
index 0000000..1eb10f3
--- /dev/null
+++ b/src/include/radclient.h
@@ -0,0 +1,93 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef _RADCLIENT_H
+#define _RADCLIENT_H
+/**
+ * $Id$
+ *
+ * @file radclient.h
+ * @brief Structures for the radclient utility.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+#include <freeradius-devel/libradius.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Logging macros
+ */
+ #undef DEBUG
+#define DEBUG(fmt, ...) if (do_output && (fr_debug_lvl > 0)) fprintf(fr_log_fp, fmt "\n", ## __VA_ARGS__)
+#undef DEBUG2
+#define DEBUG2(fmt, ...) if (do_output && (fr_debug_lvl > 1)) fprintf(fr_log_fp, fmt "\n", ## __VA_ARGS__)
+
+
+#define ERROR(fmt, ...) if (do_output) fr_perror("radclient: " fmt, ## __VA_ARGS__)
+
+#define RDEBUG_ENABLED() (do_output && (fr_debug_lvl > 0))
+#define RDEBUG_ENABLED2() (do_output && (fr_debug_lvl > 1))
+
+#define REDEBUG(fmt, ...) if (do_output) fr_perror("(%" PRIu64 ") " fmt , request->num, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (do_output && (fr_debug_lvl > 0)) fprintf(fr_log_fp, "(%" PRIu64 ") " fmt "\n", request->num, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (do_output && (fr_debug_lvl > 1)) fprintf(fr_log_fp, "(%" PRIu64 ") " fmt "\n", request->num, ## __VA_ARGS__)
+
+typedef struct rc_stats {
+ uint64_t accepted; //!< Requests to which we received a accept
+ uint64_t rejected; //!< Requests to which we received a reject
+ uint64_t lost; //!< Requests to which we received no response
+ uint64_t passed; //!< Requests which passed a filter
+ uint64_t failed; //!< Requests which failed a fitler
+} rc_stats_t;
+
+typedef struct rc_file_pair {
+ char const *packets; //!< The file containing the request packet
+ char const *filters; //!< The file containing the definition of the
+ //!< packet we want to match.
+} rc_file_pair_t;
+
+typedef struct rc_request rc_request_t;
+
+struct rc_request {
+ uint64_t num; //!< The number (within the file) of the request were reading.
+
+ rc_request_t *prev;
+ rc_request_t *next;
+
+ rc_file_pair_t *files; //!< Request and response file names.
+
+ VALUE_PAIR *password; //!< Cleartext-Password
+ time_t timestamp;
+
+ RADIUS_PACKET *packet; //!< The outgoing request.
+ RADIUS_PACKET *reply; //!< The incoming response.
+ VALUE_PAIR *filter; //!< If the reply passes the filter, then the request passes.
+ PW_CODE filter_code; //!< Expected code of the response packet.
+
+ int resend;
+ int tries;
+ bool done; //!< Whether the request is complete.
+
+ char const *name; //!< Test name (as specified in the request).
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RADCLIENT_H */
diff --git a/src/include/radius.h b/src/include/radius.h
new file mode 100644
index 0000000..473528d
--- /dev/null
+++ b/src/include/radius.h
@@ -0,0 +1,186 @@
+/*
+ * radius.h Constants of the radius protocol.
+ *
+ * Version: $Id$
+ *
+ */
+
+/** Internal data types used within libfreeradius
+ *
+ */
+typedef enum {
+ PW_TYPE_INVALID = 0, //!< Invalid (uninitialised) attribute type.
+ PW_TYPE_STRING, //!< String of printable characters.
+ PW_TYPE_INTEGER, //!< 32 Bit unsigned integer.
+ PW_TYPE_IPV4_ADDR, //!< 32 Bit IPv4 Address.
+ PW_TYPE_DATE, //!< 32 Bit Unix timestamp.
+ PW_TYPE_ABINARY, //!< Ascend binary format a packed data structure.
+ PW_TYPE_OCTETS, //!< Raw octets.
+ PW_TYPE_IFID, //!< Interface ID.
+ PW_TYPE_IPV6_ADDR, //!< 128 Bit IPv6 Address.
+ PW_TYPE_IPV6_PREFIX, //!< IPv6 Prefix.
+ PW_TYPE_BYTE, //!< 8 Bit unsigned integer.
+ PW_TYPE_SHORT, //!< 16 Bit unsigned integer.
+ PW_TYPE_ETHERNET, //!< 48 Bit Mac-Address.
+ PW_TYPE_SIGNED, //!< 32 Bit signed integer.
+ PW_TYPE_COMBO_IP_ADDR, //!< WiMAX IPv4 or IPv6 address depending on length.
+ PW_TYPE_TLV, //!< Contains nested attributes.
+ PW_TYPE_EXTENDED, //!< Extended attribute space attribute.
+ PW_TYPE_LONG_EXTENDED, //!< Long extended attribute space attribute.
+ PW_TYPE_EVS, //!< Extended attribute, vendor specific.
+ PW_TYPE_INTEGER64, //!< 64 Bit unsigned integer.
+ PW_TYPE_IPV4_PREFIX, //!< IPv4 Prefix.
+ PW_TYPE_VSA, //!< Vendor-Specific, for RADIUS attribute 26.
+ PW_TYPE_TIMEVAL, //!< Time value (struct timeval), only for config items.
+ PW_TYPE_BOOLEAN, //!< A truth value.
+ PW_TYPE_COMBO_IP_PREFIX, //!< WiMAX IPv4 or IPv6 address prefix depending on length.
+ PW_TYPE_MAX //!< Number of defined data types.
+} PW_TYPE;
+
+/** RADIUS packet codes
+ *
+ */
+typedef enum {
+ PW_CODE_UNDEFINED = 0, //!< Packet code has not been set
+ PW_CODE_ACCESS_REQUEST = 1, //!< RFC2865 - Access-Request
+ PW_CODE_ACCESS_ACCEPT = 2, //!< RFC2865 - Access-Accept
+ PW_CODE_ACCESS_REJECT = 3, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCOUNTING_REQUEST = 4, //!< RFC2866 - Accounting-Request
+ PW_CODE_ACCOUNTING_RESPONSE = 5, //!< RFC2866 - Accounting-Response
+ PW_CODE_ACCOUNTING_STATUS = 6, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_REQUEST = 7, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_ACK = 8, //!< RFC3575 - Reserved
+ PW_CODE_PASSWORD_REJECT = 9, //!< RFC3575 - Reserved
+ PW_CODE_ACCOUNTING_MESSAGE = 10, //!< RFC3575 - Reserved
+ PW_CODE_ACCESS_CHALLENGE = 11, //!< RFC2865 - Access-Challenge
+ PW_CODE_STATUS_SERVER = 12, //!< RFC2865/RFC5997 - Status Server (request)
+ PW_CODE_STATUS_CLIENT = 13, //!< RFC2865/RFC5997 - Status Server (response)
+ PW_CODE_DISCONNECT_REQUEST = 40, //!< RFC3575/RFC5176 - Disconnect-Request
+ PW_CODE_DISCONNECT_ACK = 41, //!< RFC3575/RFC5176 - Disconnect-Ack (positive)
+ PW_CODE_DISCONNECT_NAK = 42, //!< RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
+ PW_CODE_COA_REQUEST = 43, //!< RFC3575/RFC5176 - CoA-Request
+ PW_CODE_COA_ACK = 44, //!< RFC3575/RFC5176 - CoA-Ack (positive)
+ PW_CODE_COA_NAK = 45, //!< RFC3575/RFC5176 - CoA-Nak (not willing to perform)
+ PW_CODE_MAX = 255, //!< Maximum possible code
+} PW_CODE;
+
+#define PW_AUTH_UDP_PORT 1812
+#define PW_AUTH_UDP_PORT_ALT 1645
+#define PW_ACCT_UDP_PORT 1813
+#define PW_ACCT_UDP_PORT_ALT 1646
+#define PW_POD_UDP_PORT 3799
+#define PW_RADIUS_TLS_PORT 2083
+#define PW_COA_UDP_PORT 3799
+
+/*
+ * The RFC says 4096 octets max, and most packets are less than 256.
+ */
+#define MAX_PACKET_LEN 4096
+
+#include <freeradius-devel/rfc2865.h>
+#include <freeradius-devel/rfc2866.h>
+#include <freeradius-devel/rfc2867.h>
+#include <freeradius-devel/rfc2868.h>
+#include <freeradius-devel/rfc2869.h>
+
+#include <freeradius-devel/rfc3162.h>
+#include <freeradius-devel/rfc3576.h>
+#include <freeradius-devel/rfc3580.h>
+
+#include <freeradius-devel/rfc4072.h>
+#include <freeradius-devel/rfc4372.h>
+
+#define PW_CUI PW_CHARGEABLE_USER_IDENTITY
+
+#include <freeradius-devel/rfc4675.h>
+#include <freeradius-devel/rfc4818.h>
+#include <freeradius-devel/rfc4849.h>
+
+#include <freeradius-devel/rfc5580.h>
+#include <freeradius-devel/rfc5607.h>
+#include <freeradius-devel/rfc5904.h>
+
+#include <freeradius-devel/rfc6572.h>
+#include <freeradius-devel/rfc6677.h>
+#include <freeradius-devel/rfc6911.h>
+#include <freeradius-devel/rfc6929.h>
+#include <freeradius-devel/rfc6930.h>
+
+#include <freeradius-devel/rfc7055.h>
+#include <freeradius-devel/rfc7155.h>
+#include <freeradius-devel/rfc7268.h>
+
+/*
+ * All internal attributes are now defined in this file.
+ */
+#include <freeradius-devel/attributes.h>
+
+#include <freeradius-devel/freeradius.h>
+
+#include <freeradius-devel/vqp.h>
+
+#define PW_DIGEST_RESPONSE 206
+#define PW_DIGEST_ATTRIBUTES 207
+
+/*
+ * Integer Translations
+ */
+
+/* User Types */
+
+#define PW_LOGIN_USER 1
+#define PW_FRAMED_USER 2
+#define PW_CALLBACK_LOGIN_USER 3
+#define PW_CALLBACK_FRAMED_USER 4
+#define PW_OUTBOUND_USER 5
+#define PW_ADMINISTRATIVE_USER 6
+#define PW_NAS_PROMPT_USER 7
+#define PW_AUTHENTICATE_ONLY 8
+#define PW_CALLBACK_NAS_PROMPT 9
+#define PW_AUTHORIZE_ONLY 17
+
+/* Framed Protocols */
+
+#define PW_PPP 1
+#define PW_SLIP 2
+
+/* Status Types */
+
+#define PW_STATUS_START 1
+#define PW_STATUS_STOP 2
+#define PW_STATUS_ALIVE 3
+#define PW_STATUS_ACCOUNTING_ON 7
+#define PW_STATUS_ACCOUNTING_OFF 8
+
+/*
+ * Vendor Private Enterprise Codes
+ */
+#define VENDORPEC_MICROSOFT 311
+#define VENDORPEC_FREERADIUS 11344
+#define VENDORPEC_WIMAX 24757
+#define VENDORPEC_UKERNA 25622
+
+/*
+ * Microsoft has vendor code 311.
+ */
+#define PW_MSCHAP_RESPONSE 1
+#define PW_MSCHAP_ERROR 2
+#define PW_MSCHAP_CPW_1 3
+#define PW_MSCHAP_CPW_2 4
+#define PW_MSCHAP_NT_ENC_PW 6
+#define PW_MSCHAP_MPPE_ENCRYPTION_POLICY 7
+#define PW_MSCHAP_MPPE_ENCRYPTION_TYPES 8
+#define PW_MSCHAP_CHALLENGE 11
+#define PW_MSCHAP_MPPE_SEND_KEY 16
+#define PW_MSCHAP_MPPE_RECV_KEY 17
+#define PW_MSCHAP2_RESPONSE 25
+#define PW_MSCHAP2_SUCCESS 26
+#define PW_MSCHAP2_CPW 27
+#define PW_MS_QUARANTINE_SOH 55
+
+/*
+ * JANET's code for transporting eap channel binding data over ttls
+ */
+
+#define PW_UKERNA_CHBIND 135
+#define PW_UKERNA_TR_COI 136
diff --git a/src/include/radiusd.h b/src/include/radiusd.h
new file mode 100644
index 0000000..594a6bd
--- /dev/null
+++ b/src/include/radiusd.h
@@ -0,0 +1,631 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef RADIUSD_H
+#define RADIUSD_H
+/**
+ * $Id$
+ *
+ * @file radiusd.h
+ * @brief Structures, prototypes and global variables for the FreeRADIUS server.
+ *
+ * @copyright 1999-2000,2002-2008 The FreeRADIUS server project
+ */
+
+RCSIDH(radiusd_h, "$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/conffile.h>
+#include <freeradius-devel/event.h>
+#include <freeradius-devel/connection.h>
+
+typedef struct rad_request REQUEST;
+
+#include <freeradius-devel/log.h>
+
+#ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+#else
+# include <sys/wait.h>
+#endif
+
+#ifndef NDEBUG
+# define REQUEST_MAGIC (0xdeadbeef)
+#endif
+
+/*
+ * WITH_VMPS is handled by src/include/features.h
+ */
+#ifdef WITHOUT_VMPS
+# undef WITH_VMPS
+#endif
+
+#ifdef WITH_TLS
+# include <freeradius-devel/tls.h>
+#endif
+
+#include <freeradius-devel/stats.h>
+#include <freeradius-devel/realms.h>
+#include <freeradius-devel/xlat.h>
+#include <freeradius-devel/tmpl.h>
+#include <freeradius-devel/map.h>
+#include <freeradius-devel/clients.h>
+#include <freeradius-devel/process.h>
+/*
+ * All POSIX systems should have these headers
+ */
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * See util.c
+ */
+typedef struct request_data_t request_data_t;
+
+/** Return codes indicating the result of the module call
+ *
+ * All module functions must return one of the codes listed below (apart from
+ * RLM_MODULE_NUMCODES, which is used to check for validity).
+ */
+typedef enum rlm_rcodes {
+ RLM_MODULE_REJECT = 0, //!< Immediately reject the request.
+ RLM_MODULE_FAIL, //!< Module failed, don't reply.
+ RLM_MODULE_OK, //!< The module is OK, continue.
+ RLM_MODULE_HANDLED, //!< The module handled the request, so stop.
+ RLM_MODULE_INVALID, //!< The module considers the request invalid.
+ RLM_MODULE_USERLOCK, //!< Reject the request (user is locked out).
+ RLM_MODULE_NOTFOUND, //!< User not found.
+ RLM_MODULE_NOOP, //!< Module succeeded without doing anything.
+ RLM_MODULE_UPDATED, //!< OK (pairs modified).
+ RLM_MODULE_NUMCODES, //!< How many valid return codes there are.
+ RLM_MODULE_UNKNOWN //!< Error resolving rcode (should not be
+ //!< returned by modules).
+} rlm_rcode_t;
+extern const FR_NAME_NUMBER modreturn_table[];
+
+/** Main server configuration
+ *
+ * The parsed version of the main server config.
+ */
+typedef struct main_config {
+ struct main_config *next; //!< Next version of the main_config.
+
+ char const *name; //!< Name of the daemon, usually 'radiusd'.
+ CONF_SECTION *config; //!< Root of the server config.
+
+ fr_ipaddr_t myip; //!< IP to bind to. Set on command line.
+ uint16_t port; //!< Port to bind to. Set on command line.
+
+ bool suppress_secrets; //!< for debug levels < 3
+ bool log_auth; //!< Log all authentication attempts.
+ bool log_accept; //!< Log Access-Accept
+ bool log_reject; //!< Log Access-Reject
+ bool log_auth_badpass; //!< Log successful authentications.
+ bool log_auth_goodpass; //!< Log failed authentications.
+ char const *auth_badpass_msg; //!< Additional text to append to successful auth messages.
+ char const *auth_goodpass_msg; //!< Additional text to append to failed auth messages.
+
+ char const *denied_msg; //!< Additional text to append if the user is already logged
+ //!< in (simultaneous use check failed).
+
+ bool daemonize; //!< Should the server daemonize on startup.
+ char const *pid_file; //!< Path to write out PID file.
+
+#ifdef WITH_PROXY
+ bool proxy_requests; //!< Toggle to enable/disable proxying globally.
+#endif
+ struct timeval reject_delay; //!< How long to wait before sending an Access-Reject.
+ bool status_server; //!< Whether to respond to status-server messages.
+
+
+ uint32_t max_request_time; //!< How long a request can be processed for before
+ //!< timing out.
+ uint32_t cleanup_delay; //!< How long before cleaning up cached responses.
+ uint32_t max_requests;
+
+ bool postauth_client_lost; //!< Whether to run Post-Auth-Type Client-Lost section
+
+ uint32_t debug_level;
+ char const *log_file;
+ int syslog_facility;
+
+ char const *dictionary_dir; //!< Where to load dictionaries from.
+
+ char const *checkrad; //!< Script to use to determine if a user is already
+ //!< connected.
+
+ rad_listen_t *listen; //!< Head of a linked list of listeners.
+
+
+ char const *panic_action; //!< Command to execute if the server receives a fatal
+ //!< signal.
+
+ struct timeval init_delay; //!< Initial request processing delay.
+
+ uint32_t talloc_pool_size; //!< Size of pool to allocate to hold each #REQUEST.
+ bool debug_memory; //!< Cleanup the server properly on exit, freeing
+ //!< up any memory we allocated.
+ bool memory_report; //!< Print a memory report on what's left unfreed.
+ //!< Can only be used when the server is running in single
+ //!< threaded mode.
+
+ bool allow_core_dumps; //!< Whether the server is allowed to drop a core when
+ //!< receiving a fatal signal.
+
+ bool write_pid; //!< write the PID file
+
+ bool exiting; //!< are we exiting?
+
+
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+ char const *allow_vulnerable_openssl; //!< The CVE number of the last security issue acknowledged.
+#endif
+} main_config_t;
+
+#if defined(WITH_VERIFY_PTR)
+# define VERIFY_REQUEST(_x) verify_request(__FILE__, __LINE__, _x)
+#else
+/*
+ * Even if were building without WITH_VERIFY_PTR
+ * the pointer must not be NULL when these various macros are used
+ * so we can add some sneaky asserts.
+ */
+# define VERIFY_REQUEST(_x) rad_assert(_x)
+#endif
+
+typedef enum {
+ REQUEST_ACTIVE = 1,
+ REQUEST_STOP_PROCESSING,
+ REQUEST_COUNTED
+} rad_master_state_t;
+#define REQUEST_MASTER_NUM_STATES (REQUEST_COUNTED + 1)
+
+typedef enum {
+ REQUEST_QUEUED = 1,
+ REQUEST_RUNNING,
+ REQUEST_PROXIED,
+ REQUEST_RESPONSE_DELAY,
+ REQUEST_CLEANUP_DELAY,
+ REQUEST_DONE
+} rad_child_state_t;
+#define REQUEST_CHILD_NUM_STATES (REQUEST_DONE + 1)
+
+struct rad_request {
+#ifndef NDEBUG
+ uint32_t magic; //!< Magic number used to detect memory corruption,
+ //!< or request structs that have not been properly initialised.
+#endif
+ unsigned int number; //!< Monotonically increasing request number. Reset on server restart.
+ time_t timestamp; //!< When the request was received.
+
+ request_data_t *data; //!< Request metadata.
+
+ rad_listen_t *listener; //!< The listener that received the request.
+ RADCLIENT *client; //!< The client that originally sent us the request.
+
+ RADIUS_PACKET *packet; //!< Incoming request.
+ VALUE_PAIR *username; //!< Cached username #VALUE_PAIR from request #RADIUS_PACKET.
+ VALUE_PAIR *password; //!< Cached password #VALUE_PAIR from request #RADIUS_PACKET.
+
+ RADIUS_PACKET *reply; //!< Outgoing response.
+
+ VALUE_PAIR *config; //!< #VALUE_PAIR (s) used to set per request parameters
+ //!< for modules and the server core at runtime.
+
+ TALLOC_CTX *state_ctx; //!< for request->state
+ VALUE_PAIR *state; //!< #VALUE_PAIR (s) available over the lifetime of the authentication
+ //!< attempt. Useful where the attempt involves a sequence of
+ //!< many request/challenge packets, like OTP, and EAP.
+
+#ifdef WITH_PROXY
+ rad_listen_t *proxy_listener;//!< Listener for outgoing requests.
+ RADIUS_PACKET *proxy; //!< Outgoing request to proxy server.
+ RADIUS_PACKET *proxy_reply; //!< Incoming response from proxy server.
+
+ home_server_t *home_server;
+ home_pool_t *home_pool; //!< For dynamic failover
+#endif
+
+ fr_request_process_t process; //!< The function to call to move the request through the state machine.
+
+ struct timeval response_delay; //!< How long to wait before sending Access-Rejects.
+ fr_state_action_t timer_action; //!< What action to perform when the timer event fires.
+ fr_event_t *ev; //!< Event in event loop tied to this request.
+
+ RAD_REQUEST_FUNP handle; //!< The function to call to move the request through the
+ //!< various server configuration sections.
+ rlm_rcode_t rcode; //!< Last rcode returned by a module
+ char const *module; //!< Module the request is currently being processed by.
+ char const *component; //!< Section the request is in.
+
+ int delay;
+
+ rad_master_state_t master_state; //!< Set by the master thread to signal the child that's currently
+ //!< working with the request, to do something.
+ rad_child_state_t child_state;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_t child_pid; //!< Current thread handling the request.
+#endif
+
+ main_config_t *root; //!< Pointer to the main config hack to try and deal with hup.
+
+
+ int simul_max; //!< Maximum number of concurrent sessions for this user.
+#ifdef WITH_SESSION_MGMT
+ int simul_count; //!< The current number of sessions for this user.
+ int simul_mpp; //!< WEIRD: 1 is false, 2 is true.
+#endif
+
+ RAD_LISTEN_TYPE priority;
+
+ bool max_time; //!< did we hit max time?
+
+ bool in_request_hash;
+#ifdef WITH_PROXY
+ bool in_proxy_hash;
+
+ uint32_t num_proxied_requests; //!< How many times this request was proxied.
+ //!< Retransmissions are driven by requests from the NAS.
+ uint32_t num_proxied_responses;
+#endif
+
+ char const *server;
+ REQUEST *parent;
+
+ struct {
+ radlog_func_t func; //!< Function to call to output log messages about this
+ //!< request.
+
+ log_lvl_t lvl; //!< Controls the verbosity of debug statements regarding
+ //!< the request.
+
+ uint8_t indent; //!< By how much to indent log messages. uin8_t so it's obvious
+ //!< when a request has been exdented too much.
+ } log;
+
+ uint32_t options; //!< mainly for proxying EAP-MSCHAPv2.
+
+#ifdef WITH_COA
+ REQUEST *coa; //!< CoA request originated by this request.
+ uint32_t num_coa_requests;//!< Counter for number of requests sent including
+ //!< retransmits.
+#endif
+}; /* REQUEST typedef */
+
+#define RAD_REQUEST_LVL_NONE (0) //!< No debug messages should be printed.
+#define RAD_REQUEST_LVL_DEBUG (1)
+#define RAD_REQUEST_LVL_DEBUG2 (2)
+#define RAD_REQUEST_LVL_DEBUG3 (3)
+#define RAD_REQUEST_LVL_DEBUG4 (4)
+
+#define RAD_REQUEST_OPTION_COA (1 << 0)
+#define RAD_REQUEST_OPTION_CTX (1 << 1)
+#define RAD_REQUEST_OPTION_CANCELLED (1 << 2)
+
+#define SECONDS_PER_DAY 86400
+#define MAX_REQUEST_TIME 30
+#define CLEANUP_DELAY 5
+#define MAX_REQUESTS 256
+#define RETRY_DELAY 5
+#define RETRY_COUNT 3
+#define DEAD_TIME 120
+#define EXEC_TIMEOUT 10
+
+/* for paircompare_register */
+typedef int (*RAD_COMPARE_FUNC)(void *instance, REQUEST *,VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **);
+
+typedef enum request_fail {
+ REQUEST_FAIL_UNKNOWN = 0,
+ REQUEST_FAIL_NO_THREADS, //!< No threads to handle it.
+ REQUEST_FAIL_DECODE, //!< Rad_decode didn't like it.
+ REQUEST_FAIL_PROXY, //!< Call to proxy modules failed.
+ REQUEST_FAIL_PROXY_SEND, //!< Proxy_send didn't like it.
+ REQUEST_FAIL_NO_RESPONSE, //!< We weren't told to respond, so we reject.
+ REQUEST_FAIL_HOME_SERVER, //!< The home server didn't respond.
+ REQUEST_FAIL_HOME_SERVER2, //!< Another case of the above.
+ REQUEST_FAIL_HOME_SERVER3, //!< Another case of the above.
+ REQUEST_FAIL_NORMAL_REJECT, //!< Authentication failure.
+ REQUEST_FAIL_SERVER_TIMEOUT //!< The server took too long to process the request.
+} request_fail_t;
+
+/*
+ * Global variables.
+ *
+ * We really shouldn't have this many.
+ */
+extern log_lvl_t rad_debug_lvl;
+extern char const *radacct_dir;
+extern char const *radlog_dir;
+extern char const *radlib_dir;
+extern bool log_stripped_names;
+extern HIDDEN char const *radiusd_version;
+extern HIDDEN char const *radiusd_version_short;
+void radius_signal_self(int flag);
+
+typedef enum {
+ RADIUS_SIGNAL_SELF_NONE = (0),
+ RADIUS_SIGNAL_SELF_HUP = (1 << 0),
+ RADIUS_SIGNAL_SELF_TERM = (1 << 1),
+ RADIUS_SIGNAL_SELF_EXIT = (1 << 2),
+ RADIUS_SIGNAL_SELF_DETAIL = (1 << 3),
+ RADIUS_SIGNAL_SELF_NEW_FD = (1 << 4),
+ RADIUS_SIGNAL_SELF_MAX = (1 << 5)
+} radius_signal_t;
+/*
+ * Function prototypes.
+ */
+
+/* acct.c */
+int rad_accounting(REQUEST *);
+
+int rad_coa_recv(REQUEST *request);
+
+/* session.c */
+int rad_check_ts(fr_ipaddr_t const *nas_addr, uint32_t nas_port, char const *nas_port_id, char const *user, char const *sessionid);
+int session_zap(REQUEST *request, fr_ipaddr_t const *nas_addr,
+ uint32_t nas_port, char const *nas_port_id, char const *user,
+ char const *sessionid, uint32_t cliaddr,
+ char proto, int session_time);
+
+/* radiusd.c */
+#undef debug_pair
+void debug_pair(VALUE_PAIR *);
+void rdebug_pair(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *);
+void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *);
+void rdebug_proto_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *);
+int log_err (char *);
+
+/* util.c */
+#define MEM(x) if (!(x)) { ERROR("%s[%u] OUT OF MEMORY", __FILE__, __LINE__); _fr_exit_now(__FILE__, __LINE__, 1); }
+void (*reset_signal(int signo, void (*func)(int)))(int);
+int rad_mkdir(char *directory, mode_t mode, uid_t uid, gid_t gid);
+size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen,
+ char const *in, UNUSED void *arg);
+size_t rad_filename_escape(UNUSED REQUEST *request, char *out, size_t outlen,
+ char const *in, UNUSED void *arg);
+ssize_t rad_filename_unescape(char *out, size_t outlen, char const *in, size_t inlen);
+void *rad_malloc(size_t size); /* calls exit(1) on error! */
+void rad_const_free(void const *ptr);
+REQUEST *request_alloc(TALLOC_CTX *ctx);
+REQUEST *request_alloc_fake(REQUEST *oldreq);
+REQUEST *request_alloc_coa(REQUEST *request);
+int request_data_add(REQUEST *request,
+ void *unique_ptr, int unique_int,
+ void *opaque, bool free_opaque);
+void *request_data_get(REQUEST *request,
+ void *unique_ptr, int unique_int);
+void *request_data_reference(REQUEST *request,
+ void *unique_ptr, int unique_int);
+int rad_copy_string(char *dst, char const *src);
+int rad_copy_string_bare(char *dst, char const *src);
+int rad_copy_variable(char *dst, char const *from);
+uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now);
+int rad_expand_xlat(REQUEST *request, char const *cmd,
+ int max_argc, char const *argv[], bool can_fail,
+ size_t argv_buflen, char *argv_buf);
+void rad_tv_sub(struct timeval const *end, struct timeval const *start, struct timeval *elapsed);
+
+void verify_request(char const *file, int line, REQUEST *request); /* only for special debug builds */
+void rad_mode_to_str(char out[10], mode_t mode);
+void rad_mode_to_oct(char out[5], mode_t mode);
+int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid);
+int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name);
+int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid);
+int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name);
+int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name);
+int rad_prints_uid(TALLOC_CTX *ctx, char *out, size_t outlen, uid_t uid);
+int rad_prints_gid(TALLOC_CTX *ctx, char *out, size_t outlen, gid_t gid);
+int rad_seuid(uid_t uid);
+int rad_segid(gid_t gid);
+
+void rad_suid_set_down_uid(uid_t uid);
+void rad_suid_down(void);
+void rad_suid_up(void);
+void rad_suid_down_permanent(void);
+/* regex.c */
+
+#ifdef HAVE_REGEX
+/*
+ * Increasing this is essentially free
+ * It just increases memory usage. 12-16 bytes for each additional subcapture.
+ */
+# define REQUEST_MAX_REGEX 32
+
+void regex_sub_to_request(REQUEST *request, regex_t **preg, char const *value,
+ size_t len, regmatch_t rxmatch[], size_t nmatch);
+
+int regex_request_to_sub(TALLOC_CTX *ctx, char **out, REQUEST *request, uint32_t num);
+
+/*
+ * Named capture groups only supported by PCRE.
+ */
+# ifdef HAVE_PCRE
+int regex_request_to_sub_named(TALLOC_CTX *ctx, char **out, REQUEST *request, char const *name);
+# endif
+#endif
+
+/* files.c */
+int pairlist_read(TALLOC_CTX *ctx, char const *file, PAIR_LIST **list, int complain);
+void pairlist_free(PAIR_LIST **);
+
+/* version.c */
+int rad_check_lib_magic(uint64_t magic);
+int ssl_check_consistency(void);
+char const *ssl_version_by_num(uint32_t version);
+char const *ssl_version_num(void);
+char const *ssl_version_range(uint32_t low, uint32_t high);
+char const *ssl_version(void);
+int version_add_feature(CONF_SECTION *cs, char const *name, bool enabled);
+int version_add_number(CONF_SECTION *cs, char const *name, char const *version);
+void version_init_features(CONF_SECTION *cs);
+void version_init_numbers(CONF_SECTION *cs);
+void version_print(void);
+
+/* auth.c */
+char *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli);
+int rad_authenticate (REQUEST *);
+int rad_postauth(REQUEST *);
+int rad_virtual_server(REQUEST *);
+
+/* exec.c */
+pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
+ int *input_fd, int *output_fd,
+ VALUE_PAIR *input_pairs, bool shell_escape);
+int radius_readfrom_program(int fd, pid_t pid, int timeout,
+ char *answer, int left);
+int radius_exec_program(TALLOC_CTX *ctx, char *out, size_t outlen, VALUE_PAIR **output_pairs,
+ REQUEST *request, char const *cmd, VALUE_PAIR *input_pairs,
+ bool exec_wait, bool shell_escape, int timeout) CC_HINT(nonnull (5, 6));
+void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, int quench)
+ CC_HINT(nonnull (3));
+
+/* valuepair.c */
+int paircompare_register_byname(char const *name, DICT_ATTR const *from,
+ bool first_only, RAD_COMPARE_FUNC func, void *instance);
+int paircompare_register(DICT_ATTR const *attribute, DICT_ATTR const *from,
+ bool first_only, RAD_COMPARE_FUNC func, void *instance);
+void paircompare_unregister(DICT_ATTR const *attr, RAD_COMPARE_FUNC func);
+void paircompare_unregister_instance(void *instance);
+int paircompare(REQUEST *request, VALUE_PAIR *req_list,
+ VALUE_PAIR *check, VALUE_PAIR **rep_list);
+vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *xlat);
+xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt);
+int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp);
+int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp);
+int radius_callback_compare(REQUEST *request, VALUE_PAIR *req,
+ VALUE_PAIR *check, VALUE_PAIR *check_pairs,
+ VALUE_PAIR **reply_pairs);
+int radius_find_compare(DICT_ATTR const *attribute);
+VALUE_PAIR *radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor);
+
+void module_failure_msg(REQUEST *request, char const *fmt, ...) CC_HINT(format (printf, 2, 3));
+void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap) CC_HINT(format (printf, 2, 0));
+
+int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name);
+int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name);
+
+
+/*
+ * Less code == fewer bugs
+ *
+ * @param _a attribute
+ * @param _b value
+ * @param _c op
+ */
+#define pair_make_request(_a, _b, _c) fr_pair_make(request->packet, &request->packet->vps, _a, _b, _c)
+#define pair_make_reply(_a, _b, _c) fr_pair_make(request->reply, &request->reply->vps, _a, _b, _c)
+#define pair_make_config(_a, _b, _c) fr_pair_make(request, &request->config, _a, _b, _c)
+
+/* threads.c */
+int thread_pool_init(CONF_SECTION *cs, bool *spawn_flag);
+void thread_pool_stop(void);
+int thread_pool_addrequest(REQUEST *, RAD_REQUEST_FUNP);
+pid_t rad_fork(void);
+pid_t rad_waitpid(pid_t pid, int *status);
+int total_active_threads(void);
+void thread_pool_lock(void);
+void thread_pool_unlock(void);
+void thread_pool_queue_stats(int array[RAD_LISTEN_MAX], int pps[2]);
+void thread_pool_thread_stats(int stats[3]);
+
+#ifndef HAVE_PTHREAD_H
+# define rad_fork(n) fork()
+# define rad_waitpid(a,b) waitpid(a,b, 0)
+#endif
+
+/* main_config.c */
+/* Define a global config structure */
+extern bool log_dates_utc;
+extern main_config_t main_config;
+extern bool event_loop_started;
+
+void set_radius_dir(TALLOC_CTX *ctx, char const *path);
+char const *get_radius_dir(void);
+int main_config_init(void);
+int main_config_free(void);
+void main_config_hup(void);
+void hup_logfile(void);
+
+/* listen.c */
+void listen_free(rad_listen_t **head);
+int listen_init(CONF_SECTION *cs, rad_listen_t **head, bool spawn_flag);
+rad_listen_t *proxy_new_listener(TALLOC_CTX *ctx, home_server_t *home, uint16_t src_port);
+RADCLIENT *client_listener_find(rad_listen_t *listener, fr_ipaddr_t const *ipaddr, uint16_t src_port);
+
+#ifdef WITH_STATS
+RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr, uint16_t port, int proto);
+#endif
+rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, uint16_t port, int proto);
+int rad_status_server(REQUEST *request);
+
+/* event.c */
+typedef enum event_corral_t {
+ EVENT_CORRAL_MAIN = 0, //!< Always main thread event list
+ EVENT_CORRAL_AUX //!< Maybe main thread or one shared by modules
+} event_corral_t;
+
+fr_event_list_t *radius_event_list_corral(event_corral_t hint);
+int radius_event_init(TALLOC_CTX *ctx);
+int radius_event_start(CONF_SECTION *cs, bool spawn_flag);
+void radius_event_free(void);
+int radius_event_process(void);
+void radius_update_listener(rad_listen_t *listener);
+void revive_home_server(void *ctx);
+void mark_home_server_dead(home_server_t *home, struct timeval *when, bool down);
+
+/* evaluate.c */
+typedef struct fr_cond_t fr_cond_t;
+int radius_evaluate_tmpl(REQUEST *request, int modreturn, int depth,
+ vp_tmpl_t const *vpt);
+int radius_evaluate_map(REQUEST *request, int modreturn, int depth,
+ fr_cond_t const *c);
+int radius_evaluate_cond(REQUEST *request, int modreturn, int depth,
+ fr_cond_t const *c);
+void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat) CC_HINT(nonnull);
+
+#ifdef WITH_TLS
+/*
+ * For run-time patching of which function handles which socket.
+ */
+int dual_tls_recv(rad_listen_t *listener);
+int dual_tls_send(rad_listen_t *listener, REQUEST *request);
+int proxy_tls_recv(rad_listen_t *listener);
+int proxy_tls_send(rad_listen_t *listener, REQUEST *request);
+#ifdef WITH_COA_TUNNEL
+int proxy_tls_send_reply(rad_listen_t *listener, REQUEST *request);
+int dual_tls_send_coa_request(rad_listen_t *listener, REQUEST *request);
+void listen_coa_free(void);
+void listen_coa_add(rad_listen_t *listener, char const *key);
+int listen_coa_find(REQUEST *request, char const *key);
+#endif
+#endif
+
+/*
+ * For radmin over TCP.
+ */
+#define PW_RADMIN_PORT 18120
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*RADIUSD_H*/
diff --git a/src/include/radsniff.h b/src/include/radsniff.h
new file mode 100644
index 0000000..c909ecd
--- /dev/null
+++ b/src/include/radsniff.h
@@ -0,0 +1,323 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file radsniff.h
+ * @brief Structures and prototypes for the RADIUS sniffer.
+ *
+ * @copyright 2013 Arran Cudbard-Bell <arran.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ */
+
+RCSIDH(radsniff_h, "$Id$")
+
+#include <sys/types.h>
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/pcap.h>
+#include <freeradius-devel/event.h>
+
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
+#endif
+
+#define RS_DEFAULT_PREFIX "radsniff" //!< Default instance
+#define RS_DEFAULT_SECRET "testing123" //!< Default secret
+#define RS_DEFAULT_TIMEOUT 5200 //!< Standard timeout of 5s + 300ms to cover network latency
+#define RS_FORCE_YIELD 1000 //!< Service another descriptor every X number of packets
+#define RS_RETRANSMIT_MAX 5 //!< Maximum number of times we expect to see a packet retransmitted
+#define RS_MAX_ATTRS 50 //!< Maximum number of attributes we can filter on.
+#define RS_SOCKET_REOPEN_DELAY 5000 //!< How long we delay re-opening a collectd socket.
+
+/*
+ * Logging macros
+ */
+#undef DEBUG2
+#define DEBUG2(fmt, ...) if (fr_debug_lvl > 2) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef DEBUG
+#define DEBUG(fmt, ...) if (fr_debug_lvl > 1) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+#undef INFO
+#define INFO(fmt, ...) if (fr_debug_lvl > 0) fprintf(fr_log_fp , fmt "\n", ## __VA_ARGS__)
+
+#define ERROR(fmt, ...) fr_perror("radsniff: " fmt, ## __VA_ARGS__)
+
+#define RIDEBUG_ENABLED() (conf->print_packet && (fr_debug_lvl > 0))
+#define RDEBUG_ENABLED() (conf->print_packet && (fr_debug_lvl > 1))
+#define RDEBUG_ENABLED2() (conf->print_packet && (fr_debug_lvl > 2))
+
+#define REDEBUG(fmt, ...) if (conf->print_packet) fr_perror("%s (%" PRIu64 ") " fmt , timestr, count, ## __VA_ARGS__)
+#define RIDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_lvl > 0)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG(fmt, ...) if (conf->print_packet && (fr_debug_lvl > 1)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+#define RDEBUG2(fmt, ...) if (conf->print_packet && (fr_debug_lvl > 2)) fprintf(fr_log_fp , "%s (%" PRIu64 ") " fmt "\n", timestr, count, ## __VA_ARGS__)
+
+typedef enum {
+ RS_NORMAL = 0x01,
+ RS_UNLINKED = 0x02,
+ RS_RTX = 0x04,
+ RS_REUSED = 0x08,
+ RS_ERROR = 0x10,
+ RS_LOST = 0x20
+} rs_status_t;
+
+typedef void (*rs_packet_logger_t)(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body);
+typedef enum {
+#ifdef HAVE_COLLECTDC_H
+ RS_STATS_OUT_COLLECTD = 1,
+#endif
+ RS_STATS_OUT_STDIO
+} stats_out_t;
+
+typedef struct rs rs_t;
+
+#ifdef HAVE_COLLECTDC_H
+typedef struct rs_stats_tmpl rs_stats_tmpl_t;
+typedef struct rs_stats_value_tmpl rs_stats_value_tmpl_t;
+#endif
+
+typedef struct rs_counters {
+ uint64_t type[PW_CODE_MAX];
+} rs_counters_t;
+
+/** Stats for a single interval
+ *
+ * And interval is defined as the time between a call to the stats output function.
+ */
+typedef struct rs_latency {
+ int intervals; //!< Number of stats intervals.
+
+ double latency_smoothed; //!< Smoothed moving average.
+ uint64_t latency_smoothed_count; //!< Number of CMA datapoints processed.
+
+ struct {
+ uint64_t received_total; //!< Total received over interval.
+ uint64_t linked_total; //!< Total request/response pairs over interval.
+ uint64_t unlinked_total; //!< Total unlinked over interval.
+ uint64_t reused_total; //!< Total reused over interval.
+ uint64_t lost_total; //!< Total packets definitely lost in this interval.
+ uint64_t rt_total[RS_RETRANSMIT_MAX + 1]; //!< Number of RTX until complete
+ //!< over interval.
+
+
+ double received; //!< Number of this type of packet we've received.
+ double linked; //!< Number of request/response pairs
+ double unlinked; //!< Response with no request.
+ double reused; //!< ID re-used too quickly.
+ double lost; //!< Never got a response to a request.
+ double rt[RS_RETRANSMIT_MAX + 1]; //!< Number of times we saw the same
+ //!< request packet.
+
+ long double latency_total; //!< Total latency between requests/responses in the
+ //!< interval.
+ double latency_average; //!< Average latency (this iteration).
+
+ double latency_high; //!< Latency high water mark.
+ double latency_low; //!< Latency low water mark.
+ } interval;
+} rs_latency_t;
+
+typedef struct rs_malformed {
+ uint64_t min_length_packet;
+ uint64_t min_length_field;
+ uint64_t min_length_mimatch;
+ uint64_t header_overflow;
+ uint64_t invalid_attribute;
+ uint64_t attribute_too_short;
+ uint64_t attribute_overflow;
+ uint64_t ma_invalid_length;
+ uint64_t attribute_underflow;
+ uint64_t too_many_attributes;
+ uint64_t ma_missing;
+} rs_malformed_t;
+
+/** One set of statistics
+ *
+ */
+typedef struct rs_stats {
+ int intervals; //!< Number of stats intervals.
+
+ rs_latency_t exchange[PW_CODE_MAX]; //!< We end up allocating ~16K, but memory is cheap so
+ //!< what the hell. This is required because instances of
+ //!< FreeRADIUS delay Access-Rejects, which would artificially
+ //!< increase latency stats for Access-Requests.
+
+ struct timeval quiet; //!< We may need to 'mute' the stats if libpcap starts
+ //!< dropping packets, or we run out of memory.
+} rs_stats_t;
+
+typedef struct rs_capture {
+ struct pcap_pkthdr *header; //!< PCAP packet header.
+ uint8_t *data; //!< PCAP packet data.
+} rs_capture_t;
+
+/** Wrapper for RADIUS_PACKET
+ *
+ * Allows an event to be associated with a request packet. This is required because we need to disarm
+ * the event timer when a response is received, so we don't erroneously log the response as lost.
+ */
+typedef struct rs_request {
+ uint64_t id; //!< Monotonically increasing packet counter.
+ fr_event_t *event; //!< Event created when we received the original request.
+
+ bool logged; //!< Whether any messages regarding this request were logged.
+
+ struct timeval when; //!< Time when the packet was received, or next time an event
+ //!< is scheduled.
+ fr_pcap_t *in; //!< PCAP handle the original request was received on.
+ RADIUS_PACKET *packet; //!< The original packet.
+ RADIUS_PACKET *expect; //!< Request/response.
+ RADIUS_PACKET *linked; //!< The subsequent response or forwarded request the packet
+ //!< was linked against.
+
+
+ rs_capture_t capture[RS_RETRANSMIT_MAX]; //!< Buffered request packets (if a response filter
+ //!< has been applied).
+ rs_capture_t *capture_p; //!< Next packet slot.
+
+ uint64_t rt_req; //!< Number of times we saw the same request packet.
+ uint64_t rt_rsp; //!< Number of times we saw a retransmitted response
+ //!< packet.
+ rs_latency_t *stats_req; //!< Latency entry for the request type.
+ rs_latency_t *stats_rsp; //!< Latency entry for the request type.
+
+ bool silent_cleanup; //!< Cleanup was forced before normal expiry period,
+ //!< ignore stats about packet loss.
+
+ VALUE_PAIR *link_vps; //!< VALUE_PAIRs used to link retransmissions.
+
+ bool in_request_tree; //!< Whether the request is currently in the request tree.
+ bool in_link_tree; //!< Whether the request is currently in the linked tree.
+} rs_request_t;
+
+/** Statistic write/print event
+ *
+ */
+typedef struct rs_event {
+ fr_event_list_t *list; //!< The event list.
+
+ fr_pcap_t *in; //!< PCAP handle event occurred on.
+ fr_pcap_t *out; //!< Where to write output.
+
+ rs_stats_t *stats; //!< Where to write stats.
+} rs_event_t;
+
+/** FD data which gets passed to callbacks
+ *
+ */
+typedef struct rs_update {
+ fr_event_list_t *list; //!< List to insert new event into.
+
+ fr_pcap_t *in; //!< Linked list of PCAP handles to check for drops.
+ rs_stats_t *stats; //!< Stats to process.
+} rs_update_t;
+
+
+struct rs {
+ bool from_file; //!< Were reading pcap data from files.
+ bool from_dev; //!< Were reading pcap data from devices.
+ bool from_stdin; //!< Were reading pcap data from stdin.
+ bool to_file; //!< Were writing pcap data to files.
+ bool to_stdout; //!< Were writing pcap data to stdout.
+
+ bool daemonize; //!< Daemonize and write PID out to file.
+ char const *pidfile; //!< File to write PID to.
+
+ bool from_auto; //!< From list was auto-generated.
+ bool promiscuous; //!< Capture in promiscuous mode.
+ bool print_packet; //!< Print packet info, disabled with -W
+ bool decode_attrs; //!< Whether we should decode attributes in the request
+ //!< and response.
+ bool verify_udp_checksum; //!< Check UDP checksum in packets.
+
+ char const *radius_secret; //!< Secret to decode encrypted attributes.
+
+ char *pcap_filter; //!< PCAP filter string applied to live capture devices.
+
+ char *list_attributes; //!< Raw attribute filter string.
+ DICT_ATTR const *list_da[RS_MAX_ATTRS]; //!< Output CSV with these attribute values.
+ int list_da_num;
+
+ char *link_attributes; //!< Names of DICT_ATTRs to use for rtx.
+ DICT_ATTR const *link_da[RS_MAX_ATTRS]; //!< DICT_ATTRs to link on.
+ int link_da_num; //!< Number of rtx DICT_ATTRs.
+
+ char const *filter_request; //!< Raw request filter string.
+ char const *filter_response; //!< Raw response filter string.
+
+ VALUE_PAIR *filter_request_vps; //!< Sorted filter vps.
+ VALUE_PAIR *filter_response_vps; //!< Sorted filter vps.
+ PW_CODE filter_request_code; //!< Filter request packets by code.
+ PW_CODE filter_response_code; //!< Filter response packets by code.
+
+ rs_status_t event_flags; //!< Events we log and capture on.
+ rs_packet_logger_t logger; //!< Packet logger
+
+ int buffer_pkts; //!< Size of the ring buffer to setup for live capture.
+ uint64_t limit; //!< Maximum number of packets to capture
+
+ struct {
+ int interval; //!< Time between stats updates in seconds.
+ stats_out_t out; //!< Where to write stats.
+ int timeout; //!< Maximum length of time we wait for a response.
+
+#ifdef HAVE_COLLECTDC_H
+ char const *collectd; //!< Collectd server/port/unixsocket
+ char const *prefix; //!< Prefix collectd stats with this value.
+ lcc_connection_t *handle; //!< Collectd client handle.
+ rs_stats_tmpl_t *tmpl; //!< The stats templates we created on startup.
+#endif
+ } stats;
+};
+
+#ifdef HAVE_COLLECTDC_H
+
+/** Callback for processing stats values.
+ *
+ */
+typedef void (*rs_stats_cb_t)(rs_t *conf, rs_stats_value_tmpl_t *tmpl);
+struct rs_stats_value_tmpl {
+ void *src; //!< Pointer to source field in struct. Must be set by
+ //!< stats_collectdc_init caller.
+ int type; //!< Stats type.
+ rs_stats_cb_t cb; //!< Callback used to process stats
+ void *dst; //!< Pointer to dst field in value struct. Must be set
+ //!< by stats_collectdc_init caller.
+};
+
+/** Stats templates
+ *
+ * This gets processed to turn radsniff stats structures into collectd lcc_value_list_t structures.
+ */
+struct rs_stats_tmpl
+{
+ rs_stats_value_tmpl_t *value_tmpl; //!< Value template
+ void *stats; //!< Struct containing the raw stats to process
+ lcc_value_list_t *value; //!< Collectd stats struct to populate
+
+ rs_stats_tmpl_t *next; //!< Next...
+};
+
+/*
+ * collectd.c - Registration and processing functions
+ */
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code);
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now);
+int rs_stats_collectd_open(rs_t *conf);
+int rs_stats_collectd_close(rs_t *conf);
+
+#endif
diff --git a/src/include/radutmp.h b/src/include/radutmp.h
new file mode 100644
index 0000000..77b7551
--- /dev/null
+++ b/src/include/radutmp.h
@@ -0,0 +1,65 @@
+/*
+ * radutmp.h Definitions for the Radius UTMP file.
+ *
+ * Version: $Id$
+ */
+
+#ifndef _RADUTMP_H
+#define _RADUTMP_H
+
+RCSIDH(radutmp_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Types of connection.
+ */
+#ifndef P_UNKNOWN
+# define P_UNKNOWN 0
+# define P_LOCAL 'L'
+# define P_RLOGIN 'R'
+# define P_SLIP 'S'
+# define P_CSLIP 'C'
+# define P_PPP 'P'
+# define P_AUTOPPP 'A'
+# define P_TELNET 'E'
+# define P_TCPCLEAR 'T'
+# define P_TCPLOGIN 'U'
+# define P_CONSOLE '!'
+# define P_SHELL 'X'
+#endif
+
+#define P_IDLE 0
+#define P_LOGIN 1
+
+struct radutmp {
+ char login[32]; /* Loginname */
+ /* FIXME: extend to 48 or 64 bytes */
+ unsigned int nas_port; /* Port on the terminal server (32 bits). */
+ char session_id[8]; /* Radius session ID (first 8 bytes at least)*/
+ /* FIXME: extend to 16 or 32 bytes */
+ unsigned int nas_address; /* IP of portmaster. */
+ unsigned int framed_address; /* SLIP/PPP address or login-host. */
+ int proto; /* Protocol. */
+ time_t time; /* Time entry was last updated. */
+ time_t delay; /* Delay time of request */
+ int type; /* Type of entry (login/logout) */
+ char porttype; /* Porttype (I=ISDN A=Async T=Async-ISDN */
+ char res1,res2,res3; /* Fills up to one int */
+ char caller_id[16]; /* Calling-Station-ID */
+ char reserved[12]; /* 3 ints reserved */
+};
+
+/*
+ * Take the size of the structure from the actual structure definition.
+ */
+#define RUT_NAMESIZE sizeof(((struct radutmp *) NULL)->login)
+#define RUT_SESSSIZE sizeof(((struct radutmp *) NULL)->session_id)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RADUTMP_H */
diff --git a/src/include/realms.h b/src/include/realms.h
new file mode 100644
index 0000000..23806f4
--- /dev/null
+++ b/src/include/realms.h
@@ -0,0 +1,235 @@
+#ifndef REALMS_H
+#define REALMS_H
+
+/*
+ * realms.h Structures, prototypes and global variables
+ * for realms
+ *
+ * Version: $Id$
+ *
+ */
+
+RCSIDH(realms_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern bool home_servers_udp; //!< Whether there are any UDP home servers
+
+typedef enum {
+ HOME_TYPE_INVALID = 0,
+ HOME_TYPE_AUTH, //!< Authentication server
+ HOME_TYPE_ACCT, //!< Accounting server
+ HOME_TYPE_AUTH_ACCT, //!< Authentication and accounting server
+
+#ifdef WITH_COA
+ HOME_TYPE_COA, //!< CoA destination (NAS or Proxy)
+
+#ifdef WITH_COA_TUNNEL
+ HOME_TYPE_AUTH_COA, //!< auth + coa
+ HOME_TYPE_AUTH_ACCT_COA, //!< auth + acct + coa
+#endif
+#endif
+} home_type_t;
+
+typedef enum {
+ HOME_PING_CHECK_INVALID = 0,
+ HOME_PING_CHECK_NONE,
+ HOME_PING_CHECK_STATUS_SERVER,
+ HOME_PING_CHECK_REQUEST
+} home_ping_check_t;
+
+typedef enum {
+ HOME_STATE_ALIVE = 0,
+ HOME_STATE_ZOMBIE,
+ HOME_STATE_IS_DEAD,
+ HOME_STATE_UNKNOWN,
+ HOME_STATE_ADMIN_DOWN,
+ HOME_STATE_CONNECTION_FAIL,
+} home_state_t;
+
+#define HOME_SERVER_IS_DEAD(_x) (((_x)->state == HOME_STATE_IS_DEAD) || ((_x)->state == HOME_STATE_ADMIN_DOWN) || ((_x)->state == HOME_STATE_CONNECTION_FAIL))
+
+typedef struct fr_socket_limit_t {
+ uint32_t max_connections;
+ uint32_t num_connections;
+ uint32_t max_requests;
+ uint32_t num_requests;
+ uint32_t lifetime;
+ uint32_t idle_timeout;
+} fr_socket_limit_t;
+
+typedef struct home_server {
+ char const *log_name; //!< The name used for log messages.
+
+ char const *name; //!< Name the server may be referenced by for querying
+ //!< stats or when specifying home servers for a pool.
+
+ bool dual; //!< One of a pair of homeservers on consecutive ports.
+ bool dynamic; //!< is this a dynamically added home server?
+ bool nonblock; //!< Enable a socket non-blocking to the home server.
+#ifdef WITH_COA_TUNNEL
+ bool recv_coa; //!< receive CoA packets, too
+#endif
+ char const *virtual_server; //!< For internal proxying
+ char const *parent_server;
+
+ fr_ipaddr_t ipaddr; //!< IP address of home server.
+ uint16_t port;
+
+ char const *type_str; //!< String representation of type.
+ home_type_t type; //!< Auth, Acct, CoA etc.
+
+ char const *src_ipaddr_str; //!< Need to parse the string specially as it may
+ //!< require a DNS lookup and the address family for that
+ //!< is the same as ipaddr.
+ fr_ipaddr_t src_ipaddr; //!< Resolved version of src_ipaddr_str. Preferred source
+ //!< IP address (useful for multihomed systems).
+
+ char const *proto_str; //!< String representation of protocol.
+ int proto; //!< TCP or UDP.
+
+ fr_socket_limit_t limit;
+
+ char const *secret;
+
+ fr_event_t *ev;
+ struct timeval when;
+
+ struct timeval response_window;
+ uint32_t response_timeouts;
+ uint32_t max_response_timeouts;
+ uint32_t max_outstanding; //!< Maximum outstanding requests.
+ uint32_t currently_outstanding;
+
+ time_t last_packet_sent;
+ time_t last_packet_recv;
+ time_t last_failed_open;
+ struct timeval revive_time;
+ struct timeval zombie_period_start;
+ uint32_t zombie_period; //!< Unresponsive for T, mark it dead.
+
+ int state;
+
+ char const *ping_check_str;
+ home_ping_check_t ping_check; //!< What method we use to perform the 'ping'
+ //!< none, status-server or fake request.
+
+ char const *ping_user_name;
+ char const *ping_user_password;
+
+ uint32_t ping_interval;
+ uint32_t num_pings_to_alive;
+ uint32_t num_sent_pings;
+ uint32_t num_received_pings;
+ uint32_t ping_timeout;
+
+ uint32_t revive_interval; //!< How often we revive it (if it doesn't support pings).
+ CONF_SECTION *cs;
+#ifdef WITH_COA
+ uint32_t coa_irt;
+ uint32_t coa_mrc;
+ uint32_t coa_mrt;
+ uint32_t coa_mrd;
+#ifdef WITH_COA_TUNNEL
+ char const *recv_coa_server; //!< for accepting incoming CoA requests
+#endif
+#endif
+#ifdef WITH_TLS
+ fr_tls_server_conf_t *tls;
+ uint32_t connect_timeout;
+ rbtree_t *listeners;
+#endif
+
+#ifdef WITH_STATS
+ int number;
+
+ fr_stats_t stats;
+
+ fr_stats_ema_t ema;
+#endif
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+ time_t expiration;
+#endif
+
+} home_server_t;
+
+
+typedef enum home_pool_type_t {
+ HOME_POOL_INVALID = 0,
+ HOME_POOL_LOAD_BALANCE,
+ HOME_POOL_FAIL_OVER,
+ HOME_POOL_CLIENT_BALANCE,
+ HOME_POOL_CLIENT_PORT_BALANCE,
+ HOME_POOL_KEYED_BALANCE
+} home_pool_type_t;
+
+
+typedef struct home_pool_t {
+ char const *name;
+ home_pool_type_t type;
+
+ home_type_t server_type;
+ CONF_SECTION *cs;
+
+ char const *virtual_server; /* for pre/post-proxy */
+
+ home_server_t *fallback;
+ int in_fallback;
+ time_t time_all_dead;
+ time_t last_serviced;
+
+ int num_home_servers;
+ home_server_t *servers[1];
+} home_pool_t;
+
+
+typedef struct _realm {
+ char const *name;
+
+ bool strip_realm;
+
+ home_pool_t *auth_pool;
+ home_pool_t *acct_pool;
+#ifdef WITH_COA
+ home_pool_t *coa_pool;
+#endif
+} REALM;
+
+typedef struct realm_config realm_config_t;
+
+int realms_init(CONF_SECTION *config);
+void realms_free(void);
+REALM *realm_find(char const *name); /* name is from a packet */
+REALM *realm_find2(char const *name); /* ... with name taken from realm_find */
+
+void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs);
+int realm_pool_add(home_pool_t *pool, CONF_SECTION *cs);
+void realm_pool_free(home_pool_t *pool);
+bool realm_home_server_add(home_server_t *home);
+int realm_realm_add( REALM *r, CONF_SECTION *cs);
+
+void home_server_update_request(home_server_t *home, REQUEST *request);
+home_server_t *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
+home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto);
+home_server_t *home_server_find_bysrc(fr_ipaddr_t *ipaddr, uint16_t port, int proto, fr_ipaddr_t *src_ipaddr);
+home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SECTION *cs);
+CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client);
+#ifdef WITH_COA
+home_server_t *home_server_byname(char const *name, int type);
+#endif
+#ifdef WITH_STATS
+extern int home_server_max_number;
+home_server_t *home_server_bynumber(int number);
+#endif
+home_pool_t *home_pool_byname(char const *name, int type);
+
+int home_server_afrom_file(char const *filename);
+int home_server_delete(char const *name, char const *type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REALMS_H */
diff --git a/src/include/regex.h b/src/include/regex.h
new file mode 100644
index 0000000..efb7b86
--- /dev/null
+++ b/src/include/regex.h
@@ -0,0 +1,77 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef REGEX_H
+#define REGEX_H
+#ifdef HAVE_REGEX
+/*
+ * $Id$
+ *
+ * @file regex.h
+ * @brief Wrappers around various regular expression libraries.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSIDH(regex_h, "$Id$")
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+# ifdef HAVE_PCRE
+# include <pcre.h>
+/*
+ * Versions older then 8.20 didn't have the JIT functionality
+ * gracefully degrade.
+ */
+# ifndef PCRE_STUDY_JIT_COMPILE
+# define PCRE_STUDY_JIT_COMPILE 0
+# endif
+/*
+ * libpcre defines its matches as an array of ints which is a
+ * multiple of three.
+ */
+typedef struct regmatch {
+ int a;
+ int b;
+ int c;
+} regmatch_t;
+
+typedef struct regex {
+ bool precompiled; //!< Whether this regex was precompiled, or compiled for one of evaluation.
+ pcre *compiled; //!< Compiled regular expression.
+ pcre_extra *extra; //!< Result of studying a regular expression.
+} regex_t;
+# else
+# include <regex.h>
+/*
+ * Allow REG_EXTENDED and REG_NOSUB to be or'd with flags
+ * if they're not defined.
+ */
+# ifndef REG_EXTENDED
+# define REG_EXTENDED (0)
+# endif
+
+# ifndef REG_NOSUB
+# define REG_NOSUB (0)
+# endif
+# endif
+ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
+ bool ignore_case, bool multiline, bool subcaptures, bool runtime);
+int regex_exec(regex_t *preg, char const *string, size_t len, regmatch_t pmatch[], size_t *nmatch);
+# ifdef __cplusplus
+}
+# endif
+#endif
+#endif
diff --git a/src/include/sha1.h b/src/include/sha1.h
new file mode 100644
index 0000000..86c3d9f
--- /dev/null
+++ b/src/include/sha1.h
@@ -0,0 +1,57 @@
+#ifndef _FR_SHA1_H
+#define _FR_SHA1_H
+
+#ifdef WITH_OPENSSL_SHA1
+#include <openssl/sha.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef SHA1_DIGEST_LENGTH
+# define SHA1_DIGEST_LENGTH 20
+#endif
+
+#ifndef WITH_OPENSSL_SHA1
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ uint8_t buffer[64];
+} fr_sha1_ctx;
+
+void fr_sha1_transform(uint32_t state[5], uint8_t const buffer[64]);
+void fr_sha1_init(fr_sha1_ctx *context);
+void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *data, size_t len);
+void fr_sha1_final(uint8_t digest[20], fr_sha1_ctx *context);
+
+/*
+ * this version implements a raw SHA1 transform, no length is appended,
+ * nor any 128s out to the block size.
+ */
+void fr_sha1_final_no_len(uint8_t digest[20], fr_sha1_ctx* context);
+
+#else /* WITH_OPENSSL_SHA1 */
+USES_APPLE_DEPRECATED_API
+#define fr_sha1_ctx SHA_CTX
+#define fr_sha1_init SHA1_Init
+#define fr_sha1_update SHA1_Update
+#define fr_sha1_final SHA1_Final
+#define fr_sha1_transform SHA1_Transform
+#endif
+
+/*
+ * FIPS 186-2 PRF based upon SHA1.
+ */
+void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160]);
+
+/* hmacsha1.c */
+
+void fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FR_SHA1_H */
diff --git a/src/include/socket.h b/src/include/socket.h
new file mode 100644
index 0000000..821c2a0
--- /dev/null
+++ b/src/include/socket.h
@@ -0,0 +1,53 @@
+#pragma once
+
+/*
+ * 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
+ */
+
+/** Functions for establishing and managing low level sockets
+ *
+ * @file src/include/socket.h
+ *
+ * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @author Alan DeKok (aland@freeradius.org)
+ *
+ * @copyright 2015 The FreeRADIUS project
+ */
+RCSIDH(socket_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeradius-devel/build.h>
+#include <freeradius-devel/missing.h>
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+/*
+ * The linux headers define the macro as:
+ *
+ * # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ * + strlen ((ptr)->sun_path))
+ *
+ * Which trips UBSAN, because it sees an operation on a NULL pointer.
+ */
+# undef SUN_LEN
+# define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/include/soh.h b/src/include/soh.h
new file mode 100644
index 0000000..c1187cc
--- /dev/null
+++ b/src/include/soh.h
@@ -0,0 +1,42 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_SOH_H
+#define FR_SOH_H
+/**
+ * $Id$
+ *
+ * @file soh.h
+ * @brief Microsoft SoH support
+ *
+ * @copyright 2010 Phil Mayers <p.mayers@imperial.ac.uk>
+ */
+
+RCSIDH(soh_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) CC_HINT(nonnull);
+uint16_t soh_pull_be_16(uint8_t const *p);
+uint32_t soh_pull_be_24(uint8_t const *p);
+uint32_t soh_pull_be_32(uint8_t const *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/state.h b/src/include/state.h
new file mode 100644
index 0000000..d9b47a0
--- /dev/null
+++ b/src/include/state.h
@@ -0,0 +1,47 @@
+#ifndef FR_STATE_H
+#define FR_STATE_H
+
+/*
+ * state.h handle multi-packet state
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2014 The FreeRADIUS server project
+ * Copyright 2014 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(state_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_state_t fr_state_t;
+
+fr_state_t *fr_state_init(TALLOC_CTX *ctx);
+void fr_state_delete(fr_state_t *state);
+
+void fr_state_discard(REQUEST *request, RADIUS_PACKET *original);
+
+void fr_state_get_vps(REQUEST *request, RADIUS_PACKET *packet);
+bool fr_state_put_vps(REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *packet);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_HASH_H */
diff --git a/src/include/stats.h b/src/include/stats.h
new file mode 100644
index 0000000..68903f9
--- /dev/null
+++ b/src/include/stats.h
@@ -0,0 +1,101 @@
+#ifndef FR_STATS_H
+#define FR_STATS_H
+
+/*
+ * stats.h Structures and functions for statistics.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006,2007,2008 The FreeRADIUS server project
+ */
+
+RCSIDH(stats_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WITH_STATS
+typedef struct fr_stats_t {
+ uint64_t total_requests;
+ uint64_t total_invalid_requests;
+ uint64_t total_dup_requests;
+ uint64_t total_responses;
+ uint64_t total_access_accepts;
+ uint64_t total_access_rejects;
+ uint64_t total_access_challenges;
+ uint64_t total_malformed_requests;
+ uint64_t total_bad_authenticators;
+ uint64_t total_packets_dropped;
+ uint64_t total_no_records;
+ uint64_t total_unknown_types;
+ uint64_t total_timeouts;
+ uint64_t total_conflicts;
+ uint64_t unresponsive_child;
+ time_t last_packet;
+ uint64_t elapsed[8];
+} fr_stats_t;
+
+typedef struct fr_stats_ema_t {
+ uint32_t window;
+
+ uint32_t f1, f10;
+ uint32_t ema1, ema10;
+} fr_stats_ema_t;
+
+extern fr_stats_t radius_auth_stats;
+#ifdef WITH_ACCOUNTING
+extern fr_stats_t radius_acct_stats;
+#endif
+#ifdef WITH_COA
+extern fr_stats_t radius_coa_stats;
+extern fr_stats_t radius_dsc_stats;
+#endif
+#ifdef WITH_PROXY
+extern fr_stats_t proxy_auth_stats;
+#ifdef WITH_ACCOUNTING
+extern fr_stats_t proxy_acct_stats;
+#endif
+#ifdef WITH_COA
+extern fr_stats_t proxy_coa_stats;
+extern fr_stats_t proxy_dsc_stats;
+#endif
+#endif
+
+void radius_stats_init(int flag);
+void request_stats_final(REQUEST *request);
+void request_stats_reply(REQUEST *request);
+void radius_stats_ema(fr_stats_ema_t *ema,
+ struct timeval *start, struct timeval *end);
+
+#define FR_STATS_INC(_x, _y) radius_ ## _x ## _stats._y++;if (listener) listener->stats._y++;if (client) client->_x._y++;
+#define FR_STATS_TYPE_INC(_x) _x++
+
+#else /* WITH_STATS */
+#define request_stats_init(_x)
+#define request_stats_final(_x)
+
+#define FR_STATS_INC(_x, _y)
+#define FR_STATS_TYPE_INC(_x)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_STATS_H */
diff --git a/src/include/stdatomic.h b/src/include/stdatomic.h
new file mode 100644
index 0000000..780e5a0
--- /dev/null
+++ b/src/include/stdatomic.h
@@ -0,0 +1,364 @@
+#pragma once
+/*
+ * An implementation of C11 stdatomic.h directly borrowed from FreeBSD
+ * (original copyright follows), with minor modifications for
+ * portability to other systems. Works for recent Clang (that
+ * implement the feature c_atomic) and GCC 4.7+; includes
+ * compatibility for GCC below 4.7 but I wouldn't recommend it.
+ *
+ * Caveats and limitations:
+ * - Only the ``_Atomic parentheses'' notation is implemented, while
+ * the ``_Atomic space'' one is not.
+ * - _Atomic types must be typedef'ed, or programs using them will
+ * not type check correctly (incompatible anonymous structure
+ * types).
+ * - Non-scalar _Atomic types would require runtime support for
+ * runtime locking, which, as far as I know, is not currently
+ * available on any system.
+ */
+
+/*-
+ * @copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
+ * David Chisnall <theraven@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/include/stdatomic.h,v 1.10.2.2 2012/05/30 19:21:54 theraven Exp $
+ */
+#include <stddef.h>
+#include <stdint.h>
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+#if !defined(__has_builtin)
+#define __has_builtin(x) 0
+#endif
+#if !defined(__GNUC_PREREQ__)
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+#define __GNUC_PREREQ__(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GNUC_PREREQ__(maj, min) 0
+#endif
+#endif
+
+#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
+#if __has_feature(c_atomic)
+#define __CLANG_ATOMICS
+#elif __GNUC_PREREQ__(4, 7)
+#define __GNUC_ATOMICS
+#elif !defined(__GNUC__)
+#error "stdatomic.h does not support your compiler"
+#endif
+#endif
+
+#if !defined(__CLANG_ATOMICS)
+#define _Atomic(T) struct { volatile __typeof__(T) __val; }
+#endif
+
+/*
+ * 7.17.2 Initialization.
+ */
+
+#if defined(__CLANG_ATOMICS)
+#define ATOMIC_VAR_INIT(value) (value)
+#define atomic_init(obj, value) __c11_atomic_init(obj, value)
+#else
+#define ATOMIC_VAR_INIT(value) { .__val = (value) }
+#define atomic_init(obj, value) do { \
+ (obj)->__val = (value); \
+} while (0)
+#endif
+
+/*
+ * Clang and recent GCC both provide predefined macros for the memory
+ * orderings. If we are using a compiler that doesn't define them, use the
+ * clang values - these will be ignored in the fallback path.
+ */
+
+#ifndef __ATOMIC_RELAXED
+#define __ATOMIC_RELAXED 0
+#endif
+#ifndef __ATOMIC_CONSUME
+#define __ATOMIC_CONSUME 1
+#endif
+#ifndef __ATOMIC_ACQUIRE
+#define __ATOMIC_ACQUIRE 2
+#endif
+#ifndef __ATOMIC_RELEASE
+#define __ATOMIC_RELEASE 3
+#endif
+#ifndef __ATOMIC_ACQ_REL
+#define __ATOMIC_ACQ_REL 4
+#endif
+#ifndef __ATOMIC_SEQ_CST
+#define __ATOMIC_SEQ_CST 5
+#endif
+
+/*
+ * 7.17.3 Order and consistency.
+ *
+ * The memory_order_* constants that denote the barrier behaviour of the
+ * atomic operations.
+ */
+
+enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+};
+
+typedef enum memory_order memory_order;
+
+/*
+ * 7.17.4 Fences.
+ */
+
+#ifdef __CLANG_ATOMICS
+#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
+#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
+#elif defined(__GNUC_ATOMICS)
+#define atomic_thread_fence(order) __atomic_thread_fence(order)
+#define atomic_signal_fence(order) __atomic_signal_fence(order)
+#else
+#define atomic_thread_fence(order) __sync_synchronize()
+#define atomic_signal_fence(order) __asm volatile ("" : : : "memory")
+#endif
+
+/*
+ * 7.17.5 Lock-free property.
+ */
+
+#if defined(__CLANG_ATOMICS)
+#define atomic_is_lock_free(obj) \
+ __c11_atomic_is_lock_free(sizeof(obj))
+#elif defined(__GNUC_ATOMICS)
+#define atomic_is_lock_free(obj) \
+ __atomic_is_lock_free(sizeof((obj)->__val))
+#else
+#define atomic_is_lock_free(obj) \
+ (sizeof((obj)->__val) <= sizeof(void *))
+#endif
+
+/*
+ * 7.17.6 Atomic integer types.
+ */
+
+typedef _Atomic(_Bool) atomic_bool;
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+#if 0
+typedef _Atomic(char16_t) atomic_char16_t;
+typedef _Atomic(char32_t) atomic_char32_t;
+#endif
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+
+/*
+ * 7.17.7 Operations on atomic types.
+ */
+
+/*
+ * Compiler-specific operations.
+ */
+
+#if defined(__CLANG_ATOMICS)
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) \
+ __c11_atomic_compare_exchange_strong(object, expected, desired, \
+ success, failure)
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ __c11_atomic_compare_exchange_weak(object, expected, desired, \
+ success, failure)
+#define atomic_exchange_explicit(object, desired, order) \
+ __c11_atomic_exchange(object, desired, order)
+#define atomic_fetch_add_explicit(object, operand, order) \
+ __c11_atomic_fetch_add(object, operand, order)
+#define atomic_fetch_and_explicit(object, operand, order) \
+ __c11_atomic_fetch_and(object, operand, order)
+#define atomic_fetch_or_explicit(object, operand, order) \
+ __c11_atomic_fetch_or(object, operand, order)
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ __c11_atomic_fetch_sub(object, operand, order)
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ __c11_atomic_fetch_xor(object, operand, order)
+#define atomic_load_explicit(object, order) \
+ __c11_atomic_load(object, order)
+#define atomic_store_explicit(object, desired, order) \
+ __c11_atomic_store(object, desired, order)
+#elif defined(__GNUC_ATOMICS)
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) \
+ __atomic_compare_exchange_n(&(object)->__val, expected, \
+ desired, 0, success, failure)
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ __atomic_compare_exchange_n(&(object)->__val, expected, \
+ desired, 1, success, failure)
+#define atomic_exchange_explicit(object, desired, order) \
+ __atomic_exchange_n(&(object)->__val, desired, order)
+#define atomic_fetch_add_explicit(object, operand, order) \
+ __atomic_fetch_add(&(object)->__val, operand, order)
+#define atomic_fetch_and_explicit(object, operand, order) \
+ __atomic_fetch_and(&(object)->__val, operand, order)
+#define atomic_fetch_or_explicit(object, operand, order) \
+ __atomic_fetch_or(&(object)->__val, operand, order)
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ __atomic_fetch_sub(&(object)->__val, operand, order)
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ __atomic_fetch_xor(&(object)->__val, operand, order)
+#define atomic_load_explicit(object, order) \
+ __atomic_load_n(&(object)->__val, order)
+#define atomic_store_explicit(object, desired, order) \
+ __atomic_store_n(&(object)->__val, desired, order)
+#else
+#define atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure) ({ \
+ __typeof__((object)->__val) __v; \
+ _Bool __r; \
+ __v = __sync_val_compare_and_swap(&(object)->__val, \
+ *(expected), desired); \
+ __r = *(expected) == __v; \
+ *(expected) = __v; \
+ __r; \
+})
+
+#define atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, success, failure) \
+ atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, success, failure)
+#if __has_builtin(__sync_swap)
+/* Clang provides a full-barrier atomic exchange - use it if available. */
+#define atomic_exchange_explicit(object, desired, order) \
+ __sync_swap(&(object)->__val, desired)
+#else
+/*
+ * __sync_lock_test_and_set() is only an acquire barrier in theory (although in
+ * practice it is usually a full barrier) so we need an explicit barrier after
+ * it.
+ */
+#define atomic_exchange_explicit(object, desired, order) ({ \
+ __typeof__((object)->__val) __v; \
+ __v = __sync_lock_test_and_set(&(object)->__val, desired); \
+ __sync_synchronize(); \
+ __v; \
+})
+#endif
+#define atomic_fetch_add_explicit(object, operand, order) \
+ __sync_fetch_and_add(&(object)->__val, operand)
+#define atomic_fetch_and_explicit(object, operand, order) \
+ __sync_fetch_and_and(&(object)->__val, operand)
+#define atomic_fetch_or_explicit(object, operand, order) \
+ __sync_fetch_and_or(&(object)->__val, operand)
+#define atomic_fetch_sub_explicit(object, operand, order) \
+ __sync_fetch_and_sub(&(object)->__val, operand)
+#define atomic_fetch_xor_explicit(object, operand, order) \
+ __sync_fetch_and_xor(&(object)->__val, operand)
+#define atomic_load_explicit(object, order) \
+ __sync_fetch_and_add(&(object)->__val, 0)
+#define atomic_store_explicit(object, desired, order) do { \
+ __sync_synchronize(); \
+ (object)->__val = (desired); \
+ __sync_synchronize(); \
+} while (0)
+#endif
+
+/*
+ * Convenience functions.
+ */
+
+#define atomic_compare_exchange_strong(object, expected, desired) \
+ atomic_compare_exchange_strong_explicit(object, expected, \
+ desired, memory_order_seq_cst, memory_order_seq_cst)
+#define atomic_compare_exchange_weak(object, expected, desired) \
+ atomic_compare_exchange_weak_explicit(object, expected, \
+ desired, memory_order_seq_cst, memory_order_seq_cst)
+#define atomic_exchange(object, desired) \
+ atomic_exchange_explicit(object, desired, memory_order_seq_cst)
+#define atomic_fetch_add(object, operand) \
+ atomic_fetch_add_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_and(object, operand) \
+ atomic_fetch_and_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_or(object, operand) \
+ atomic_fetch_or_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_sub(object, operand) \
+ atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst)
+#define atomic_fetch_xor(object, operand) \
+ atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst)
+#define atomic_load(object) \
+ atomic_load_explicit(object, memory_order_seq_cst)
+#define atomic_store(object, desired) \
+ atomic_store_explicit(object, desired, memory_order_seq_cst)
+
+/*
+ * 7.17.8 Atomic flag type and operations.
+ */
+
+typedef atomic_bool atomic_flag;
+
+#define ATOMIC_FLAG_INIT ATOMIC_VAR_INIT(0)
+
+#define atomic_flag_clear_explicit(object, order) \
+ atomic_store_explicit(object, 0, order)
+#define atomic_flag_test_and_set_explicit(object, order) \
+ atomic_compare_exchange_strong_explicit(object, 0, 1, order, order)
+
+#define atomic_flag_clear(object) \
+ atomic_flag_clear_explicit(object, memory_order_seq_cst)
+#define atomic_flag_test_and_set(object) \
+ atomic_flag_test_and_set_explicit(object, memory_order_seq_cst)
diff --git a/src/include/sysutmp.h b/src/include/sysutmp.h
new file mode 100644
index 0000000..13a47b5
--- /dev/null
+++ b/src/include/sysutmp.h
@@ -0,0 +1,108 @@
+/*
+ * sysutmp.h Compatibility stuff for the different UTMP systems.
+ *
+ * Version: $Id$
+ */
+
+#ifndef SYSUTMP_H_INCLUDED
+#define SYSUTMP_H_INCLUDED
+
+RCSIDH(sysutmp_h, "$Id$")
+
+/*
+ * If we have BOTH utmp.h and utmpx.h, then
+ * we prefer to use utmp.h, but only on systems other than Solaris.
+ */
+#if !defined(__sun) && !defined(sgi) && !defined(hpux)
+# ifdef HAVE_UTMP_H
+# undef HAVE_UTMPX_H
+# endif
+#endif
+
+#if defined(HAVE_UTMP_H) || defined(HAVE_UTMPX_H)
+
+/* UTMP stuff. Uses utmpx on svr4 */
+#ifdef HAVE_UTMPX_H
+# include <utmpx.h>
+# include <sys/fcntl.h>
+# define utmp utmpx
+# define UT_NAMESIZE 32
+# define UT_LINESIZE 32
+# define UT_HOSTSIZE 257
+#if defined(hpux) || defined(__FreeBSD__)
+# define ut_name ut_user
+#endif
+#else
+# include <utmp.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __osf__
+# define UT_NAMESIZE 32
+# define UT_LINESIZE 32
+# define UT_HOSTSIZE 64
+#endif
+
+#if (defined(__FreeBSD__) && !defined(HAVE_UTMPX_H)) || defined(__NetBSD__) || defined(bsdi) || defined(__OpenBSD__) || defined(__APPLE__)
+# ifndef UTMP_FILE
+# define UTMP_FILE "/var/run/utmp"
+# endif
+# define ut_user ut_name
+#endif
+
+/*
+ * Generate definitions for systems which are too broken to
+ * do it themselves.
+ *
+ * Hmm... this means that we can probably get rid of a lot of
+ * the static defines above, as the following lines will generate
+ * the proper defines for any system.
+ */
+#ifndef UT_LINESIZE
+#define UT_LINESIZE sizeof(((struct utmp *) NULL)->ut_line)
+#endif
+
+#ifndef UT_NAMESIZE
+#define UT_NAMESIZE sizeof(((struct utmp *) NULL)->ut_user)
+#endif
+
+#ifndef UT_HOSTSIZE
+#define UT_HOSTSIZE sizeof(((struct utmp *) NULL)->ut_host)
+#endif
+
+#else /* HAVE_UTMP_H */
+
+/*
+ * No <utmp.h> file - define stuff ourselves (minimally).
+ */
+#define UT_LINESIZE 16
+#define UT_NAMESIZE 16
+#define UT_HOSTSIZE 16
+
+#define USER_PROCESS 7
+#define DEAD_PROCESS 8
+
+#define UTMP_FILE "/var/run/utmp"
+#define ut_name ut_user
+
+struct utmp {
+ short ut_type;
+ int ut_pid;
+ char ut_line[UT_LINESIZE];
+ char ut_id[4];
+ long ut_time;
+ char ut_user[UT_NAMESIZE];
+ char ut_host[UT_HOSTSIZE];
+ long ut_addr;
+};
+
+#endif /* HAVE_UTMP_H */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYSUTMP_H_INCLUDED */
diff --git a/src/include/talloc.h b/src/include/talloc.h
new file mode 100644
index 0000000..b9e6abd
--- /dev/null
+++ b/src/include/talloc.h
@@ -0,0 +1,51 @@
+#pragma once
+/*
+ * 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
+ */
+
+/** Functions which we wish were included in the standard talloc distribution
+ *
+ * @file src/lib/util/talloc.h
+ *
+ * @copyright 2017 The FreeRADIUS server project
+ * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSIDH(talloc_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#include <talloc.h>
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+#include <freeradius-devel/autoconf.h> /* Very easy to miss including in special builds */
+#include <freeradius-devel/build.h>
+#include <freeradius-devel/missing.h>
+
+TALLOC_CTX *talloc_aligned_array(TALLOC_CTX *ctx, void **start, size_t alignment, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/include/tcp.h b/src/include/tcp.h
new file mode 100644
index 0000000..624560e
--- /dev/null
+++ b/src/include/tcp.h
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_TCP_H
+#define FR_TCP_H
+/**
+ * $Id$
+ *
+ * @file tcp.h
+ * @brief RADIUS over TCP
+ *
+ * @copyright 2009 Dante http://dante.net
+ */
+
+RCSIDH(tcp_h, "$Id$")
+
+int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags);
+RADIUS_PACKET *fr_tcp_recv(int sockfd, int flags);
+#endif /* FR_TCP_H */
diff --git a/src/include/threads.h b/src/include/threads.h
new file mode 100644
index 0000000..f2aea77
--- /dev/null
+++ b/src/include/threads.h
@@ -0,0 +1,119 @@
+#ifndef FR_THREADS_H
+#define FR_THREADS_H
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file threads.h
+ * @brief Macros to abstract Thread Local Storage
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ */
+typedef void (*pthread_destructor_t)(void*);
+
+#if !defined(HAVE_PTHREAD_H) && defined(WITH_THREADS)
+# error WITH_THREADS defined, but pthreads not available
+#endif
+
+/*
+ * First figure whether we have compiler support this is usually the case except on OSX,
+ * where we need to use pthreads.
+ */
+#ifdef TLS_STORAGE_CLASS
+# define __THREAD TLS_STORAGE_CLASS
+#endif
+
+/*
+ * Now we define three macros for initialisation, updating, and retrieving
+ */
+#ifndef WITH_THREADS
+# define fr_thread_local_setup(_t, _n) static _t _n;\
+static inline int __fr_thread_local_destructor_##_n(pthread_destructor_t *ctx)\
+{\
+ pthread_destructor_t func = *ctx;\
+ func(_n);\
+ return 0;\
+}\
+DIAG_OFF(deprecated-declarations) \
+static inline _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+{\
+ static pthread_destructor_t *ctx;\
+ if (!ctx) {\
+ ctx = talloc(talloc_autofree_context(), pthread_destructor_t);\
+ talloc_set_destructor(ctx, __fr_thread_local_destructor_##_n);\
+ *ctx = func;\
+ }\
+ return _n;\
+} \
+DIAG_ON(deprecated-declarations)
+
+# define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
+# define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
+# define fr_thread_local_get(_n) _n
+#elif defined(__THREAD)
+# include <pthread.h>
+# define fr_thread_local_setup(_t, _n) static __THREAD _t _n;\
+static pthread_key_t __fr_thread_local_key_##_n;\
+static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
+static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
+static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
+{\
+ __fr_thread_local_destructor_##_n(_n);\
+}\
+static void __fr_thread_local_key_init_##_n(void)\
+{\
+ (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
+}\
+static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+{\
+ __fr_thread_local_destructor_##_n = func;\
+ if (_n) return _n; \
+ (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
+ (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
+ return _n;\
+}
+# define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
+# define fr_thread_local_set(_n, _v) ((int)!((_n = _v) || 1))
+# define fr_thread_local_get(_n) _n
+#elif defined(HAVE_PTHREAD_H)
+# include <pthread.h>
+# define fr_thread_local_setup(_t, _n) \
+static pthread_key_t __fr_thread_local_key_##_n;\
+static pthread_once_t __fr_thread_local_once_##_n = PTHREAD_ONCE_INIT;\
+static pthread_destructor_t __fr_thread_local_destructor_##_n = NULL;\
+static void __fr_thread_local_destroy_##_n(UNUSED void *unused)\
+{\
+ __fr_thread_local_destructor_##_n(_n);\
+}\
+static void __fr_thread_local_key_init_##_n(void)\
+{\
+ (void) pthread_key_create(&__fr_thread_local_key_##_n, __fr_thread_local_destroy_##_n);\
+ (void) pthread_setspecific(__fr_thread_local_key_##_n, &(_n));\
+}\
+static _t __fr_thread_local_init_##_n(pthread_destructor_t func)\
+{\
+ __fr_thread_local_destructor_##_n = func;\
+ if (_n) return _n; \
+ (void) pthread_once(&__fr_thread_local_once_##_n, __fr_thread_local_key_init_##_n);\
+ return _n;\
+}
+# define fr_thread_local_init(_n, _f) __fr_thread_local_init_##_n(_f)
+# define fr_thread_local_set(_n, _v) __fr_thread_local_set_##_n(_v)
+# define fr_thread_local_get(_n) __fr_thread_local_get_##_n()
+#endif
+#endif
diff --git a/src/include/tls-h b/src/include/tls-h
new file mode 100644
index 0000000..4bf1665
--- /dev/null
+++ b/src/include/tls-h
@@ -0,0 +1,453 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_TLS_H
+#define FR_TLS_H
+
+#ifdef WITH_TLS
+/**
+ * $Id$
+ *
+ * @file tls.h
+ * @brief Structures and prototypes for TLS wrappers
+ *
+ * @copyright 2010 Network RADIUS SARL <info@networkradius.com>
+ */
+
+RCSIDH(tls_h, "$Id$")
+
+#include <freeradius-devel/conffile.h>
+
+/*
+ * For RH 9, which apparently needs this.
+ */
+#ifndef OPENSSL_NO_KRB5
+# define OPENSSL_NO_KRB5
+#endif
+#include <openssl/err.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+# include <openssl/engine.h>
+#endif
+#include <openssl/ssl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct fr_tls_server_conf_t fr_tls_server_conf_t;
+
+typedef enum {
+ FR_TLS_INVALID = 0, //!< Invalid, don't reply.
+ FR_TLS_REQUEST, //!< Request, ok to send, invalid to receive.
+ FR_TLS_RESPONSE, //!< Response, ok to receive, invalid to send.
+ FR_TLS_SUCCESS, //!< Success, send success.
+ FR_TLS_FAIL, //!< Fail, send fail.
+ FR_TLS_NOOP, //!< Noop, continue.
+
+ FR_TLS_START, //!< Start, ok to send, invalid to receive.
+ FR_TLS_OK, //!< Ok, continue.
+ FR_TLS_ACK, //!< Acknowledge, continue.
+ FR_TLS_FIRST_FRAGMENT, //!< First fragment.
+ FR_TLS_MORE_FRAGMENTS, //!< More fragments, to send/receive.
+ FR_TLS_LENGTH_INCLUDED, //!< Length included.
+ FR_TLS_MORE_FRAGMENTS_WITH_LENGTH, //!< More fragments with length.
+ FR_TLS_HANDLED //!< TLS code has handled it.
+} fr_tls_status_t;
+extern FR_NAME_NUMBER const fr_tls_status_table[];
+
+#define MAX_RECORD_SIZE 65536
+
+/*
+ * A single TLS record may be up to 16384 octets in length, but a
+ * TLS message may span multiple TLS records, and a TLS
+ * certificate message may in principle be as long as 16MB.
+ *
+ * However, note that in order to protect against reassembly
+ * lockup and denial of service attacks, it may be desirable for
+ * an implementation to set a maximum size for one such group of
+ * TLS messages.
+ *
+ * The TLS Message Length field is four octets, and provides the
+ * total length of the TLS message or set of messages that is
+ * being fragmented; this simplifies buffer allocation.
+ */
+
+/*
+ * FIXME: Dynamic allocation of buffer to overcome MAX_RECORD_SIZE overflows.
+ * or configure TLS not to exceed MAX_RECORD_SIZE.
+ */
+typedef struct _record_t {
+ size_t used;
+ uint8_t data[MAX_RECORD_SIZE];
+} record_t;
+
+typedef struct _tls_info_t {
+ int origin; // 0 - received (from peer), 1 - sending (to peer)
+ int content_type;
+ uint8_t handshake_type;
+ uint8_t alert_level;
+ uint8_t alert_description;
+ bool initialized;
+
+ char info_description[256];
+ size_t record_len;
+} tls_info_t;
+
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+#define ssl_session ssl->session
+#else
+#define ssl_session session
+#endif
+
+/** Contains EAP-REQUEST specific data (ie FR_TLS_DATA(fragment), EAPTLS-ALERT, EAPTLS-REQUEST ...)
+ *
+ * The tls_session_t Structure gets stored as opaque in eap_handler_t
+ */
+typedef struct _tls_session_t {
+ SSL_CTX *ctx;
+ SSL *ssl;
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_SESSION *session;
+#endif
+ tls_info_t info;
+
+ BIO *into_ssl;
+ BIO *from_ssl;
+ record_t clean_in; //!< Data that needs to be sent but only after it is soiled.
+ record_t clean_out; //!< Data that is cleaned after receiving.
+ record_t dirty_in; //!< Data EAP server receives.
+ record_t dirty_out; //!< Data EAP server sends.
+
+ void (*record_init)(record_t *buf);
+ void (*record_close)(record_t *buf);
+ unsigned int (*record_plus)(record_t *buf, void const *ptr, unsigned int size);
+ unsigned int (*record_minus)(record_t *buf, void *ptr, unsigned int size);
+
+ bool invalid_hb_used; //!< Whether heartbleed attack was detected.
+ bool connected; //!< whether the outgoing socket is connected
+ bool is_init_finished; //!< whether or not init is finished
+ bool client_cert_ok; //!< whether or not we validated the client certificate
+ bool authentication_success; //!< whether or not the user was authenticated (cert or PW)
+ bool quick_session_tickets; //!< for EAP-TLS.
+
+ /*
+ * Framed-MTU attribute in RADIUS, if present, can also be used to set this
+ */
+ size_t mtu; //!< Current fragment size transmitted.
+ size_t tls_msg_len; //!< Actual/Total TLS message length.
+ bool fragment; //!< Flag, In fragment mode or not.
+ bool length_flag; //!< A flag to include length in every TLS Data/Alert packet.
+ //!< If set to no then only the first fragment contains length.
+ int peap_flag;
+
+ size_t tls_record_in_total_len; //!< How long the peer indicated the complete tls record
+ //!< would be.
+ size_t tls_record_in_recvd_len; //!< How much of the record we've received so far.
+
+ /*
+ * Used by TTLS & PEAP to keep track of other per-session data.
+ */
+ void *opaque;
+ void (*free_opaque)(void *opaque);
+
+ char const *label;
+ bool allow_session_resumption; //!< Whether session resumption is allowed.
+ bool session_not_resumed; //!< Whether our session was not resumed.
+
+ fr_tls_server_conf_t const *conf; //! for better complaints
+} tls_session_t;
+
+/*
+ * RFC 2716, Section 4.2:
+ *
+ * Flags
+ *
+ * 0 1 2 3 4 5 6 7 8
+ * +-+-+-+-+-+-+-+-+
+ * |L M S R R R R R|
+ * +-+-+-+-+-+-+-+-+
+ *
+ * L = Length included
+ * M = More fragments
+ * S = EAP-TLS start
+ * R = Reserved
+ */
+#define TLS_START(x) (((x) & 0x20) != 0)
+#define TLS_MORE_FRAGMENTS(x) (((x) & 0x40) != 0)
+#define TLS_LENGTH_INCLUDED(x) (((x) & 0x80) != 0)
+
+#define TLS_CHANGE_CIPHER_SPEC(x) (((x) & 0x0014) == 0x0014)
+#define TLS_ALERT(x) (((x) & 0x0015) == 0x0015)
+#define TLS_HANDSHAKE(x) (((x) & 0x0016) == 0x0016)
+
+#define SET_START(x) ((x) | (0x20))
+#define SET_MORE_FRAGMENTS(x) ((x) | (0x40))
+#define SET_LENGTH_INCLUDED(x) ((x) | (0x80))
+
+/*
+ * Following enums from rfc2246
+ *
+ * Hmm... since we dpeend on OpenSSL, it would be smarter to
+ * use the OpenSSL names for these.
+ */
+enum ContentType {
+ change_cipher_spec = 20,
+ alert = 21,
+ handshake = 22,
+ application_data = 23
+};
+
+enum AlertLevel {
+ warning = 1,
+ fatal = 2
+};
+
+enum AlertDescription {
+ close_notify = 0,
+ unexpected_message = 10,
+ bad_record_mac = 20,
+ decryption_failed = 21,
+ record_overflow = 22,
+ decompression_failure = 30,
+ handshake_failure = 40,
+ bad_certificate = 42,
+ unsupported_certificate = 43,
+ certificate_revoked = 44,
+ certificate_expired = 45,
+ certificate_unknown = 46,
+ illegal_parameter = 47,
+ unknown_ca = 48,
+ access_denied = 49,
+ decode_error = 50,
+ decrypt_error = 51,
+ export_restriction = 60,
+ protocol_version = 70,
+ insufficient_security = 71,
+ internal_error = 80,
+ user_canceled = 90,
+ no_renegotiation = 100
+};
+
+enum HandshakeType {
+ hello_request = 0,
+ client_hello = 1,
+ server_hello = 2,
+ certificate = 11,
+ server_key_exchange = 12,
+ certificate_request = 13,
+ server_hello_done = 14,
+ certificate_verify = 15,
+ client_key_exchange = 16,
+ handshake_finished = 20
+};
+
+
+/*
+ * From rfc
+ Flags
+
+ 0 1 2 3 4 5 6 7 8
+ +-+-+-+-+-+-+-+-+
+ |L M S R R R R R|
+ +-+-+-+-+-+-+-+-+
+
+ L = Length included
+ M = More fragments
+ S = EAP-TLS start
+ R = Reserved
+
+ The L bit (length included) is set to indicate the presence of the
+ four octet TLS Message Length field, and MUST be set for the first
+ fragment of a fragmented TLS message or set of messages. The M bit
+ (more fragments) is set on all but the last fragment. The S bit
+ (EAP-TLS start) is set in an EAP-TLS Start message. This
+ differentiates the EAP-TLS Start message from a fragment
+ acknowledgement.
+
+ TLS Message Length
+
+ The TLS Message Length field is four octets, and is present only
+ if the L bit is set. This field provides the total length of the
+ TLS message or set of messages that is being fragmented.
+
+ TLS data
+
+ The TLS data consists of the encapsulated TLS packet in TLS record
+ format.
+ *
+ * The data structures present here
+ * maps only to the typedata in the EAP packet
+ *
+ * Based on the L bit flag, first 4 bytes of data indicate the length
+ */
+
+/* Callbacks */
+int cbtls_password(char *buf, int num, int rwflag, void *userdata);
+void cbtls_info(SSL const *s, int where, int ret);
+void cbtls_msg(int write_p, int msg_version, int content_type, void const *buf, size_t len, SSL *ssl,
+ void *arg);
+int cbtls_verify(int ok, X509_STORE_CTX *ctx);
+
+/* threads.c */
+int tls_mutexes_init(void);
+
+/* TLS */
+int tls_global_init(bool spawn_flag, bool check);
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+int tls_global_version_check(char const *acknowledged);
+#endif
+
+int tls_error_log(REQUEST *request, char const *msg, ...) CC_HINT(format (printf, 2, 3));
+int tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5));
+
+void tls_global_cleanup(void);
+tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQUEST *request, bool client_cert, bool allow_tls13);
+tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, int fd, VALUE_PAIR **certs);
+fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs);
+fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs);
+fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx);
+SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client, char const *chain_file, char const *private_key_file);
+int tls_handshake_recv(REQUEST *, tls_session_t *ssn);
+int tls_handshake_send(REQUEST *, tls_session_t *ssn);
+void tls_session_information(tls_session_t *ssn);
+void tls_session_id(SSL_SESSION *ssn, char *buffer, size_t bufsize);
+X509_STORE *fr_init_x509_store(fr_tls_server_conf_t *conf);
+
+/*
+ * Low-level TLS stuff
+ */
+int tls_success(tls_session_t *ssn, REQUEST *request);
+void tls_fail(tls_session_t *ssn);
+fr_tls_status_t tls_ack_handler(tls_session_t *tls_session, REQUEST *request);
+fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request);
+
+#define FR_TLS_EX_INDEX_HANDLER (10)
+#define FR_TLS_EX_INDEX_CONF (11)
+#define FR_TLS_EX_INDEX_REQUEST (12)
+#define FR_TLS_EX_INDEX_IDENTITY (13)
+#define FR_TLS_EX_INDEX_STORE (14)
+#define FR_TLS_EX_INDEX_SSN (15)
+#define FR_TLS_EX_INDEX_TALLOC (16)
+#define FR_TLS_EX_INDEX_FIX_CERT_ORDER (17)
+
+extern int fr_tls_ex_index_certs;
+extern int fr_tls_ex_index_vps;
+
+/* configured values goes right here */
+struct fr_tls_server_conf_t {
+ SSL_CTX *ctx;
+ CONF_SECTION *cs;
+
+ char const *private_key_password;
+ char const *private_key_file;
+ char const *certificate_file;
+ char const *random_file;
+ char const *ca_path;
+ char const *ca_file;
+ char const *dh_file;
+ char const *rsa_file;
+ uint32_t verify_depth;
+ bool file_type;
+ bool include_length;
+ bool auto_chain;
+ bool disable_single_dh_use;
+ bool disable_tlsv1;
+ bool disable_tlsv1_1;
+ bool disable_tlsv1_2;
+ bool disallow_untrusted; //!< allow untrusted CAs to issue client certificates
+
+ int min_version;
+ int max_version;
+
+ char const *tls_min_version;
+ char const *tls_max_version;
+
+ /*
+ * Always < 4096 (due to radius limit), 0 by default = 1024
+ */
+ uint32_t fragment_size;
+ bool check_crl;
+ bool check_all_crl;
+ bool allow_expired_crl;
+ uint32_t ca_path_reload_interval;
+ uint32_t ca_path_last_reload;
+ X509_STORE *old_x509_store;
+ char const *check_cert_cn;
+ char const *cipher_list;
+ bool cipher_server_preference;
+ char const *check_cert_issuer;
+ char const *sigalgs_list;
+
+ bool session_cache_enable;
+ uint32_t session_lifetime;
+ uint32_t session_cache_size;
+ char const *session_id_name;
+ char const *session_cache_path;
+ char const *session_cache_server;
+ fr_hash_table_t *cache_ht;
+ char session_context_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+
+ bool verify_skip_if_ocsp_ok;
+ char const *verify_tmp_dir;
+ char const *verify_client_cert_cmd;
+ bool require_client_cert;
+
+ bool fix_cert_order;
+
+ pthread_mutex_t mutex;
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ /*
+ * OCSP Configuration
+ */
+ bool ocsp_enable;
+ bool ocsp_override_url;
+ char const *ocsp_url;
+ bool ocsp_use_nonce;
+ X509_STORE *ocsp_store;
+ uint32_t ocsp_timeout;
+ bool ocsp_softfail;
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ char const *ecdh_curve;
+#endif
+#endif
+
+#ifdef PSK_MAX_IDENTITY_LEN
+ char const *psk_identity;
+ char const *psk_password;
+ char const *psk_query;
+#endif
+
+ char const *realm_dir;
+ fr_hash_table_t *realms;
+
+ char const *client_hostname;
+
+#ifdef WITH_RADIUSV11
+ char const *radiusv11_name;
+ fr_radiusv11_t radiusv11;
+#endif
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WITH_TLS */
+#endif /* FR_TLS_H */
diff --git a/src/include/tmpl.h b/src/include/tmpl.h
new file mode 100644
index 0000000..92884b1
--- /dev/null
+++ b/src/include/tmpl.h
@@ -0,0 +1,345 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef TMPL_H
+#define TMPL_H
+/**
+ * $Id$
+ *
+ * @file tmpl.h
+ * @brief Structures and prototypes for templates
+ *
+ * These functions are used to work with #vp_tmpl_t structs.
+ *
+ * #vp_tmpl_t (VPTs) specify either a data source, or a data sink.
+ *
+ * Examples of sources are #TMPL_TYPE_XLAT, #TMPL_TYPE_EXEC and #TMPL_TYPE_ATTR.
+ * Examples of sinks are #TMPL_TYPE_ATTR, #TMPL_TYPE_LIST.
+ *
+ * VPTs are used to gather values or attributes for evaluation, or copying, and to specify
+ * where values or #VALUE_PAIR should be copied to.
+ *
+ * To create new #vp_tmpl_t use one of the tmpl_*from_* functions. These parse
+ * strings into VPTs. The main parsing function is #tmpl_afrom_str, which can produce
+ * most types of VPTs. It uses the type of quoting (passed as an #FR_TOKEN) to determine
+ * what type of VPT to parse the string as. For example a #T_DOUBLE_QUOTED_STRING will
+ * produce either a #TMPL_TYPE_XLAT or a #TMPL_TYPE_LITERAL (depending if the string
+ * contained a non-literal expansion).
+ *
+ * @see tmpl_afrom_str
+ * @see tmpl_afrom_attr_str
+ * @see tmpl_from_attr_str
+ * @see tmpl_from_attr_substr
+ *
+ * In the case of #TMPL_TYPE_ATTR and #TMPL_TYPE_LIST, there are special cursor overlay
+ * functions which can be used to iterate over only the #VALUE_PAIR that match a
+ * vp_tmpl_t in a given list.
+ *
+ * @see tmpl_cursor_init
+ * @see tmpl_cursor_next
+ *
+ * Or for simplicity, there are functions which wrap the cursor functions, to copy or
+ * return the #VALUE_PAIR that match the VPT.
+ *
+ * @see tmpl_copy_vps
+ * @see tmpl_find_vp
+ *
+ * If you just need the string value of whatever the VPT refers to, the tmpl_*expand
+ * functions may be used. These functions evaluate the VPT, execing, and xlat expanding
+ * as necessary. In the case of #TMPL_TYPE_ATTR, and #PW_TYPE_STRING or #PW_TYPE_OCTETS
+ * #tmpl_expand will return a pointer to the raw #VALUE_PAIR buffer. This can be very
+ * useful when using the #PW_TYPE_TMPL type in #CONF_PARSER structs, as it allows the
+ * user to determine whether they want the module to sanitise the value using presentation
+ * format specific #xlat_escape_t function, or to operate on the raw value.
+ *
+ * @see tmpl_expand
+ * @see tmpl_aexpand
+ *
+ * @copyright 2014-2015 The FreeRADIUS server project
+ */
+
+RCSIDH(tmpl_h, "$Id$")
+
+#include <freeradius-devel/xlat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#
+typedef enum pair_lists {
+ PAIR_LIST_UNKNOWN = 0, //!< Unknown list.
+ PAIR_LIST_REQUEST, //!< Attributes in incoming or internally proxied
+ ///< request.
+ PAIR_LIST_REPLY, //!< Attributes to send in the response.
+ PAIR_LIST_CONTROL, //!< Attributes that change the behaviour of
+ ///< modules.
+ PAIR_LIST_STATE, //!< Attributes to store multiple rounds of
+ ///< challenges/responses.
+#ifdef WITH_PROXY
+ PAIR_LIST_PROXY_REQUEST, //!< A copy of attributes in the request list
+ ///< that may be modified in pre-proxy before
+ //!< proxying the request.
+ PAIR_LIST_PROXY_REPLY, //!< Attributes sent in response to the proxied
+ ///< request.
+#endif
+#ifdef WITH_COA
+ PAIR_LIST_COA, //!< Attributes to send in a forked CoA-Request.
+ PAIR_LIST_COA_REPLY, //!< Attributes sent in response to the forked
+ ///< CoA-Request.
+ PAIR_LIST_DM, //!< Attributes to send in a forked Disconnect-Request.
+ PAIR_LIST_DM_REPLY //!< Attributes sent in response to the forked
+ //!< Disconnect-Request.
+#endif
+} pair_lists_t;
+
+extern const FR_NAME_NUMBER pair_lists[];
+
+typedef enum requests {
+ REQUEST_UNKNOWN = 0, //!< Unknown request.
+ REQUEST_OUTER, //!< #REQUEST containing the outer layer of the EAP
+ //!< conversation. Usually the RADIUS request sent
+ //!< by the NAS.
+ REQUEST_CURRENT, //!< The current request.
+ REQUEST_PARENT //!< Not currently used.
+} request_refs_t;
+
+extern const FR_NAME_NUMBER request_refs[];
+
+typedef struct pair_list {
+ char const *name;
+ VALUE_PAIR *check;
+ VALUE_PAIR *reply;
+ int order; /* for ordering! */
+ int lineno;
+ struct pair_list *next;
+} PAIR_LIST;
+
+/** Types of #vp_tmpl_t
+ */
+typedef enum tmpl_type {
+ TMPL_TYPE_UNKNOWN = 0, //!< Uninitialised.
+ TMPL_TYPE_LITERAL, //!< Literal string.
+ TMPL_TYPE_XLAT, //!< XLAT expansion.
+ TMPL_TYPE_ATTR, //!< Dictionary attribute.
+ TMPL_TYPE_ATTR_UNDEFINED, //!< Attribute not found in the global dictionary.
+ TMPL_TYPE_LIST, //!< Attribute list.
+ TMPL_TYPE_REGEX, //!< Regular expression.
+ TMPL_TYPE_EXEC, //!< Callout to an external script or program.
+ TMPL_TYPE_DATA, //!< Value in native format.
+ TMPL_TYPE_XLAT_STRUCT, //!< Pre-parsed XLAT expansion.
+ TMPL_TYPE_REGEX_STRUCT, //!< Pre-parsed regular expression.
+ TMPL_TYPE_NULL //!< Has no value.
+} tmpl_type_t;
+
+extern const FR_NAME_NUMBER tmpl_names[];
+
+/** Describes a #TMPL_TYPE_ATTR, #TMPL_TYPE_ATTR_UNDEFINED or #TMPL_TYPE_LIST
+ */
+typedef struct {
+ request_refs_t request; //!< Request to search or insert in.
+ pair_lists_t list; //!< List to search or insert in.
+
+ DICT_ATTR const *da; //!< Resolved dictionary attribute.
+ union {
+ uint8_t da[DICT_ATTR_SIZE]; //!< Unknown dictionary attribute buffer.
+ char name[DICT_ATTR_SIZE]; //!< Raw unknown dictionary name.
+ } unknown;
+ int num; //!< For array references.
+ int8_t tag; //!< For tag references.
+} value_pair_tmpl_attr_t;
+
+/** A source or sink of value data.
+ *
+ * Is used as both the RHS and LHS of a map (both update, and conditional types)
+ *
+ * @section update_maps Use in update vp_map_t
+ * When used on the LHS it describes an attribute to create and should be one of these types:
+ * - #TMPL_TYPE_ATTR
+ * - #TMPL_TYPE_LIST
+ *
+ * When used on the RHS it describes the value to assign to the attribute being created and
+ * should be one of these types:
+ * - #TMPL_TYPE_LITERAL
+ * - #TMPL_TYPE_XLAT
+ * - #TMPL_TYPE_ATTR
+ * - #TMPL_TYPE_LIST
+ * - #TMPL_TYPE_EXEC
+ * - #TMPL_TYPE_DATA
+ * - #TMPL_TYPE_XLAT_STRUCT (pre-parsed xlat)
+ *
+ * @section conditional_maps Use in conditional vp_map_t
+ * When used as part of a condition it may be any of the RHS side types, as well as:
+ * - #TMPL_TYPE_REGEX_STRUCT (pre-parsed regex)
+ *
+ * @see vp_map_t
+ */
+typedef struct vp_tmpl_t {
+ tmpl_type_t type; //!< What type of value tmpl refers to.
+ char const *name; //!< Original attribute ref string, or
+ //!< where this refers to a none FR
+ //!< attribute, just the string id for
+ //!< the attribute.
+ size_t len; //!< Name length.
+ char quote; //!< Quotation character for "name"
+ bool auto_converted; //!< Attr-26.9.1 --> Cisco-AVPair
+
+#ifdef HAVE_REGEX
+ bool iflag; //!< regex - case insensitive (if operand is used in regex comparison)
+ bool mflag; //!< regex - multiline flags (controls $ matching)
+#endif
+
+ union {
+ /*
+ * Attribute reference. Either an attribute currently in the request
+ * or an attribute to create.
+ */
+ value_pair_tmpl_attr_t attribute;
+
+ /*
+ * Attribute value. Typically used as the RHS of an update map.
+ */
+ struct {
+ PW_TYPE type; //!< Type of data.
+ size_t length; //!< of the vpd data.
+ value_data_t data; //!< Value data.
+ } literal;
+
+ xlat_exp_t *xlat; //!< pre-parsed xlat_exp_t
+
+#ifdef HAVE_REGEX
+ regex_t *preg; //!< pre-parsed regex_t
+#endif
+ } data;
+} vp_tmpl_t;
+
+/** @name Field accessors for #TMPL_TYPE_ATTR, #TMPL_TYPE_ATTR_UNDEFINED, #TMPL_TYPE_LIST
+ *
+ * @{
+ */
+#define tmpl_request data.attribute.request
+#define tmpl_list data.attribute.list
+#define tmpl_da data.attribute.da
+#define tmpl_unknown data.attribute.unknown.da
+#define tmpl_unknown_name data.attribute.unknown.name
+#define tmpl_num data.attribute.num
+#define tmpl_tag data.attribute.tag
+/* @} **/
+
+/** @name Field accessors for #TMPL_TYPE_XLAT_STRUCT
+ *
+ * @{
+ */
+#define tmpl_xlat data.xlat
+/* @} **/
+
+/** @name Field accessors for #TMPL_TYPE_DATA
+ *
+ * @{
+ */
+#define tmpl_data data.literal
+#define tmpl_data_type data.literal.type
+#define tmpl_data_length data.literal.length
+#define tmpl_data_value data.literal.data
+/* @} **/
+
+/** @name Field accessors for #TMPL_TYPE_REGEX_STRUCT and #TMPL_TYPE_REGEX
+ *
+ * @{
+ */
+#ifdef HAVE_REGEX
+# define tmpl_preg data.preg //!< #TMPL_TYPE_REGEX_STRUCT only.
+# define tmpl_iflag iflag
+# define tmpl_mflag mflag
+#endif
+/* @} **/
+
+#ifndef WITH_VERIFY_PTR
+# define VERIFY_TMPL(_x)
+#else
+# define VERIFY_TMPL(_x) tmpl_verify(__FILE__, __LINE__, _x)
+void tmpl_verify(char const *file, int line, vp_tmpl_t const *vpt);
+#endif
+
+VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list);
+
+RADIUS_PACKET *radius_packet(REQUEST *request, pair_lists_t list_name);
+
+TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list_name);
+
+size_t radius_list_name(pair_lists_t *out, char const *name, pair_lists_t default_list);
+
+int radius_request(REQUEST **request, request_refs_t name);
+
+size_t radius_request_name(request_refs_t *out, char const *name, request_refs_t unknown);
+
+vp_tmpl_t *tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type,
+ char const *name, ssize_t len);
+
+vp_tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name,
+ ssize_t len);
+
+ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined);
+
+ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name,
+ request_refs_t request_def,
+ pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined);
+
+ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined);
+
+ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
+ request_refs_t request_def,
+ pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined);
+
+ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, size_t inlen,
+ FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def, bool do_escape);
+
+int tmpl_cast_in_place(vp_tmpl_t *vpt, PW_TYPE type, DICT_ATTR const *enumv);
+
+void tmpl_cast_in_place_str(vp_tmpl_t *vpt);
+
+int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request,
+ vp_tmpl_t const *vpt, DICT_ATTR const *cast);
+
+size_t tmpl_prints(char *buffer, size_t bufsize, vp_tmpl_t const *vpt,
+ DICT_ATTR const *values);
+
+ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request,
+ vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx);
+
+ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt,
+ xlat_escape_t escape, void *escape_ctx);
+
+VALUE_PAIR *tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request,
+ vp_tmpl_t const *vpt);
+
+VALUE_PAIR *tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt);
+
+int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request,
+ vp_tmpl_t const *vpt);
+
+int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt);
+
+int tmpl_define_unknown_attr(vp_tmpl_t *vpt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TMPL_H */
diff --git a/src/include/token.h b/src/include/token.h
new file mode 100644
index 0000000..c8bb748
--- /dev/null
+++ b/src/include/token.h
@@ -0,0 +1,95 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_TOKEN_H
+#define FR_TOKEN_H
+
+/**
+ * $Id$
+ *
+ * @file token.h
+ * @brief Tokenisation code and constants.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ */
+
+RCSIDH(token_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum fr_token_t {
+ T_INVALID = 0, /* invalid token */
+ T_EOL, /* end of line */
+ T_LCBRACE, /* { */
+ T_RCBRACE, /* } */
+ T_LBRACE, /* ( */
+ T_RBRACE, /* ) 5 */
+ T_COMMA, /* , */
+ T_SEMICOLON, /* ; */
+
+ T_OP_INCRM, /* ++ */
+ T_OP_ADD, /* += */
+ T_OP_SUB, /* -= 10 */
+ T_OP_SET, /* := */
+ T_OP_EQ, /* = */
+ T_OP_NE, /* != */
+ T_OP_GE, /* >= */
+ T_OP_GT, /* > 15 */
+ T_OP_LE, /* <= */
+ T_OP_LT, /* < */
+ T_OP_REG_EQ, /* =~ */
+ T_OP_REG_NE, /* !~ */
+ T_OP_CMP_TRUE, /* =* 20 */
+ T_OP_CMP_FALSE, /* !* */
+ T_OP_CMP_EQ, /* == */
+ T_OP_PREPEND, /* ^= */
+ T_HASH, /* # */
+ T_BARE_WORD, /* bare word 25 */
+ T_DOUBLE_QUOTED_STRING, /* "foo" */
+ T_SINGLE_QUOTED_STRING, /* 'foo' */
+ T_BACK_QUOTED_STRING, /* `foo` */
+ T_TOKEN_LAST
+} FR_TOKEN;
+
+#define T_EQSTART T_OP_ADD
+#define T_EQEND (T_OP_PREPEND + 1)
+
+typedef struct FR_NAME_NUMBER {
+ char const *name;
+ int number;
+} FR_NAME_NUMBER;
+
+extern const FR_NAME_NUMBER fr_tokens[];
+extern const bool fr_assignment_op[];
+extern const bool fr_equality_op[];
+extern const bool fr_str_tok[];
+
+int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def);
+int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len);
+char const *fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def);
+
+int getword (char const **ptr, char *buf, int buflen, bool unescape);
+FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape);
+FR_TOKEN getop(char const **ptr);
+FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape);
+char const *fr_token_name(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_TOKEN_H */
diff --git a/src/include/udpfromto.h b/src/include/udpfromto.h
new file mode 100644
index 0000000..7b029cd
--- /dev/null
+++ b/src/include/udpfromto.h
@@ -0,0 +1,31 @@
+#ifndef UDPFROMTO_H
+#define UDPFROMTO_H
+/*
+ * $Id$
+ *
+ * @file udpfromto.h
+ */
+
+RCSIDH(udpfromtoh, "$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WITH_UDPFROMTO
+int udpfromto_init(int s);
+int recvfromto(int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen,
+ struct sockaddr *to, socklen_t *tolen);
+int sendfromto(int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t fromlen,
+ struct sockaddr *to, socklen_t tolen);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/xlat.h b/src/include/xlat.h
new file mode 100644
index 0000000..535dd81
--- /dev/null
+++ b/src/include/xlat.h
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef XLAT_H
+#define XLAT_H
+
+/**
+ * $Id$
+ *
+ * @file xlat.h
+ * @brief Structures and prototypes for templates
+ *
+ * @copyright 2015 The FreeRADIUS server project
+ */
+
+RCSIDH(xlat_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeradius-devel/conffile.h>
+
+typedef struct xlat_exp xlat_exp_t;
+
+typedef size_t (*xlat_escape_t)(REQUEST *, char *out, size_t outlen, char const *in, void *arg);
+typedef ssize_t (*xlat_func_t)(void *instance, REQUEST *, char const *, char *, size_t);
+
+ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape,
+ void *escape_ctx)
+ CC_HINT(nonnull (1 ,3 ,4));
+
+ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat,
+ xlat_escape_t escape, void *ctx)
+ CC_HINT(nonnull (1 ,3 ,4));
+
+ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx)
+ CC_HINT(nonnull (1, 2, 3));
+
+ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape,
+ void *ctx)
+ CC_HINT(nonnull (1, 2, 3));
+
+ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error);
+
+size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node);
+
+int xlat_register(char const *module, xlat_func_t func, xlat_escape_t escape,
+ void *instance);
+void xlat_unregister(char const *module, xlat_func_t func, void *instance);
+void xlat_unregister_module(void *instance);
+bool xlat_register_redundant(CONF_SECTION *cs);
+ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt);
+void xlat_free(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TMPL_H */
diff --git a/src/lib/LICENSE b/src/lib/LICENSE
new file mode 100644
index 0000000..fffbb23
--- /dev/null
+++ b/src/lib/LICENSE
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/lib/README b/src/lib/README
new file mode 100644
index 0000000..1c1da3a
--- /dev/null
+++ b/src/lib/README
@@ -0,0 +1,2 @@
+ The files in this directory are placed under the LGPL, as given
+in the LICENSE file in this directory.
diff --git a/src/lib/all.mk b/src/lib/all.mk
new file mode 100644
index 0000000..eef85d7
--- /dev/null
+++ b/src/lib/all.mk
@@ -0,0 +1,53 @@
+#
+# Makefile
+#
+# Version: $Id$
+#
+TARGET := libfreeradius-radius.a
+
+SOURCES := cbuff.c \
+ cursor.c \
+ debug.c \
+ dict.c \
+ filters.c \
+ hash.c \
+ hmacmd5.c \
+ hmacsha1.c \
+ isaac.c \
+ log.c \
+ misc.c \
+ missing.c \
+ md4.c \
+ md5.c \
+ net.c \
+ pair.c \
+ pcap.c \
+ print.c \
+ radius.c \
+ rbtree.c \
+ regex.c \
+ sha1.c \
+ snprintf.c \
+ strlcat.c \
+ strlcpy.c \
+ socket.c \
+ token.c \
+ udpfromto.c \
+ value.c \
+ fifo.c \
+ packet.c \
+ event.c \
+ getaddrinfo.c \
+ heap.c \
+ tcp.c \
+ base64.c \
+ version.c \
+ atomic_queue.c \
+ talloc.c
+
+SRC_CFLAGS := -D_LIBRADIUS -I$(top_builddir)/src
+
+# System libraries discovered by our top level configure script, links things
+# like pthread and the regexp libraries.
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS)
diff --git a/src/lib/atomic_queue.c b/src/lib/atomic_queue.c
new file mode 100644
index 0000000..cece3c4
--- /dev/null
+++ b/src/lib/atomic_queue.c
@@ -0,0 +1,337 @@
+/*
+ * 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 Thread-safe queues.
+ * @file atomic_queue.c
+ *
+ * @copyright 2016 Alan DeKok (aland@freeradius.org)
+ * @copyright 2016 Alister Winfield
+ */
+RCSID("$Id$")
+
+#ifdef HAVE_STDALIGN_H
+
+#include <stdint.h>
+#include <stdalign.h>
+#include <inttypes.h>
+
+#include <freeradius-devel/autoconf.h>
+
+#include <freeradius-devel/atomic_queue.h>
+#include <freeradius-devel/talloc.h>
+
+#define CACHE_LINE_SIZE 64
+
+/** Entry in the queue
+ *
+ * @note This structure is cache line aligned for modern AMD/Intel CPUs.
+ * This is to avoid contention when the producer and consumer are executing
+ * on different CPU cores.
+ */
+typedef struct CC_HINT(packed, aligned(CACHE_LINE_SIZE)) {
+ atomic_int64_t seq; //!< Must be seq then data to ensure
+ ///< seq is 64bit aligned for 32bit address
+ ///< spaces.
+ void *data;
+} fr_atomic_queue_entry_t;
+
+/** Structure to hold the atomic queue
+ *
+ */
+struct fr_atomic_queue_s {
+ alignas(CACHE_LINE_SIZE) atomic_int64_t head; //!< Head, aligned bytes to ensure
+ ///< it's in a different cache line to tail
+ ///< to reduce memory contention.
+ atomic_int64_t tail;
+
+ size_t size;
+
+ void *chunk; //!< To pass to free. The non-aligned address.
+
+ alignas(CACHE_LINE_SIZE) fr_atomic_queue_entry_t entry[]; //!< The entry array, also aligned
+ ///< to ensure it's not in the same cache
+ ///< line as tail and size.
+};
+
+/** Create fixed-size atomic queue
+ *
+ * @note the queue must be freed explicitly by the ctx being freed, or by using
+ * the #fr_atomic_queue_free function.
+ *
+ * @param[in] ctx The talloc ctx to allocate the queue in.
+ * @param[in] size The number of entries in the queue.
+ * @return
+ * - NULL on error.
+ * - fr_atomic_queue_t *, a pointer to the allocated and initialized queue.
+ */
+fr_atomic_queue_t *fr_atomic_queue_alloc(TALLOC_CTX *ctx, size_t size)
+{
+ size_t i;
+ int64_t seq;
+ fr_atomic_queue_t *aq;
+ TALLOC_CTX *chunk;
+
+ if (size == 0) return NULL;
+
+ /*
+ * Allocate a contiguous blob for the header and queue.
+ * This helps with memory locality.
+ *
+ * Since we're allocating a blob, we should also set the
+ * name of the data, too.
+ */
+ chunk = talloc_aligned_array(ctx, (void **)&aq, CACHE_LINE_SIZE,
+ sizeof(*aq) + (size) * sizeof(aq->entry[0]));
+ if (!chunk) return NULL;
+ aq->chunk = chunk;
+
+ talloc_set_name_const(chunk, "fr_atomic_queue_t");
+
+ /*
+ * Initialize the array. Data is NULL, and indexes are
+ * the array entry number.
+ */
+ for (i = 0; i < size; i++) {
+ seq = i;
+
+ aq->entry[i].data = NULL;
+ store(aq->entry[i].seq, seq);
+ }
+
+ aq->size = size;
+
+ /*
+ * Set the head / tail indexes, and force other CPUs to
+ * see the writes.
+ */
+ store(aq->head, 0);
+ store(aq->tail, 0);
+ atomic_thread_fence(memory_order_seq_cst);
+
+ return aq;
+}
+
+/** Free an atomic queue if it's not freed by ctx
+ *
+ * This function is needed because the atomic queue memory
+ * must be cache line aligned.
+ */
+void fr_atomic_queue_free(fr_atomic_queue_t **aq)
+{
+ if (!*aq) return;
+
+ talloc_free((*aq)->chunk);
+ *aq = NULL;
+}
+
+/** Push a pointer into the atomic queue
+ *
+ * @param[in] aq The atomic queue to add data to.
+ * @param[in] data to push.
+ * @return
+ * - true on successful push
+ * - false on queue full
+ */
+bool fr_atomic_queue_push(fr_atomic_queue_t *aq, void *data)
+{
+ int64_t head;
+ fr_atomic_queue_entry_t *entry;
+
+ if (!data) return false;
+
+ head = load(aq->head);
+
+ /*
+ * Try to find the current head.
+ */
+ for (;;) {
+ int64_t seq, diff;
+
+ entry = &aq->entry[ head % aq->size ];
+ seq = aquire(entry->seq);
+ diff = (seq - head);
+
+ /*
+ * head is larger than the current entry, the queue is full.
+ */
+ if (diff < 0) {
+#if 0
+ fr_atomic_queue_debug(aq, stderr);
+#endif
+ return false;
+ }
+
+ /*
+ * Someone else has already written to this entry. Get the new head pointer, and continue.
+ */
+ if (diff > 0) {
+ head = load(aq->head);
+ continue;
+ }
+
+ /*
+ * We have the possibility that we can write to
+ * this entry. Try it. If the write succeeds,
+ * we're done. If the write fails, re-load the
+ * current head entry, and continue.
+ */
+ if (cas_incr(aq->head, head)) {
+ break;
+ }
+ }
+
+ /*
+ * Store the data in the queue, and increment the entry
+ * with the new index, and make the write visible to
+ * other CPUs.
+ */
+ entry->data = data;
+ store(entry->seq, head + 1);
+ return true;
+}
+
+
+/** Pop a pointer from the atomic queue
+ *
+ * @param[in] aq the atomic queue to retrieve data from.
+ * @param[out] p_data where to write the data.
+ * @return
+ * - true on successful pop
+ * - false on queue empty
+ */
+bool fr_atomic_queue_pop(fr_atomic_queue_t *aq, void **p_data)
+{
+ int64_t tail, seq;
+ fr_atomic_queue_entry_t *entry;
+
+ if (!p_data) return false;
+
+ tail = load(aq->tail);
+
+ for (;;) {
+ int64_t diff;
+
+ entry = &aq->entry[ tail % aq->size ];
+ seq = aquire(entry->seq);
+
+ diff = (seq - (tail + 1));
+
+ /*
+ * tail is smaller than the current entry, the queue is full.
+ */
+ if (diff < 0) {
+ return false;
+ }
+
+ if (diff > 0) {
+ tail = load(aq->tail);
+ continue;
+ }
+
+ if (cas_incr(aq->tail, tail)) {
+ break;
+ }
+ }
+
+ /*
+ * Copy the pointer to the caller BEFORE updating the
+ * queue entry.
+ */
+ *p_data = entry->data;
+
+ /*
+ * Set the current entry to past the end of the queue.
+ * i.e. it's unused.
+ */
+ seq = tail + aq->size;
+ store(entry->seq, seq);
+
+ return true;
+}
+
+size_t fr_atomic_queue_size(fr_atomic_queue_t *aq)
+{
+ return aq->size;
+}
+
+#ifdef WITH_VERIFY_PTR
+/** Check the talloc chunk is still valid
+ *
+ */
+void fr_atomic_queue_verify(fr_atomic_queue_t *aq)
+{
+ (void)talloc_get_type_abort(aq->chunk, fr_atomic_queue_t);
+}
+#endif
+
+#ifndef NDEBUG
+
+#if 0
+typedef struct {
+ int status; //!< status of this message
+ size_t data_size; //!< size of the data we're sending
+
+ int signal; //!< the signal to send
+ uint64_t ack; //!< or the endpoint..
+ void *ch; //!< the channel
+} fr_control_message_t;
+#endif
+
+
+/** Dump an atomic queue.
+ *
+ * Absolutely NOT thread-safe.
+ *
+ * @param[in] aq The atomic queue to debug.
+ * @param[in] fp where the debugging information will be printed.
+ */
+void fr_atomic_queue_debug(fr_atomic_queue_t *aq, FILE *fp)
+{
+ size_t i;
+ int64_t head, tail;
+
+ head = load(aq->head);
+ tail = load(aq->head);
+
+ fprintf(fp, "AQ %p size %zu, head %" PRId64 ", tail %" PRId64 "\n",
+ aq, aq->size, head, tail);
+
+ for (i = 0; i < aq->size; i++) {
+ fr_atomic_queue_entry_t *entry;
+
+ entry = &aq->entry[i];
+
+ fprintf(fp, "\t[%zu] = { %p, %" PRId64 " }",
+ i, entry->data, load(entry->seq));
+#if 0
+ if (entry->data) {
+ fr_control_message_t *c;
+
+ c = entry->data;
+
+ fprintf(fp, "\tstatus %d, data_size %zd, signal %d, ack %zd, ch %p",
+ c->status, c->data_size, c->signal, c->ack, c->ch);
+ }
+#endif
+ fprintf(fp, "\n");
+ }
+}
+#endif
+
+#endif /* HAVE_STDALIGN_H */
diff --git a/src/lib/base64.c b/src/lib/base64.c
new file mode 100644
index 0000000..6b40866
--- /dev/null
+++ b/src/lib/base64.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006 Free Software
+ * Foundation, Inc.
+ *
+ * This program is left 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, 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @brief Encode/decode binary data using printable characters.
+ * @author Simon Josefsson.
+ * @see RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>.
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/base64.h>
+
+#define us(x) (uint8_t) x
+
+/** Base 64 encode binary data
+ *
+ * Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+ *
+ * @param[out] out Where to write Base64 string.
+ * @param[in] outlen size of buffer including NULL byte.
+ * @param[in] in Data to encode.
+ * @param[in] inlen Length of data to encode.
+ * @return The amount of data we wrote to the buffer or -1 if output buffer
+ * was too small.
+ */
+ssize_t fr_base64_encode(char *out, size_t outlen, uint8_t const *in, size_t inlen)
+{
+ static char const b64str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ char *p = out;
+ if (outlen < (FR_BASE64_ENC_LENGTH(inlen) + 1)) {
+ *out = '\0';
+ return -1;
+ }
+
+ while (inlen) {
+ *p++ = b64str[(in[0] >> 2) & 0x3f];
+ *p++ = b64str[((in[0] << 4) + (--inlen ? in[1] >> 4 : 0)) & 0x3f];
+ *p++ = (inlen ? b64str[((in[1] << 2) + (--inlen ? in[2] >> 6 : 0)) & 0x3f] : '=');
+ *p++ = inlen ? b64str[in[2] & 0x3f] : '=';
+
+ if (inlen) inlen--;
+ if (inlen) in += 3;
+ }
+
+ p[0] = '\0';
+
+ return p - out;
+}
+
+/*
+ * With this approach this file works independent of the charset used
+ * (think EBCDIC). However, it does assume that the characters in the
+ * Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
+ * 1003.1-2001 require that char and unsigned char are 8-bit
+ * quantities, though, taking care of that problem. But this may be a
+ * potential problem on non-POSIX C99 platforms.
+ *
+ * IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
+ * as the formal parameter rather than "x".
+ */
+#define B64(_) \
+ ((_) == 'A' ? 0 \
+ : (_) == 'B' ? 1 \
+ : (_) == 'C' ? 2 \
+ : (_) == 'D' ? 3 \
+ : (_) == 'E' ? 4 \
+ : (_) == 'F' ? 5 \
+ : (_) == 'G' ? 6 \
+ : (_) == 'H' ? 7 \
+ : (_) == 'I' ? 8 \
+ : (_) == 'J' ? 9 \
+ : (_) == 'K' ? 10 \
+ : (_) == 'L' ? 11 \
+ : (_) == 'M' ? 12 \
+ : (_) == 'N' ? 13 \
+ : (_) == 'O' ? 14 \
+ : (_) == 'P' ? 15 \
+ : (_) == 'Q' ? 16 \
+ : (_) == 'R' ? 17 \
+ : (_) == 'S' ? 18 \
+ : (_) == 'T' ? 19 \
+ : (_) == 'U' ? 20 \
+ : (_) == 'V' ? 21 \
+ : (_) == 'W' ? 22 \
+ : (_) == 'X' ? 23 \
+ : (_) == 'Y' ? 24 \
+ : (_) == 'Z' ? 25 \
+ : (_) == 'a' ? 26 \
+ : (_) == 'b' ? 27 \
+ : (_) == 'c' ? 28 \
+ : (_) == 'd' ? 29 \
+ : (_) == 'e' ? 30 \
+ : (_) == 'f' ? 31 \
+ : (_) == 'g' ? 32 \
+ : (_) == 'h' ? 33 \
+ : (_) == 'i' ? 34 \
+ : (_) == 'j' ? 35 \
+ : (_) == 'k' ? 36 \
+ : (_) == 'l' ? 37 \
+ : (_) == 'm' ? 38 \
+ : (_) == 'n' ? 39 \
+ : (_) == 'o' ? 40 \
+ : (_) == 'p' ? 41 \
+ : (_) == 'q' ? 42 \
+ : (_) == 'r' ? 43 \
+ : (_) == 's' ? 44 \
+ : (_) == 't' ? 45 \
+ : (_) == 'u' ? 46 \
+ : (_) == 'v' ? 47 \
+ : (_) == 'w' ? 48 \
+ : (_) == 'x' ? 49 \
+ : (_) == 'y' ? 50 \
+ : (_) == 'z' ? 51 \
+ : (_) == '0' ? 52 \
+ : (_) == '1' ? 53 \
+ : (_) == '2' ? 54 \
+ : (_) == '3' ? 55 \
+ : (_) == '4' ? 56 \
+ : (_) == '5' ? 57 \
+ : (_) == '6' ? 58 \
+ : (_) == '7' ? 59 \
+ : (_) == '8' ? 60 \
+ : (_) == '9' ? 61 \
+ : (_) == '+' ? 62 \
+ : (_) == '/' ? 63 \
+ : -1)
+
+static const signed char b64[0x100] = {
+ B64 (0), B64 (1), B64 (2), B64 (3),
+ B64 (4), B64 (5), B64 (6), B64 (7),
+ B64 (8), B64 (9), B64 (10), B64 (11),
+ B64 (12), B64 (13), B64 (14), B64 (15),
+ B64 (16), B64 (17), B64 (18), B64 (19),
+ B64 (20), B64 (21), B64 (22), B64 (23),
+ B64 (24), B64 (25), B64 (26), B64 (27),
+ B64 (28), B64 (29), B64 (30), B64 (31),
+ B64 (32), B64 (33), B64 (34), B64 (35),
+ B64 (36), B64 (37), B64 (38), B64 (39),
+ B64 (40), B64 (41), B64 (42), B64 (43),
+ B64 (44), B64 (45), B64 (46), B64 (47),
+ B64 (48), B64 (49), B64 (50), B64 (51),
+ B64 (52), B64 (53), B64 (54), B64 (55),
+ B64 (56), B64 (57), B64 (58), B64 (59),
+ B64 (60), B64 (61), B64 (62), B64 (63),
+ B64 (64), B64 (65), B64 (66), B64 (67),
+ B64 (68), B64 (69), B64 (70), B64 (71),
+ B64 (72), B64 (73), B64 (74), B64 (75),
+ B64 (76), B64 (77), B64 (78), B64 (79),
+ B64 (80), B64 (81), B64 (82), B64 (83),
+ B64 (84), B64 (85), B64 (86), B64 (87),
+ B64 (88), B64 (89), B64 (90), B64 (91),
+ B64 (92), B64 (93), B64 (94), B64 (95),
+ B64 (96), B64 (97), B64 (98), B64 (99),
+ B64 (100), B64 (101), B64 (102), B64 (103),
+ B64 (104), B64 (105), B64 (106), B64 (107),
+ B64 (108), B64 (109), B64 (110), B64 (111),
+ B64 (112), B64 (113), B64 (114), B64 (115),
+ B64 (116), B64 (117), B64 (118), B64 (119),
+ B64 (120), B64 (121), B64 (122), B64 (123),
+ B64 (124), B64 (125), B64 (126), B64 (127),
+ B64 (128), B64 (129), B64 (130), B64 (131),
+ B64 (132), B64 (133), B64 (134), B64 (135),
+ B64 (136), B64 (137), B64 (138), B64 (139),
+ B64 (140), B64 (141), B64 (142), B64 (143),
+ B64 (144), B64 (145), B64 (146), B64 (147),
+ B64 (148), B64 (149), B64 (150), B64 (151),
+ B64 (152), B64 (153), B64 (154), B64 (155),
+ B64 (156), B64 (157), B64 (158), B64 (159),
+ B64 (160), B64 (161), B64 (162), B64 (163),
+ B64 (164), B64 (165), B64 (166), B64 (167),
+ B64 (168), B64 (169), B64 (170), B64 (171),
+ B64 (172), B64 (173), B64 (174), B64 (175),
+ B64 (176), B64 (177), B64 (178), B64 (179),
+ B64 (180), B64 (181), B64 (182), B64 (183),
+ B64 (184), B64 (185), B64 (186), B64 (187),
+ B64 (188), B64 (189), B64 (190), B64 (191),
+ B64 (192), B64 (193), B64 (194), B64 (195),
+ B64 (196), B64 (197), B64 (198), B64 (199),
+ B64 (200), B64 (201), B64 (202), B64 (203),
+ B64 (204), B64 (205), B64 (206), B64 (207),
+ B64 (208), B64 (209), B64 (210), B64 (211),
+ B64 (212), B64 (213), B64 (214), B64 (215),
+ B64 (216), B64 (217), B64 (218), B64 (219),
+ B64 (220), B64 (221), B64 (222), B64 (223),
+ B64 (224), B64 (225), B64 (226), B64 (227),
+ B64 (228), B64 (229), B64 (230), B64 (231),
+ B64 (232), B64 (233), B64 (234), B64 (235),
+ B64 (236), B64 (237), B64 (238), B64 (239),
+ B64 (240), B64 (241), B64 (242), B64 (243),
+ B64 (244), B64 (245), B64 (246), B64 (247),
+ B64 (248), B64 (249), B64 (250), B64 (251),
+ B64 (252), B64 (253), B64 (254), B64 (255)
+};
+
+/** Check if char is in Base64 alphabet
+ *
+ * Note that '=' is padding and not considered to be part of the alphabet.
+ *
+ * @param c char to check.
+ * @return true if CH is a character from the Base64 alphabet, and false
+ * otherwise.
+ */
+bool fr_is_base64(char c)
+{
+ return b64[us(c)] >= 0;
+}
+
+/* Decode base64 encoded input array.
+ *
+ * Decode base64 encoded input array IN of length INLEN to output array OUT that
+ * can hold *OUTLEN bytes. Return true if decoding was successful, i.e.
+ * if the input was valid base64 data, -1 otherwise.
+ *
+ * If *OUTLEN is too small, as many bytes as possible will be written to OUT.
+ * On return, *OUTLEN holds the length of decoded bytes in OUT.
+ *
+ * Note that as soon as any non-alphabet characters are encountered,
+ * decoding is stopped and -1 is returned.
+ *
+ * This means that, when applicable, you must remove any line terminators
+ * that is part of the data stream before calling this function.
+ *
+ * @param[out] out Where to write the decoded data.
+ * @param[in] outlen The length of the output buffer.
+ * @param[in] in Base64 string to decode.
+ * @param[in] inlen length of Base64 string.
+ * @return -1 on error, else the length of decoded data.
+ */
+ssize_t fr_base64_decode(uint8_t *out, size_t outlen, char const *in, size_t inlen)
+{
+ uint8_t *out_p = out;
+ uint8_t *out_end = out + outlen;
+ char const *p = in, *q;
+ char const *end = p + inlen;
+
+ /*
+ * Process complete 24bit quanta
+ */
+ while ((end - p) >= 4) {
+ if (!fr_is_base64(p[0]) || !fr_is_base64(p[1]) || !fr_is_base64(p[2]) || !fr_is_base64(p[3])) break;
+
+ /*
+ * Check we have enough bytes to write out
+ * the 24bit quantum.
+ */
+ if ((out_end - out_p) <= 3) {
+ oob:
+ fr_strerror_printf("Output buffer too small, needed at least %zu bytes", outlen + 1);
+ return p - end;
+ }
+
+ *out_p++ = ((b64[us(p[0])] << 2) | (b64[us(p[1])] >> 4));
+ *out_p++ = ((b64[us(p[1])] << 4) & 0xf0) | (b64[us(p[2])] >> 2);
+ *out_p++ = ((b64[us(p[2])] << 6) & 0xc0) | b64[us(p[3])];
+
+ p += 4; /* 32bit input -> 24bit output */
+ }
+
+ q = p;
+
+ /*
+ * Find the first non-base64 char
+ */
+ while ((q < end) && fr_is_base64(*q)) q++;
+
+ switch (q - p) {
+ case 0: /* Final quantum is 24 bits */
+ break;
+
+ case 2: /* Final quantum is 8 bits */
+ if ((out_end - out_p) < 1) goto oob;
+ *out_p++ = ((b64[us(p[0])] << 2) | (b64[us(p[1])] >> 4));
+ p += 2;
+ break;
+
+ case 3: /* Final quantum is 16 bits */
+ if ((out_end - out_p) < 2) goto oob;
+ *out_p++ = ((b64[us(p[0])] << 2) | (b64[us(p[1])] >> 4));
+ *out_p++ = ((b64[us(p[1])] << 4) & 0xf0) | (b64[us(p[2])] >> 2);
+ p += 3;
+ break;
+
+ default:
+ fr_strerror_printf("Invalid base64 padding data");
+ return p - end;
+ }
+
+ while (p < end) {
+ if (*p != '=') {
+ fr_strerror_printf("Found non-padding char '%c' at end of base64 string", *p);
+ return p - end;
+ }
+ p++;
+ }
+
+ return out_p - out;
+}
diff --git a/src/lib/cbuff.c b/src/lib/cbuff.c
new file mode 100644
index 0000000..32646ca
--- /dev/null
+++ b/src/lib/cbuff.c
@@ -0,0 +1,145 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file cbuff.c
+ * @brief Implementation of a ring buffer
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef HAVE_PTHREAD_H
+# define PTHREAD_MUTEX_LOCK(_x) if (_x->lock) pthread_mutex_lock(&((_x)->mutex))
+# define PTHREAD_MUTEX_UNLOCK(_x) if (_x->lock) pthread_mutex_unlock(&((_x)->mutex))
+#else
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+/** Standard thread safe circular buffer
+ *
+ */
+struct fr_cbuff {
+ void const *end; //!< End of allocated memory
+
+ uint32_t size;
+ uint32_t in; //!< Write index
+ uint32_t out; //!< Read index
+
+ void **elem; //!< Ring buffer data
+
+ bool lock; //!< Perform thread synchronisation
+ pthread_mutex_t mutex; //!< Thread synchronisation mutex
+};
+
+/** Initialise a new circular buffer
+ *
+ * @param ctx to allocate the buffer in.
+ * @param size of buffer to allocate.
+ * @param lock If true, insert and next operations will lock the buffer.
+ * @return new cbuff, or NULL on error.
+ */
+#ifdef HAVE_PTHREAD_H
+fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
+#else
+fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, UNUSED bool lock)
+#endif
+{
+ fr_cbuff_t *cbuff;
+
+ uint32_t pow;
+
+ /*
+ * Find the nearest power of 2 (rounding up)
+ */
+ for (pow = 0x00000001;
+ pow < size;
+ pow <<= 1);
+ size = pow;
+ size--;
+
+ cbuff = talloc_zero(ctx, fr_cbuff_t);
+ if (!cbuff) {
+ return NULL;
+ }
+ cbuff->elem = talloc_zero_array(cbuff, void *, size);
+ if (!cbuff->elem) {
+ return NULL;
+ }
+ cbuff->size = size;
+
+#ifdef HAVE_PTHREAD_H
+ if (lock) {
+ cbuff->lock = true;
+ pthread_mutex_init(&cbuff->mutex, NULL);
+ }
+#endif
+ return cbuff;
+}
+
+/** Insert a new element into the buffer, and steal it from it's original context
+ *
+ * cbuff will steal obj and insert it into it's own context.
+ *
+ * @param cbuff to insert element into
+ * @param obj to insert, must of been allocated with talloc
+ */
+void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj)
+{
+ PTHREAD_MUTEX_LOCK(cbuff);
+
+ if (cbuff->elem[cbuff->in]) {
+ TALLOC_FREE(cbuff->elem[cbuff->in]);
+ }
+
+ cbuff->elem[cbuff->in] = talloc_steal(cbuff, obj);
+
+ cbuff->in = (cbuff->in + 1) & cbuff->size;
+
+ /* overwrite - out is advanced ahead of in */
+ if (cbuff->in == cbuff->out) {
+ cbuff->out = (cbuff->out + 1) & cbuff->size;
+ }
+
+ PTHREAD_MUTEX_UNLOCK(cbuff);
+}
+
+/** Remove an item from the buffer, and reparent to ctx
+ *
+ * @param cbuff to remove element from
+ * @param ctx to hang obj off.
+ * @return NULL if no elements in the buffer, else an element from the buffer reparented to ctx.
+ */
+void *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx)
+{
+ void *obj = NULL;
+
+ PTHREAD_MUTEX_LOCK(cbuff);
+
+ /* Buffer is empty */
+ if (cbuff->out == cbuff->in) goto done;
+
+ obj = talloc_steal(ctx, cbuff->elem[cbuff->out]);
+ cbuff->out = (cbuff->out + 1) & cbuff->size;
+
+done:
+ PTHREAD_MUTEX_UNLOCK(cbuff);
+ return obj;
+}
diff --git a/src/lib/cursor.c b/src/lib/cursor.c
new file mode 100644
index 0000000..ae88ebe
--- /dev/null
+++ b/src/lib/cursor.c
@@ -0,0 +1,461 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file cursor.c
+ * @brief Functions to iterate over collections of VALUE_PAIRs
+ *
+ * @note Do not modify collections of VALUE_PAIRs pointed to be a cursor
+ * with none fr_cursor_* functions, during the lifetime of that cursor.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013-2015 The FreeRADIUS Server Project.
+ */
+
+#include <freeradius-devel/libradius.h>
+
+/** Internal function to update cursor state
+ *
+ * @param cursor to operate on.
+ * @param vp to set current and found positions to.
+ * @return value passed in as vp.
+ */
+inline static VALUE_PAIR *fr_cursor_update(vp_cursor_t *cursor, VALUE_PAIR *vp)
+{
+ if (!vp) {
+ cursor->next = NULL;
+ cursor->current = NULL;
+
+ return NULL;
+ }
+
+ cursor->next = vp->next;
+ cursor->current = vp;
+ cursor->found = vp;
+
+ return vp;
+}
+
+/** Setup a cursor to iterate over attribute pairs
+ *
+ * @param cursor Where to initialise the cursor (uses existing structure).
+ * @param const_vp to start from.
+ * @return the attribute pointed to by vp.
+ */
+VALUE_PAIR *fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR * const *const_vp)
+{
+ VALUE_PAIR **vp;
+
+ if (!const_vp || !cursor) {
+ return NULL;
+ }
+
+ memset(cursor, 0, sizeof(*cursor));
+
+ memcpy(&vp, &const_vp, sizeof(vp)); /* stupid const hacks */
+
+ /*
+ * Useful check to see if uninitialised memory is pointed
+ * to by vp
+ */
+#ifndef NDEBUG
+ if (*vp) VERIFY_VP(*vp);
+#endif
+ memcpy(&cursor->first, &vp, sizeof(cursor->first));
+ cursor->current = *cursor->first;
+
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+ cursor->next = cursor->current->next;
+ }
+
+ return cursor->current;
+}
+
+/** Copy a cursor
+ *
+ * @param in Cursor to copy.
+ * @param out Where to copy the cursor to.
+ */
+void fr_cursor_copy(vp_cursor_t *out, vp_cursor_t *in)
+{
+ memcpy(out, in, sizeof(*out));
+}
+
+/** Rewind cursor to the start of the list
+ *
+ * @param cursor to operate on.
+ * @return the VALUE_PAIR at the start of the list.
+ */
+VALUE_PAIR *fr_cursor_first(vp_cursor_t *cursor)
+{
+ if (!cursor->first) return NULL;
+
+ cursor->current = *cursor->first;
+
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+ cursor->next = cursor->current->next;
+ if (cursor->next) VERIFY_VP(cursor->next);
+ cursor->found = NULL;
+ }
+
+ return cursor->current;
+}
+
+/** Wind cursor to the last pair in the list
+ *
+ * @param cursor to operate on.
+ * @return the VALUE_PAIR at the end of the list.
+ */
+VALUE_PAIR *fr_cursor_last(vp_cursor_t *cursor)
+{
+ if (!cursor->first || !*cursor->first) return NULL;
+
+ /* Need to start at the start */
+ if (!cursor->current) fr_cursor_first(cursor);
+
+ /* Wind to the end */
+ while (cursor->next) fr_cursor_next(cursor);
+
+ return cursor->current;
+}
+
+/** Iterate over a collection of VALUE_PAIRs of a given type in the pairlist
+ *
+ * Find the next attribute of a given type. If no fr_cursor_next_by_* function
+ * has been called on a cursor before, or the previous call returned
+ * NULL, the search will start with the current attribute. Subsequent calls to
+ * fr_cursor_next_by_* functions will start the search from the previously
+ * matched attribute.
+ *
+ * @param cursor to operate on.
+ * @param attr number to match.
+ * @param vendor number to match (0 for none vendor attribute).
+ * @param tag to match. Either a tag number or TAG_ANY to match any tagged or
+ * untagged attribute, TAG_NONE to match attributes without tags.
+ * @return the next matching VALUE_PAIR, or NULL if no VALUE_PAIRs match.
+ */
+VALUE_PAIR *fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ VALUE_PAIR *i;
+
+ if (!cursor->first) return NULL;
+
+ for (i = !cursor->found ? cursor->current : cursor->found->next;
+ i != NULL;
+ i = i->next) {
+ VERIFY_VP(i);
+ if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
+ (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
+ break;
+ }
+ }
+
+ return fr_cursor_update(cursor, i);
+}
+
+/** Iterate over attributes of a given DA in the pairlist
+ *
+ * Find the next attribute of a given type. If no fr_cursor_next_by_* function
+ * has been called on a cursor before, or the previous call returned
+ * NULL, the search will start with the current attribute. Subsequent calls to
+ * fr_cursor_next_by_* functions will start the search from the previously
+ * matched attribute.
+ *
+ * @note DICT_ATTR pointers are compared, not the attribute numbers and vendors.
+ *
+ * @param cursor to operate on.
+ * @param da to match.
+ * @param tag to match. Either a tag number or TAG_ANY to match any tagged or
+ * untagged attribute, TAG_NONE to match attributes without tags.
+ * @return the next matching VALUE_PAIR, or NULL if no VALUE_PAIRs match.
+ */
+VALUE_PAIR *fr_cursor_next_by_da(vp_cursor_t *cursor, DICT_ATTR const *da, int8_t tag)
+{
+ VALUE_PAIR *i;
+
+ if (!cursor->first) return NULL;
+
+ for (i = !cursor->found ? cursor->current : cursor->found->next;
+ i != NULL;
+ i = i->next) {
+ VERIFY_VP(i);
+ if ((i->da == da) &&
+ (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
+ break;
+ }
+ }
+
+ return fr_cursor_update(cursor, i);
+}
+
+/** Advanced the cursor to the next VALUE_PAIR
+ *
+ * @param cursor to operate on.
+ * @return the next VALUE_PAIR, or NULL if no more VALUE_PAIRS in the collection.
+ */
+VALUE_PAIR *fr_cursor_next(vp_cursor_t *cursor)
+{
+ if (!cursor->first) return NULL;
+
+ cursor->current = cursor->next;
+ if (cursor->current) {
+ VERIFY_VP(cursor->current);
+
+ /*
+ * Set this now in case 'current' gets freed before
+ * fr_cursor_next is called again.
+ */
+ cursor->next = cursor->current->next;
+
+ /*
+ * Next call to fr_cursor_next_by_num will start from the current
+ * position in the list, not the last found instance.
+ */
+ cursor->found = NULL;
+ }
+
+ return cursor->current;
+}
+
+/** Return the next VALUE_PAIR without advancing the cursor
+ *
+ * @param cursor to operate on.
+ * @return the next VALUE_PAIR, or NULL if no more VALUE_PAIRS in the collection.
+ */
+VALUE_PAIR *fr_cursor_next_peek(vp_cursor_t *cursor)
+{
+ return cursor->next;
+}
+
+/** Return the VALUE_PAIR the cursor current points to
+ *
+ * @param cursor to operate on.
+ * @return the VALUE_PAIR the cursor currently points to.
+ */
+VALUE_PAIR *fr_cursor_current(vp_cursor_t *cursor)
+{
+ if (cursor->current) VERIFY_VP(cursor->current);
+
+ return cursor->current;
+}
+
+/** Insert a single VALUE_PAIR at the end of the list
+ *
+ * @note Will not advance cursor position to new attribute, but will set cursor
+ * to this attribute, if it's the first one in the list.
+ *
+ * Insert a VALUE_PAIR at the end of the list.
+ *
+ * @param cursor to operate on.
+ * @param vp to insert.
+ */
+void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
+{
+ VALUE_PAIR *i;
+
+ if (!fr_assert(cursor->first)) return; /* cursor must have been initialised */
+
+ if (!vp) return;
+
+ VERIFY_VP(vp);
+
+ /*
+ * Only allow one VP to by inserted at a time
+ */
+ vp->next = NULL;
+
+ /*
+ * Cursor was initialised with a pointer to a NULL value_pair
+ */
+ if (!*cursor->first) {
+ *cursor->first = vp;
+ cursor->current = vp;
+
+ return;
+ }
+
+ /*
+ * We don't yet know where the last VALUE_PAIR is
+ *
+ * Assume current is closer to the end of the list and
+ * use that if available.
+ */
+ if (!cursor->last) cursor->last = cursor->current ? cursor->current : *cursor->first;
+
+ VERIFY_VP(cursor->last);
+
+ /*
+ * Wind last to the end of the list.
+ */
+ if (cursor->last->next) {
+ for (i = cursor->last; i; i = i->next) {
+ VERIFY_VP(i);
+ cursor->last = i;
+ }
+ }
+
+ /*
+ * Either current was never set, or something iterated to the
+ * end of the attribute list. In both cases the newly inserted
+ * VALUE_PAIR should be set as the current VALUE_PAIR.
+ */
+ if (!cursor->current) cursor->current = vp;
+
+ /*
+ * Add the VALUE_PAIR to the end of the list
+ */
+ cursor->last->next = vp;
+ cursor->last = vp; /* Wind it forward a little more */
+
+ /*
+ * If the next pointer was NULL, and the VALUE_PAIR
+ * just added has a next pointer value, set the cursor's next
+ * pointer to the VALUE_PAIR's next pointer.
+ */
+ if (!cursor->next) cursor->next = cursor->current->next;
+}
+
+/** Merges multiple VALUE_PAIR into the cursor
+ *
+ * Add multiple VALUE_PAIR from add to cursor.
+ *
+ * @param cursor to insert VALUE_PAIRs with
+ * @param add one or more VALUE_PAIRs (may be NULL, which results in noop).
+ */
+void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *add)
+{
+ vp_cursor_t from;
+ VALUE_PAIR *vp;
+
+ if (!add) return;
+
+ if (!fr_assert(cursor->first)) return; /* cursor must have been initialised */
+
+ for (vp = fr_cursor_init(&from, &add);
+ vp;
+ vp = fr_cursor_next(&from)) {
+ fr_cursor_insert(cursor, vp);
+ }
+}
+
+/** Remove the current pair
+ *
+ * @todo this is really inefficient and should be fixed...
+ *
+ * The current VP will be set to the one before the VP being removed,
+ * this is so the commonly used check and remove loop (below) works
+ * as expected.
+ @code {.c}
+ for (vp = fr_cursor_init(&cursor, head);
+ vp;
+ vp = fr_cursor_next(&cursor) {
+ if (<condition>) {
+ vp = fr_cursor_remove(&cursor);
+ talloc_free(vp);
+ }
+ }
+ @endcode
+ *
+ * @param cursor to remove the current pair from.
+ * @return NULL on error, else the VALUE_PAIR that was just removed.
+ */
+VALUE_PAIR *fr_cursor_remove(vp_cursor_t *cursor)
+{
+ VALUE_PAIR *vp, *before;
+
+ if (!fr_assert(cursor->first)) return NULL; /* cursor must have been initialised */
+
+ vp = cursor->current;
+ if (!vp) return NULL;
+
+ /*
+ * Where VP is head of the list
+ */
+ if (*(cursor->first) == vp) {
+ *(cursor->first) = vp->next;
+ cursor->current = vp->next;
+ cursor->next = vp->next ? vp->next->next : NULL;
+ before = NULL;
+ goto fixup;
+ }
+
+ /*
+ * Where VP is not head of the list
+ */
+ before = *(cursor->first);
+ if (!before) return NULL;
+
+ /*
+ * Find the VP immediately preceding the one being removed
+ */
+ while (before->next != vp) before = before->next;
+
+ cursor->next = before->next = vp->next; /* close the gap */
+ cursor->current = before; /* current jumps back one, but this is usually desirable */
+
+fixup:
+ vp->next = NULL; /* limit scope of fr_pair_list_free() */
+
+ /*
+ * Fixup cursor->found if we removed the VP it was referring to,
+ * and point to the previous one.
+ */
+ if (vp == cursor->found) cursor->found = before;
+
+ /*
+ * Fixup cursor->last if we removed the VP it was referring to
+ */
+ if (vp == cursor->last) cursor->last = cursor->current;
+ return vp;
+}
+
+/** Replace the current pair
+ *
+ * @todo this is really inefficient and should be fixed...
+ *
+ * @param cursor to replace the current pair in.
+ * @param new VALUE_PAIR to insert.
+ * @return NULL on error, else the VALUE_PAIR we just replaced.
+ */
+VALUE_PAIR *fr_cursor_replace(vp_cursor_t *cursor, VALUE_PAIR *new)
+{
+ VALUE_PAIR *vp, **last;
+
+ if (!fr_assert(cursor->first)) return NULL; /* cursor must have been initialised */
+
+ vp = cursor->current;
+ if (!vp) {
+ *cursor->first = new;
+ return NULL;
+ }
+
+ last = cursor->first;
+ while (*last != vp) {
+ last = &(*last)->next;
+ }
+
+ fr_cursor_next(cursor); /* Advance the cursor past the one were about to replace */
+
+ *last = new;
+ new->next = vp->next;
+ vp->next = NULL;
+
+ return vp;
+}
diff --git a/src/lib/debug.c b/src/lib/debug.c
new file mode 100644
index 0000000..b000903
--- /dev/null
+++ b/src/lib/debug.c
@@ -0,0 +1,1217 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file debug.c
+ * @brief Various functions to aid in debugging
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <assert.h>
+#include <freeradius-devel/libradius.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+USES_APPLE_DEPRECATED_API
+
+#if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
+# include <malloc.h>
+#endif
+
+/*
+ * runtime backtrace functions are not POSIX but are included in
+ * glibc, OSX >= 10.5 and various BSDs
+ */
+#ifdef HAVE_EXECINFO
+# include <execinfo.h>
+#endif
+
+#ifdef HAVE_SYS_PRCTL_H
+# include <sys/prctl.h>
+#endif
+
+#ifdef HAVE_SYS_PROCCTL_H
+# include <sys/procctl.h>
+#endif
+
+#ifdef HAVE_SYS_PTRACE_H
+# include <sys/ptrace.h>
+# if !defined(PT_ATTACH) && defined(PTRACE_ATTACH)
+# define PT_ATTACH PTRACE_ATTACH
+# endif
+# if !defined(PT_DETACH) && defined(PTRACE_DETACH)
+# define PT_DETACH PTRACE_DETACH
+# endif
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+# define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+# define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+#ifdef HAVE_EXECINFO
+# ifndef MAX_BT_FRAMES
+# define MAX_BT_FRAMES 128
+# endif
+# ifndef MAX_BT_CBUFF
+# define MAX_BT_CBUFF 1048576 //!< Should be a power of 2
+# endif
+
+# ifdef HAVE_PTHREAD_H
+static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
+# endif
+
+typedef struct fr_bt_info {
+ void *obj; //!< Memory address of the block of allocated memory.
+ void *frames[MAX_BT_FRAMES]; //!< Backtrace frame data
+ int count; //!< Number of frames stored
+} fr_bt_info_t;
+
+struct fr_bt_marker {
+ void *obj; //!< Pointer to the parent object, this is our needle
+ //!< when we iterate over the contents of the circular buffer.
+ fr_cbuff_t *cbuff; //!< Where we temporarily store the backtraces
+};
+#endif
+
+static char panic_action[512]; //!< The command to execute when panicking.
+static fr_fault_cb_t panic_cb = NULL; //!< Callback to execute whilst panicking, before the
+ //!< panic_action.
+
+static bool dump_core; //!< Whether we should drop a core on fatal signals.
+
+static int fr_fault_log_fd = STDERR_FILENO; //!< Where to write debug output.
+
+fr_debug_state_t fr_debug_state = DEBUG_STATE_UNKNOWN; //!< Whether we're attached to by a debugger.
+
+#ifdef HAVE_SYS_RESOURCE_H
+static struct rlimit core_limits;
+#endif
+
+static TALLOC_CTX *talloc_null_ctx;
+static TALLOC_CTX *talloc_autofree_ctx;
+
+/*
+ * On BSD systems, ptrace(PT_DETACH) uses a third argument for
+ * resume address, with the magic value (void *)1 to resume where
+ * process stopped. Specifying NULL there leads to a crash because
+ * process resumes at address 0.
+ */
+#ifdef HAVE_SYS_PTRACE_H
+# ifdef __linux__
+# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, NULL)
+# define _PTRACE_DETACH(_x) ptrace(PT_DETACH, _x, NULL, NULL)
+# else
+# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
+# define _PTRACE_DETACH(_x) ptrace(PT_DETACH, _x, (void *)1, 0)
+# endif
+
+# ifdef HAVE_CAPABILITY_H
+# include <sys/capability.h>
+# endif
+
+/** Determine if we're running under a debugger by attempting to attach using pattach
+ *
+ * @return 0 if we're not, 1 if we are, -1 if we can't tell because of an error,
+ * -2 if we can't tell because we don't have the CAP_SYS_PTRACE capability.
+ */
+static int fr_get_debug_state(void)
+{
+ int pid;
+
+ int from_child[2] = {-1, -1};
+
+#ifdef HAVE_CAPABILITY_H
+ cap_flag_value_t value;
+ cap_t current;
+
+ /*
+ * If we're running under linux, we first need to check if we have
+ * permission to to ptrace. We do that using the capabilities
+ * functions.
+ */
+ current = cap_get_proc();
+ if (!current) {
+ fr_strerror_printf("Failed getting process capabilities: %s", fr_syserror(errno));
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ if (cap_get_flag(current, CAP_SYS_PTRACE, CAP_PERMITTED, &value) < 0) {
+ fr_strerror_printf("Failed getting permitted ptrace capability state: %s",
+ fr_syserror(errno));
+ cap_free(current);
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ if ((value == CAP_SET) && (cap_get_flag(current, CAP_SYS_PTRACE, CAP_EFFECTIVE, &value) < 0)) {
+ fr_strerror_printf("Failed getting effective ptrace capability state: %s",
+ fr_syserror(errno));
+ cap_free(current);
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ /*
+ * We don't have permission to ptrace, so this test will always fail.
+ */
+ if (value == CAP_CLEAR) {
+ fr_strerror_printf("ptrace capability not set. If debugger detection is required run as root or: "
+ "setcap cap_sys_ptrace+ep <path_to_radiusd>");
+ cap_free(current);
+ return DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP;
+ }
+ cap_free(current);
+#endif
+
+ if (pipe(from_child) < 0) {
+ fr_strerror_printf("Error opening internal pipe: %s", fr_syserror(errno));
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ pid = fork();
+ if (pid == -1) {
+ fr_strerror_printf("Error forking: %s", fr_syserror(errno));
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ /* Child */
+ if (pid == 0) {
+ int8_t ret = DEBUG_STATE_NOT_ATTACHED;
+ int ppid = getppid();
+
+ /* Close parent's side */
+ close(from_child[0]);
+
+ /*
+ * FreeBSD is extremely picky about the order of operations here
+ * we need to attach, wait *then* write whilst the parent is still
+ * suspended, then detach, continuing the process.
+ *
+ * If we don't do it in that order the read in the parent triggers
+ * a SIGKILL.
+ */
+ if (_PTRACE(PT_ATTACH, ppid) == 0) {
+ /* Wait for the parent to stop */
+ waitpid(ppid, NULL, 0);
+
+ /* Tell the parent what happened */
+ if (write(from_child[1], &ret, sizeof(ret)) < 0) {
+ fprintf(stderr, "Writing ptrace status to parent failed: %s", fr_syserror(errno));
+ }
+
+ /* Detach */
+ _PTRACE_DETACH(ppid);
+ exit(0);
+ }
+
+ ret = DEBUG_STATE_ATTACHED;
+ /* Tell the parent what happened */
+ if (write(from_child[1], &ret, sizeof(ret)) < 0) {
+ fprintf(stderr, "Writing ptrace status to parent failed: %s", fr_syserror(errno));
+ }
+
+ exit(0);
+ /* Parent */
+ } else {
+ int8_t ret = DEBUG_STATE_UNKNOWN;
+
+ /*
+ * The child writes errno (reason) if pattach failed else 0.
+ *
+ * This read may be interrupted by pattach,
+ * which is why we need the loop.
+ */
+ while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
+
+ /* Close the pipes here (if we did it above, it might race with pattach) */
+ close(from_child[1]);
+ close(from_child[0]);
+
+ /* Collect the status of the child */
+ waitpid(pid, NULL, 0);
+
+ return ret;
+ }
+}
+#elif defined(HAVE_SYS_PROCCTL_H)
+static int fr_get_debug_state(void)
+{
+ int status;
+
+ if (procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status) == -1) {
+ fr_strerror_printf("Cannot get dumpable flag: procctl(PROC_TRACE_STATUS) failed: %s", fr_syserror(errno));
+ return DEBUG_STATE_UNKNOWN;
+ }
+
+ /*
+ * As FreeBSD docs say about "PROC_TRACE_STATUS":
+ *
+ * Returns the current tracing status for the specified process in the
+ * integer variable pointed to by data. If tracing is disabled, data
+ * is set to -1. If tracing is enabled, but no debugger is attached by
+ * the ptrace(2) syscall, data is set to 0. If a debugger is attached,
+ * data is set to the pid of the debugger process.
+ */
+ if (status <= 0) return DEBUG_STATE_NOT_ATTACHED;
+
+ return DEBUG_STATE_ATTACHED;
+}
+#else
+static int fr_get_debug_state(void)
+{
+ fr_strerror_printf("PTRACE not available");
+
+ return DEBUG_STATE_UNKNOWN_NO_PTRACE;
+}
+#endif
+
+/** Should be run before using setuid or setgid to get useful results
+ *
+ * @note sets the fr_debug_state global.
+ */
+void fr_store_debug_state(void)
+{
+ fr_debug_state = fr_get_debug_state();
+
+#ifndef NDEBUG
+ /*
+ * There are many reasons why this might happen with
+ * a vanilla install, so we don't want to spam users
+ * with messages they won't understand and may not
+ * want to resolve.
+ */
+ if (fr_debug_state < 0) fprintf(stderr, "Getting debug state failed: %s\n", fr_strerror());
+#endif
+}
+
+/** Return current value of debug_state
+ *
+ * @param state to translate into a humanly readable value.
+ * @return humanly readable version of debug state.
+ */
+char const *fr_debug_state_to_msg(fr_debug_state_t state)
+{
+ switch (state) {
+ case DEBUG_STATE_UNKNOWN_NO_PTRACE:
+ return "Debug state unknown (ptrace functionality not available)";
+
+ case DEBUG_STATE_UNKNOWN_NO_PTRACE_CAP:
+ return "Debug state unknown (cap_sys_ptrace capability not set)";
+
+ case DEBUG_STATE_UNKNOWN:
+ return "Debug state unknown";
+
+ case DEBUG_STATE_ATTACHED:
+ return "Found debugger attached";
+
+ case DEBUG_STATE_NOT_ATTACHED:
+ return "Debugger not attached";
+ }
+
+ return "<INVALID>";
+}
+
+/** Break in debugger (if were running under a debugger)
+ *
+ * If the server is running under a debugger this will raise a
+ * SIGTRAP which will pause the running process.
+ *
+ * If the server is not running under debugger then this will do nothing.
+ */
+void fr_debug_break(bool always)
+{
+ if (always) raise(SIGTRAP);
+
+ if (fr_debug_state < 0) fr_debug_state = fr_get_debug_state();
+ if (fr_debug_state == DEBUG_STATE_ATTACHED) {
+ fprintf(stderr, "Debugger detected, raising SIGTRAP\n");
+ fflush(stderr);
+
+ raise(SIGTRAP);
+ }
+}
+
+#ifdef HAVE_EXECINFO
+/** Print backtrace entry for a given object
+ *
+ * @param cbuff to search in.
+ * @param obj pointer to original object
+ */
+void backtrace_print(fr_cbuff_t *cbuff, void *obj)
+{
+ fr_bt_info_t *p;
+ bool found = false;
+
+ while ((p = fr_cbuff_rp_next(cbuff, NULL))) {
+ if ((p->obj == obj) || !obj) {
+ found = true;
+
+ fprintf(stderr, "Stacktrace for: %p\n", p->obj);
+ backtrace_symbols_fd(p->frames, p->count, STDERR_FILENO);
+ }
+ };
+
+ if (!found) {
+ fprintf(stderr, "No backtrace available for %p", obj);
+ }
+}
+
+/** Generate a backtrace for an object
+ *
+ * If this is the first entry being inserted
+ */
+int fr_backtrace_do(fr_bt_marker_t *marker)
+{
+ fr_bt_info_t *bt;
+
+ if (!fr_assert(marker->obj) || !fr_assert(marker->cbuff)) return -1;
+
+ bt = talloc_zero(NULL, fr_bt_info_t);
+ if (!bt) return -1;
+
+ bt->obj = marker->obj;
+ bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
+
+ fr_cbuff_rp_insert(marker->cbuff, bt);
+
+ return 0;
+}
+
+/** Inserts a backtrace marker into the provided context
+ *
+ * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
+ *
+ * Code augmentation should look something like:
+@verbatim
+ // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it
+ static fr_cbuff_t *my_obj_bt;
+
+ my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
+ my_obj_t *this;
+
+ this = talloc(ctx, my_obj_t);
+
+ // Attach backtrace marker to object
+ backtrace_attach(&my_obj_bt, this);
+
+ return this;
+ }
+@endverbatim
+ *
+ * Then, later when a double free occurs:
+@verbatim
+ (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
+@endverbatim
+ *
+ * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
+ * values, but should at least show the code path taken.
+ *
+ * @param cbuff this should be a pointer to a static *fr_cbuff.
+ * @param obj we want to generate a backtrace for.
+ */
+fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj)
+{
+ fr_bt_marker_t *marker;
+
+ if (*cbuff == NULL) {
+ PTHREAD_MUTEX_LOCK(&fr_debug_init);
+ /* Check again now we hold the mutex - eww*/
+ if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true);
+ PTHREAD_MUTEX_UNLOCK(&fr_debug_init);
+ }
+
+ marker = talloc(obj, fr_bt_marker_t);
+ if (!marker) {
+ return NULL;
+ }
+
+ marker->obj = (void *) obj;
+ marker->cbuff = *cbuff;
+
+ fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
+ /*
+ * Generate the backtrace for memory allocation
+ */
+ fr_backtrace_do(marker);
+ talloc_set_destructor(marker, fr_backtrace_do);
+
+ return marker;
+}
+#else
+void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj)
+{
+ fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
+}
+fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj)
+{
+ fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
+ abort();
+}
+#endif /* ifdef HAVE_EXECINFO */
+
+static int _panic_on_free(UNUSED char *foo)
+{
+ fr_fault(SIGABRT);
+ return -1; /* this should make the free fail */
+}
+
+/** Insert memory into the context of another talloc memory chunk which
+ * causes a panic when freed.
+ *
+ * @param ctx TALLOC_CTX to monitor for frees.
+ */
+void fr_panic_on_free(TALLOC_CTX *ctx)
+{
+ char *ptr;
+
+ ptr = talloc(ctx, char);
+ talloc_set_destructor(ptr, _panic_on_free);
+}
+
+/** Set the dumpable flag, also controls whether processes can PATTACH
+ *
+ * @param dumpable whether we should allow core dumping
+ */
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
+static int fr_set_dumpable_flag(bool dumpable)
+{
+ if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
+ fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+#elif defined(HAVE_SYS_PROCCTL_H)
+static int fr_set_dumpable_flag(bool dumpable)
+{
+ int mode = dumpable ? PROC_TRACE_CTL_ENABLE : PROC_TRACE_CTL_DISABLE;
+
+ if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &mode) == -1) {
+ fr_strerror_printf("Cannot re-enable core dumps: procctl(PROC_TRACE_CTL) failed: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+#else
+static int fr_set_dumpable_flag(UNUSED bool dumpable)
+{
+ fr_strerror_printf("Changing value of PR_DUMPABLE not supported on this system");
+ return -2;
+}
+#endif
+
+/** Get the processes dumpable flag
+ *
+ */
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE)
+static int fr_get_dumpable_flag(void)
+{
+ int ret;
+
+ ret = prctl(PR_GET_DUMPABLE);
+ if (ret < 0) {
+ fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Linux is crazy and prctl sometimes returns 2 for disabled
+ */
+ if (ret != 1) return 0;
+ return 1;
+}
+#elif defined(HAVE_SYS_PROCCTL_H)
+static int fr_get_dumpable_flag(void)
+{
+ int status;
+
+ if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &status) == -1) {
+ fr_strerror_printf("Cannot get dumpable flag: procctl(PROC_TRACE_CTL) failed: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * There are a few different kinds of disabled, but only
+ * one ENABLE.
+ */
+ if (status != PROC_TRACE_CTL_ENABLE) return 0;
+
+ return 1;
+}
+#else
+static int fr_get_dumpable_flag(void)
+{
+ fr_strerror_printf("Getting value of PR_DUMPABLE not supported on this system");
+ return -2;
+}
+#endif
+
+
+/** Get the current maximum for core files
+ *
+ * Do this before anything else so as to ensure it's properly initialized.
+ */
+int fr_set_dumpable_init(void)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+ if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/** Enable or disable core dumps
+ *
+ * @param allow_core_dumps whether to enable or disable core dumps.
+ */
+int fr_set_dumpable(bool allow_core_dumps)
+{
+ dump_core = allow_core_dumps;
+ /*
+ * If configured, turn core dumps off.
+ */
+ if (!allow_core_dumps) {
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit no_core;
+
+ no_core.rlim_cur = 0;
+ no_core.rlim_max = core_limits.rlim_max;
+
+ if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
+ fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
+
+ return -1;
+ }
+#endif
+ return 0;
+ }
+
+ if (fr_set_dumpable_flag(true) < 0) return -1;
+
+ /*
+ * Reset the core dump limits to their original value.
+ */
+#ifdef HAVE_SYS_RESOURCE_H
+ if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
+ fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
+
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+/** Reset dumpable state to previously configured value
+ *
+ * Needed after suid up/down
+ *
+ * @return 0 on success, else -1 on failure.
+ */
+int fr_reset_dumpable(void)
+{
+ return fr_set_dumpable(dump_core);
+}
+
+/** Check to see if panic_action file is world writeable
+ *
+ * @return 0 if file is OK, else -1.
+ */
+static int fr_fault_check_permissions(void)
+{
+ char const *p, *q;
+ size_t len;
+ char filename[256];
+ struct stat statbuf;
+
+ /*
+ * Try and guess which part of the command is the binary, and check to see if
+ * it's world writeable, to try and save the admin from their own stupidity.
+ *
+ * @fixme we should do this properly and take into account single and double
+ * quotes.
+ */
+ if ((q = strchr(panic_action, ' '))) {
+ /*
+ * need to use a static buffer, because mallocing memory in a signal handler
+ * is a bad idea and can result in deadlock.
+ */
+ len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
+ if (is_truncated(len, sizeof(filename))) {
+ fr_strerror_printf("Failed writing panic_action to temporary buffer (truncated)");
+ return -1;
+ }
+ p = filename;
+ } else {
+ p = panic_action;
+ }
+
+ if (stat(p, &statbuf) == 0) {
+#ifdef S_IWOTH
+ if ((statbuf.st_mode & S_IWOTH) != 0) {
+ fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
+ return -1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
+ *
+ * @param sig caught
+ */
+NEVER_RETURNS void fr_fault(int sig)
+{
+ char cmd[sizeof(panic_action) + 20];
+ char *out = cmd;
+ size_t left = sizeof(cmd), ret;
+
+ char const *p = panic_action;
+ char const *q;
+
+ int code;
+
+ /*
+ * If a debugger is attached, we don't want to run the panic action,
+ * as it may interfere with the operation of the debugger.
+ * If something calls us directly we just raise the signal and let
+ * the debugger handle it how it wants.
+ */
+ if (fr_debug_state == DEBUG_STATE_ATTACHED) {
+ FR_FAULT_LOG("RAISING SIGNAL: %s", strsignal(sig));
+ raise(sig);
+ goto finish;
+ }
+
+ /*
+ * Makes the backtraces slightly cleaner
+ */
+ memset(cmd, 0, sizeof(cmd));
+
+ FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
+
+ /*
+ * Check for administrator sanity.
+ */
+ if (fr_fault_check_permissions() < 0) {
+ FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
+ goto finish;
+ }
+
+ /*
+ * Run the callback if one was registered
+ */
+ if (panic_cb && (panic_cb(sig) < 0)) goto finish;
+
+ /*
+ * Produce a simple backtrace - They're very basic but at least give us an
+ * idea of the area of the code we hit the issue in.
+ *
+ * See below in fr_fault_setup() and
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=16159
+ * for why we only print backtraces in debug builds if we're using GLIBC.
+ */
+#if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
+ if (fr_fault_log_fd >= 0) {
+ size_t frame_count;
+ void *stack[MAX_BT_FRAMES];
+
+ frame_count = backtrace(stack, MAX_BT_FRAMES);
+
+ FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
+
+ backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
+ }
+#endif
+
+ /* No panic action set... */
+ if (panic_action[0] == '\0') {
+ FR_FAULT_LOG("No panic action set");
+ goto finish;
+ }
+
+ /* Substitute %p for the current PID (useful for attaching a debugger) */
+ while ((q = strstr(p, "%p"))) {
+ out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
+ if (left <= ret) {
+ oob:
+ FR_FAULT_LOG("Panic action too long");
+ fr_exit_now(1);
+ }
+ left -= ret;
+ p = q + 2;
+ }
+ if (strlen(p) >= left) goto oob;
+ strlcpy(out, p, left);
+
+ {
+ bool disable = false;
+
+ FR_FAULT_LOG("Calling: %s", cmd);
+
+ /*
+ * Here we temporarily enable the dumpable flag so if GBD or LLDB
+ * is called in the panic_action, they can pattach to the running
+ * process.
+ */
+ if (fr_get_dumpable_flag() == 0) {
+ if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) {
+ FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
+ } else {
+ disable = true;
+ }
+ FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
+ }
+
+ code = system(cmd);
+
+ /*
+ * We only want to error out here, if dumpable was originally disabled
+ * and we managed to change the value to enabled, but failed
+ * setting it back to disabled.
+ */
+ if (disable) {
+ FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
+ if (fr_set_dumpable_flag(false) < 0) {
+ FR_FAULT_LOG("Failed resetting dumpable flag to off: %s", fr_strerror());
+ FR_FAULT_LOG("Exiting due to insecure process state");
+ fr_exit_now(1);
+ }
+ }
+
+ FR_FAULT_LOG("Panic action exited with %i", code);
+
+ fr_exit_now(code);
+ }
+
+
+finish:
+ /*
+ * (Re-)Raise the signal, so that if we're running under
+ * a debugger, the debugger can break when it receives
+ * the signal.
+ */
+ fr_unset_signal(sig); /* Make sure we don't get into a loop */
+
+ raise(sig);
+
+ fr_exit_now(1); /* Function marked as noreturn */
+}
+
+/** Callback executed on fatal talloc error
+ *
+ * This is the simple version which mostly behaves the same way as the default
+ * one, and will not call panic_action.
+ *
+ * @param reason string provided by talloc.
+ */
+static void _fr_talloc_fault_simple(char const *reason) CC_HINT(noreturn);
+static void _fr_talloc_fault_simple(char const *reason)
+{
+ FR_FAULT_LOG("talloc abort: %s\n", reason);
+
+#if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
+ if (fr_fault_log_fd >= 0) {
+ size_t frame_count;
+ void *stack[MAX_BT_FRAMES];
+
+ frame_count = backtrace(stack, MAX_BT_FRAMES);
+ FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
+ backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
+ }
+#endif
+ abort();
+}
+
+/** Callback executed on fatal talloc error
+ *
+ * Translates a talloc abort into a fr_fault call.
+ * Mostly to work around issues with some debuggers not being able to
+ * attach after a SIGABRT has been raised.
+ *
+ * @param reason string provided by talloc.
+ */
+static void _fr_talloc_fault(char const *reason) CC_HINT(noreturn);
+static void _fr_talloc_fault(char const *reason)
+{
+ FR_FAULT_LOG("talloc abort: %s", reason);
+#ifdef SIGABRT
+ fr_fault(SIGABRT);
+#endif
+ fr_exit_now(1);
+}
+
+/** Wrapper to pass talloc log output to our fr_fault_log function
+ *
+ */
+static void _fr_talloc_log(char const *msg)
+{
+ fr_fault_log("%s\n", msg);
+}
+
+/** Generate a talloc memory report for a context and print to stderr/stdout
+ *
+ * @param ctx to generate a report for, may be NULL in which case the root context is used.
+ */
+int fr_log_talloc_report(TALLOC_CTX *ctx)
+{
+#define TALLOC_REPORT_MAX_DEPTH 20
+
+ FILE *log;
+ int fd;
+
+ fd = dup(fr_fault_log_fd);
+ if (fd < 0) {
+ fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
+ return -1;
+ }
+ log = fdopen(fd, "w");
+ if (!log) {
+ close(fd);
+ fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ if (!ctx) {
+ fprintf(log, "Current state of talloced memory:\n");
+ talloc_report_full(talloc_null_ctx, log);
+ } else {
+ int i;
+
+ fprintf(log, "Talloc chunk lineage:\n");
+ fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx));
+
+ i = 0;
+ while ((i < TALLOC_REPORT_MAX_DEPTH) && (ctx = talloc_parent(ctx))) {
+ fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx));
+ i++;
+ }
+ fprintf(log, "\n");
+
+ i = 0;
+ do {
+ fprintf(log, "Talloc context level %i:\n", i++);
+ talloc_report_full(ctx, log);
+ } while ((ctx = talloc_parent(ctx)) &&
+ (i < TALLOC_REPORT_MAX_DEPTH) &&
+ (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */
+ (talloc_parent(ctx) != talloc_null_ctx)); /* Stop before we hit NULL ctx */
+ }
+
+ fclose(log);
+
+ return 0;
+}
+
+
+static int _fr_disable_null_tracking(UNUSED bool *p)
+{
+ talloc_disable_null_tracking();
+ return 0;
+}
+
+/** Register talloc fault handlers
+ *
+ * Just register the fault handlers we need to make talloc
+ * produce useful debugging output.
+ */
+void fr_talloc_fault_setup(void)
+{
+ talloc_set_log_fn(_fr_talloc_log);
+ talloc_set_abort_fn(_fr_talloc_fault_simple);
+}
+
+/** Registers signal handlers to execute panic_action on fatal signal
+ *
+ * May be called multiple time to change the panic_action/program.
+ *
+ * @param cmd to execute on fault. If present %p will be substituted
+ * for the parent PID before the command is executed, and %e
+ * will be substituted for the currently running program.
+ * @param program Name of program currently executing (argv[0]).
+ * @return 0 on success -1 on failure.
+ */
+DIAG_OFF(deprecated-declarations)
+int fr_fault_setup(char const *cmd, char const *program)
+{
+ static bool setup = false;
+
+ char *out = panic_action;
+ size_t left = sizeof(panic_action);
+
+ char const *p = cmd;
+ char const *q;
+
+ if (cmd) {
+ size_t ret;
+
+ /* Substitute %e for the current program */
+ while ((q = strstr(p, "%e"))) {
+ out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
+ if (left <= ret) {
+ oob:
+ fr_strerror_printf("Panic action too long");
+ return -1;
+ }
+ left -= ret;
+ p = q + 2;
+ }
+ if (strlen(p) >= left) goto oob;
+ strlcpy(out, p, left);
+ } else {
+ *panic_action = '\0';
+ }
+
+ /*
+ * Check for administrator sanity.
+ */
+ if (fr_fault_check_permissions() < 0) return -1;
+
+ /* Unsure what the side effects of changing the signal handler mid execution might be */
+ if (!setup) {
+ char *env;
+ fr_debug_state_t debug_state;
+
+ /*
+ * Installing signal handlers interferes with some debugging
+ * operations. Give the developer control over whether the
+ * signal handlers are installed or not.
+ */
+ env = getenv("DEBUG");
+ if (!env || (strcmp(env, "no") == 0)) {
+ debug_state = DEBUG_STATE_NOT_ATTACHED;
+ } else if (!strcmp(env, "auto") || !strcmp(env, "yes")) {
+ /*
+ * Figure out if we were started under a debugger
+ */
+ if (fr_debug_state < 0) fr_debug_state = fr_get_debug_state();
+ debug_state = fr_debug_state;
+ } else {
+ debug_state = DEBUG_STATE_ATTACHED;
+ }
+
+ talloc_set_log_fn(_fr_talloc_log);
+
+ /*
+ * These signals can't be properly dealt with in the debugger
+ * if we set our own signal handlers.
+ */
+ switch (debug_state) {
+ default:
+#ifndef NDEBUG
+ FR_FAULT_LOG("Debugger check failed: %s", fr_strerror());
+ FR_FAULT_LOG("Signal processing in debuggers may not work as expected");
+#endif
+ /* FALL-THROUGH */
+
+ case DEBUG_STATE_NOT_ATTACHED:
+#ifdef SIGABRT
+ if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
+
+ /*
+ * Use this instead of abort so we get a
+ * full backtrace with broken versions of LLDB
+ */
+ talloc_set_abort_fn(_fr_talloc_fault);
+#endif
+#ifdef SIGILL
+ if (fr_set_signal(SIGILL, fr_fault) < 0) return -1;
+#endif
+#ifdef SIGFPE
+ if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
+#endif
+#ifdef SIGSEGV
+ if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
+#endif
+ break;
+
+ case DEBUG_STATE_ATTACHED:
+ break;
+ }
+
+ /*
+ * Needed for memory reports
+ */
+ {
+ TALLOC_CTX *tmp;
+ bool *marker;
+
+ tmp = talloc(NULL, bool);
+ talloc_null_ctx = talloc_parent(tmp);
+ talloc_free(tmp);
+
+ /*
+ * Disable null tracking on exit, else valgrind complains
+ */
+ talloc_autofree_ctx = talloc_autofree_context();
+ marker = talloc(talloc_autofree_ctx, bool);
+ talloc_set_destructor(marker, _fr_disable_null_tracking);
+ }
+
+#if defined(HAVE_MALLOPT) && !defined(NDEBUG)
+ /*
+ * If were using glibc malloc > 2.4 this scribbles over
+ * uninitialised and freed memory, to make memory issues easier
+ * to track down.
+ */
+ if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42);
+ mallopt(M_CHECK_ACTION, 3);
+#endif
+
+#if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
+ /*
+ * We need to pre-load lgcc_s, else we can get into a deadlock
+ * in fr_fault, as backtrace() attempts to dlopen it.
+ *
+ * Apparently there's a performance impact of loading lgcc_s,
+ * so only do it if this is a debug build.
+ *
+ * See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159
+ */
+ {
+ void *stack[10];
+
+ backtrace(stack, 10);
+ }
+#endif
+ }
+ setup = true;
+
+ return 0;
+}
+DIAG_ON(deprecated-declarations)
+
+/** Set a callback to be called before fr_fault()
+ *
+ * @param func to execute. If callback returns < 0
+ * fr_fault will exit before running panic_action code.
+ */
+void fr_fault_set_cb(fr_fault_cb_t func)
+{
+ panic_cb = func;
+}
+
+/** Log output to the fr_fault_log_fd
+ *
+ * We used to support a user defined callback, which was set to a radlog
+ * function. Unfortunately, when logging to syslog, syslog would malloc memory
+ * which would result in a deadlock if fr_fault was triggered from within
+ * a malloc call.
+ *
+ * Now we just write directly to the FD.
+ */
+void fr_fault_log(char const *msg, ...)
+{
+ va_list ap;
+
+ if (fr_fault_log_fd < 0) return;
+
+ va_start(ap, msg);
+ vdprintf(fr_fault_log_fd, msg, ap);
+ va_end(ap);
+}
+
+/** Set a file descriptor to log memory reports to.
+ *
+ * @param fd to write output to.
+ */
+void fr_fault_set_log_fd(int fd)
+{
+ fr_fault_log_fd = fd;
+}
+
+/** A soft assertion which triggers the fault handler in debug builds
+ *
+ * @param file the assertion failed in.
+ * @param line of the assertion in the file.
+ * @param expr that was evaluated.
+ * @param cond Result of evaluating the expression.
+ * @return the value of cond.
+ */
+bool fr_assert_cond(char const *file, int line, char const *expr, bool cond)
+{
+ if (!cond) {
+ FR_FAULT_LOG("SOFT ASSERT FAILED %s[%u]: %s", file, line, expr);
+#if !defined(NDEBUG)
+ fr_fault(SIGABRT);
+#endif
+ return false;
+ }
+
+ return cond;
+}
+
+/** Exit possibly printing a message about why we're exiting.
+ *
+ * @note Use the fr_exit(status) macro instead of calling this function directly.
+ *
+ * @param file where fr_exit() was called.
+ * @param line where fr_exit() was called.
+ * @param status we're exiting with.
+ */
+void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
+{
+#ifndef NDEBUG
+ char const *error = fr_strerror();
+
+ if (error && *error && (status != 0)) {
+ FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
+ } else {
+ FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]", status, file, line);
+ }
+#endif
+ fr_debug_break(false); /* If running under GDB we'll break here */
+
+ exit(status);
+}
+
+/** Exit possibly printing a message about why we're exiting.
+ *
+ * @note Use the fr_exit_now(status) macro instead of calling this function directly.
+ *
+ * @param file where fr_exit_now() was called.
+ * @param line where fr_exit_now() was called.
+ * @param status we're exiting with.
+ */
+void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status)
+{
+#ifndef NDEBUG
+ char const *error = fr_strerror();
+
+ if (error && (status != 0)) {
+ FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
+ } else {
+ FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]", status, file, line);
+ }
+#endif
+ fr_debug_break(false); /* If running under GDB we'll break here */
+
+ _exit(status);
+}
diff --git a/src/lib/dict.c b/src/lib/dict.c
new file mode 100644
index 0000000..d425a67
--- /dev/null
+++ b/src/lib/dict.c
@@ -0,0 +1,3506 @@
+/*
+ * dict.c Routines to read the dictionary file.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef WITH_DHCP
+#include <freeradius-devel/dhcp.h>
+#endif
+
+#include <ctype.h>
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+static fr_hash_table_t *vendors_byname = NULL;
+static fr_hash_table_t *vendors_byvalue = NULL;
+
+static fr_hash_table_t *attributes_byname = NULL;
+static fr_hash_table_t *attributes_byvalue = NULL;
+
+static fr_hash_table_t *attributes_combo = NULL;
+
+static fr_hash_table_t *values_byvalue = NULL;
+static fr_hash_table_t *values_byname = NULL;
+
+static DICT_ATTR *dict_base_attrs[256];
+
+/*
+ * For faster HUP's, we cache the stat information for
+ * files we've $INCLUDEd
+ */
+typedef struct dict_stat_t {
+ struct dict_stat_t *next;
+ struct stat stat_buf;
+} dict_stat_t;
+
+static dict_stat_t *stat_head = NULL;
+static dict_stat_t *stat_tail = NULL;
+
+typedef struct value_fixup_t {
+ char attrstr[DICT_ATTR_MAX_NAME_LEN];
+ DICT_VALUE *dval;
+ struct value_fixup_t *next;
+} value_fixup_t;
+
+
+/*
+ * So VALUEs in the dictionary can have forward references.
+ */
+static value_fixup_t *value_fixup = NULL;
+
+const FR_NAME_NUMBER dict_attr_types[] = {
+ { "integer", PW_TYPE_INTEGER },
+ { "string", PW_TYPE_STRING },
+ { "ipaddr", PW_TYPE_IPV4_ADDR },
+ { "date", PW_TYPE_DATE },
+ { "abinary", PW_TYPE_ABINARY },
+ { "octets", PW_TYPE_OCTETS },
+ { "ifid", PW_TYPE_IFID },
+ { "ipv6addr", PW_TYPE_IPV6_ADDR },
+ { "ipv6prefix", PW_TYPE_IPV6_PREFIX },
+ { "byte", PW_TYPE_BYTE },
+ { "short", PW_TYPE_SHORT },
+ { "ether", PW_TYPE_ETHERNET },
+ { "combo-ip", PW_TYPE_COMBO_IP_ADDR },
+ { "tlv", PW_TYPE_TLV },
+ { "signed", PW_TYPE_SIGNED },
+ { "extended", PW_TYPE_EXTENDED },
+ { "long-extended", PW_TYPE_LONG_EXTENDED },
+ { "evs", PW_TYPE_EVS },
+ { "uint8", PW_TYPE_BYTE },
+ { "uint16", PW_TYPE_SHORT },
+ { "uint32", PW_TYPE_INTEGER },
+ { "int32", PW_TYPE_SIGNED },
+ { "integer64", PW_TYPE_INTEGER64 },
+ { "uint64", PW_TYPE_INTEGER64 },
+ { "ipv4prefix", PW_TYPE_IPV4_PREFIX },
+ { "cidr", PW_TYPE_IPV4_PREFIX },
+ { "vsa", PW_TYPE_VSA },
+ { NULL, 0 }
+};
+
+/*
+ * Map data types to min / max data sizes.
+ */
+const size_t dict_attr_sizes[PW_TYPE_MAX][2] = {
+ [PW_TYPE_INVALID] = {~0, 0},
+ [PW_TYPE_STRING] = {0, ~0},
+ [PW_TYPE_INTEGER] = {4, 4 },
+ [PW_TYPE_IPV4_ADDR] = {4, 4},
+ [PW_TYPE_DATE] = {4, 4},
+ [PW_TYPE_ABINARY] = {32, ~0},
+ [PW_TYPE_OCTETS] = {0, ~0},
+ [PW_TYPE_IFID] = {8, 8},
+ [PW_TYPE_IPV6_ADDR] = {16, 16},
+ [PW_TYPE_IPV6_PREFIX] = {2, 18},
+ [PW_TYPE_BYTE] = {1, 1},
+ [PW_TYPE_SHORT] = {2, 2},
+ [PW_TYPE_ETHERNET] = {6, 6},
+ [PW_TYPE_SIGNED] = {4, 4},
+ [PW_TYPE_COMBO_IP_ADDR] = {4, 16},
+ [PW_TYPE_TLV] = {2, ~0},
+ [PW_TYPE_EXTENDED] = {2, ~0},
+ [PW_TYPE_LONG_EXTENDED] = {3, ~0},
+ [PW_TYPE_EVS] = {6, ~0},
+ [PW_TYPE_INTEGER64] = {8, 8},
+ [PW_TYPE_IPV4_PREFIX] = {6, 6},
+ [PW_TYPE_VSA] = {4, ~0}
+};
+
+/*
+ * For packing multiple TLV numbers into one 32-bit integer. The
+ * first 3 bytes are just the 8-bit number. The next two are
+ * more limited. We only allow 31 attributes nested 3 layers
+ * deep, and only 7 nested 4 layers deep. This should be
+ * sufficient for most purposes.
+ *
+ * For TLVs and extended attributes, we packet the base attribute
+ * number into the upper 8 bits of the "vendor" field.
+ *
+ * e.g. OID attribute vendor
+ * 241.1 1 (241 << 24)
+ * 241.26.9.1 1 (241 << 24) | (9)
+ * 241.1.2 1 | (2 << 8) (241 << 24)
+ */
+#define MAX_TLV_NEST (4)
+/*
+ * Bit packing:
+ * 8 bits of base attribute
+ * 8 bits for nested TLV 1
+ * 8 bits for nested TLV 2
+ * 5 bits for nested TLV 3
+ * 3 bits for nested TLV 4
+ */
+int const fr_attr_max_tlv = MAX_TLV_NEST;
+int const fr_attr_shift[MAX_TLV_NEST + 1] = { 0, 8, 16, 24, 29 };
+
+unsigned const fr_attr_mask[MAX_TLV_NEST + 1] = { 0xff, 0xff, 0xff, 0x1f, 0x07 };
+
+/*
+ * attr & fr_attr_parent_mask[i] == Nth parent of attr
+ */
+static unsigned int const fr_attr_parent_mask[MAX_TLV_NEST + 1] = { 0, 0x000000ff, 0x0000ffff, 0x00ffffff, 0x1fffffff };
+
+/*
+ * Create the hash of the name.
+ *
+ * We copy the hash function here because it's substantially faster.
+ */
+#define FNV_MAGIC_INIT (0x811c9dc5)
+#define FNV_MAGIC_PRIME (0x01000193)
+
+static uint32_t dict_hashname(char const *name)
+{
+ uint32_t hash = FNV_MAGIC_INIT;
+ char const *p;
+
+ for (p = name; *p != '\0'; p++) {
+ int c = *(unsigned char const *) p;
+ if (isalpha(c)) c = tolower(c);
+
+ hash *= FNV_MAGIC_PRIME;
+ hash ^= (uint32_t ) (c & 0xff);
+ }
+
+ return hash;
+}
+
+
+/*
+ * Hash callback functions.
+ */
+static uint32_t dict_attr_name_hash(void const *data)
+{
+ return dict_hashname(((DICT_ATTR const *)data)->name);
+}
+
+static int dict_attr_name_cmp(void const *one, void const *two)
+{
+ DICT_ATTR const *a = one;
+ DICT_ATTR const *b = two;
+
+ return strcasecmp(a->name, b->name);
+}
+
+static uint32_t dict_attr_value_hash(void const *data)
+{
+ uint32_t hash;
+ DICT_ATTR const *attr = data;
+
+ hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
+ return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
+}
+
+static int dict_attr_value_cmp(void const *one, void const *two)
+{
+ DICT_ATTR const *a = one;
+ DICT_ATTR const *b = two;
+
+ if (a->vendor < b->vendor) return -1;
+ if (a->vendor > b->vendor) return +1;
+
+ return a->attr - b->attr;
+}
+
+static uint32_t dict_attr_combo_hash(void const *data)
+{
+ uint32_t hash;
+ DICT_ATTR const *attr = data;
+
+ hash = fr_hash(&attr->vendor, sizeof(attr->vendor));
+ hash = fr_hash_update(&attr->type, sizeof(attr->type), hash);
+ return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);
+}
+
+static int dict_attr_combo_cmp(void const *one, void const *two)
+{
+ DICT_ATTR const *a = one;
+ DICT_ATTR const *b = two;
+
+ if (a->type < b->type) return -1;
+ if (a->type > b->type) return +1;
+
+ if (a->vendor < b->vendor) return -1;
+ if (a->vendor > b->vendor) return +1;
+
+ return a->attr - b->attr;
+}
+
+static uint32_t dict_vendor_name_hash(void const *data)
+{
+ return dict_hashname(((DICT_VENDOR const *)data)->name);
+}
+
+static int dict_vendor_name_cmp(void const *one, void const *two)
+{
+ DICT_VENDOR const *a = one;
+ DICT_VENDOR const *b = two;
+
+ return strcasecmp(a->name, b->name);
+}
+
+static uint32_t dict_vendor_value_hash(void const *data)
+{
+ return fr_hash(&(((DICT_VENDOR const *)data)->vendorpec),
+ sizeof(((DICT_VENDOR const *)data)->vendorpec));
+}
+
+static int dict_vendor_value_cmp(void const *one, void const *two)
+{
+ DICT_VENDOR const *a = one;
+ DICT_VENDOR const *b = two;
+
+ return a->vendorpec - b->vendorpec;
+}
+
+static uint32_t dict_value_name_hash(void const *data)
+{
+ uint32_t hash;
+ DICT_VALUE const *dval = data;
+
+ hash = dict_hashname(dval->name);
+ hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
+ return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);
+}
+
+static int dict_value_name_cmp(void const *one, void const *two)
+{
+ int rcode;
+ DICT_VALUE const *a = one;
+ DICT_VALUE const *b = two;
+
+ rcode = a->attr - b->attr;
+ if (rcode != 0) return rcode;
+
+ rcode = a->vendor - b->vendor;
+ if (rcode != 0) return rcode;
+
+ return strcasecmp(a->name, b->name);
+}
+
+static uint32_t dict_value_value_hash(void const *data)
+{
+ uint32_t hash;
+ DICT_VALUE const *dval = data;
+
+ hash = fr_hash(&dval->attr, sizeof(dval->attr));
+ hash = fr_hash_update(&dval->vendor, sizeof(dval->vendor), hash);
+ return fr_hash_update(&dval->value, sizeof(dval->value), hash);
+}
+
+static int dict_value_value_cmp(void const *one, void const *two)
+{
+ int rcode;
+ DICT_VALUE const *a = one;
+ DICT_VALUE const *b = two;
+
+ if (a->vendor < b->vendor) return -1;
+ if (a->vendor > b->vendor) return +1;
+
+ rcode = a->attr - b->attr;
+ if (rcode != 0) return rcode;
+
+ return a->value - b->value;
+}
+
+
+/*
+ * Free the list of stat buffers
+ */
+static void dict_stat_free(void)
+{
+ dict_stat_t *this, *next;
+
+ if (!stat_head) {
+ stat_tail = NULL;
+ return;
+ }
+
+ for (this = stat_head; this != NULL; this = next) {
+ next = this->next;
+ free(this);
+ }
+
+ stat_head = stat_tail = NULL;
+}
+
+
+/*
+ * Add an entry to the list of stat buffers.
+ */
+static void dict_stat_add(struct stat const *stat_buf)
+{
+ dict_stat_t *this;
+
+ this = malloc(sizeof(*this));
+ if (!this) return;
+ memset(this, 0, sizeof(*this));
+
+ memcpy(&(this->stat_buf), stat_buf, sizeof(this->stat_buf));
+
+ if (!stat_head) {
+ stat_head = stat_tail = this;
+ } else {
+ stat_tail->next = this;
+ stat_tail = this;
+ }
+}
+
+
+/*
+ * See if any dictionaries have changed. If not, don't
+ * do anything.
+ */
+static int dict_stat_check(char const *dir, char const *file)
+{
+ struct stat stat_buf;
+ dict_stat_t *this;
+ char buffer[2048];
+
+ /*
+ * Nothing cached, all files are new.
+ */
+ if (!stat_head) return 0;
+
+ /*
+ * Stat the file.
+ */
+ snprintf(buffer, sizeof(buffer), "%s/%s", dir, file);
+ if (stat(buffer, &stat_buf) < 0) return 0;
+
+ /*
+ * Find the cache entry.
+ * FIXME: use a hash table.
+ * FIXME: check dependencies, via children.
+ * if A loads B and B changes, we probably want
+ * to reload B at the minimum.
+ */
+ for (this = stat_head; this != NULL; this = this->next) {
+ if (this->stat_buf.st_dev != stat_buf.st_dev) continue;
+ if (this->stat_buf.st_ino != stat_buf.st_ino) continue;
+
+ /*
+ * The file has changed. Re-read it.
+ */
+ if (this->stat_buf.st_mtime < stat_buf.st_mtime) return 0;
+
+ /*
+ * The file is the same. Ignore it.
+ */
+ return 1;
+ }
+
+ /*
+ * Not in the cache.
+ */
+ return 0;
+}
+
+typedef struct fr_pool_t {
+ void *page_end;
+ void *free_ptr;
+ struct fr_pool_t *page_free;
+ struct fr_pool_t *page_next;
+} fr_pool_t;
+
+#define FR_POOL_SIZE (32768)
+#define FR_ALLOC_ALIGN (8)
+
+static fr_pool_t *dict_pool = NULL;
+
+static fr_pool_t *fr_pool_create(void)
+{
+ fr_pool_t *fp = malloc(FR_POOL_SIZE);
+
+ if (!fp) return NULL;
+
+ memset(fp, 0, FR_POOL_SIZE);
+
+ fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE;
+ fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp);
+ fp->page_free = fp;
+ fp->page_next = NULL;
+ return fp;
+}
+
+static void fr_pool_delete(fr_pool_t **pfp)
+{
+ fr_pool_t *fp, *next;
+
+ if (!pfp || !*pfp) return;
+
+ for (fp = *pfp; fp != NULL; fp = next) {
+ next = fp->page_next;
+ fp->page_next = NULL;
+ free(fp);
+ }
+ *pfp = NULL;
+}
+
+
+static void *fr_pool_alloc(size_t size)
+{
+ void *ptr;
+
+ if (size == 0) return NULL;
+
+ if (size > 256) return NULL; /* shouldn't happen */
+
+ if (!dict_pool) {
+ dict_pool = fr_pool_create();
+ if (!dict_pool) return NULL;
+ }
+
+ if ((size & (FR_ALLOC_ALIGN - 1)) != 0) {
+ size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1));
+ }
+
+ if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) {
+ dict_pool->page_free->page_next = fr_pool_create();
+ if (!dict_pool->page_free->page_next) return NULL;
+ dict_pool->page_free = dict_pool->page_free->page_next;
+ }
+
+ ptr = dict_pool->page_free->free_ptr;
+ dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size;
+
+ return ptr;
+}
+
+
+static void fr_pool_free(UNUSED void *ptr)
+{
+ /*
+ * Place-holder for later code.
+ */
+}
+
+/*
+ * Free the dictionary_attributes and dictionary_values lists.
+ */
+void dict_free(void)
+{
+ /*
+ * Free the tables
+ */
+ fr_hash_table_free(vendors_byname);
+ fr_hash_table_free(vendors_byvalue);
+ vendors_byname = NULL;
+ vendors_byvalue = NULL;
+
+ fr_hash_table_free(attributes_byname);
+ fr_hash_table_free(attributes_byvalue);
+ fr_hash_table_free(attributes_combo);
+ attributes_byname = NULL;
+ attributes_byvalue = NULL;
+ attributes_combo = NULL;
+
+ fr_hash_table_free(values_byname);
+ fr_hash_table_free(values_byvalue);
+ values_byname = NULL;
+ values_byvalue = NULL;
+
+ memset(dict_base_attrs, 0, sizeof(dict_base_attrs));
+
+ fr_pool_delete(&dict_pool);
+
+ dict_stat_free();
+}
+
+/*
+ * Add vendor to the list.
+ */
+int dict_addvendor(char const *name, unsigned int value)
+{
+ size_t length;
+ DICT_VENDOR *dv;
+
+ if (value >= FR_MAX_VENDOR) {
+ fr_strerror_printf("dict_addvendor: Cannot handle vendor ID larger than 2^24");
+ return -1;
+ }
+
+ if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) {
+ fr_strerror_printf("dict_addvendor: vendor name too long");
+ return -1;
+ }
+
+ if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) {
+ fr_strerror_printf("dict_addvendor: out of memory");
+ return -1;
+ }
+
+ strcpy(dv->name, name);
+ dv->vendorpec = value;
+ dv->type = dv->length = 1; /* defaults */
+
+ if (!fr_hash_table_insert(vendors_byname, dv)) {
+ DICT_VENDOR *old_dv;
+
+ old_dv = fr_hash_table_finddata(vendors_byname, dv);
+ if (!old_dv) {
+ fr_strerror_printf("dict_addvendor: Failed inserting vendor name %s", name);
+ return -1;
+ }
+ if (old_dv->vendorpec != dv->vendorpec) {
+ fr_strerror_printf("dict_addvendor: Duplicate vendor name %s", name);
+ return -1;
+ }
+
+ /*
+ * Already inserted. Discard the duplicate entry.
+ */
+ fr_pool_free(dv);
+ return 0;
+ }
+
+ /*
+ * Insert the SAME pointer (not free'd when this table is
+ * deleted), into another table.
+ *
+ * We want this behaviour because we want OLD names for
+ * the attributes to be read from the configuration
+ * files, but when we're printing them, (and looking up
+ * by value) we want to use the NEW name.
+ */
+ if (!fr_hash_table_replace(vendors_byvalue, dv)) {
+ fr_strerror_printf("dict_addvendor: Failed inserting vendor %s",
+ name);
+ return -1;
+ }
+
+ return 0;
+}
+
+const int dict_attr_allowed_chars[256] = {
+/* 0x 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+/* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+/* 4 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+/* 6 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * [a-zA-Z0-9_-:.]+
+ */
+int dict_valid_name(char const *name)
+{
+ uint8_t const *p;
+
+ for (p = (uint8_t const *) name; *p != '\0'; p++) {
+ if (!dict_attr_allowed_chars[*p]) {
+ char buff[5];
+
+ fr_prints(buff, sizeof(buff), (char const *)p, 1, '\'');
+ fr_strerror_printf("Invalid character '%s' in attribute", buff);
+
+ return -(p - (uint8_t const *)name);
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Find the parent of the attr/vendor.
+ */
+DICT_ATTR const *dict_parent(unsigned int attr, unsigned int vendor)
+{
+ int i;
+ unsigned int base_vendor;
+
+ /*
+ * RFC attributes can't be of type "tlv", except for dictionary.rfc6930
+ */
+ if (!vendor) {
+#ifdef PW_IPV6_6RD_CONFIGURATION
+ if (attr == PW_IPV6_6RD_CONFIGURATION) return NULL;
+
+ if (((attr & 0xff) == PW_IPV6_6RD_CONFIGURATION) &&
+ (attr >> 8) < 4) {
+ return dict_attrbyvalue(PW_IPV6_6RD_CONFIGURATION, 0);
+ }
+#endif
+ return NULL;
+ }
+
+ base_vendor = vendor & (FR_MAX_VENDOR - 1);
+
+ /*
+ * It's a real vendor.
+ */
+ if (base_vendor != 0) {
+ DICT_VENDOR const *dv;
+
+ dv = dict_vendorbyvalue(base_vendor);
+ if (!dv) return NULL;
+
+ /*
+ * Only standard format attributes can be of type "tlv",
+ * Except for DHCP. <sigh>
+ */
+ if ((vendor != 54) && ((dv->type != 1) || (dv->length != 1))) return NULL;
+
+ for (i = MAX_TLV_NEST; i > 0; i--) {
+ unsigned int parent;
+
+ parent = attr & fr_attr_parent_mask[i];
+
+ if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */
+ }
+
+ /*
+ * It was a top-level VSA. There's no parent.
+ * We COULD return the appropriate enclosing VSA
+ * (26, or 241.26, etc.) but that's not what we
+ * want.
+ */
+ return NULL;
+ }
+
+ /*
+ * It's an extended attribute. Return the base Extended-Attr-X
+ */
+ if (attr < 256) return dict_attrbyvalue((vendor / FR_MAX_VENDOR) & 0xff, 0);
+
+ /*
+ * Figure out which attribute it is.
+ */
+ for (i = MAX_TLV_NEST; i > 0; i--) {
+ unsigned int parent;
+
+ parent = attr & fr_attr_parent_mask[i];
+ if (parent != attr) return dict_attrbyvalue(parent, vendor); /* not base_vendor */
+ }
+
+ return NULL;
+}
+
+
+/** Add an attribute to the dictionary
+ *
+ * @return 0 on success -1 on failure.
+ */
+int dict_addattr(char const *name, int attr, unsigned int vendor, PW_TYPE type,
+ ATTR_FLAGS flags)
+{
+ size_t namelen;
+ DICT_ATTR const *parent;
+ DICT_ATTR *n;
+ DICT_ATTR const *old;
+ static int max_attr = 0;
+
+ namelen = strlen(name);
+ if (namelen >= DICT_ATTR_MAX_NAME_LEN) {
+ fr_strerror_printf("dict_addattr: attribute name too long");
+ return -1;
+ }
+
+ if (dict_valid_name(name) < 0) return -1;
+
+ if (flags.has_tag &&
+ !((type == PW_TYPE_INTEGER) || (type == PW_TYPE_STRING))) {
+ fr_strerror_printf("dict_addattr: Only 'integer' and 'string' attributes can have tags");
+ return -1;
+ }
+
+ /*
+ * Disallow attributes of type zero.
+ */
+ if (!attr && !vendor) {
+ fr_strerror_printf("dict_addattr: Attribute 0 is invalid and cannot be used");
+ return -1;
+ }
+
+ /*
+ * If the attr is '-1', that means use a pre-existing
+ * one (if it already exists). If one does NOT already exist,
+ * then create a new attribute, with a non-conflicting value,
+ * and use that.
+ */
+ if (attr == -1) {
+ if (dict_attrbyname(name)) {
+ return 0; /* exists, don't add it again */
+ }
+
+ attr = ++max_attr;
+
+ } else if (vendor == 0) {
+ /*
+ * Update 'max_attr'
+ */
+ if (attr > max_attr) {
+ max_attr = attr;
+ }
+ }
+
+ /*
+ * Check the parent attribute, and set the various flags
+ * based on the parents values. It's OK for the caller
+ * to not set them, as we'll set them. But if the caller
+ * sets them when he's not supposed to set them, that's
+ * an error.
+ */
+ parent = dict_parent(attr, vendor);
+ if (parent) {
+ /*
+ * We're still in the same space and the parent isn't a TLV. That's an error.
+ *
+ * Otherwise, dict_parent() has taken us from an Extended sub-attribute to
+ * a *the* Extended attribute, whish isn't what we want here.
+ */
+ if ((vendor == parent->vendor) && (parent->type != PW_TYPE_TLV)) {
+ fr_strerror_printf("dict_addattr: Attribute %s has parent attribute %s which is not of type 'tlv'",
+ name, parent->name);
+ return -1;
+ }
+
+ flags.extended |= parent->flags.extended;
+ flags.long_extended |= parent->flags.long_extended;
+ flags.evs |= parent->flags.evs;
+ }
+
+ /*
+ * Manually extended flags for extended attributes. We
+ * can't expect the caller to know all of the details of the flags.
+ */
+ if (vendor >= FR_MAX_VENDOR) {
+ DICT_ATTR const *da;
+
+ /*
+ * Trying to manually create an extended
+ * attribute, but the parent extended attribute
+ * doesn't exist? That's an error.
+ */
+ da = dict_attrbyvalue(vendor / FR_MAX_VENDOR, 0);
+ if (!da) {
+ fr_strerror_printf("Extended attributes must be defined from the extended space");
+ return -1;
+ }
+
+ flags.extended |= da->flags.extended;
+ flags.long_extended |= da->flags.long_extended;
+ flags.evs |= da->flags.evs;
+
+ /*
+ * There's still a real vendor. Since it's an
+ * extended attribute, set the EVS flag.
+ */
+ if ((vendor & (FR_MAX_VENDOR -1)) != 0) flags.evs = 1;
+ }
+
+ /*
+ * Additional checks for extended attributes.
+ */
+ if (flags.extended || flags.long_extended || flags.evs) {
+ if (vendor && (vendor < FR_MAX_VENDOR)) {
+ fr_strerror_printf("dict_addattr: VSAs cannot use the \"extended\" or \"evs\" attribute formats");
+ return -1;
+ }
+ if (flags.has_tag
+#ifdef WITH_DHCP
+ || flags.array
+#endif
+ || ((flags.encrypt != FLAG_ENCRYPT_NONE) && (flags.encrypt != FLAG_ENCRYPT_TUNNEL_PASSWORD))) {
+ fr_strerror_printf("dict_addattr: The \"extended\" attributes MUST NOT have any flags set");
+ return -1;
+ }
+ }
+
+ if (flags.evs) {
+ if (!(flags.extended || flags.long_extended)) {
+ fr_strerror_printf("dict_addattr: Attributes of type \"evs\" MUST have a parent of type \"extended\"");
+ return -1;
+ }
+ }
+
+ /*
+ * Do various sanity checks.
+ */
+ if (attr < 0) {
+ fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (less than zero)");
+ return -1;
+ }
+
+ if (flags.has_tlv && flags.length) {
+ fr_strerror_printf("TLVs cannot have a fixed length");
+ return -1;
+ }
+
+ if (vendor && flags.concat) {
+ fr_strerror_printf("VSAs cannot have the \"concat\" flag set");
+ return -1;
+ }
+
+ if (flags.concat && (type != PW_TYPE_OCTETS)) {
+ fr_strerror_printf("The \"concat\" flag can only be set for attributes of type \"octets\"");
+ return -1;
+ }
+
+ if (flags.concat && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
+ flags.length || flags.evs || flags.extended || flags.long_extended ||
+ (flags.encrypt != FLAG_ENCRYPT_NONE))) {
+ fr_strerror_printf("The \"concat\" flag cannot be used with any other flag");
+ return -1;
+ }
+
+ if (flags.encrypt) flags.secret = 1;
+
+ if (flags.length && (type != PW_TYPE_OCTETS)) {
+ fr_strerror_printf("The \"length\" flag can only be set for attributes of type \"octets\"");
+ return -1;
+ }
+
+ if (flags.length && (flags.has_tag || flags.array || flags.is_tlv || flags.has_tlv ||
+ flags.concat || flags.evs || flags.extended || flags.long_extended ||
+ (flags.encrypt > FLAG_ENCRYPT_USER_PASSWORD))) {
+ fr_strerror_printf("The \"length\" flag cannot be used with any other flag");
+ return -1;
+ }
+
+ /*
+ * Force "length" for data types of fixed length;
+ */
+ switch (type) {
+ case PW_TYPE_BYTE:
+ flags.length = 1;
+ break;
+
+ case PW_TYPE_SHORT:
+ flags.length = 2;
+ break;
+
+ case PW_TYPE_DATE:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_SIGNED:
+ flags.length = 4;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ flags.length = 8;
+ break;
+
+ case PW_TYPE_ETHERNET:
+ flags.length = 6;
+ break;
+
+ case PW_TYPE_IFID:
+ flags.length = 8;
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ flags.length = 16;
+ break;
+
+ case PW_TYPE_EXTENDED:
+ if ((vendor != 0) || (attr < 241)) {
+ fr_strerror_printf("Attributes of type \"extended\" MUST be "
+ "RFC attributes with value >= 241.");
+ return -1;
+ }
+
+ flags.length = 0;
+ flags.extended = 1;
+ break;
+
+ case PW_TYPE_LONG_EXTENDED:
+ if ((vendor != 0) || (attr < 241)) {
+ fr_strerror_printf("Attributes of type \"long-extended\" MUST "
+ "be RFC attributes with value >= 241.");
+ return -1;
+ }
+
+ flags.length = 0;
+ flags.extended = 1;
+ flags.long_extended = 1;
+ break;
+
+ case PW_TYPE_EVS:
+ if (attr != PW_VENDOR_SPECIFIC) {
+ fr_strerror_printf("Attributes of type \"evs\" MUST have "
+ "attribute code 26.");
+ return -1;
+ }
+
+ flags.length = 0;
+ flags.extended = 1;
+ flags.evs = 1;
+ break;
+
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ flags.is_pointer = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Stupid hacks for MS-CHAP-MPPE-Keys. The User-Password
+ * encryption method has no provisions for encoding the
+ * length of the data. For User-Password, the data is
+ * (presumably) all printable non-zero data. For
+ * MS-CHAP-MPPE-Keys, the data is binary crap. So... we
+ * MUST specify a length in the dictionary.
+ */
+ if ((flags.encrypt == FLAG_ENCRYPT_USER_PASSWORD) && (type != PW_TYPE_STRING)) {
+ if (type != PW_TYPE_OCTETS) {
+ fr_strerror_printf("The \"encrypt=1\" flag cannot be used with non-string data types");
+ return -1;
+ }
+
+ if (flags.length == 0) {
+ fr_strerror_printf("The \"encrypt=1\" flag MUST be used with an explicit length for 'octets' data types");
+ return -1;
+ }
+ }
+
+ if ((vendor & (FR_MAX_VENDOR -1)) != 0) {
+ DICT_VENDOR *dv;
+ static DICT_VENDOR *last_vendor = NULL;
+
+ if (flags.has_tlv && (flags.encrypt != FLAG_ENCRYPT_NONE)) {
+ fr_strerror_printf("TLV's cannot be encrypted");
+ return -1;
+ }
+
+ if (flags.is_tlv && flags.has_tag) {
+ fr_strerror_printf("Sub-TLV's cannot have a tag");
+ return -1;
+ }
+
+ if (flags.has_tlv && flags.has_tag) {
+ fr_strerror_printf("TLV's cannot have a tag");
+ return -1;
+ }
+
+ /*
+ * Most ATTRIBUTEs are bunched together by
+ * VENDOR. We can save a lot of lookups on
+ * dictionary initialization by caching the last
+ * vendor.
+ */
+ if (last_vendor &&
+ ((vendor & (FR_MAX_VENDOR - 1)) == last_vendor->vendorpec)) {
+ dv = last_vendor;
+ } else {
+ /*
+ * Ignore the high byte (sigh)
+ */
+ dv = dict_vendorbyvalue(vendor & (FR_MAX_VENDOR - 1));
+ last_vendor = dv;
+ }
+
+ /*
+ * If the vendor isn't defined, die.
+ */
+ if (!dv) {
+ fr_strerror_printf("dict_addattr: Unknown vendor %u",
+ vendor & (FR_MAX_VENDOR - 1));
+ return -1;
+ }
+
+ if (!attr && dv->type != 1) {
+ fr_strerror_printf("dict_addattr: Attribute %s cannot have value zero",
+ name);
+ return -1;
+ }
+
+ /*
+ * FIXME: Switch over dv->type, and limit things
+ * properly.
+ */
+ if ((dv->type == 1) && (attr >= 256) && !flags.is_tlv) {
+ fr_strerror_printf("dict_addattr: ATTRIBUTE has invalid number (larger than 255)");
+ return -1;
+ } /* else 256..65535 are allowed */
+
+ /*
+ * <sigh> Alvarion, being *again* a horribly
+ * broken vendor, has re-used the WiMAX format in
+ * their proprietary vendor space. This re-use
+ * means that there are *multiple* conflicting
+ * Alvarion dictionaries.
+ */
+ flags.wimax = dv->flags;
+ } /* it's a VSA of some kind */
+
+ /*
+ * Create a new attribute for the list
+ */
+ if ((n = fr_pool_alloc(sizeof(*n) + namelen)) == NULL) {
+ oom:
+ fr_strerror_printf("dict_addattr: out of memory");
+ return -1;
+ }
+
+ memcpy(n->name, name, namelen);
+ n->name[namelen] = '\0';
+ n->attr = attr;
+ n->vendor = vendor;
+ n->type = type;
+ n->flags = flags;
+
+ /*
+ * Allow old-style names, but they always end up as
+ * new-style names.
+ */
+ old = dict_attrbyvalue(n->attr, n->vendor);
+ if (old && (old->type == n->type)) {
+ DICT_ATTR *mutable;
+
+ memcpy(&mutable, &old, sizeof(old)); /* const issues */
+ mutable->flags.is_dup = true;
+ }
+
+ /*
+ * Insert the attribute, only if it's not a duplicate.
+ */
+ if (!fr_hash_table_insert(attributes_byname, n)) {
+ DICT_ATTR *a;
+
+ /*
+ * If the attribute has identical number, then
+ * ignore the duplicate.
+ */
+ a = fr_hash_table_finddata(attributes_byname, n);
+ if (a && (strcasecmp(a->name, n->name) == 0)) {
+ if (a->attr != n->attr) {
+ fr_strerror_printf("dict_addattr: Duplicate attribute name %s", name);
+ fr_pool_free(n);
+ return -1;
+ }
+
+ /*
+ * Same name, same vendor, same attr,
+ * maybe the flags and/or type is
+ * different. Let the new value
+ * over-ride the old one.
+ */
+ }
+
+
+ fr_hash_table_delete(attributes_byvalue, a);
+
+ if (!fr_hash_table_replace(attributes_byname, n)) {
+ fr_strerror_printf("dict_addattr: Internal error storing attribute %s", name);
+ fr_pool_free(n);
+ return -1;
+ }
+ }
+
+ /*
+ * Insert the SAME pointer (not free'd when this entry is
+ * deleted), into another table.
+ *
+ * We want this behaviour because we want OLD names for
+ * the attributes to be read from the configuration
+ * files, but when we're printing them, (and looking up
+ * by value) we want to use the NEW name.
+ */
+ if (!fr_hash_table_replace(attributes_byvalue, n)) {
+ fr_strerror_printf("dict_addattr: Failed inserting attribute name %s", name);
+ return -1;
+ }
+
+ /*
+ * Hacks for combo-IP
+ */
+ if (n->type == PW_TYPE_COMBO_IP_ADDR) {
+ DICT_ATTR *v4, *v6;
+
+ v4 = fr_pool_alloc(sizeof(*v4) + namelen);
+ if (!v4) goto oom;
+
+ v6 = fr_pool_alloc(sizeof(*v6) + namelen);
+ if (!v6) goto oom;
+
+ memcpy(v4, n, sizeof(*v4) + namelen);
+ v4->type = PW_TYPE_IPV4_ADDR;
+
+ memcpy(v6, n, sizeof(*v6) + namelen);
+ v6->type = PW_TYPE_IPV6_ADDR;
+ if (!fr_hash_table_replace(attributes_combo, v4)) {
+ fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv4", name);
+ return -1;
+ }
+
+ if (!fr_hash_table_replace(attributes_combo, v6)) {
+ fr_strerror_printf("dict_addattr: Failed inserting attribute name %s - IPv6", name);
+ return -1;
+ }
+ }
+
+ if (!vendor && (attr > 0) && (attr < 256)) {
+ dict_base_attrs[attr] = n;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Add a value for an attribute to the dictionary.
+ */
+int dict_addvalue(char const *namestr, char const *attrstr, int value)
+{
+ size_t length;
+ DICT_ATTR const *da;
+ DICT_VALUE *dval;
+
+ static DICT_ATTR const *last_attr = NULL;
+
+ if (!*namestr) {
+ fr_strerror_printf("dict_addvalue: empty names are not permitted");
+ return -1;
+ }
+
+ if ((length = strlen(namestr)) >= DICT_VALUE_MAX_NAME_LEN) {
+ fr_strerror_printf("dict_addvalue: value name too long");
+ return -1;
+ }
+
+ if ((dval = fr_pool_alloc(sizeof(*dval) + length)) == NULL) {
+ fr_strerror_printf("dict_addvalue: out of memory");
+ return -1;
+ }
+ memset(dval, 0, sizeof(*dval));
+
+ strcpy(dval->name, namestr);
+ dval->value = value;
+
+ /*
+ * Most VALUEs are bunched together by ATTRIBUTE. We can
+ * save a lot of lookups on dictionary initialization by
+ * caching the last attribute.
+ */
+ if (last_attr && (strcasecmp(attrstr, last_attr->name) == 0)) {
+ da = last_attr;
+ } else {
+ da = dict_attrbyname(attrstr);
+ last_attr = da;
+ }
+
+ /*
+ * Remember which attribute is associated with this
+ * value, if possible.
+ */
+ if (da) {
+ if (da->flags.has_value_alias) {
+ fr_strerror_printf("dict_addvalue: Cannot add VALUE for ATTRIBUTE \"%s\": It already has a VALUE-ALIAS", attrstr);
+ return -1;
+ }
+
+ dval->attr = da->attr;
+ dval->vendor = da->vendor;
+
+ /*
+ * Enforce valid values
+ *
+ * Don't worry about fixups...
+ */
+ switch (da->type) {
+ case PW_TYPE_BYTE:
+ if (value > 255) {
+ fr_pool_free(dval);
+ fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'byte' cannot have VALUEs larger than 255");
+ return -1;
+ }
+ break;
+ case PW_TYPE_SHORT:
+ if (value > 65535) {
+ fr_pool_free(dval);
+ fr_strerror_printf("dict_addvalue: ATTRIBUTEs of type 'short' cannot have VALUEs larger than 65535");
+ return -1;
+ }
+ break;
+
+ /*
+ * Allow octets for now, because
+ * of dictionary.cablelabs
+ */
+ case PW_TYPE_OCTETS:
+
+ case PW_TYPE_INTEGER:
+ break;
+
+ case PW_TYPE_INTEGER64:
+ default:
+ fr_pool_free(dval);
+ fr_strerror_printf("dict_addvalue: VALUEs cannot be defined for attributes of type '%s'",
+ fr_int2str(dict_attr_types, da->type, "?Unknown?"));
+ return -1;
+ }
+ /* in v4 this is done with the UNCONST #define */
+ ((DICT_ATTR *)((uintptr_t)(da)))->flags.has_value = 1;
+ } else {
+ value_fixup_t *fixup;
+
+ fixup = (value_fixup_t *) malloc(sizeof(*fixup));
+ if (!fixup) {
+ fr_pool_free(dval);
+ fr_strerror_printf("dict_addvalue: out of memory");
+ return -1;
+ }
+ memset(fixup, 0, sizeof(*fixup));
+
+ strlcpy(fixup->attrstr, attrstr, sizeof(fixup->attrstr));
+ fixup->dval = dval;
+
+ /*
+ * Insert to the head of the list.
+ */
+ fixup->next = value_fixup;
+ value_fixup = fixup;
+
+ return 0;
+ }
+
+ /*
+ * Add the value into the dictionary.
+ */
+ {
+ DICT_ATTR *tmp;
+ memcpy(&tmp, &dval, sizeof(tmp));
+
+ if (!fr_hash_table_insert(values_byname, tmp)) {
+ if (da) {
+ DICT_VALUE *old;
+
+ /*
+ * Suppress duplicates with the same
+ * name and value. There are lots in
+ * dictionary.ascend.
+ */
+ old = dict_valbyname(da->attr, da->vendor, namestr);
+ if (old && (old->value == dval->value)) {
+ fr_pool_free(dval);
+ return 0;
+ }
+ }
+
+ fr_pool_free(dval);
+ fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", namestr, attrstr);
+ return -1;
+ }
+ }
+
+ /*
+ * There are multiple VALUE's, keyed by attribute, so we
+ * take care of that here.
+ */
+ if (!fr_hash_table_replace(values_byvalue, dval)) {
+ fr_strerror_printf("dict_addvalue: Failed inserting value %s",
+ namestr);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sscanf_i(char const *str, unsigned int *pvalue)
+{
+ unsigned int rcode = 0;
+ int base = 10;
+ static char const *tab = "0123456789";
+
+ if ((str[0] == '0') &&
+ ((str[1] == 'x') || (str[1] == 'X'))) {
+ tab = "0123456789abcdef";
+ base = 16;
+
+ str += 2;
+ }
+
+ while (*str) {
+ char const *c;
+
+ if (*str == '.') break;
+
+ c = memchr(tab, tolower((uint8_t) *str), base);
+ if (!c) return 0;
+
+ rcode *= base;
+ rcode += (c - tab);
+ str++;
+ }
+
+ *pvalue = rcode;
+ return 1;
+}
+
+
+/*
+ * Get the OID based on various pieces of information.
+ *
+ * Remember, the packing format is weird.
+ *
+ * Vendor Attribute
+ * ------ ---------
+ * 00VID 000000AA normal VSA for vendor VID
+ * 00VID AABBCCDD normal VSAs with TLVs
+ * EE000 000000AA extended attr (241.1)
+ * EE000 AABBCCDD extended attr with TLVs
+ * EEVID 000000AA EVS with vendor VID, attr AAA
+ * EEVID AABBCCDD EVS with TLVs
+ *
+ * <whew>! Are we crazy, or what?
+ */
+int dict_str2oid(char const *ptr, unsigned int *pvalue, unsigned int *pvendor,
+ int tlv_depth)
+{
+ char const *p;
+ unsigned int attr;
+
+#ifdef WITH_DICT_OID_DEBUG
+ fprintf(stderr, "PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+ tlv_depth, *pvalue, *pvendor);
+#endif
+
+ if (tlv_depth > fr_attr_max_tlv) {
+ fr_strerror_printf("Too many sub-attributes");
+ return -1;
+ }
+
+ /*
+ * No vendor, try to do basic parsing.
+ */
+ if (!*pvendor && !*pvalue) {
+ /*
+ * Can't call us with a pre-parsed value and no vendor.
+ */
+ if (tlv_depth != 0) {
+ fr_strerror_printf("Invalid call with wrong TLV depth %d", tlv_depth);
+ return -1;
+ }
+
+ p = strchr(ptr, '.');
+ if (!sscanf_i(ptr, &attr)) {
+ fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+ return -1;
+ }
+
+ /*
+ * Normal attribute with no OID. Return it.
+ */
+ if (!p) {
+ *pvalue = attr;
+ goto done;
+ }
+
+ /*
+ * We have an OID, look up the attribute to see what it is.
+ */
+ if (attr != PW_VENDOR_SPECIFIC) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbyvalue(attr, 0);
+ if (!da) {
+ *pvalue = attr;
+ goto done;
+ }
+
+ /*
+ * Standard attributes (including internal
+ * ones) can have TLVs, but only for some
+ * of them.
+ */
+ if (!da->flags.extended) {
+#ifdef PW_IPV6_6RD_CONFIGURATION
+ if (attr == PW_IPV6_6RD_CONFIGURATION) {
+ *pvalue = attr;
+ ptr = p + 1;
+ tlv_depth = 1;
+ goto keep_parsing;
+ }
+#endif
+ fr_strerror_printf("Standard attributes cannot use OIDs");
+ return -1;
+ }
+
+ *pvendor = attr * FR_MAX_VENDOR;
+ ptr = p + 1;
+ } /* and fall through to re-parsing the VSA */
+
+ /*
+ * Look for the attribute number.
+ */
+ if (!sscanf_i(ptr, &attr)) {
+ fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+ return -1;
+ }
+
+ p = strchr(ptr, '.');
+
+ /*
+ * Handle VSAs. Either in the normal space, or in the extended space.
+ */
+ if (attr == PW_VENDOR_SPECIFIC) {
+ if (!p) {
+ *pvalue = attr;
+ goto done;
+ }
+ ptr = p + 1;
+
+ if (!sscanf_i(ptr, &attr)) {
+ fr_strerror_printf("Invalid data '%s' in vendor identifier", ptr);
+ return -1;
+ }
+
+ p = strchr(ptr, '.');
+ if (!p) {
+ fr_strerror_printf("Cannot define VENDOR in an ATTRIBUTE");
+ return -1;
+ }
+ ptr = p + 1;
+
+ *pvendor |= attr;
+ } else {
+ *pvalue = attr;
+ }
+ } /* fall through to processing an OID with pre-defined *pvendor and *pvalue */
+
+keep_parsing:
+#ifdef WITH_DICT_OID_DEBUG
+ fprintf(stderr, "KEEP PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+ tlv_depth, *pvalue, *pvendor);
+#endif
+
+ /*
+ * Check the vendor. Only RFC format attributes can have TLVs.
+ */
+ if (*pvendor) {
+ DICT_VENDOR const *dv = NULL;
+
+ dv = dict_vendorbyvalue(*pvendor);
+ if (dv && (dv->type != 1)) {
+ if (*pvalue || (tlv_depth != 0)) {
+ fr_strerror_printf("Attribute cannot have TLVs");
+ return -1;
+ }
+
+ if (!sscanf_i(ptr, &attr)) {
+ fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+ return -1;
+ }
+
+ if ((dv->type < 3) && (attr > (unsigned int) (1 << (8 * dv->type)))) {
+ fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
+ return -1;
+ }
+
+ *pvalue = attr;
+
+#ifdef WITH_DHCP
+ /*
+ * DHCP attributes can have TLVs. <sigh>
+ */
+ if (*pvendor == 54) goto dhcp_skip;
+#endif
+ goto done;
+ }
+ }
+
+ /*
+ * Parse the rest of the TLVs.
+ */
+ while (tlv_depth <= fr_attr_max_tlv) {
+#ifdef WITH_DICT_OID_DEBUG
+ fprintf(stderr, "TLV PARSING %s tlv_depth %d pvalue %08x pvendor %08x\n", ptr,
+ tlv_depth, *pvalue, *pvendor);
+#endif
+
+ if (!sscanf_i(ptr, &attr)) {
+ fr_strerror_printf("Invalid data '%s' in attribute identifier", ptr);
+ return -1;
+ }
+
+ if (attr > fr_attr_mask[tlv_depth]) {
+ fr_strerror_printf("Number '%s' out of allowed range in attribute identifier", ptr);
+ return -1;
+ }
+
+ attr <<= fr_attr_shift[tlv_depth];
+
+#ifdef WITH_DICT_OID_DEBUG
+ if (*pvendor) {
+ DICT_ATTR const *da;
+
+ da = dict_parent(*pvalue | attr, *pvendor);
+ if (!da) {
+ fprintf(stderr, "STR2OID FAILED PARENT %08x | %08x, %08x\n",
+ *pvalue, attr, *pvendor);
+ } else if ((da->attr != *pvalue) || (da->vendor != *pvendor)) {
+ fprintf(stderr, "STR2OID DISAGREEMENT WITH PARENT %08x, %08x\t%08x, %08x\n",
+ *pvalue, *pvendor, da->attr, da->vendor);
+ }
+ }
+#endif
+
+ *pvalue |= attr;
+
+#ifdef WITH_DHCP
+ dhcp_skip:
+#endif
+ p = strchr(ptr, '.');
+ if (!p) break;
+
+ ptr = p + 1;
+ tlv_depth++;
+ }
+
+done:
+#ifdef WITH_DICT_OID_DEBUG
+ fprintf(stderr, "RETURNING %08x %08x\n", *pvalue, *pvendor);
+#endif
+ return 0;
+}
+
+
+/*
+ * Process the ATTRIBUTE command
+ */
+static int process_attribute(char const* fn, int const line,
+ unsigned int block_vendor,
+ DICT_ATTR const *block_tlv, int tlv_depth,
+ char **argv, int argc)
+{
+ int oid = 0;
+ unsigned int vendor = 0;
+ unsigned int value;
+ int type;
+ unsigned int length;
+ ATTR_FLAGS flags;
+ char *p;
+
+ if ((argc < 3) || (argc > 4)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid ATTRIBUTE line",
+ fn, line);
+ return -1;
+ }
+
+ /*
+ * Dictionaries need to have real names, not shitty ones.
+ */
+ if (strncmp(argv[0], "Attr-", 5) == 0) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid attribute name",
+ fn, line);
+ return -1;
+ }
+
+ memset(&flags, 0, sizeof(flags));
+
+ /*
+ * Look for OIDs before doing anything else.
+ */
+ if (strchr(argv[1], '.') != NULL) oid = 1;
+
+ {
+ DICT_ATTR const *da;
+
+ vendor = block_vendor;
+
+ if (!block_tlv) {
+ value = 0;
+ } else {
+ value = block_tlv->attr;
+ }
+
+ /*
+ * Parse OID.
+ */
+ if (dict_str2oid(argv[1], &value, &vendor, tlv_depth) < 0) {
+ char buffer[256];
+
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+ fr_strerror_printf("dict_init: %s[%d]: Invalid attribute identifier: %s", fn, line, buffer);
+ return -1;
+ }
+ block_vendor = vendor;
+
+ if (oid) {
+ /*
+ * Set the flags based on the parents flags.
+ */
+ da = dict_parent(value, vendor);
+ if (!da) {
+ fr_strerror_printf("dict_init: %s[%d]: Parent attribute for %08x,%08x is undefined.", fn, line, value, vendor);
+ return -1;
+ }
+
+ flags.extended = da->flags.extended;
+ flags.long_extended = da->flags.long_extended;
+ flags.evs = da->flags.evs;
+ if (da->flags.has_tlv) flags.is_tlv = 1;
+ }
+ }
+
+ if (strncmp(argv[2], "octets[", 7) != 0) {
+ /*
+ * find the type of the attribute.
+ */
+ type = fr_str2int(dict_attr_types, argv[2], -1);
+ if (type < 0) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
+ fn, line, argv[2]);
+ return -1;
+ }
+
+ } else {
+ type = PW_TYPE_OCTETS;
+
+ p = strchr(argv[2] + 7, ']');
+ if (!p) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
+ return -1;
+ }
+
+ *p = 0;
+
+ if (!sscanf_i(argv[2] + 7, &length)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
+ return -1;
+ }
+
+ if ((length == 0) || (length > 253)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
+ return -1;
+ }
+
+ flags.length = length;
+ }
+
+ /*
+ * Parse options.
+ */
+ if (argc >= 4) {
+ char *key, *next, *last;
+
+ /*
+ * Keep it real.
+ */
+ if (flags.extended) {
+ fr_strerror_printf("dict_init: %s[%d]: Extended attributes cannot use flags", fn, line);
+ return -1;
+ }
+
+ key = argv[3];
+ do {
+ next = strchr(key, ',');
+ if (next) *(next++) = '\0';
+
+ /*
+ * Boolean flag, means this is a tagged
+ * attribute.
+ */
+ if ((strcmp(key, "has_tag") == 0) || (strcmp(key, "has_tag=1") == 0)) {
+ flags.has_tag = 1;
+
+ /*
+ * Encryption method, defaults to 0 (none).
+ * Currently valid is just type 2,
+ * Tunnel-Password style, which can only
+ * be applied to strings.
+ */
+ } else if (strncmp(key, "encrypt=", 8) == 0) {
+ flags.encrypt = strtol(key + 8, &last, 0);
+ if (*last) {
+ fr_strerror_printf("dict_init: %s[%d] invalid option %s",
+ fn, line, key);
+ return -1;
+ }
+
+ if ((flags.encrypt == FLAG_ENCRYPT_ASCEND_SECRET) &&
+ (type != PW_TYPE_STRING)) {
+ fr_strerror_printf("dict_init: %s[%d] Only \"string\" types can have the "
+ "\"encrypt=3\" flag set", fn, line);
+ return -1;
+ }
+ flags.secret = 1;
+
+ } else if (strncmp(key, "secret", 6) == 0) {
+ flags.secret = 1;
+
+ } else if (strncmp(key, "array", 6) == 0) {
+ flags.array = 1;
+
+ switch (type) {
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ case PW_TYPE_STRING:
+ break;
+
+ default:
+ fr_strerror_printf("dict_init: %s[%d] \"%s\" type cannot have the "
+ "\"array\" flag set",
+ fn, line,
+ fr_int2str(dict_attr_types, type, "<UNKNOWN>"));
+ return -1;
+ }
+
+ } else if (strncmp(key, "concat", 7) == 0) {
+ flags.concat = 1;
+
+ if (type != PW_TYPE_OCTETS) {
+ fr_strerror_printf("dict_init: %s[%d] Only \"octets\" type can have the "
+ "\"concat\" flag set", fn, line);
+ return -1;
+ }
+
+ } else if (strncmp(key, "virtual", 8) == 0) {
+ flags.virtual = 1;
+
+ if (vendor != 0) {
+ fr_strerror_printf("dict_init: %s[%d] VSAs cannot have the \"virtual\" "
+ "flag set", fn, line);
+ return -1;
+ }
+
+ if (value < 256) {
+ fr_strerror_printf("dict_init: %s[%d] Standard attributes cannot "
+ "have the \"virtual\" flag set", fn, line);
+ return -1;
+ }
+
+ /*
+ * The only thing is the vendor name,
+ * and it's a known name: allow it.
+ */
+ } else if ((key == argv[3]) && !next) {
+ if (oid) {
+ fr_strerror_printf("dict_init: %s[%d] New-style attributes cannot use "
+ "a vendor flag", fn, line);
+ return -1;
+ }
+
+ if (block_vendor) {
+ fr_strerror_printf("dict_init: %s[%d] Vendor flag inside of \"BEGIN-VENDOR\" "
+ "is not allowed", fn, line);
+ return -1;
+ }
+
+ vendor = dict_vendorbyname(key);
+ if (!vendor) goto unknown;
+ break;
+
+ } else {
+ unknown:
+ fr_strerror_printf("dict_init: %s[%d]: unknown option \"%s\"", fn, line, key);
+ return -1;
+ }
+
+ key = next;
+ if (key && !*key) break;
+ } while (key);
+ }
+
+ if (block_vendor) vendor = block_vendor;
+
+ /*
+ * Special checks for tags, they make our life much more
+ * difficult.
+ */
+ if (flags.has_tag) {
+ /*
+ * Only string, octets, and integer can be tagged.
+ */
+ switch (type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_INTEGER:
+ break;
+
+ default:
+ fr_strerror_printf("dict_init: %s[%d]: Attributes of type %s cannot be tagged.",
+ fn, line,
+ fr_int2str(dict_attr_types, type, "?Unknown?"));
+ return -1;
+ }
+ }
+
+ if (type == PW_TYPE_TLV) {
+ if (vendor && (vendor < FR_MAX_VENDOR)
+#ifdef WITH_DHCP
+ && (vendor != DHCP_MAGIC_VENDOR)
+#endif
+ ) {
+ DICT_VENDOR *dv;
+
+ dv = dict_vendorbyvalue(vendor);
+ if (!dv || (dv->type != 1) || (dv->length != 1)) {
+ fr_strerror_printf("dict_init: %s[%d]: Type \"tlv\" can only be for \"format=1,1\".",
+ fn, line);
+ return -1;
+ }
+
+ }
+ flags.has_tlv = 1;
+ }
+
+ if (block_tlv) {
+ /*
+ * TLV's can be only one octet.
+ */
+ if ((value == 0) || ((value & ~fr_attr_mask[tlv_depth]) != 0)) {
+ fr_strerror_printf( "dict_init: %s[%d]: sub-tlv has invalid attribute number",
+ fn, line);
+ return -1;
+ }
+
+ /*
+ * Shift the value left.
+ */
+ value <<= fr_attr_shift[tlv_depth];
+ value |= block_tlv->attr;
+ flags.is_tlv = 1;
+ }
+
+#ifdef WITH_DICTIONARY_WARNINGS
+ /*
+ * Hack to help us discover which vendors have illegal
+ * attributes.
+ */
+ if (!vendor && (value < 256) &&
+ !strstr(fn, "rfc") && !strstr(fn, "illegal")) {
+ fprintf(stderr, "WARNING: Illegal Attribute %s in %s\n",
+ argv[0], fn);
+ }
+#endif
+
+ /*
+ * Add it in.
+ */
+ if (dict_addattr(argv[0], value, vendor, type, flags) < 0) {
+ char buffer[256];
+
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+ fr_strerror_printf("dict_init: %s[%d]: %s",
+ fn, line, buffer);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Process the VALUE command
+ */
+static int process_value(char const* fn, int const line, char **argv,
+ int argc)
+{
+ unsigned int value;
+
+ if (argc != 3) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid VALUE line",
+ fn, line);
+ return -1;
+ }
+ /*
+ * For Compatibility, skip "Server-Config"
+ */
+ if (strcasecmp(argv[0], "Server-Config") == 0)
+ return 0;
+
+ /*
+ * Validate all entries
+ */
+ if (!sscanf_i(argv[2], &value)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid value",
+ fn, line);
+ return -1;
+ }
+
+ if (dict_addvalue(argv[1], argv[0], value) < 0) {
+ char buffer[256];
+
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+ fr_strerror_printf("dict_init: %s[%d]: %s",
+ fn, line, buffer);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Process the VALUE-ALIAS command
+ *
+ * This allows VALUE mappings to be shared among multiple
+ * attributes.
+ */
+static int process_value_alias(char const* fn, int const line, char **argv,
+ int argc)
+{
+ DICT_ATTR const *my_da, *da;
+ DICT_VALUE *dval;
+
+ if (argc != 2) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid VALUE-ALIAS line",
+ fn, line);
+ return -1;
+ }
+
+ my_da = dict_attrbyname(argv[0]);
+ if (!my_da) {
+ fr_strerror_printf("dict_init: %s[%d]: ATTRIBUTE \"%s\" does not exist",
+ fn, line, argv[1]);
+ return -1;
+ }
+
+ if (my_da->flags.has_value_alias) {
+ fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" with pre-existing VALUE-ALIAS",
+ fn, line, argv[0]);
+ return -1;
+ }
+
+ da = dict_attrbyname(argv[1]);
+ if (!da) {
+ fr_strerror_printf("dict_init: %s[%d]: Cannot find ATTRIBUTE \"%s\" for alias",
+ fn, line, argv[1]);
+ return -1;
+ }
+
+ if (da->flags.has_value_alias) {
+ fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS to ATTRIBUTE \"%s\" which itself has a VALUE-ALIAS",
+ fn, line, argv[1]);
+ return -1;
+ }
+
+ if (my_da->type != da->type) {
+ fr_strerror_printf("dict_init: %s[%d]: Cannot add VALUE-ALIAS between attributes of differing type",
+ fn, line);
+ return -1;
+ }
+
+ if ((dval = fr_pool_alloc(sizeof(*dval))) == NULL) {
+ fr_strerror_printf("dict_addvalue: out of memory");
+ return -1;
+ }
+
+ dval->name[0] = '\0'; /* empty name */
+ dval->attr = my_da->attr;
+ dval->vendor = my_da->vendor;
+ dval->value = da->attr;
+
+ if (!fr_hash_table_insert(values_byname, dval)) {
+ fr_strerror_printf("dict_init: %s[%d]: Error create alias",
+ fn, line);
+ fr_pool_free(dval);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int parse_format(char const *fn, int line, char const *format, int *ptype, int *plength, bool *pcontinuation)
+{
+ char const *p;
+ int type, length;
+ bool continuation = false;
+
+ if (strncasecmp(format, "format=", 7) != 0) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected \"format=\", got \"%s\"",
+ fn, line, format);
+ return -1;
+ }
+
+ p = format + 7;
+ if ((strlen(p) < 3) ||
+ !isdigit((uint8_t) p[0]) ||
+ (p[1] != ',') ||
+ !isdigit((uint8_t) p[2]) ||
+ (p[3] && (p[3] != ','))) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
+ fn, line, p);
+ return -1;
+ }
+
+ type = (int) (p[0] - '0');
+ length = (int) (p[2] - '0');
+
+ if ((type != 1) && (type != 2) && (type != 4)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid type value %d for VENDOR",
+ fn, line, type);
+ return -1;
+ }
+
+ if ((length != 0) && (length != 1) && (length != 2)) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid length value %d for VENDOR",
+ fn, line, length);
+ return -1;
+ }
+
+ if (p[3] == ',') {
+ if (!p[4]) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
+ fn, line, p);
+ return -1;
+ }
+
+ if ((p[4] != 'c') ||
+ (p[5] != '\0')) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"",
+ fn, line, p);
+ return -1;
+ }
+ continuation = true;
+
+ if ((type != 1) || (length != 1)) {
+ fr_strerror_printf("dict_init: %s[%d]: Only 'format=1,1' VSAs can have continuations",
+ fn, line);
+ return -1;
+ }
+ }
+
+ *ptype = type;
+ *plength = length;
+ *pcontinuation = continuation;
+ return 0;
+}
+
+
+/*
+ * Process the VENDOR command
+ */
+static int process_vendor(char const* fn, int const line, char **argv,
+ int argc)
+{
+ int value;
+ int type, length;
+ bool continuation = false;
+ DICT_VENDOR *dv;
+
+ if ((argc < 2) || (argc > 3)) {
+ fr_strerror_printf( "dict_init: %s[%d] invalid VENDOR entry",
+ fn, line);
+ return -1;
+ }
+
+ /*
+ * Validate all entries
+ */
+ if (!isdigit((uint8_t) argv[1][0])) {
+ fr_strerror_printf("dict_init: %s[%d]: invalid value",
+ fn, line);
+ return -1;
+ }
+ value = atoi(argv[1]);
+
+ /* Create a new VENDOR entry for the list */
+ if (dict_addvendor(argv[0], value) < 0) {
+ char buffer[256];
+
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+
+ fr_strerror_printf("dict_init: %s[%d]: %s",
+ fn, line, buffer);
+ return -1;
+ }
+
+ /*
+ * Look for a format statement. Allow it to over-ride the hard-coded formats below.
+ */
+ if (argc == 3) {
+ if (parse_format(fn, line, argv[2], &type, &length, &continuation) < 0) {
+ return -1;
+ }
+
+ } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */
+ type = 4;
+ length = 0;
+
+ } else if (value == VENDORPEC_LUCENT) {
+ type = 2;
+ length = 1;
+
+ } else if (value == VENDORPEC_STARENT) {
+ type = 2;
+ length = 2;
+
+ } else {
+ type = length = 1;
+ }
+
+ dv = dict_vendorbyvalue(value);
+ if (!dv) {
+ fr_strerror_printf("dict_init: %s[%d]: Failed adding format for VENDOR",
+ fn, line);
+ return -1;
+ }
+
+ dv->type = type;
+ dv->length = length;
+ dv->flags = continuation;
+
+ return 0;
+}
+
+/*
+ * String split routine. Splits an input string IN PLACE
+ * into pieces, based on spaces.
+ */
+int str2argv(char *str, char **argv, int max_argc)
+{
+ int argc = 0;
+
+ while (*str) {
+ if (argc >= max_argc) break;
+
+ /*
+ * Chop out comments early.
+ */
+ if (*str == '#') {
+ *str = '\0';
+ break;
+ }
+
+ while ((*str == ' ') ||
+ (*str == '\t') ||
+ (*str == '\r') ||
+ (*str == '\n')) *(str++) = '\0';
+
+ if (!*str) break;
+
+ argv[argc] = str;
+ argc++;
+
+ while (*str &&
+ (*str != ' ') &&
+ (*str != '\t') &&
+ (*str != '\r') &&
+ (*str != '\n')) str++;
+ }
+
+ return argc;
+}
+
+static int my_dict_init(char const *parent, char const *filename,
+ char const *src_file, int src_line);
+
+int dict_read(char const *dir, char const *filename)
+{
+ if (!attributes_byname) {
+ fr_strerror_printf("Must call dict_init() before dict_read()");
+ return -1;
+ }
+
+ return my_dict_init(dir, filename, NULL, 0);
+}
+
+
+#define MAX_ARGV (16)
+
+/*
+ * Initialize the dictionary.
+ */
+static int my_dict_init(char const *parent, char const *filename,
+ char const *src_file, int src_line)
+{
+ FILE *fp;
+ char dir[256], fn[256];
+ char buf[256];
+ char *p;
+ int line = 0;
+ unsigned int vendor;
+ unsigned int block_vendor;
+ struct stat statbuf;
+ char *argv[MAX_ARGV];
+ int argc;
+ DICT_ATTR const *da, *block_tlv[MAX_TLV_NEST + 1];
+ int which_block_tlv = 0;
+
+ block_tlv[0] = NULL;
+ block_tlv[1] = NULL;
+ block_tlv[2] = NULL;
+ block_tlv[3] = NULL;
+
+ if ((strlen(parent) + 3 + strlen(filename)) > sizeof(dir)) {
+ fr_strerror_printf("dict_init: filename name too long");
+ return -1;
+ }
+
+ /*
+ * If it's an absolute dir, forget the parent dir,
+ * and remember the new one.
+ *
+ * If it's a relative dir, tack on the current filename
+ * to the parent dir. And use that.
+ */
+ if (!FR_DIR_IS_RELATIVE(filename)) {
+ strlcpy(dir, filename, sizeof(dir));
+ p = strrchr(dir, FR_DIR_SEP);
+ if (p) {
+ p[1] = '\0';
+ } else {
+ strlcat(dir, "/", sizeof(dir));
+ }
+
+ strlcpy(fn, filename, sizeof(fn));
+ } else {
+ strlcpy(dir, parent, sizeof(dir));
+ p = strrchr(dir, FR_DIR_SEP);
+ if (p) {
+ if (p[1]) strlcat(dir, "/", sizeof(dir));
+ } else {
+ strlcat(dir, "/", sizeof(dir));
+ }
+ strlcat(dir, filename, sizeof(dir));
+ p = strrchr(dir, FR_DIR_SEP);
+ if (p) {
+ p[1] = '\0';
+ } else {
+ strlcat(dir, "/", sizeof(dir));
+ }
+
+ p = strrchr(filename, FR_DIR_SEP);
+ if (p) {
+ snprintf(fn, sizeof(fn), "%s%s", dir, p);
+ } else {
+ snprintf(fn, sizeof(fn), "%s%s", dir, filename);
+ }
+
+ }
+
+ /*
+ * Check if we've loaded this file before. If so, ignore it.
+ */
+ p = strrchr(fn, FR_DIR_SEP);
+ if (p) {
+ *p = '\0';
+ if (dict_stat_check(fn, p + 1)) {
+ *p = FR_DIR_SEP;
+ return 0;
+ }
+ *p = FR_DIR_SEP;
+ }
+
+ if ((fp = fopen(fn, "r")) == NULL) {
+ if (!src_file) {
+ fr_strerror_printf("dict_init: Couldn't open dictionary \"%s\": %s",
+ fn, fr_syserror(errno));
+ } else {
+ fr_strerror_printf("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s",
+ src_file, src_line, fn, fr_syserror(errno));
+ }
+ return -2;
+ }
+
+ stat(fn, &statbuf); /* fopen() guarantees this will succeed */
+ if (!S_ISREG(statbuf.st_mode)) {
+ fclose(fp);
+ fr_strerror_printf("dict_init: Dictionary \"%s\" is not a regular file",
+ fn);
+ return -1;
+ }
+
+ /*
+ * Globally writable dictionaries means that users can control
+ * the server configuration with little difficulty.
+ */
+#ifdef S_IWOTH
+ if ((statbuf.st_mode & S_IWOTH) != 0) {
+ fclose(fp);
+ fr_strerror_printf("dict_init: Dictionary \"%s\" is globally writable. Refusing to start due to insecure configuration.",
+ fn);
+ return -1;
+ }
+#endif
+
+ dict_stat_add(&statbuf);
+
+ /*
+ * Seed the random pool with data.
+ */
+ fr_rand_seed(&statbuf, sizeof(statbuf));
+
+ block_vendor = 0;
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ line++;
+ if (buf[0] == '#' || buf[0] == 0 ||
+ buf[0] == '\n' || buf[0] == '\r')
+ continue;
+
+ /*
+ * Comment characters should NOT be appearing anywhere but
+ * as start of a comment;
+ */
+ p = strchr(buf, '#');
+ if (p) *p = '\0';
+
+ argc = str2argv(buf, argv, MAX_ARGV);
+ if (argc == 0) continue;
+
+ if (argc == 1) {
+ fr_strerror_printf( "dict_init: %s[%d] invalid entry",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+ /*
+ * Process VALUE lines.
+ */
+ if (strcasecmp(argv[0], "VALUE") == 0) {
+ if (process_value(fn, line,
+ argv + 1, argc - 1) == -1) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ }
+
+ /*
+ * Perhaps this is an attribute.
+ */
+ if (strcasecmp(argv[0], "ATTRIBUTE") == 0) {
+ if (process_attribute(fn, line, block_vendor,
+ block_tlv[which_block_tlv],
+ which_block_tlv,
+ argv + 1, argc - 1) == -1) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ }
+
+ /*
+ * See if we need to import another dictionary.
+ */
+ if (strcasecmp(argv[0], "$INCLUDE") == 0) {
+ if (my_dict_init(dir, argv[1], fn, line) < 0) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ } /* $INCLUDE */
+
+ /*
+ * Optionally include a dictionary
+ */
+ if ((strcasecmp(argv[0], "$INCLUDE-") == 0) ||
+ (strcasecmp(argv[0], "$-INCLUDE") == 0)) {
+ int rcode = my_dict_init(dir, argv[1], fn, line);
+
+ if (rcode == -2) continue;
+
+ if (rcode < 0) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ } /* $INCLUDE- */
+
+ if (strcasecmp(argv[0], "VALUE-ALIAS") == 0) {
+ if (process_value_alias(fn, line,
+ argv + 1, argc - 1) == -1) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ }
+
+ /*
+ * Process VENDOR lines.
+ */
+ if (strcasecmp(argv[0], "VENDOR") == 0) {
+ if (process_vendor(fn, line,
+ argv + 1, argc - 1) == -1) {
+ fclose(fp);
+ return -1;
+ }
+ continue;
+ }
+
+ if (strcasecmp(argv[0], "BEGIN-TLV") == 0) {
+ if (argc != 2) {
+ fr_strerror_printf(
+ "dict_init: %s[%d] invalid BEGIN-TLV entry",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+ da = dict_attrbyname(argv[1]);
+ if (!da) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: unknown attribute %s",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+
+ if (da->type != PW_TYPE_TLV) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: attribute %s is not of type tlv",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+
+ if (which_block_tlv >= MAX_TLV_NEST) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: TLVs are nested too deep",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+
+ block_tlv[++which_block_tlv] = da;
+ continue;
+ } /* BEGIN-TLV */
+
+ if (strcasecmp(argv[0], "END-TLV") == 0) {
+ if (argc != 2) {
+ fr_strerror_printf(
+ "dict_init: %s[%d] invalid END-TLV entry",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+ da = dict_attrbyname(argv[1]);
+ if (!da) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: unknown attribute %s",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+
+ if (da != block_tlv[which_block_tlv]) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: END-TLV %s does not match any previous BEGIN-TLV",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+ block_tlv[which_block_tlv--] = NULL;
+ continue;
+ } /* END-VENDOR */
+
+ if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) {
+ if (argc < 2) {
+ fr_strerror_printf(
+ "dict_init: %s[%d] invalid BEGIN-VENDOR entry",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+ vendor = dict_vendorbyname(argv[1]);
+ if (!vendor) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: unknown vendor %s",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+
+ block_vendor = vendor;
+
+ /*
+ * Check for extended attr VSAs
+ *
+ * BEGIN-VENDOR foo format=Foo-Encapsulation-Attr
+ */
+ if (argc > 2) {
+ if ((strncmp(argv[2], "format=", 7) != 0) &&
+ (strncmp(argv[2], "parent=", 7) != 0)) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: Invalid format %s",
+ fn, line, argv[2]);
+ fclose(fp);
+ return -1;
+ }
+
+ p = argv[2] + 7;
+ da = dict_attrbyname(p);
+ if (!da) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR: unknown attribute \"%s\"",
+ fn, line, p);
+ fclose(fp);
+ return -1;
+ }
+
+ if (!da->flags.evs) {
+ fr_strerror_printf("dict_init: %s[%d]: Invalid format for BEGIN-VENDOR. Attribute \"%s\" is not of \"evs\" data type",
+ fn, line, p);
+ fclose(fp);
+ return -1;
+ }
+
+ /*
+ * Pack the encapsulating
+ * attribute into the upper 8
+ * bits of the vendor ID
+ */
+ block_vendor |= da->vendor;
+ }
+
+ continue;
+ } /* BEGIN-VENDOR */
+
+ if (strcasecmp(argv[0], "END-VENDOR") == 0) {
+ if (argc != 2) {
+ fr_strerror_printf(
+ "dict_init: %s[%d] invalid END-VENDOR entry",
+ fn, line);
+ fclose(fp);
+ return -1;
+ }
+
+ vendor = dict_vendorbyname(argv[1]);
+ if (!vendor) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: unknown vendor %s",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+
+ if (vendor != (block_vendor & (FR_MAX_VENDOR - 1))) {
+ fr_strerror_printf(
+ "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR",
+ fn, line, argv[1]);
+ fclose(fp);
+ return -1;
+ }
+ block_vendor = 0;
+ continue;
+ } /* END-VENDOR */
+
+ /*
+ * Any other string: We don't recognize it.
+ */
+ fr_strerror_printf("dict_init: %s[%d] invalid keyword \"%s\"",
+ fn, line, argv[0]);
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+ return 0;
+}
+
+
+/*
+ * Empty callback for hash table initialization.
+ */
+static int null_callback(UNUSED void *ctx, UNUSED void *data)
+{
+ return 0;
+}
+
+
+/*
+ * Initialize the directory, then fix the attr member of
+ * all attributes.
+ */
+int dict_init(char const *dir, char const *fn)
+{
+ /*
+ * Check if we need to change anything. If not, don't do
+ * anything.
+ */
+ if (dict_stat_check(dir, fn)) {
+ return 0;
+ }
+
+ /*
+ * Free the dictionaries, and the stat cache.
+ */
+ dict_free();
+
+ /*
+ * Create the table of vendor by name. There MAY NOT
+ * be multiple vendors of the same name.
+ *
+ * Each vendor is malloc'd, so the free function is free.
+ */
+ vendors_byname = fr_hash_table_create(dict_vendor_name_hash,
+ dict_vendor_name_cmp,
+ fr_pool_free);
+ if (!vendors_byname) {
+ return -1;
+ }
+
+ /*
+ * Create the table of vendors by value. There MAY
+ * be vendors of the same value. If there are, we
+ * pick the latest one.
+ */
+ vendors_byvalue = fr_hash_table_create(dict_vendor_value_hash,
+ dict_vendor_value_cmp,
+ fr_pool_free);
+ if (!vendors_byvalue) {
+ return -1;
+ }
+
+ /*
+ * Create the table of attributes by name. There MAY NOT
+ * be multiple attributes of the same name.
+ *
+ * Each attribute is malloc'd, so the free function is free.
+ */
+ attributes_byname = fr_hash_table_create(dict_attr_name_hash,
+ dict_attr_name_cmp,
+ fr_pool_free);
+ if (!attributes_byname) {
+ return -1;
+ }
+
+ /*
+ * Create the table of attributes by value. There MAY
+ * be attributes of the same value. If there are, we
+ * pick the latest one.
+ */
+ attributes_byvalue = fr_hash_table_create(dict_attr_value_hash,
+ dict_attr_value_cmp,
+ fr_pool_free);
+ if (!attributes_byvalue) {
+ return -1;
+ }
+
+ /*
+ * Horrible hacks for combo-IP.
+ */
+ attributes_combo = fr_hash_table_create(dict_attr_combo_hash,
+ dict_attr_combo_cmp,
+ fr_pool_free);
+ if (!attributes_combo) {
+ return -1;
+ }
+
+ values_byname = fr_hash_table_create(dict_value_name_hash,
+ dict_value_name_cmp,
+ fr_pool_free);
+ if (!values_byname) {
+ return -1;
+ }
+
+ values_byvalue = fr_hash_table_create(dict_value_value_hash,
+ dict_value_value_cmp,
+ fr_pool_free);
+ if (!values_byvalue) {
+ return -1;
+ }
+
+ value_fixup = NULL; /* just to be safe. */
+
+ if (my_dict_init(dir, fn, NULL, 0) < 0)
+ return -1;
+
+ if (value_fixup) {
+ DICT_ATTR const *a;
+ value_fixup_t *this, *next;
+
+ for (this = value_fixup; this != NULL; this = next) {
+ next = this->next;
+
+ a = dict_attrbyname(this->attrstr);
+ if (!a) {
+ fr_strerror_printf(
+ "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"",
+ this->attrstr, this->dval->name);
+ return -1; /* leak, but they should die... */
+ }
+
+ this->dval->attr = a->attr;
+
+ /*
+ * Add the value into the dictionary.
+ */
+ if (!fr_hash_table_replace(values_byname,
+ this->dval)) {
+ fr_strerror_printf("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name);
+ return -1;
+ }
+
+ /*
+ * Allow them to use the old name, but
+ * prefer the new name when printing
+ * values.
+ */
+ if (!fr_hash_table_finddata(values_byvalue, this->dval)) {
+ fr_hash_table_replace(values_byvalue,
+ this->dval);
+ }
+ free(this);
+
+ /*
+ * Just so we don't lose track of things.
+ */
+ value_fixup = next;
+ }
+ }
+
+ /*
+ * Walk over all of the hash tables to ensure they're
+ * initialized. We do this because the threads may perform
+ * lookups, and we don't want multi-threaded re-ordering
+ * of the table entries. That would be bad.
+ */
+ fr_hash_table_walk(vendors_byname, null_callback, NULL);
+ fr_hash_table_walk(vendors_byvalue, null_callback, NULL);
+
+ fr_hash_table_walk(attributes_byname, null_callback, NULL);
+ fr_hash_table_walk(attributes_byvalue, null_callback, NULL);
+
+ fr_hash_table_walk(values_byvalue, null_callback, NULL);
+ fr_hash_table_walk(values_byname, null_callback, NULL);
+
+ return 0;
+}
+
+static size_t print_attr_oid(char *buffer, size_t bufsize, unsigned int attr, unsigned int vendor)
+{
+ int nest, dv_type = 1;
+ size_t len;
+ char *p = buffer;
+
+ if (vendor > FR_MAX_VENDOR) {
+ len = snprintf(p, bufsize, "%u.", vendor / FR_MAX_VENDOR);
+ p += len;
+ bufsize -= len;
+ vendor &= (FR_MAX_VENDOR) - 1;
+ }
+
+ if (vendor) {
+ DICT_VENDOR *dv;
+
+ /*
+ * dv_type is the length of the vendor's type field
+ * RFC 2865 never defined a mandatory length, so
+ * different vendors have different length type fields.
+ */
+ dv = dict_vendorbyvalue(vendor);
+ if (dv) dv_type = dv->type;
+
+ len = snprintf(p, bufsize, "26.%u.", vendor);
+
+ p += len;
+ bufsize -= len;
+ }
+
+
+ switch (dv_type) {
+ default:
+ case 1:
+ len = snprintf(p, bufsize, "%u", attr & 0xff);
+ p += len;
+ bufsize -= len;
+ if ((attr >> 8) == 0) return p - buffer;
+ break;
+
+ case 2:
+ len = snprintf(p, bufsize, "%u", attr & 0xffff);
+ p += len;
+ return p - buffer;
+
+ case 4:
+ len = snprintf(p, bufsize, "%u", attr);
+ p += len;
+ return p - buffer;
+
+ }
+
+ /*
+ * "attr" is a sequence of packed numbers. Unpack them.
+ */
+ for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
+ if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
+
+ len = snprintf(p, bufsize, ".%u",
+ (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
+
+ p += len;
+ bufsize -= len;
+ }
+
+ return p - buffer;
+}
+
+/** Free dynamically allocated (unknown attributes)
+ *
+ * If the da was dynamically allocated it will be freed, else the function
+ * will return without doing anything.
+ *
+ * @param da to free.
+ */
+void dict_attr_free(DICT_ATTR const **da)
+{
+ DICT_ATTR **tmp;
+
+ if (!da || !*da) return;
+
+ /* Don't free real DAs */
+ if (!(*da)->flags.is_unknown) {
+ return;
+ }
+
+ memcpy(&tmp, &da, sizeof(*tmp));
+ talloc_free(*tmp);
+
+ *tmp = NULL;
+}
+
+
+/** Initialises a dictionary attr for unknown attributes
+ *
+ * Initialises a dict attr for an unknown attribute/vendor/type without adding
+ * it to dictionary pools/hashes.
+ *
+ * @param[in,out] da struct to initialise, must be at least DICT_ATTR_SIZE bytes.
+ * @param[in] attr number.
+ * @param[in] vendor number.
+ * @return 0 on success.
+ */
+int dict_unknown_from_fields(DICT_ATTR *da, unsigned int attr, unsigned int vendor)
+{
+ char *p;
+ size_t len = 0;
+ size_t bufsize = DICT_ATTR_MAX_NAME_LEN;
+
+ memset(da, 0, DICT_ATTR_SIZE);
+
+ da->attr = attr;
+ da->vendor = vendor;
+ da->type = PW_TYPE_OCTETS;
+ da->flags.is_unknown = true;
+ da->flags.is_pointer = true;
+
+ /*
+ * Unknown attributes of the "WiMAX" vendor get marked up
+ * as being for WiMAX.
+ */
+ if (vendor == VENDORPEC_WIMAX) {
+ da->flags.wimax = 1;
+ }
+
+ p = da->name;
+
+ len = snprintf(p, bufsize, "Attr-");
+ p += len;
+ bufsize -= len;
+
+ print_attr_oid(p, bufsize , attr, vendor);
+
+ return 0;
+}
+
+/** Allocs a dictionary attr for unknown attributes
+ *
+ * Allocs a dict attr for an unknown attribute/vendor/type without adding
+ * it to dictionary pools/hashes.
+ *
+ * @param[in] ctx to allocate DA in.
+ * @param[in] attr number.
+ * @param[in] vendor number.
+ * @return 0 on success.
+ */
+DICT_ATTR const *dict_unknown_afrom_fields(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor)
+{
+ uint8_t *p;
+ DICT_ATTR *da;
+
+ p = talloc_zero_array(ctx, uint8_t, DICT_ATTR_SIZE);
+ if (!p) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+ da = (DICT_ATTR *) p;
+ talloc_set_type(da, DICT_ATTR);
+
+ if (dict_unknown_from_fields(da, attr, vendor) < 0) {
+ talloc_free(p);
+ return NULL;
+ }
+
+ return da;
+}
+
+/** Create a DICT_ATTR from an ASCII attribute and value
+ *
+ * Where the attribute name is in the form:
+ * - Attr-%d
+ * - Attr-%d.%d.%d...
+ * - Vendor-%d-Attr-%d
+ * - VendorName-Attr-%d
+ *
+ * @param[in] da to initialise.
+ * @param[in] name of attribute.
+ * @return 0 on success -1 on failure.
+ */
+int dict_unknown_from_str(DICT_ATTR *da, char const *name)
+{
+ unsigned int attr = 0, vendor = 0;
+
+ char const *p = name;
+ char *q;
+
+ if (dict_valid_name(name) < 0) return -1;
+
+ /*
+ * Pull off vendor prefix first.
+ */
+ if (strncasecmp(p, "Attr-", 5) != 0) {
+ if (strncasecmp(p, "Vendor-", 7) == 0) {
+ vendor = (int) strtol(p + 7, &q, 10);
+ if ((vendor == 0) || (vendor > FR_MAX_VENDOR)) {
+ fr_strerror_printf("Invalid vendor value in attribute name \"%s\"", name);
+
+ return -1;
+ }
+
+ p = q;
+
+ /* must be vendor name */
+ } else {
+ char buffer[256];
+
+ q = strchr(p, '-');
+
+ if (!q) {
+ fr_strerror_printf("Invalid vendor name in attribute name \"%s\"", name);
+ return -1;
+ }
+
+ if ((size_t) (q - p) >= sizeof(buffer)) {
+ fr_strerror_printf("Vendor name too long in attribute name \"%s\"", name);
+
+ return -1;
+ }
+
+ memcpy(buffer, p, (q - p));
+ buffer[q - p] = '\0';
+
+ vendor = dict_vendorbyname(buffer);
+ if (!vendor) {
+ fr_strerror_printf("Unknown name \"%s\"", name);
+
+ return -1;
+ }
+
+ p = q;
+ }
+
+ if (*p != '-') {
+ fr_strerror_printf("Invalid text following vendor definition in attribute name \"%s\"", name);
+
+ return -1;
+ }
+ p++;
+ }
+
+ /*
+ * Attr-%d
+ */
+ if (strncasecmp(p, "Attr-", 5) != 0) {
+ fr_strerror_printf("Unknown attribute \"%s\"", name);
+
+ return -1;
+ }
+
+ /*
+ * Parse the OID, with a (possibly) pre-defined vendor.
+ */
+ if (dict_str2oid(p + 5, &attr, &vendor, 0) < 0) {
+ return -1;
+ }
+
+ return dict_unknown_from_fields(da, attr, vendor);
+}
+
+/** Create a DICT_ATTR from an ASCII attribute and value
+ *
+ * Where the attribute name is in the form:
+ * - Attr-%d
+ * - Attr-%d.%d.%d...
+ * - Vendor-%d-Attr-%d
+ * - VendorName-Attr-%d
+ *
+ * @param[in] ctx to alloc new attribute in.
+ * @param[in] name of attribute.
+ * @return 0 on success -1 on failure.
+ */
+DICT_ATTR const *dict_unknown_afrom_str(TALLOC_CTX *ctx, char const *name)
+{
+ uint8_t *p;
+ DICT_ATTR *da;
+
+ p = talloc_zero_array(ctx, uint8_t, DICT_ATTR_SIZE);
+ if (!p) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+ da = (DICT_ATTR *) p;
+ talloc_set_type(da, DICT_ATTR);
+
+ if (dict_unknown_from_str(da, name) < 0) {
+ talloc_free(p);
+ return NULL;
+ }
+
+ return da;
+}
+
+/** Create a dictionary attribute by name embedded in another string
+ *
+ * Find the first invalid attribute name char in the string pointed
+ * to by name.
+ *
+ * Copy the characters between the start of the name string and the first
+ * none dict_attr_allowed_char to a buffer and initialise da as an
+ * unknown attribute.
+ *
+ * @param[out] da to initialise.
+ * @param[in,out] name string start.
+ * @return 0 on success or -1 on error;
+ */
+int dict_unknown_from_substr(DICT_ATTR *da, char const **name)
+{
+ char const *p;
+ size_t len;
+ char buffer[DICT_ATTR_MAX_NAME_LEN + 1];
+
+ if (!name || !*name) return -1;
+
+ /*
+ * Advance p until we get something that's not part of
+ * the dictionary attribute name.
+ */
+ for (p = *name; dict_attr_allowed_chars[(int) *p] || (*p == '.' ) || (*p == '-'); p++);
+
+ len = p - *name;
+ if (len > DICT_ATTR_MAX_NAME_LEN) {
+ fr_strerror_printf("Attribute name too long");
+
+ return -1;
+ }
+ if (len == 0) {
+ fr_strerror_printf("Invalid attribute name");
+ return -1;
+ }
+ strlcpy(buffer, *name, len + 1);
+
+ if (dict_unknown_from_str(da, buffer) < 0) return -1;
+
+ *name = p;
+
+ return 0;
+}
+
+/*
+ * Get an attribute by its numerical value.
+ */
+DICT_ATTR const *dict_attrbyvalue(unsigned int attr, unsigned int vendor)
+{
+ DICT_ATTR da;
+
+ if ((attr > 0) && (attr < 256) && !vendor) return dict_base_attrs[attr];
+
+ da.attr = attr;
+ da.vendor = vendor;
+
+ return fr_hash_table_finddata(attributes_byvalue, &da);
+}
+
+
+/** Get an attribute by its numerical value and data type
+ *
+ * Used only for COMBO_IP
+ *
+ * @return The attribute, or NULL if not found
+ */
+DICT_ATTR const *dict_attrbytype(unsigned int attr, unsigned int vendor,
+ PW_TYPE type)
+{
+ DICT_ATTR da;
+
+ da.attr = attr;
+ da.vendor = vendor;
+ da.type = type;
+
+ return fr_hash_table_finddata(attributes_combo, &da);
+}
+
+/** Using a parent and attr/vendor, find a child attr/vendor
+ *
+ */
+int dict_attr_child(DICT_ATTR const *parent,
+ unsigned int *pattr, unsigned int *pvendor)
+{
+ unsigned int attr, vendor;
+ DICT_ATTR da;
+
+ if (!parent || !pattr || !pvendor) return false;
+
+ attr = *pattr;
+ vendor = *pvendor;
+
+ /*
+ * Only some types can have children
+ */
+ switch (parent->type) {
+ default: return false;
+
+ case PW_TYPE_VSA:
+ case PW_TYPE_TLV:
+ case PW_TYPE_EVS:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ break;
+ }
+
+ if ((vendor == 0) && (parent->vendor != 0)) return false;
+
+ /*
+ * Bootstrap by starting off with the parents values.
+ */
+ da.attr = parent->attr;
+ da.vendor = parent->vendor;
+
+ /*
+ * Do various butchery to insert the "attr" value.
+ *
+ * 00VID 000000AA normal VSA for vendor VID
+ * 00VID DDCCBBAA normal VSAs with TLVs
+ * EE000 000000AA extended attr (241.1)
+ * EE000 DDCCBBAA extended attr with TLVs
+ * EEVID 000000AA EVS with vendor VID, attr AAA
+ * EEVID DDCCBBAA EVS with TLVs
+ */
+ if (!da.vendor) {
+ da.vendor = parent->attr * FR_MAX_VENDOR;
+ da.vendor |= vendor;
+ da.attr = attr;
+
+ } else {
+ int i;
+
+ /*
+ * Trying to nest too deep. It's an error
+ */
+ if (parent->attr & (fr_attr_mask[MAX_TLV_NEST] << fr_attr_shift[MAX_TLV_NEST])) {
+ return false;
+ }
+
+ for (i = MAX_TLV_NEST - 1; i >= 0; i--) {
+ if ((parent->attr & (fr_attr_mask[i] << fr_attr_shift[i]))) {
+ da.attr |= (attr & fr_attr_mask[i + 1]) << fr_attr_shift[i + 1];
+ goto find;
+ }
+ }
+
+ return false;
+ }
+
+find:
+#if 0
+ fprintf(stderr, "LOOKING FOR %08x %08x + %08x %08x --> %08x %08x\n",
+ parent->vendor, parent->attr, attr, vendor,
+ da.vendor, da.attr);
+#endif
+
+ *pattr = da.attr;
+ *pvendor = da.vendor;
+ return true;
+}
+
+/*
+ * Get an attribute by it's numerical value, and the parent
+ */
+DICT_ATTR const *dict_attrbyparent(DICT_ATTR const *parent, unsigned int attr, unsigned int vendor)
+{
+ unsigned int my_attr, my_vendor;
+ DICT_ATTR da;
+
+ my_attr = attr;
+ my_vendor = vendor;
+
+ if (!dict_attr_child(parent, &my_attr, &my_vendor)) return NULL;
+
+ da.attr = my_attr;
+ da.vendor = my_vendor;
+
+ return fr_hash_table_finddata(attributes_byvalue, &da);
+}
+
+
+/*
+ * Get an attribute by its name.
+ */
+DICT_ATTR const *dict_attrbyname(char const *name)
+{
+ DICT_ATTR *da;
+ uint32_t buffer[(sizeof(*da) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
+
+ if (!name) return NULL;
+
+ da = (DICT_ATTR *) buffer;
+ strlcpy(da->name, name, DICT_ATTR_MAX_NAME_LEN + 1);
+
+ da = fr_hash_table_finddata(attributes_byname, da);
+ if (!da) return NULL;
+
+ if (!da->flags.is_dup) return da;
+
+ /*
+ * This MUST exist if the dup flag is set.
+ */
+ return dict_attrbyvalue(da->attr, da->vendor);
+}
+
+/** Look up a dictionary attribute by name embedded in another string
+ *
+ * Find the first invalid attribute name char in the string pointed
+ * to by name.
+ *
+ * Copy the characters between the start of the name string and the first
+ * none dict_attr_allowed_char to a buffer and perform a dictionary lookup
+ * using that value.
+ *
+ * If the attribute exists, advance the pointer pointed to by name
+ * to the first none dict_attr_allowed_char char, and return the DA.
+ *
+ * If the attribute does not exist, don't advance the pointer and return
+ * NULL.
+ *
+ * @param[in,out] name string start.
+ * @return NULL if no attributes matching the name could be found, else
+ */
+DICT_ATTR const *dict_attrbyname_substr(char const **name)
+{
+ DICT_ATTR *find;
+ DICT_ATTR const *da;
+ char const *p;
+ size_t len;
+ uint32_t buffer[(sizeof(*find) + DICT_ATTR_MAX_NAME_LEN + 3)/4];
+
+ if (!name || !*name) return NULL;
+
+ find = (DICT_ATTR *) buffer;
+
+ /*
+ * Advance p until we get something that's not part of
+ * the dictionary attribute name.
+ */
+ for (p = *name; dict_attr_allowed_chars[(int) *p]; p++);
+
+ len = p - *name;
+ if (len > DICT_ATTR_MAX_NAME_LEN) {
+ fr_strerror_printf("Attribute name too long");
+
+ return NULL;
+ }
+ strlcpy(find->name, *name, len + 1);
+
+ da = fr_hash_table_finddata(attributes_byname, find);
+ if (!da) {
+ fr_strerror_printf("Unknown attribute \"%s\"", find->name);
+ return NULL;
+ }
+ *name = p;
+
+ return da;
+}
+
+/*
+ * Associate a value with an attribute and return it.
+ */
+DICT_VALUE *dict_valbyattr(unsigned int attr, unsigned int vendor, int value)
+{
+ DICT_VALUE dval, *dv;
+
+ /*
+ * First, look up aliases.
+ */
+ dval.attr = attr;
+ dval.vendor = vendor;
+ dval.name[0] = '\0';
+
+ /*
+ * Look up the attribute alias target, and use
+ * the correct attribute number if found.
+ */
+ dv = fr_hash_table_finddata(values_byname, &dval);
+ if (dv) dval.attr = dv->value;
+
+ dval.value = value;
+
+ return fr_hash_table_finddata(values_byvalue, &dval);
+}
+
+/*
+ * Associate a value with an attribute and return it.
+ */
+char const *dict_valnamebyattr(unsigned int attr, unsigned int vendor, int value)
+{
+ DICT_VALUE *dv;
+
+ dv = dict_valbyattr(attr, vendor, value);
+ if (!dv) return "";
+
+ return dv->name;
+}
+
+/*
+ * Get a value by its name, keyed off of an attribute.
+ */
+DICT_VALUE *dict_valbyname(unsigned int attr, unsigned int vendor, char const *name)
+{
+ DICT_VALUE *my_dv, *dv;
+ uint32_t buffer[(sizeof(*my_dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4];
+
+ if (!name) return NULL;
+
+ my_dv = (DICT_VALUE *) buffer;
+ my_dv->attr = attr;
+ my_dv->vendor = vendor;
+ my_dv->name[0] = '\0';
+
+ /*
+ * Look up the attribute alias target, and use
+ * the correct attribute number if found.
+ */
+ dv = fr_hash_table_finddata(values_byname, my_dv);
+ if (dv) my_dv->attr = dv->value;
+
+ strlcpy(my_dv->name, name, DICT_VALUE_MAX_NAME_LEN + 1);
+
+ return fr_hash_table_finddata(values_byname, my_dv);
+}
+
+/*
+ * Get the vendor PEC based on the vendor name
+ *
+ * This is efficient only for small numbers of vendors.
+ */
+int dict_vendorbyname(char const *name)
+{
+ DICT_VENDOR *dv;
+ size_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + sizeof(size_t) - 1) / sizeof(size_t)];
+
+ if (!name) return 0;
+
+ dv = (DICT_VENDOR *) buffer;
+ strlcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN + 1);
+
+ dv = fr_hash_table_finddata(vendors_byname, dv);
+ if (!dv) return 0;
+
+ return dv->vendorpec;
+}
+
+/*
+ * Return the vendor struct based on the PEC.
+ */
+DICT_VENDOR *dict_vendorbyvalue(int vendorpec)
+{
+ DICT_VENDOR dv;
+
+ dv.vendorpec = vendorpec;
+
+ return fr_hash_table_finddata(vendors_byvalue, &dv);
+}
+
+/** Converts an unknown to a known by adding it to the internal dictionaries.
+ *
+ * Does not free old DICT_ATTR, that is left up to the caller.
+ *
+ * @param old unknown attribute to add.
+ * @return existing DICT_ATTR if old was found in a dictionary, else the new entry in the dictionary
+ * representing old.
+ */
+DICT_ATTR const *dict_unknown_add(DICT_ATTR const *old)
+{
+ DICT_ATTR const *da, *parent;
+ ATTR_FLAGS flags;
+
+ if (!old) return NULL;
+
+ if (!old->flags.is_unknown) return old;
+
+ da = dict_attrbyvalue(old->attr, old->vendor);
+ if (da) return da;
+
+ memcpy(&flags, &old->flags, sizeof(flags));
+ flags.is_unknown = false;
+
+ parent = dict_parent(old->attr, old->vendor);
+ if (parent) {
+ if (parent->flags.has_tlv) flags.is_tlv = true;
+ flags.evs = parent->flags.evs;
+ flags.extended = parent->flags.extended;
+ flags.long_extended = parent->flags.long_extended;
+ }
+
+ if (dict_addattr(old->name, old->attr, old->vendor, old->type, flags) < 0) {
+ return NULL;
+ }
+
+ da = dict_attrbyvalue(old->attr, old->vendor);
+ return da;
+}
+
+size_t dict_print_oid(char *buffer, size_t buflen, DICT_ATTR const *da)
+{
+ return print_attr_oid(buffer, buflen, da->attr, da->vendor);
+}
+
+int dict_walk(fr_hash_table_walk_t callback, void *context)
+{
+ return fr_hash_table_walk(attributes_byname, callback, context);
+}
diff --git a/src/lib/event.c b/src/lib/event.c
new file mode 100644
index 0000000..9eb9d1a
--- /dev/null
+++ b/src/lib/event.c
@@ -0,0 +1,843 @@
+/*
+ * event.c Non-thread-safe event handling, specific to a RADIUS
+ * server.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/heap.h>
+#include <freeradius-devel/event.h>
+
+#include <pthread.h>
+
+#ifdef HAVE_KQUEUE
+#ifndef HAVE_SYS_EVENT_H
+#error kqueue requires <sys/event.h>
+
+#else
+#include <sys/event.h>
+#endif
+#endif /* HAVE_KQUEUE */
+
+typedef struct fr_event_fd_t {
+ int fd;
+
+ fr_event_fd_handler_t handler;
+ fr_event_fd_handler_t write_handler;
+ void *ctx;
+} fr_event_fd_t;
+
+#define FR_EV_MAX_FDS (512)
+
+#undef USEC
+#define USEC (1000000)
+
+struct fr_event_list_t {
+ fr_heap_t *times;
+
+ int exit;
+
+ fr_event_status_t status;
+
+ struct timeval now;
+ bool dispatch;
+
+ int num_readers;
+#ifndef HAVE_KQUEUE
+ int max_readers;
+ int max_fd;
+
+ fd_set read_fds;
+ fd_set write_fds;
+#else
+ int kq;
+ struct kevent events[FR_EV_MAX_FDS]; /* so it doesn't go on the stack every time */
+#endif
+
+ fr_event_fd_t readers[FR_EV_MAX_FDS];
+};
+
+/*
+ * Internal structure for managing events.
+ */
+struct fr_event_t {
+ fr_event_callback_t callback;
+ void *ctx;
+ struct timeval when;
+ fr_event_t **parent;
+ int heap;
+};
+
+
+static int fr_event_list_time_cmp(void const *one, void const *two)
+{
+ fr_event_t const *a = one;
+ fr_event_t const *b = two;
+
+ if (a->when.tv_sec < b->when.tv_sec) return -1;
+ if (a->when.tv_sec > b->when.tv_sec) return +1;
+
+ if (a->when.tv_usec < b->when.tv_usec) return -1;
+ if (a->when.tv_usec > b->when.tv_usec) return +1;
+
+ return 0;
+}
+
+
+static int _event_list_free(fr_event_list_t *list)
+{
+ fr_event_list_t *el = list;
+ fr_event_t *ev;
+
+ while ((ev = fr_heap_peek(el->times)) != NULL) {
+ fr_event_delete(el, &ev);
+ }
+
+ fr_heap_delete(el->times);
+
+#ifdef HAVE_KQUEUE
+ close(el->kq);
+#endif
+
+ return 0;
+}
+
+
+fr_event_list_t *fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
+{
+ int i;
+ fr_event_list_t *el;
+
+ el = talloc_zero(ctx, fr_event_list_t);
+ if (!fr_assert(el)) {
+ return NULL;
+ }
+ talloc_set_destructor(el, _event_list_free);
+
+ el->times = fr_heap_create(fr_event_list_time_cmp, offsetof(fr_event_t, heap));
+ if (!el->times) {
+ talloc_free(el);
+ return NULL;
+ }
+
+ for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ el->readers[i].fd = -1;
+ }
+
+#ifndef HAVE_KQUEUE
+ el->max_fd = 0;
+ FD_ZERO(&el->read_fds);
+ FD_ZERO(&el->write_fds);
+#else
+ el->kq = kqueue();
+ if (el->kq < 0) {
+ talloc_free(el);
+ return NULL;
+ }
+#endif
+
+ el->status = status;
+
+ return el;
+}
+
+int fr_event_list_num_fds(fr_event_list_t *el)
+{
+ if (!el) return 0;
+
+ return el->num_readers;
+}
+
+int fr_event_list_num_elements(fr_event_list_t *el)
+{
+ if (!el) return 0;
+
+ return fr_heap_num_elements(el->times);
+}
+
+
+int fr_event_delete(fr_event_list_t *el, fr_event_t **parent)
+{
+ int ret;
+
+ fr_event_t *ev;
+
+ if (!el || !parent || !*parent) return 0;
+
+#ifndef NDEBUG
+ /*
+ * Validate the event_t struct to detect memory issues early.
+ */
+ ev = talloc_get_type_abort(*parent, fr_event_t);
+
+#else
+ ev = *parent;
+#endif
+
+ if (ev->parent) {
+ fr_assert(*(ev->parent) == ev);
+ *ev->parent = NULL;
+ }
+ *parent = NULL;
+
+ ret = fr_heap_extract(el->times, ev);
+ fr_assert(ret == 1); /* events MUST be in the heap */
+ talloc_free(ev);
+
+ return ret;
+}
+
+
+int fr_event_insert(fr_event_list_t *el, fr_event_callback_t callback, void *ctx, struct timeval *when,
+ fr_event_t **parent)
+{
+ fr_event_t *ev;
+
+ if (!el) {
+ fr_strerror_printf("Invalid arguments (NULL event list)");
+ return 0;
+ }
+
+ if (!callback) {
+ fr_strerror_printf("Invalid arguments (NULL callback)");
+ return 0;
+ }
+
+ if (!when || (when->tv_usec >= USEC)) {
+ fr_strerror_printf("Invalid arguments (time)");
+ return 0;
+ }
+
+ if (!parent) {
+ fr_strerror_printf("Invalid arguments (NULL parent)");
+ return 0;
+ }
+
+ /*
+ * If there is an event, re-use it instead of freeing it
+ * and allocating a new one.
+ */
+ if (*parent) {
+ int ret;
+
+#ifndef NDEBUG
+ ev = talloc_get_type_abort(*parent, fr_event_t);
+#else
+ ev = *parent;
+#endif
+
+ ret = fr_heap_extract(el->times, ev);
+ fr_assert(ret == 1); /* events MUST be in the heap */
+
+ memset(ev, 0, sizeof(*ev));
+ } else {
+ ev = talloc_zero(el, fr_event_t);
+ if (!ev) return 0;
+ }
+
+ ev->callback = callback;
+ ev->ctx = ctx;
+ ev->when = *when;
+ ev->parent = parent;
+
+ if (!fr_heap_insert(el->times, ev)) {
+ talloc_free(ev);
+ return 0;
+ }
+
+ *parent = ev;
+ return 1;
+}
+
+
+int fr_event_run(fr_event_list_t *el, struct timeval *when)
+{
+ fr_event_callback_t callback;
+ void *ctx;
+ fr_event_t *ev;
+
+ if (!el) return 0;
+
+ if (fr_heap_num_elements(el->times) == 0) {
+ when->tv_sec = 0;
+ when->tv_usec = 0;
+ return 0;
+ }
+
+ ev = fr_heap_peek(el->times);
+ if (!ev) {
+ when->tv_sec = 0;
+ when->tv_usec = 0;
+ return 0;
+ }
+
+#ifndef NDEBUG
+ ev = talloc_get_type_abort(ev, fr_event_t);
+#endif
+
+ /*
+ * See if it's time to do this one.
+ */
+ if ((ev->when.tv_sec > when->tv_sec) ||
+ ((ev->when.tv_sec == when->tv_sec) &&
+ (ev->when.tv_usec > when->tv_usec))) {
+ *when = ev->when;
+ return 0;
+ }
+
+ callback = ev->callback;
+ ctx = ev->ctx;
+
+ /*
+ * Delete the event before calling it.
+ */
+ fr_event_delete(el, ev->parent);
+
+ callback(ctx);
+ return 1;
+}
+
+
+int fr_event_now(fr_event_list_t *el, struct timeval *when)
+{
+ if (!when) return 0;
+
+ if (el && el->dispatch) {
+ *when = el->now;
+ } else {
+ gettimeofday(when, NULL);
+ }
+
+ return 1;
+}
+
+
+int fr_event_fd_insert(fr_event_list_t *el, int type, int fd,
+ fr_event_fd_handler_t handler, void *ctx)
+{
+ int i;
+ fr_event_fd_t *ef;
+
+ if (!el) {
+ fr_strerror_printf("Invalid arguments (NULL event list)");
+ return 0;
+ }
+
+ if (!handler) {
+ fr_strerror_printf("Invalid arguments (NULL handler)");
+ return 0;
+ }
+
+ if (!ctx) {
+ fr_strerror_printf("Invalid arguments (NULL ctx)");
+ return 0;
+ }
+
+ if (fd < 0) {
+ fr_strerror_printf("Invalid arguments (bad FD %i)", fd);
+ return 0;
+ }
+
+ if (type != 0) {
+ fr_strerror_printf("Invalid type %i", type);
+ return 0;
+ }
+
+ if (el->num_readers >= FR_EV_MAX_FDS) {
+ fr_strerror_printf("Too many readers");
+ return 0;
+ }
+ ef = NULL;
+
+#ifdef HAVE_KQUEUE
+ /*
+ * We need to store TWO fields with the event. kqueue
+ * only lets us store one. If we put the two fields into
+ * a malloc'd structure, that would help. Except that
+ * kqueue can silently delete the event when the socket
+ * is closed, and not give us the opportunity to free it.
+ * <sigh>
+ *
+ * The solution is to put the fields into an array, and
+ * do a linear search on addition/deletion of the FDs.
+ * However, to avoid MOST linear issues, we start off the
+ * search at "FD" offset. Since FDs are unique, AND
+ * usually less than 256, we do "FD & 0xff", which is a
+ * good guess, and makes the lookups mostly O(1).
+ */
+ for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ int j;
+ struct kevent evset;
+
+ j = (i + fd) & (FR_EV_MAX_FDS - 1);
+
+ if (el->readers[j].fd >= 0) continue;
+
+ /*
+ * We want to read from the FD.
+ */
+ EV_SET(&evset, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, &el->readers[j]);
+ if (kevent(el->kq, &evset, 1, NULL, 0, NULL) < 0) {
+ fr_strerror_printf("Failed inserting event for FD %i: %s", fd, fr_syserror(errno));
+ return 0;
+ }
+
+ ef = &el->readers[j];
+ el->num_readers++;
+ break;
+ }
+
+#else /* HAVE_KQUEUE */
+
+ /*
+ * select() has limits.
+ */
+ if (fd > FD_SETSIZE) {
+ fprintf(stderr, "FD is larger than FD_SETSIZE");
+ return 0;
+ }
+
+ for (i = 0; i <= el->max_readers; i++) {
+ /*
+ * Be fail-safe on multiple inserts.
+ */
+ if (el->readers[i].fd == fd) {
+ if ((el->readers[i].handler != handler) ||
+ (el->readers[i].ctx != ctx)) {
+ fr_strerror_printf("Multiple handlers for same FD");
+ return 0;
+ }
+
+ /*
+ * No change.
+ */
+ return 1;
+ }
+
+ if (el->readers[i].fd < 0) {
+ ef = &el->readers[i];
+ el->num_readers++;
+
+ if (i == el->max_readers) el->max_readers = i + 1;
+
+ FD_SET(fd, &el->read_fds);
+ if (el->max_fd <= fd) el->max_fd = fd;
+ break;
+ }
+ }
+#endif
+
+ if (!ef) {
+ fr_strerror_printf("Failed assigning FD");
+ return 0;
+ }
+
+ ef->fd = fd;
+ ef->handler = handler;
+ ef->ctx = ctx;
+
+ return 1;
+}
+
+int fr_event_fd_write_handler(fr_event_list_t *el, int type, int fd,
+ fr_event_fd_handler_t write_handler, void *ctx)
+{
+ int i;
+
+ if (!el || (fd < 0)) return 0;
+
+ if (type != 0) return 0;
+
+#ifdef HAVE_KQUEUE
+ for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ int j;
+ struct kevent evset;
+
+ j = (i + fd) & (FR_EV_MAX_FDS - 1);
+
+ if (el->readers[j].fd != fd) continue;
+
+ fr_assert(ctx = el->readers[j].ctx);
+
+ /*
+ * Tell us when the socket is ready for writing
+ */
+ if (write_handler) {
+ fr_assert(!el->readers[j].write_handler);
+
+ el->readers[j].write_handler = write_handler;
+
+ EV_SET(&evset, fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, &el->readers[j]);
+ } else {
+ fr_assert(el->readers[j].write_handler);
+
+ el->readers[j].write_handler = NULL;
+
+ EV_SET(&evset, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ }
+ if (kevent(el->kq, &evset, 1, NULL, 0, NULL) < 0) {
+ fr_strerror_printf("Failed inserting event for FD %i: %s", fd, fr_syserror(errno));
+ return 0;
+ }
+
+ return 1;
+ }
+
+#else
+
+ for (i = 0; i < el->max_readers; i++) {
+ if (el->readers[i].fd != fd) continue;
+
+ fr_assert(ctx = el->readers[i].ctx);
+ el->readers[i].write_handler = write_handler;
+
+ FD_SET(fd, &el->write_fds); /* fd MUST already be in the set of readers! */
+ return 1;
+ }
+#endif /* HAVE_KQUEUE */
+
+ return 0;
+}
+
+int fr_event_fd_delete(fr_event_list_t *el, int type, int fd)
+{
+ int i;
+
+ if (!el || (fd < 0)) return 0;
+
+ if (type != 0) return 0;
+
+#ifdef HAVE_KQUEUE
+ for (i = 0; i < FR_EV_MAX_FDS; i++) {
+ int j;
+ struct kevent evset;
+
+ j = (i + fd) & (FR_EV_MAX_FDS - 1);
+
+ if (el->readers[j].fd != fd) continue;
+
+ /*
+ * Tell the kernel to delete it from the list.
+ *
+ * The caller MAY have closed it, in which case
+ * the kernel has removed it from the list. So
+ * we ignore the return code from kevent().
+ */
+ EV_SET(&evset, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ (void) kevent(el->kq, &evset, 1, NULL, 0, NULL);
+
+ /*
+ * Delete the write handler if it exits.
+ */
+ if (el->readers[j].write_handler) {
+ EV_SET(&evset, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ (void) kevent(el->kq, &evset, 1, NULL, 0, NULL);
+ }
+
+ el->readers[j].fd = -1;
+ el->num_readers--;
+
+ return 1;
+ }
+
+#else
+ for (i = 0; i < el->max_readers; i++) {
+ if (el->readers[i].fd == fd) {
+ el->readers[i].fd = -1;
+ el->num_readers--;
+
+ if ((i + 1) == el->max_readers) el->max_readers = i;
+ FD_CLR(fd, &el->read_fds);
+ FD_CLR(fd, &el->write_fds);
+
+ /*
+ * @todo - update el->max_fd, too.
+ */
+ return 1;
+ }
+ }
+#endif /* HAVE_KQUEUE */
+
+ return 0;
+}
+
+
+void fr_event_loop_exit(fr_event_list_t *el, int code)
+{
+ if (!el) return;
+
+ el->exit = code;
+}
+
+bool fr_event_loop_exiting(fr_event_list_t *el)
+{
+ return (el->exit != 0);
+}
+
+int fr_event_loop(fr_event_list_t *el)
+{
+ int i, rcode;
+ struct timeval when, *wake;
+#ifdef HAVE_KQUEUE
+ struct timespec ts_when, *ts_wake;
+#else
+ fd_set read_fds, write_fds;
+#endif
+
+ el->exit = 0;
+ el->dispatch = true;
+
+ while (!el->exit) {
+ /*
+ * Find the first event. If there's none, we wait
+ * on the socket forever.
+ */
+ when.tv_sec = 0;
+ when.tv_usec = 0;
+
+ if (fr_heap_num_elements(el->times) > 0) {
+ fr_event_t *ev;
+
+ ev = fr_heap_peek(el->times);
+ if (!ev) {
+ fr_exit_now(42);
+ }
+
+ gettimeofday(&el->now, NULL);
+
+ if (timercmp(&el->now, &ev->when, <)) {
+ when = ev->when;
+ when.tv_sec -= el->now.tv_sec;
+
+ if (when.tv_sec > 0) {
+ when.tv_sec--;
+ when.tv_usec += USEC;
+ } else {
+ when.tv_sec = 0;
+ }
+ when.tv_usec -= el->now.tv_usec;
+ if (when.tv_usec >= USEC) {
+ when.tv_usec -= USEC;
+ when.tv_sec++;
+ }
+ } else { /* we've passed the event time */
+ when.tv_sec = 0;
+ when.tv_usec = 0;
+ }
+
+ wake = &when;
+ } else {
+ wake = NULL;
+ }
+
+ /*
+ * Tell someone what the status is.
+ */
+ if (el->status) el->status(wake);
+
+#ifndef HAVE_KQUEUE
+ read_fds = el->read_fds;
+ write_fds = el->write_fds;
+ rcode = select(el->max_fd + 1, &read_fds, &write_fds, NULL, wake);
+ if ((rcode < 0) && (errno != EINTR)) {
+ fr_strerror_printf("Failed in select: %s", fr_syserror(errno));
+ el->dispatch = false;
+ return -1;
+ }
+
+#else /* HAVE_KQUEUE */
+
+ if (wake) {
+ ts_wake = &ts_when;
+ ts_when.tv_sec = when.tv_sec;
+ ts_when.tv_nsec = when.tv_usec * 1000;
+
+ } else {
+ ts_wake = NULL;
+ }
+
+ rcode = kevent(el->kq, NULL, 0, el->events, FR_EV_MAX_FDS, ts_wake);
+#endif /* HAVE_KQUEUE */
+
+ if (fr_heap_num_elements(el->times) > 0) {
+ do {
+ gettimeofday(&el->now, NULL);
+ when = el->now;
+ } while (fr_event_run(el, &when) == 1);
+ }
+
+ if (rcode <= 0) continue;
+
+#ifndef HAVE_KQUEUE
+ /*
+ * Loop over all of the sockets to see if there's
+ * an event for that socket.
+ */
+ for (i = 0; i < el->max_readers; i++) {
+ fr_event_fd_t *ef = &el->readers[i];
+
+ if (ef->fd < 0) continue;
+
+ /*
+ * Check if the socket is available for writing.
+ */
+ if (ef->write_handler && FD_ISSET(ef->fd, &write_fds)) {
+ ef->write_handler(el, ef->fd, ef->ctx);
+ }
+
+ if (!FD_ISSET(ef->fd, &read_fds)) continue;
+
+ ef->handler(el, ef->fd, ef->ctx);
+ }
+
+#else /* HAVE_KQUEUE */
+
+ /*
+ * Loop over all of the events, servicing them.
+ */
+ for (i = 0; i < rcode; i++) {
+ fr_event_fd_t *ef = el->events[i].udata;
+
+ if (el->events[i].flags & EV_EOF) {
+ /*
+ * FIXME: delete the handler
+ * here, and fix process.c to not
+ * call fr_event_fd_delete().
+ * It's cleaner.
+ *
+ * Call the handler, which SHOULD
+ * delete the connection.
+ */
+ ef->handler(el, ef->fd, ef->ctx);
+ continue;
+ }
+
+ if (el->events[i].filter == EVFILT_WRITE) {
+ ef->write_handler(el, ef->fd, ef->ctx);
+ continue;
+ }
+
+ /*
+ * Else it's our event. We only set
+ * EVFILT_READ, so it must be a read
+ * event.
+ */
+ ef->handler(el, ef->fd, ef->ctx);
+ }
+#endif /* HAVE_KQUEUE */
+ }
+
+ el->dispatch = false;
+ return el->exit;
+}
+
+
+#ifdef TESTING
+
+/*
+ * cc -g -I .. -c rbtree.c -o rbtree.o && cc -g -I .. -c isaac.c -o isaac.o && cc -DTESTING -I .. -c event.c -o event_mine.o && cc event_mine.o rbtree.o isaac.o -o event
+ *
+ * ./event
+ *
+ * And hit CTRL-S to stop the output, CTRL-Q to continue.
+ * It normally alternates printing the time and sleeping,
+ * but when you hit CTRL-S/CTRL-Q, you should see a number
+ * of events run right after each other.
+ *
+ * OR
+ *
+ * valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./event
+ */
+
+static void print_time(void *ctx)
+{
+ struct timeval *when = ctx;
+
+ printf("%d.%06d\n", when->tv_sec, when->tv_usec);
+ fflush(stdout);
+}
+
+static fr_randctx rand_pool;
+
+static uint32_t event_rand(void)
+{
+ uint32_t num;
+
+ num = rand_pool.randrsl[rand_pool.randcnt++ & 0xff];
+ if (rand_pool.randcnt == 256) {
+ fr_isaac(&rand_pool);
+ rand_pool.randcnt = 0;
+ }
+
+ return num;
+}
+
+
+#define MAX 100
+int main(int argc, char **argv)
+{
+ int i, rcode;
+ struct timeval array[MAX];
+ struct timeval now, when;
+ fr_event_list_t *el;
+
+ el = fr_event_list_create(NULL, NULL);
+ if (!el) exit(1);
+
+ memset(&rand_pool, 0, sizeof(rand_pool));
+ rand_pool.randrsl[1] = time(NULL);
+
+ fr_randinit(&rand_pool, 1);
+ rand_pool.randcnt = 0;
+
+ gettimeofday(&array[0], NULL);
+ for (i = 1; i < MAX; i++) {
+ array[i] = array[i - 1];
+
+ array[i].tv_usec += event_rand() & 0xffff;
+ if (array[i].tv_usec > 1000000) {
+ array[i].tv_usec -= 1000000;
+ array[i].tv_sec++;
+ }
+ fr_event_insert(el, print_time, &array[i], &array[i]);
+ }
+
+ while (fr_event_list_num_elements(el)) {
+ gettimeofday(&now, NULL);
+ when = now;
+ if (!fr_event_run(el, &when)) {
+ int delay = (when.tv_sec - now.tv_sec) * 1000000;
+ delay += when.tv_usec;
+ delay -= now.tv_usec;
+
+ printf("\tsleep %d\n", delay);
+ fflush(stdout);
+ usleep(delay);
+ }
+ }
+
+ talloc_free(el);
+
+ return 0;
+}
+#endif
diff --git a/src/lib/fifo.c b/src/lib/fifo.c
new file mode 100644
index 0000000..7a9ecfa
--- /dev/null
+++ b/src/lib/fifo.c
@@ -0,0 +1,197 @@
+/*
+ * fifo.c Non-thread-safe fifo (FIFO) implementation, based
+ * on hash tables.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006 The FreeRADIUS server project
+ * Copyright 2005 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+struct fr_fifo_t {
+ unsigned int num;
+ unsigned int first, last;
+ unsigned int max;
+ fr_fifo_free_t freeNode;
+
+ void *data[1];
+};
+
+
+fr_fifo_t *fr_fifo_create(TALLOC_CTX *ctx, int max, fr_fifo_free_t freeNode)
+{
+ fr_fifo_t *fi;
+
+ if ((max < 2) || (max > (1024 * 1024))) return NULL;
+
+ fi = talloc_zero_size(ctx, (sizeof(*fi) + (sizeof(fi->data[0])*max)));
+ if (!fi) return NULL;
+ talloc_set_type(fi, fr_fifo_t);
+
+ fi->max = max;
+ fi->freeNode = freeNode;
+
+ return fi;
+}
+
+void fr_fifo_free(fr_fifo_t *fi)
+{
+ unsigned int i;
+
+ if (!fi) return;
+
+ if (fi->freeNode) {
+ for (i = 0 ; i < fi->num; i++) {
+ unsigned int element;
+
+ element = i + fi->first;
+ if (element > fi->max) {
+ element -= fi->max;
+ }
+
+ fi->freeNode(fi->data[element]);
+ fi->data[element] = NULL;
+ }
+ }
+
+ memset(fi, 0, sizeof(*fi));
+ talloc_free(fi);
+}
+
+int fr_fifo_push(fr_fifo_t *fi, void *data)
+{
+ if (!fi || !data) return 0;
+
+ if (fi->num >= fi->max) return 0;
+
+ fi->data[fi->last++] = data;
+ if (fi->last >= fi->max) fi->last = 0;
+ fi->num++;
+
+ return 1;
+}
+
+void *fr_fifo_pop(fr_fifo_t *fi)
+{
+ void *data;
+
+ if (!fi || (fi->num == 0)) return NULL;
+
+ data = fi->data[fi->first++];
+
+ if (fi->first >= fi->max) {
+ fi->first = 0;
+ }
+ fi->num--;
+
+ return data;
+}
+
+void *fr_fifo_peek(fr_fifo_t *fi)
+{
+ if (!fi || (fi->num == 0)) return NULL;
+
+ return fi->data[fi->first];
+}
+
+unsigned int fr_fifo_num_elements(fr_fifo_t *fi)
+{
+ if (!fi) return 0;
+
+ return fi->num;
+}
+
+#ifdef TESTING
+
+/*
+ * cc -DTESTING -I .. fifo.c -o fifo
+ *
+ * ./fifo
+ */
+
+#define MAX 1024
+int main(int argc, char **argv)
+{
+ int i, j, array[MAX];
+ fr_fifo_t *fi;
+
+ fi = fr_fifo_create(NULL, MAX, NULL);
+ if (!fi) fr_exit(1);
+
+ for (j = 0; j < 5; j++) {
+#define SPLIT (MAX/3)
+#define COUNT ((j * SPLIT) + i)
+ for (i = 0; i < SPLIT; i++) {
+ array[COUNT % MAX] = COUNT;
+
+ if (!fr_fifo_push(fi, &array[COUNT % MAX])) {
+ fprintf(stderr, "%d %d\tfailed pushing %d\n",
+ j, i, COUNT);
+ fr_exit(2);
+ }
+
+ if (fr_fifo_num_elements(fi) != (i + 1)) {
+ fprintf(stderr, "%d %d\tgot size %d expected %d\n",
+ j, i, i + 1, fr_fifo_num_elements(fi));
+ fr_exit(1);
+ }
+ }
+
+ if (fr_fifo_num_elements(fi) != SPLIT) {
+ fprintf(stderr, "HALF %d %d\n",
+ fr_fifo_num_elements(fi), SPLIT);
+ fr_exit(1);
+ }
+
+ for (i = 0; i < SPLIT; i++) {
+ int *p;
+
+ p = fr_fifo_pop(fi);
+ if (!p) {
+ fprintf(stderr, "No pop at %d\n", i);
+ fr_exit(3);
+ }
+
+ if (*p != COUNT) {
+ fprintf(stderr, "%d %d\tgot %d expected %d\n",
+ j, i, *p, COUNT);
+ fr_exit(4);
+ }
+
+ if (fr_fifo_num_elements(fi) != SPLIT - (i + 1)) {
+ fprintf(stderr, "%d %d\tgot size %d expected %d\n",
+ j, i, SPLIT - (i + 1), fr_fifo_num_elements(fi));
+ fr_exit(1);
+ }
+ }
+
+ if (fr_fifo_num_elements(fi) != 0) {
+ fprintf(stderr, "ZERO %d %d\n",
+ fr_fifo_num_elements(fi), 0);
+ fr_exit(1);
+ }
+ }
+
+ fr_fifo_free(fi);
+
+ fr_exit(0);
+}
+#endif
diff --git a/src/lib/filters.c b/src/lib/filters.c
new file mode 100644
index 0000000..3f3b63d
--- /dev/null
+++ b/src/lib/filters.c
@@ -0,0 +1,1253 @@
+/*
+ * filters.c Routines to parse Ascend's filter attributes.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef WITH_ASCEND_BINARY
+#include <ctype.h>
+
+/*
+ * Two types of filters are supported, GENERIC and IP. The identifiers
+ * are:
+ */
+
+#define RAD_FILTER_GENERIC 0
+#define RAD_FILTER_IP 1
+#define RAD_FILTER_IPX 2
+
+/*
+ * Generic filters mask and match up to RAD_MAX_FILTER_LEN bytes
+ * starting at some offset. The length is:
+ */
+#define RAD_MAX_FILTER_LEN 6
+
+/*
+ * ASCEND extensions for ABINARY filters
+ */
+
+#define IPX_NODE_ADDR_LEN 6
+
+#if ! defined( false )
+# define false 0
+# define true (! false)
+#endif
+
+
+/*
+ * ascend_ip_filter_t
+ *
+ * The binary format of an IP filter. ALL fields are stored in
+ * network byte order.
+ *
+ * srcip: The source IP address.
+ *
+ * dstip: The destination IP address.
+ *
+ * srcmask: The number of leading one bits in the source address
+ * mask. Specifies the bits of interest.
+ *
+ * dstmask: The number of leading one bits in the destination
+ * address mask. Specifies the bits of interest.
+ *
+ * proto: The IP protocol number
+ *
+ * established: A boolean value. true when we care about the
+ * established state of a TCP connection. false when
+ * we dont care.
+ *
+ * srcport: TCP or UDP source port number.
+ *
+ * dstport: TCP or UDP destination port number.
+ *
+ * srcPortCmp: One of the values of the RadFilterComparison
+ * enumeration, specifying how to compare the
+ * srcport value.
+ *
+ * dstPortCmp: One of the values of the RadFilterComparison
+ * enumeration, specifying how to compare the
+ * dstport value.
+ *
+ * fill: Round things out to a int16_t boundary.
+ */
+typedef struct ascend_ip_filter_t {
+ uint32_t srcip;
+ uint32_t dstip;
+ uint8_t srcmask;
+ uint8_t dstmask;
+ uint8_t proto;
+ uint8_t established;
+ uint16_t srcport;
+ uint16_t dstport;
+ uint8_t srcPortComp;
+ uint8_t dstPortComp;
+ unsigned char fill[4]; /* used to be fill[2] */
+} ascend_ip_filter_t;
+
+
+/*
+ * ascend_ipx_net_t
+ *
+ * net: IPX Net address
+ *
+ * node: IPX Node address
+ *
+ * socket: IPX socket address
+ */
+typedef struct ascend_ipx_net_t {
+ uint32_t net;
+ uint8_t node[IPX_NODE_ADDR_LEN];
+ uint16_t socket;
+} ascend_ipx_net_t;
+
+/*
+ * ascend_ipx_filter_t
+ *
+ * The binary format of an IPX filter. ALL fields are stored in
+ * network byte order.
+ *
+ * src: Source net, node, and socket.
+ *
+ * dst: Destination net, node, and socket.
+ *
+ * srcSocComp: Source socket compare value
+ *
+ * dstSocComp: Destination socket compare value
+ */
+typedef struct ascend_ipx_filter_t {
+ ascend_ipx_net_t src;
+ ascend_ipx_net_t dst;
+ uint8_t srcSocComp;
+ uint8_t dstSocComp;
+} ascend_ipx_filter_t;
+
+
+/*
+ * ascend_generic_filter_t
+ *
+ * The binary format of a GENERIC filter. ALL fields are stored in
+ * network byte order.
+ *
+ * offset: Number of bytes into packet to start comparison.
+ *
+ * len: Number of bytes to mask and compare. May not
+ * exceed RAD_MAX_FILTER_LEN.
+ *
+ * more: Boolean. If non-zero the next filter entry is
+ * also to be applied to a packet.
+ *
+ * mask: A bit mask specifying the bits to compare.
+ *
+ * value: A value to compare against the masked bits at
+ * offset in a users packet.
+ *
+ * compNeq: Defines type of comarison (Equal or Notequal)
+ * default is Equal.
+ *
+ * fill: Round things out to a dword boundary
+ */
+typedef struct ascend_generic_filter_t {
+ uint16_t offset;
+ uint16_t len;
+ uint16_t more;
+ uint8_t mask[ RAD_MAX_FILTER_LEN ];
+ uint8_t value[ RAD_MAX_FILTER_LEN ];
+ uint8_t compNeq;
+ uint8_t fill[3]; /* used to be fill[1] */
+} ascend_generic_filter_t;
+
+/*
+ * ascend_filter_t
+ *
+ * A binary filter element. Contains one of ascend_ip_filter_t,
+ * ascend_ipx_filter_t, or ascend_generic_filter_t.
+ *
+ * All fields are stored in network byte order.
+ *
+ * type: Either RAD_FILTER_GENERIC or RAD_FILTER_IP.
+ *
+ * forward: true if we should forward packets that match this
+ * filter, false if we should drop packets that match
+ * this filter.
+ *
+ * direction: true if this is an input filter, false if this is
+ * an output filter.
+ *
+ * fill: Round things out to a dword boundary.
+ *
+ * u: A union of
+ * ip: An ip filter entry
+ * generic: A generic filter entry
+ */
+typedef struct ascend_filter_t {
+ uint8_t type;
+ uint8_t forward;
+ uint8_t direction;
+ uint8_t fill;
+ union {
+ ascend_ip_filter_t ip;
+ ascend_ipx_filter_t ipx;
+ ascend_generic_filter_t generic;
+ uint8_t data[28]; /* ensure it's 32 bytes */
+ } u;
+} ascend_filter_t;
+
+/*
+ * This is a wild C hack...
+ */
+typedef struct _cpp_hack {
+ char data[(sizeof(ascend_filter_t) == 32) ? 1 : -1 ];
+} _cpp_hack;
+
+/*
+ * FilterPortType:
+ *
+ * Ascii names of some well known tcp/udp services.
+ * Used for filtering on a port type.
+ *
+ * ??? What the heck is wrong with getservbyname?
+ */
+static const FR_NAME_NUMBER filterPortType[] = {
+ { "ftp-data", 20 },
+ { "ftp", 21 },
+ { "telnet", 23 },
+ { "smtp", 25 },
+ { "nameserver", 42 },
+ { "domain", 53 },
+ { "tftp", 69 },
+ { "gopher", 70 },
+ { "finger", 79 },
+ { "www", 80 },
+ { "kerberos", 88 },
+ { "hostname", 101 },
+ { "nntp", 119 },
+ { "ntp", 123 },
+ { "exec", 512 },
+ { "login", 513 },
+ { "cmd", 514 },
+ { "talk", 517 },
+ { NULL , 0},
+};
+
+static const FR_NAME_NUMBER filterType[] = {
+ { "generic", RAD_FILTER_GENERIC},
+ { "ip", RAD_FILTER_IP},
+ { "ipx", RAD_FILTER_IPX},
+ { NULL, 0},
+};
+
+typedef enum {
+ FILTER_GENERIC_TYPE,
+ FILTER_IP_TYPE,
+ FILTER_IN,
+ FILTER_OUT,
+ FILTER_FORWARD,
+ FILTER_DROP,
+ FILTER_GENERIC_OFFSET,
+ FILTER_GENERIC_MASK,
+ FILTER_GENERIC_VALUE,
+ FILTER_GENERIC_COMPNEQ,
+ FILTER_GENERIC_COMPEQ,
+ FILTER_MORE,
+ FILTER_IP_DST,
+ FILTER_IP_SRC,
+ FILTER_IP_PROTO,
+ FILTER_IP_DST_PORT,
+ FILTER_IP_SRC_PORT,
+ FILTER_EST,
+ FILTER_IPX_TYPE,
+ FILTER_IPX_DST_IPXNET,
+ FILTER_IPX_DST_IPXNODE,
+ FILTER_IPX_DST_IPXSOCK,
+ FILTER_IPX_SRC_IPXNET,
+ FILTER_IPX_SRC_IPXNODE,
+ FILTER_IPX_SRC_IPXSOCK
+} FilterTokens;
+
+
+static const FR_NAME_NUMBER filterKeywords[] = {
+ { "ip", FILTER_IP_TYPE },
+ { "generic", FILTER_GENERIC_TYPE },
+ { "in", FILTER_IN },
+ { "out", FILTER_OUT },
+ { "forward", FILTER_FORWARD },
+ { "drop", FILTER_DROP },
+ { "dstip", FILTER_IP_DST },
+ { "srcip", FILTER_IP_SRC },
+ { "dstport", FILTER_IP_DST_PORT },
+ { "srcport", FILTER_IP_SRC_PORT },
+ { "est", FILTER_EST },
+ { "more", FILTER_MORE },
+ { "!=", FILTER_GENERIC_COMPNEQ },
+ { "==", FILTER_GENERIC_COMPEQ },
+ { "ipx", FILTER_IPX_TYPE },
+ { "dstipxnet", FILTER_IPX_DST_IPXNET },
+ { "dstipxnode", FILTER_IPX_DST_IPXNODE },
+ { "dstipxsock", FILTER_IPX_DST_IPXSOCK },
+ { "srcipxnet", FILTER_IPX_SRC_IPXNET },
+ { "srcipxnode", FILTER_IPX_SRC_IPXNODE },
+ { "srcipxsock", FILTER_IPX_SRC_IPXSOCK },
+ { NULL , -1},
+};
+
+/*
+ * FilterProtoName:
+ *
+ * Ascii name of protocols used for filtering.
+ *
+ * ??? What the heck is wrong with getprotobyname?
+ */
+static const FR_NAME_NUMBER filterProtoName[] = {
+ { "tcp", 6 },
+ { "udp", 17 },
+ { "ospf", 89 },
+ { "icmp", 1 },
+ { "0", 0 },
+ { NULL , -1 },
+};
+
+
+/*
+ * RadFilterComparison:
+ *
+ * An enumerated values for the IP filter port comparisons.
+ */
+typedef enum {
+ RAD_NO_COMPARE = 0,
+ RAD_COMPARE_LESS,
+ RAD_COMPARE_EQUAL,
+ RAD_COMPARE_GREATER,
+ RAD_COMPARE_NOT_EQUAL
+} RadFilterComparison;
+
+static const FR_NAME_NUMBER filterCompare[] = {
+ { "<", RAD_COMPARE_LESS },
+ { "=", RAD_COMPARE_EQUAL },
+ { ">", RAD_COMPARE_GREATER },
+ { "!=", RAD_COMPARE_NOT_EQUAL },
+ { NULL, 0 },
+};
+
+
+/*
+ * ascend_parse_ipx_net
+ *
+ * srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]
+ */
+static int ascend_parse_ipx_net(int argc, char **argv,
+ ascend_ipx_net_t *net, uint8_t *comp)
+{
+ int token;
+ char const *p;
+
+ if (argc < 3) return -1;
+
+ /*
+ * Parse the net, which is a hex number.
+ */
+ net->net = htonl(strtol(argv[0], NULL, 16));
+
+ /*
+ * Parse the node.
+ */
+ token = fr_str2int(filterKeywords, argv[1], -1);
+ switch (token) {
+ case FILTER_IPX_SRC_IPXNODE:
+ case FILTER_IPX_DST_IPXNODE:
+ break;
+
+ default:
+ return -1;
+ }
+
+ /*
+ * Can have a leading "0x" or "0X"
+ */
+ p = argv[2];
+ if ((memcmp(p, "0X", 2) == 0) ||
+ (memcmp(p, "0x", 2) == 0)) p += 2;
+
+ /*
+ * Node must be 6 octets long.
+ */
+ token = fr_hex2bin(net->node, IPX_NODE_ADDR_LEN, p, strlen(p));
+ if (token != IPX_NODE_ADDR_LEN) return -1;
+
+ /*
+ * Nothing more, die.
+ */
+ if (argc == 3) return 3;
+
+ /*
+ * Can't be too little or too much.
+ */
+ if (argc != 6) return -1;
+
+ /*
+ * Parse the socket.
+ */
+ token = fr_str2int(filterKeywords, argv[3], -1);
+ switch (token) {
+ case FILTER_IPX_SRC_IPXSOCK:
+ case FILTER_IPX_DST_IPXSOCK:
+ break;
+
+ default:
+ return -1;
+ }
+
+ /*
+ * Parse the command "<", ">", "=" or "!="
+ */
+ token = fr_str2int(filterCompare, argv[4], -1);
+ switch (token) {
+ case RAD_COMPARE_LESS:
+ case RAD_COMPARE_EQUAL:
+ case RAD_COMPARE_GREATER:
+ case RAD_COMPARE_NOT_EQUAL:
+ *comp = token;
+ break;
+
+ default:
+ return -1;
+ }
+
+ /*
+ * Parse the value.
+ */
+ token = strtoul(argv[5], NULL, 16);
+ if (token > 65535) return -1;
+
+ net->socket = token;
+ net->socket = htons(net->socket);
+
+
+ /*
+ * Everything's OK, we parsed 6 entries.
+ */
+ return 6;
+}
+
+/*
+ * ascend_parse_ipx_filter
+ *
+ * This routine parses an IPX filter string from a string.
+ * The format of the string is:
+ *
+ * [ srcipxnet nnnn srcipxnode mmmmm [srcipxsoc cmd value ]]
+ * [ dstipxnet nnnn dstipxnode mmmmm [dstipxsoc cmd value ]]
+ *
+ * Fields in [...] are optional.
+ * where:
+ *
+ * srcipxnet: Keyword for source IPX address.
+ * nnnn = IPX Node address.
+ *
+ * srcipxnode: Keyword for source IPX Node address.
+ * mmmmm = IPX Node Address, could be FFFFFF.
+ * A vlid ipx node number should accompany ipx net number.
+ *
+ * srcipxsoc: Keyword for source IPX socket address.
+ *
+ * cmd: One of ">" or "<" or "=" or "!=".
+ *
+ * value: Socket value to be compared against, in hex.
+ *
+ * dstipxnet: Keyword for destination IPX address.
+ * nnnn = IPX Node address.
+ *
+ * dstipxnode: Keyword for destination IPX Node address.
+ * mmmmm = IPX Node Address, could be FFFFFF.
+ * A valid ipx node number should accompany ipx net number.
+ *
+ * dstipxsoc: Keyword for destination IPX socket address.
+ *
+ * cmd: One of ">" or "<" or "=" or "!=".
+ *
+ * value: Socket value to be compared against, in hex.
+ */
+static int ascend_parse_ipx(int argc, char **argv, ascend_ipx_filter_t *filter)
+{
+ int rcode;
+ int token;
+ int flags = 0;
+
+ /*
+ * We may have nothing, in which case we simply return.
+ */
+ if (argc == 0) return 0;
+
+ /*
+ * Must have "net N node M"
+ */
+ if (argc < 4) return -1;
+
+ while ((argc > 0) && (flags != 0x03)) {
+ token = fr_str2int(filterKeywords, argv[0], -1);
+ switch (token) {
+ case FILTER_IPX_SRC_IPXNET:
+ if (flags & 0x01) return -1;
+ rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
+ &(filter->src),
+ &(filter->srcSocComp));
+ if (rcode < 0) return -1;
+ argc -= (rcode + 1);
+ argv += rcode + 1;
+ flags |= 0x01;
+ break;
+
+ case FILTER_IPX_DST_IPXNET:
+ if (flags & 0x02) return -1;
+ rcode = ascend_parse_ipx_net(argc - 1, argv + 1,
+ &(filter->dst),
+ &(filter->dstSocComp));
+ if (rcode < 0) return -1;
+ argc -= (rcode + 1);
+ argv += rcode + 1;
+ flags |= 0x02;
+ break;
+
+ default:
+ fr_strerror_printf("Unknown string \"%s\" in IPX data filter",
+ argv[0]);
+ return -1;
+ }
+ }
+
+ /*
+ * Arguments left over: die.
+ */
+ if (argc != 0) return -1;
+
+ /*
+ * Everything's OK.
+ */
+ return 0;
+}
+
+
+/*
+ * Parse an IP address and optionally a netmask, to a uint32_t.
+ *
+ * ipaddr should already be initialized to zero.
+ * ipaddr is in network byte order.
+ *
+ * Returns -1 on error, or the number of bits in the netmask, otherwise.
+ */
+static int ascend_parse_ipaddr(uint32_t *ipaddr, char *str)
+{
+ int count = 0;
+ int ip[4];
+ int masklen;
+ uint32_t netmask = 0;
+
+ /*
+ * Look for IP's.
+ */
+ count = 0;
+ while (*str && (count < 4) && (netmask == 0)) {
+ next:
+ ip[count] = 0;
+
+ while (*str) {
+ switch (*str) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ ip[count] *= 10;
+ ip[count] += (*str) - '0';
+ str++;
+ break;
+
+
+ case '.': /* dot between IP numbers. */
+ str++;
+ if (ip[count] > 255) return -1;
+
+ /*
+ * 24, 16, 8, 0, done.
+ */
+ *ipaddr |= (ip[count] << (8 * (3 - count)));
+ count++;
+ goto next;
+
+ case '/': /* netmask */
+ str++;
+ masklen = atoi(str);
+ if ((masklen < 0) || (masklen > 32)) return -1;
+ str += strspn(str, "0123456789");
+ netmask = masklen;
+ goto finalize;
+
+ default:
+ fr_strerror_printf("Invalid character in IP address");
+ return -1;
+ }
+ } /* loop over one character */
+ } /* loop until the count hits 4 */
+
+ if (count == 3) {
+ finalize:
+ /*
+ * Do the last one, too.
+ */
+ if (ip[count] > 255) return -1;
+
+ /*
+ * 24, 16, 8, 0, done.
+ */
+ *ipaddr |= (ip[count] << (8 * (3 - count)));
+ }
+
+ /*
+ * We've hit the end of the IP address, and there's something
+ * else left over: die.
+ */
+ if (*str) return -1;
+
+ /*
+ * Set the default netmask.
+ */
+ if (!netmask) {
+ if (!*ipaddr) {
+ netmask = 0;
+ } else if ((*ipaddr & 0x80000000) == 0) {
+ netmask = 8;
+ } else if ((*ipaddr & 0xc0000000) == 0x80000000) {
+ netmask = 16;
+ } else if ((*ipaddr & 0xe0000000) == 0xc0000000) {
+ netmask = 24;
+ } else {
+ netmask = 32;
+ }
+ }
+
+ *ipaddr = htonl(*ipaddr);
+ return netmask;
+}
+
+/*
+ * ascend_parse_port: Parse a comparator and port.
+ *
+ * Returns -1 on error, or the comparator.
+ */
+static int ascend_parse_port(uint16_t *port, char *compare, char *str)
+{
+ int rcode, token = -1;
+
+ /*
+ * There MUST be a comparison string.
+ */
+ rcode = fr_str2int(filterCompare, compare, -1);
+ if (rcode < 0) return rcode;
+
+ if (strspn(str, "0123456789") == strlen(str)) {
+ token = atoi(str);
+ } else {
+ token = fr_str2int(filterPortType, str, -1);
+ }
+
+ if ((token < 0) || (token > 65535)) return -1;
+
+ *port = token;
+ *port = htons(*port);
+
+ return rcode;
+}
+
+
+#define IP_SRC_ADDR_FLAG (1 << 0)
+#define IP_DEST_ADDR_FLAG (1 << 1)
+#define IP_SRC_PORT_FLAG (1 << 2)
+#define IP_DEST_PORT_FLAG (1 << 3)
+#define IP_PROTO_FLAG (1 << 4)
+#define IP_EST_FLAG (1 << 5)
+
+#define DONE_FLAGS (IP_SRC_ADDR_FLAG | IP_DEST_ADDR_FLAG | \
+ IP_SRC_PORT_FLAG | IP_DEST_PORT_FLAG | \
+ IP_PROTO_FLAG | IP_EST_FLAG)
+
+/*
+ * ascend_parse_ip:
+ *
+ * This routine parses an IP filter string from a RADIUS
+ * reply. The format of the string is:
+ *
+ * ip dir action [ dstip n.n.n.n/nn ] [ srcip n.n.n.n/nn ]
+ * [ proto [ dstport cmp value ] [ srcport cmd value ] [ est ] ]
+ *
+ * Fields in [...] are optional.
+ *
+ * dstip: Keyword for destination IP address.
+ * n.n.n.n = IP address. /nn - netmask.
+ *
+ * srcip: Keyword for source IP address.
+ * n.n.n.n = IP address. /nn - netmask.
+ *
+ * proto: Optional protocol field. Either a name or
+ * number. Known names are in FilterProtoName[].
+ *
+ * dstport: Keyword for destination port. Only valid with tcp
+ * or udp. 'cmp' are in FilterPortType[]. 'value' can be
+ * a name or number.
+ *
+ * srcport: Keyword for source port. Only valid with tcp
+ * or udp. 'cmp' are in FilterPortType[]. 'value' can be
+ * a name or number.
+ *
+ * est: Keyword for TCP established. Valid only for tcp.
+ *
+ */
+static int ascend_parse_ip(int argc, char **argv, ascend_ip_filter_t *filter)
+{
+ int rcode;
+ int token;
+ int flags;
+
+ /*
+ * We may have nothing, in which case we simply return.
+ */
+ if (argc == 0) return 0;
+
+ /*
+ * There may, or may not, be src & dst IP's in the string.
+ */
+ flags = 0;
+ while ((argc > 0) && (flags != DONE_FLAGS)) {
+ token = fr_str2int(filterKeywords, argv[0], -1);
+ switch (token) {
+ case FILTER_IP_SRC:
+ if (flags & IP_SRC_ADDR_FLAG) return -1;
+ if (argc < 2) return -1;
+
+ rcode = ascend_parse_ipaddr(&filter->srcip, argv[1]);
+ if (rcode < 0) return rcode;
+
+ filter->srcmask = rcode;
+ flags |= IP_SRC_ADDR_FLAG;
+ argv += 2;
+ argc -= 2;
+ break;
+
+ case FILTER_IP_DST:
+ if (flags & IP_DEST_ADDR_FLAG) return -1;
+ if (argc < 2) return -1;
+
+ rcode = ascend_parse_ipaddr(&filter->dstip, argv[1]);
+ if (rcode < 0) return rcode;
+
+ filter->dstmask = rcode;
+ flags |= IP_DEST_ADDR_FLAG;
+ argv += 2;
+ argc -= 2;
+ break;
+
+ case FILTER_IP_SRC_PORT:
+ if (flags & IP_SRC_PORT_FLAG) return -1;
+ if (argc < 3) return -1;
+
+ rcode = ascend_parse_port(&filter->srcport,
+ argv[1], argv[2]);
+ if (rcode < 0) return rcode;
+ filter->srcPortComp = rcode;
+
+ flags |= IP_SRC_PORT_FLAG;
+ argv += 3;
+ argc -= 3;
+ break;
+
+ case FILTER_IP_DST_PORT:
+ if (flags & IP_DEST_PORT_FLAG) return -1;
+ if (argc < 3) return -1;
+
+ rcode = ascend_parse_port(&filter->dstport,
+ argv[1], argv[2]);
+ if (rcode < 0) return rcode;
+ filter->dstPortComp = rcode;
+
+ flags |= IP_DEST_PORT_FLAG;
+ argv += 3;
+ argc -= 3;
+ break;
+
+ case FILTER_EST:
+ if (flags & IP_EST_FLAG) return -1;
+ filter->established = 1;
+ argv++;
+ argc--;
+ flags |= IP_EST_FLAG;
+ break;
+
+ default:
+ if (flags & IP_PROTO_FLAG) return -1;
+ if (strspn(argv[0], "0123456789") == strlen(argv[0])) {
+ token = atoi(argv[0]);
+ } else {
+ token = fr_str2int(filterProtoName, argv[0], -1);
+ if (token == -1) {
+ fr_strerror_printf("Unknown IP protocol \"%s\" in IP data filter",
+ argv[0]);
+ return -1;
+ }
+ }
+ filter->proto = token;
+ flags |= IP_PROTO_FLAG;
+
+ argv++;
+ argc--;
+ break;
+ }
+ }
+
+ /*
+ * We should have parsed everything by now.
+ */
+ if (argc != 0) {
+ fr_strerror_printf("Unknown extra string \"%s\" in IP data filter",
+ argv[0]);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * ascend_parse_generic
+ *
+ * This routine parses a Generic filter string from a RADIUS
+ * reply. The format of the string is:
+ *
+ * generic dir action offset mask value [== or != ] [more]
+ *
+ * Fields in [...] are optional.
+ *
+ * offset: A Number. Specifies an offset into a frame
+ * to start comparing.
+ *
+ * mask: A hexadecimal mask of bits to compare.
+ *
+ * value: A value to compare with the masked data.
+ *
+ * compNeq: Defines type of comparison. ( "==" or "!=")
+ * Default is "==".
+ *
+ * more: Optional keyword MORE, to represent the attachment
+ * to the next entry.
+ */
+static int ascend_parse_generic(int argc, char **argv,
+ ascend_generic_filter_t *filter)
+{
+ int rcode;
+ int token;
+ int flags;
+
+ /*
+ * We may have nothing, in which case we simply return.
+ */
+ if (argc == 0) return 0;
+
+ /*
+ * We need at least "offset mask value"
+ */
+ if (argc < 3) return -1;
+
+ /*
+ * No more than optional comparison and "more"
+ */
+ if (argc > 5) return -1;
+
+ /*
+ * Offset is a uint16_t number.
+ */
+ if (strspn(argv[0], "0123456789") != strlen(argv[0])) return -1;
+
+ rcode = atoi(argv[0]);
+ if (rcode > 65535) return -1;
+
+ filter->offset = rcode;
+ filter->offset = htons(filter->offset);
+
+ rcode = fr_hex2bin(filter->mask, sizeof(filter->mask), argv[1], strlen(argv[1]));
+ if (rcode != sizeof(filter->mask)) return -1;
+
+ token = fr_hex2bin(filter->value, sizeof(filter->value), argv[2], strlen(argv[2]));
+ if (token != sizeof(filter->value)) return -1;
+
+ filter->len = rcode;
+ filter->len = htons(filter->len);
+
+ /*
+ * Nothing more. Exit.
+ */
+ if (argc == 3) return 0;
+
+ argc -= 3;
+ argv += 3;
+ flags = 0;
+
+ while (argc >= 1) {
+ token = fr_str2int(filterKeywords, argv[0], -1);
+ switch (token) {
+ case FILTER_GENERIC_COMPNEQ:
+ if (flags & 0x01) return -1;
+ filter->compNeq = true;
+ flags |= 0x01;
+ break;
+ case FILTER_GENERIC_COMPEQ:
+ if (flags & 0x01) return -1;
+ filter->compNeq = false;
+ flags |= 0x01;
+ break;
+
+ case FILTER_MORE:
+ if (flags & 0x02) return -1;
+ filter->more = htons( 1 );
+ flags |= 0x02;
+ break;
+
+ default:
+ fr_strerror_printf("Invalid string \"%s\" in generic data filter",
+ argv[0]);
+ return -1;
+ }
+
+ argc--;
+ argv++;
+ }
+
+ return 0;
+}
+
+
+/** Filter binary
+ *
+ * This routine will call routines to parse entries from an ASCII format
+ * to a binary format recognized by the Ascend boxes.
+ *
+ * @param out Where to write parsed filter.
+ * @param value ascend filter text.
+ * @param len of value.
+ * @return -1 for error or 0.
+ */
+int ascend_parse_filter(value_data_t *out, char const *value, size_t len)
+{
+ int token, type;
+ int rcode;
+ int argc;
+ char *argv[32];
+ ascend_filter_t filter;
+ char *p;
+
+ rcode = -1;
+
+ /*
+ * Tokenize the input string in the VP.
+ *
+ * Once the filter is *completely* parsed, then we will
+ * over-write it with the final binary filter.
+ */
+ p = talloc_bstrndup(NULL, value, len);
+
+ /*
+ * Rather than printing specific error messages, we create
+ * a general one here, which won't be used if the function
+ * returns OK.
+ */
+ fr_strerror_printf("Failed parsing \"%s\" as ascend filer", p);
+
+ argc = str2argv(p, argv, 32);
+ if (argc < 3) {
+ talloc_free(p);
+ return -1;
+ }
+
+ /*
+ * Decide which filter type it is: ip, ipx, or generic
+ */
+ type = fr_str2int(filterType, argv[0], -1);
+ memset(&filter, 0, sizeof(filter));
+
+ /*
+ * Validate the filter type.
+ */
+ switch (type) {
+ case RAD_FILTER_GENERIC:
+ case RAD_FILTER_IP:
+ case RAD_FILTER_IPX:
+ filter.type = type;
+ break;
+
+ default:
+ fr_strerror_printf("Unknown Ascend filter type \"%s\"", argv[0]);
+ talloc_free(p);
+ return -1;
+ }
+
+ /*
+ * Parse direction
+ */
+ token = fr_str2int(filterKeywords, argv[1], -1);
+ switch (token) {
+ case FILTER_IN:
+ filter.direction = 1;
+ break;
+
+ case FILTER_OUT:
+ filter.direction = 0;
+ break;
+
+ default:
+ fr_strerror_printf("Unknown Ascend filter direction \"%s\"", argv[1]);
+ talloc_free(p);
+ return -1;
+ }
+
+ /*
+ * Parse action
+ */
+ token = fr_str2int(filterKeywords, argv[2], -1);
+ switch (token) {
+ case FILTER_FORWARD:
+ filter.forward = 1;
+ break;
+
+ case FILTER_DROP:
+ filter.forward = 0;
+ break;
+
+ default:
+ fr_strerror_printf("Unknown Ascend filter action \"%s\"", argv[2]);
+ talloc_free(p);
+ return -1;
+ }
+
+
+ switch (type) {
+ case RAD_FILTER_GENERIC:
+ rcode = ascend_parse_generic(argc - 3, &argv[3], &filter.u.generic);
+ break;
+
+ case RAD_FILTER_IP:
+ rcode = ascend_parse_ip(argc - 3, &argv[3], &filter.u.ip);
+ break;
+
+ case RAD_FILTER_IPX:
+ rcode = ascend_parse_ipx(argc - 3, &argv[3], &filter.u.ipx);
+ break;
+ }
+
+ /*
+ * Touch the VP only if everything was OK.
+ */
+ if (rcode == 0) memcpy(out->filter, &filter, sizeof(filter));
+ talloc_free(p);
+
+ return rcode;
+}
+
+/*
+ * Print an Ascend binary filter attribute to a string,
+ * Grrr... Ascend makes the server do this work, instead
+ * of doing it on the NAS.
+ *
+ * Note we don't bother checking 'len' after the snprintf's.
+ * This function should ONLY be called with a large (~1k) buffer.
+ */
+void print_abinary(char *out, size_t outlen, uint8_t const *data, size_t len, int8_t quote)
+{
+ size_t i;
+ char *p;
+ ascend_filter_t const *filter;
+
+ static char const *action[] = {"drop", "forward"};
+ static char const *direction[] = {"out", "in"};
+
+ p = out;
+
+ /*
+ * Just for paranoia: wrong size filters get printed as octets
+ */
+ if (len != sizeof(*filter)) {
+ strcpy(p, "0x");
+ p += 2;
+ outlen -= 2;
+ for (i = 0; i < len; i++) {
+ snprintf(p, outlen, "%02x", data[i]);
+ p += 2;
+ outlen -= 2;
+ }
+ return;
+ }
+
+ if (quote > 0) {
+ *(p++) = (char) quote;
+ outlen -= 3; /* account for leading & trailing quotes */
+ }
+
+ filter = (ascend_filter_t const *) data;
+ i = snprintf(p, outlen, "%s %s %s", fr_int2str(filterType, filter->type, "??"),
+ direction[filter->direction & 0x01], action[filter->forward & 0x01]);
+
+ p += i;
+ outlen -= i;
+
+ /*
+ * Handle IP filters
+ */
+ if (filter->type == RAD_FILTER_IP) {
+
+ if (filter->u.ip.srcip) {
+ i = snprintf(p, outlen, " srcip %d.%d.%d.%d/%d",
+ ((uint8_t const *) &filter->u.ip.srcip)[0],
+ ((uint8_t const *) &filter->u.ip.srcip)[1],
+ ((uint8_t const *) &filter->u.ip.srcip)[2],
+ ((uint8_t const *) &filter->u.ip.srcip)[3],
+ filter->u.ip.srcmask);
+ p += i;
+ outlen -= i;
+ }
+
+ if (filter->u.ip.dstip) {
+ i = snprintf(p, outlen, " dstip %d.%d.%d.%d/%d",
+ ((uint8_t const *) &filter->u.ip.dstip)[0],
+ ((uint8_t const *) &filter->u.ip.dstip)[1],
+ ((uint8_t const *) &filter->u.ip.dstip)[2],
+ ((uint8_t const *) &filter->u.ip.dstip)[3],
+ filter->u.ip.dstmask);
+ p += i;
+ outlen -= i;
+ }
+
+ i = snprintf(p, outlen, " %s", fr_int2str(filterProtoName, filter->u.ip.proto, "??"));
+ p += i;
+ outlen -= i;
+
+ if (filter->u.ip.srcPortComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " srcport %s %d",
+ fr_int2str(filterCompare, filter->u.ip.srcPortComp, "??"),
+ ntohs(filter->u.ip.srcport));
+ p += i;
+ outlen -= i;
+ }
+
+ if (filter->u.ip.dstPortComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " dstport %s %d",
+ fr_int2str(filterCompare, filter->u.ip.dstPortComp, "??"),
+ ntohs(filter->u.ip.dstport));
+ p += i;
+ outlen -= i;
+ }
+
+ if (filter->u.ip.established) {
+ i = snprintf(p, outlen, " est");
+ p += i;
+ }
+
+ /*
+ * Handle IPX filters
+ */
+ } else if (filter->type == RAD_FILTER_IPX) {
+ /* print for source */
+ if (filter->u.ipx.src.net) {
+ i = snprintf(p, outlen, " srcipxnet 0x%04x srcipxnode 0x%02x%02x%02x%02x%02x%02x",
+ (unsigned int)ntohl(filter->u.ipx.src.net),
+ filter->u.ipx.src.node[0], filter->u.ipx.src.node[1],
+ filter->u.ipx.src.node[2], filter->u.ipx.src.node[3],
+ filter->u.ipx.src.node[4], filter->u.ipx.src.node[5]);
+ p += i;
+ outlen -= i;
+
+ if (filter->u.ipx.srcSocComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " srcipxsock %s 0x%04x",
+ fr_int2str(filterCompare, filter->u.ipx.srcSocComp, "??"),
+ ntohs(filter->u.ipx.src.socket));
+ p += i;
+ outlen -= i;
+ }
+ }
+
+ /* same for destination */
+ if (filter->u.ipx.dst.net) {
+ i = snprintf(p, outlen, " dstipxnet 0x%04x dstipxnode 0x%02x%02x%02x%02x%02x%02x",
+ (unsigned int)ntohl(filter->u.ipx.dst.net),
+ filter->u.ipx.dst.node[0], filter->u.ipx.dst.node[1],
+ filter->u.ipx.dst.node[2], filter->u.ipx.dst.node[3],
+ filter->u.ipx.dst.node[4], filter->u.ipx.dst.node[5]);
+ p += i;
+ outlen -= i;
+
+ if (filter->u.ipx.dstSocComp > RAD_NO_COMPARE) {
+ i = snprintf(p, outlen, " dstipxsock %s 0x%04x",
+ fr_int2str(filterCompare, filter->u.ipx.dstSocComp, "??"),
+ ntohs(filter->u.ipx.dst.socket));
+ p += i;
+ }
+ }
+ } else if (filter->type == RAD_FILTER_GENERIC) {
+ size_t count, masklen;
+
+ masklen = ntohs(filter->u.generic.len);
+ if (masklen >= sizeof(filter->u.generic.mask)) {
+ *p = '\0';
+ return;
+ }
+
+ i = snprintf(p, outlen, " %u ", (unsigned int) ntohs(filter->u.generic.offset));
+ p += i;
+
+ /* show the mask */
+ for (count = 0; count < masklen; count++) {
+ i = snprintf(p, outlen, "%02x", filter->u.generic.mask[count]);
+ p += i;
+ outlen -= i;
+ }
+
+ strcpy(p, " ");
+ p++;
+ outlen--;
+
+ /* show the value */
+ for (count = 0; count < masklen; count++) {
+ i = snprintf(p, outlen, "%02x", filter->u.generic.value[count]);
+ p += i;
+ outlen -= i;
+ }
+
+ i = snprintf(p, outlen, " %s", (filter->u.generic.compNeq) ? "!=" : "==");
+ p += i;
+ outlen -= i;
+
+ if (filter->u.generic.more != 0) {
+ i = snprintf(p, outlen, " more");
+ p += i;
+ }
+ }
+
+ if (quote > 0) {
+ *(p++) = (char) quote;
+ }
+ *p = '\0';
+}
+
+#endif
diff --git a/src/lib/getaddrinfo.c b/src/lib/getaddrinfo.c
new file mode 100644
index 0000000..1c8aa9a
--- /dev/null
+++ b/src/lib/getaddrinfo.c
@@ -0,0 +1,438 @@
+/*
+ * These functions are defined and used only if the configure
+ * cannot detect the standard getaddrinfo(), freeaddrinfo(),
+ * gai_strerror() and getnameinfo(). This avoids sprinkling of ifdefs.
+ *
+ * FIXME: getaddrinfo() & getnameinfo() should
+ * return all IPv4 addresses provided by DNS lookup.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+#include <sys/param.h>
+
+#ifndef HAVE_GETNAMEINFO
+# undef LOCAL_GETHOSTBYNAMERSTYLE
+# ifndef GETHOSTBYNAMERSTYLE
+# define LOCAL_GETHOSTBYNAMERSTYLE 1
+#elif (GETHOSTBYNAMERSTYLE != SYSVSTYLE) && (GETHOSTBYNAMERSTYLE != GNUSTYLE)
+# define LOCAL_GETHOSTBYNAMERSTYLE 1
+# endif /* GETHOSTBYNAMERSTYLE */
+#endif
+
+#ifndef HAVE_GETADDRINFO
+# undef LOCAL_GETHOSTBYADDRR
+# ifndef GETHOSTBYADDRRSTYLE
+# define LOCAL_GETHOSTBYADDRR 1
+# elif (GETHOSTBYADDRRSTYLE != SYSVSTYLE) && (GETHOSTBYADDRRSTYLE != GNUSTYLE)
+# define LOCAL_GETHOSTBYADDRR 1
+# endif /* GETHOSTBYADDRRSTYLE */
+#endif
+
+#ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+
+/* Thread safe DNS lookups */
+/*
+ * FIXME: There are some systems that use the same hostent
+ * structure to return for gethostbyname() & gethostbyaddr(), if
+ * that is the case then use only one mutex instead of separate
+ * mutexes
+ */
+# ifdef LOCAL_GETHOSTBYNAMERSTYLE
+static int fr_hostbyname = 0;
+static pthread_mutex_t fr_hostbyname_mutex;
+# endif
+
+# ifdef LOCAL_GETHOSTBYNAMERSTYLE
+static int fr_hostbyaddr = 0;
+static pthread_mutex_t fr_hostbyaddr_mutex;
+# endif
+
+#endif
+
+/*
+ * gethostbyaddr() & gethostbyname() return hostent structure
+ * To make these functions thread safe, we need to
+ * copy the data and not pointers
+ *
+ * struct hostent {
+ * char *h_name; * official name of host *
+ * char **h_aliases; * alias list *
+ * int h_addrtype; * host address type *
+ * int h_length; * length of address *
+ * char **h_addr_list; * list of addresses *
+ * }
+ * This struct contains 3 pointers as members.
+ * The data from these pointers is copied into a buffer.
+ * The buffer is formatted as below to store the data
+ * ---------------------------------------------------------------
+ * | h_name\0alias_array\0h_aliases\0..\0addr_array\0h_addr_list\0 |
+ * ---------------------------------------------------------------
+ */
+#if defined(LOCAL_GETHOSTBYNAMER) || defined(LOCAL_GETHOSTBYADDRR)
+# define BUFFER_OVERFLOW 255
+static int copy_hostent(struct hostent *from, struct hostent *to, char *buffer, int buflen, int *error)
+{
+ int i, len;
+ char *ptr = buffer;
+
+ *error = 0;
+ to->h_addrtype = from->h_addrtype;
+ to->h_length = from->h_length;
+ to->h_name = (char *)ptr;
+
+ /* copy hostname to buffer */
+ len = strlen(from->h_name) + 1;
+ strcpy(ptr, from->h_name);
+ ptr += len;
+
+ /* copy aliases to buffer */
+ to->h_aliases = (char**)ptr;
+ for (i = 0; from->h_aliases[i]; i++);
+ ptr += (i+1) * sizeof(char *);
+
+ for (i = 0; from->h_aliases[i]; i++) {
+ len = strlen(from->h_aliases[i])+1;
+ if ((ptr-buffer) + len < buflen) {
+ to->h_aliases[i] = ptr;
+ strcpy(ptr, from->h_aliases[i]);
+ ptr += len;
+ } else {
+ *error = BUFFER_OVERFLOW;
+ return *error;
+ }
+ }
+ to->h_aliases[i] = NULL;
+
+ /* copy addr_list to buffer */
+ to->h_addr_list = (char**)ptr;
+ for (i = 0; (int *)from->h_addr_list[i] != 0; i++);
+ ptr += (i + 1) * sizeof(int *);
+
+ for (i = 0; (int *)from->h_addr_list[i] != 0; i++) {
+ len = sizeof(int);
+
+ if ((ptr-buffer)+len < buflen) {
+ to->h_addr_list[i] = ptr;
+ memcpy(ptr, from->h_addr_list[i], len);
+ ptr += len;
+ } else {
+ *error = BUFFER_OVERFLOW;
+ return *error;
+ }
+ }
+ to->h_addr_list[i] = 0;
+ return *error;
+}
+#endif /* (LOCAL_GETHOSTBYNAMER == 1) || (LOCAL_GETHOSTBYADDRR == 1) */
+
+#ifdef LOCAL_GETHOSTBYNAMERSTYLE
+static struct hostent *
+gethostbyname_r(char const *hostname, struct hostent *result,
+ char *buffer, int buflen, int *error)
+{
+ struct hostent *hp;
+
+# ifdef HAVE_PTHREAD_H
+ if (fr_hostbyname == 0) {
+ pthread_mutex_init(&fr_hostbyname_mutex, NULL);
+ fr_hostbyname = 1;
+ }
+ pthread_mutex_lock(&fr_hostbyname_mutex);
+# endif
+
+ hp = gethostbyname(hostname);
+ if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
+ *error = h_errno;
+ hp = NULL;
+ } else {
+ copy_hostent(hp, result, buffer, buflen, error);
+ hp = result;
+ }
+
+# ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&fr_hostbyname_mutex);
+# endif
+
+ return hp;
+}
+#endif /* GETHOSTBYNAMERSTYLE */
+
+
+#ifdef LOCAL_GETHOSTBYADDRR
+static struct hostent *gethostbyaddr_r(char const *addr, int len, int type, struct hostent *result,
+ char *buffer, int buflen, int *error)
+{
+ struct hostent *hp;
+
+#ifdef HAVE_PTHREAD_H
+ if (fr_hostbyaddr == 0) {
+ pthread_mutex_init(&fr_hostbyaddr_mutex, NULL);
+ fr_hostbyaddr = 1;
+ }
+ pthread_mutex_lock(&fr_hostbyaddr_mutex);
+#endif
+
+ hp = gethostbyaddr(addr, len, type);
+ if ((!hp) || (hp->h_addrtype != AF_INET) || (hp->h_length != 4)) {
+ *error = h_errno;
+ hp = NULL;
+ } else {
+ copy_hostent(hp, result, buffer, buflen, error);
+ hp = result;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&fr_hostbyaddr_mutex);
+#endif
+
+ return hp;
+}
+#endif /* GETHOSTBYADDRRSTYLE */
+
+/*
+ * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
+ *
+ * Below code is based on ssh-1.2.27-IPv6-1.5 written by
+ * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+ */
+
+#ifndef HAVE_GETADDRINFO
+static struct addrinfo *malloc_ai(uint16_t port, u_long addr, int socktype, int proto)
+{
+ struct addrinfo *ai;
+
+ ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+ if (!ai) return NULL;
+
+ memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+ ai->ai_addr = (struct sockaddr *)(ai + 1);
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+# ifdef HAVE_SOCKADDR_SA_LEN
+ ai->ai_addr->sa_len = sizeof(struct sockaddr_in);
+# endif
+ ai->ai_addr->sa_family = ai->ai_family = AF_INET;
+ ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
+ ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
+ ai->ai_socktype = socktype;
+ ai->ai_protocol = proto;
+
+ return ai;
+}
+
+char const *gai_strerror(int ecode)
+{
+ switch (ecode) {
+ case EAI_MEMORY:
+ return "memory allocation failure";
+
+ case EAI_FAMILY:
+ return "ai_family not supported";
+
+ case EAI_NONAME:
+ return "hostname nor servname provided, or not known";
+
+ case EAI_SERVICE:
+ return "servname not supported for ai_socktype";
+
+ default:
+ return "unknown error";
+ }
+}
+
+void freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *next;
+
+ if (ai->ai_canonname) free(ai->ai_canonname);
+
+ do {
+ next = ai->ai_next;
+ free(ai);
+ } while ((ai = next) != NULL);
+}
+
+int getaddrinfo(char const *hostname, char const *servname, struct addrinfo const *hints, struct addrinfo **res)
+{
+ struct addrinfo *cur, *prev = NULL;
+ struct hostent *hp;
+ struct hostent result;
+ struct in_addr in;
+ int i, socktype, proto;
+ uint16_t port = 0;
+ int error;
+ char buffer[2048];
+
+ if (hints && (hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC)) return EAI_FAMILY;
+
+ socktype = (hints && hints->ai_socktype) ? hints->ai_socktype : SOCK_STREAM;
+ if (hints && hints->ai_protocol) {
+ proto = hints->ai_protocol;
+ } else {
+ switch (socktype) {
+ case SOCK_DGRAM:
+ proto = IPPROTO_UDP;
+ break;
+ case SOCK_STREAM:
+ proto = IPPROTO_TCP;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+ }
+
+ if (servname) {
+ if (isdigit((uint8_t)*servname)) {
+ port = htons(atoi(servname));
+ } else {
+ struct servent *se;
+ char const *pe_proto;
+
+ switch (socktype) {
+ case SOCK_DGRAM:
+ pe_proto = "udp";
+ break;
+
+ case SOCK_STREAM:
+ pe_proto = "tcp";
+ break;
+
+ default:
+ pe_proto = NULL;
+ break;
+ }
+ if ((se = getservbyname(servname, pe_proto)) == NULL) return EAI_SERVICE;
+
+ port = se->s_port;
+ }
+ }
+
+ if (!hostname) {
+ if (hints && hints->ai_flags & AI_PASSIVE) {
+ *res = malloc_ai(port, htonl(0x00000000), socktype, proto);
+ } else {
+ *res = malloc_ai(port, htonl(0x7f000001), socktype, proto);
+ }
+ if (!*res) return EAI_MEMORY;
+
+ return 0;
+ }
+
+ /* Numeric IP Address */
+ if (inet_aton(hostname, &in)) {
+ *res = malloc_ai(port, in.s_addr, socktype, proto);
+ if (!*res) return EAI_MEMORY;
+
+ return 0;
+ }
+
+ if (hints && hints->ai_flags & AI_NUMERICHOST) return EAI_NONAME;
+
+ /* DNS Lookup */
+#ifdef GETHOSTBYNAMERSTYLE
+# if GETHOSTBYNAMERSTYLE == SYSVSTYLE
+ hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
+# elif GETHOSTBYNAMERSTYLE == GNUSTYLE
+ if (gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &hp, &error) != 0) hp = NULL;
+# else
+ hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
+# endif
+#else
+ hp = gethostbyname_r(hostname, &result, buffer, sizeof(buffer), &error);
+#endif
+
+ if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ if ((cur = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr,
+ socktype, proto)) == NULL) {
+ if (*res) freeaddrinfo(*res);
+ return EAI_MEMORY;
+ }
+
+ if (prev) {
+ prev->ai_next = cur;
+ } else {
+ *res = cur;
+ }
+ prev = cur;
+ }
+
+ if (hints && hints->ai_flags & AI_CANONNAME && *res) {
+ if (((*res)->ai_canonname = strdup(hp->h_name)) == NULL) {
+ freeaddrinfo(*res);
+ return EAI_MEMORY;
+ }
+ }
+ return 0;
+ }
+ return EAI_NONAME;
+}
+#endif /* HAVE_GETADDRINFO */
+
+
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(struct sockaddr const *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen,
+ unsigned int flags)
+{
+ const struct sockaddr_in *sin = (struct sockaddr_in const *)sa;
+ struct hostent *hp;
+ struct hostent result;
+ char tmpserv[16];
+ char buffer[2048];
+ int error;
+
+ if (serv) {
+ snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
+ if (strlen(tmpserv) > servlen) return EAI_MEMORY;
+
+ strcpy(serv, tmpserv);
+
+ if (host) {
+ if (flags & NI_NUMERICHOST) {
+ /* No Reverse DNS lookup */
+ if (flags & NI_NAMEREQD) return EAI_NONAME;
+ if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen) return EAI_MEMORY;
+
+ strcpy(host, inet_ntoa(sin->sin_addr));
+ return 0;
+ } else {
+ /* Reverse DNS lookup required */
+#ifdef GETHOSTBYADDRRSTYLE
+# if GETHOSTBYADDRRSTYLE == SYSVSTYLE
+ hp = gethostbyaddr_r((char const *)&sin->sin_addr,
+ salen, AF_INET, &result, buffer, sizeof(buffer), &error);
+# elif GETHOSTBYADDRRSTYLE == GNUSTYLE
+ if (gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
+ &result, buffer, sizeof(buffer), &hp, &error) != 0) {
+ hp = NULL;
+ }
+# else
+ hp = gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
+ &result, buffer, sizeof(buffer), &error);
+# endif
+#else
+ hp = gethostbyaddr_r((char const *)&sin->sin_addr, salen, AF_INET,
+ &result, buffer, sizeof(buffer), &error);
+#endif
+ if (hp) {
+ if (strlen(hp->h_name) >= hostlen) return EAI_MEMORY;
+
+ strcpy(host, hp->h_name);
+ return 0;
+ }
+
+ if (flags & NI_NAMEREQD) return EAI_NONAME;
+ if (strlen(inet_ntoa(sin->sin_addr)) >= hostlen) return EAI_MEMORY;
+
+ strcpy(host, inet_ntoa(sin->sin_addr));
+ return 0;
+ }
+ }
+ return 0;
+}
+#endif /* HAVE_GETNAMEINFO */
diff --git a/src/lib/hash.c b/src/lib/hash.c
new file mode 100644
index 0000000..9efff6e
--- /dev/null
+++ b/src/lib/hash.c
@@ -0,0 +1,935 @@
+/*
+ * hash.c Non-thread-safe split-ordered hash table.
+ *
+ * The weird "reverse" function is based on an idea from
+ * "Split-Ordered Lists - Lock-free Resizable Hash Tables", with
+ * modifications so that they're not lock-free. :(
+ *
+ * However, the split-order idea allows a fast & easy splitting of the
+ * hash bucket chain when the hash table is resized. Without it, we'd
+ * have to check & update the pointers for every node in the buck chain,
+ * rather than being able to move 1/2 of the entries in the chain with
+ * one update.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+/*
+ * A reasonable number of buckets to start off with.
+ * Should be a power of two.
+ */
+#define FR_HASH_NUM_BUCKETS (64)
+
+struct fr_hash_entry_s {
+ fr_hash_entry_t *next;
+ uint32_t reversed;
+ uint32_t key;
+ void const *data;
+};
+
+
+struct fr_hash_table_t {
+ int num_elements;
+ int num_buckets; /* power of 2 */
+ int next_grow;
+ int mask;
+
+ fr_hash_table_free_t free;
+ fr_hash_table_hash_t hash;
+ fr_hash_table_cmp_t cmp;
+
+ fr_hash_entry_t null;
+
+ fr_hash_entry_t **buckets;
+};
+
+#ifdef TESTING
+static int grow = 0;
+#endif
+
+/*
+ * perl -e 'foreach $i (0..255) {$r = 0; foreach $j (0 .. 7 ) { if (($i & ( 1<< $j)) != 0) { $r |= (1 << (7 - $j));}} print $r, ", ";if (($i & 7) == 7) {print "\n";}}'
+ */
+static const uint8_t reversed_byte[256] = {
+ 0, 128, 64, 192, 32, 160, 96, 224,
+ 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232,
+ 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228,
+ 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236,
+ 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226,
+ 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234,
+ 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230,
+ 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238,
+ 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225,
+ 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233,
+ 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229,
+ 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237,
+ 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227,
+ 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235,
+ 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231,
+ 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239,
+ 31, 159, 95, 223, 63, 191, 127, 255
+};
+
+
+/*
+ * perl -e 'foreach $i (0..255) {$r = 0;foreach $j (0 .. 7) { $r = $i & (1 << (7 - $j)); last if ($r)} print $i & ~($r), ", ";if (($i & 7) == 7) {print "\n";}}'
+ */
+static uint8_t parent_byte[256] = {
+ 0, 0, 0, 1, 0, 1, 2, 3,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127
+};
+
+
+/*
+ * Reverse a key.
+ */
+static uint32_t reverse(uint32_t key)
+{
+ /*
+ * Cast to uint32_t is required because the
+ * default type of of the expression is an
+ * int and ubsan correctly complains that
+ * the result of 0xff << 24 won't fit in an
+ * unsigned 32bit integer.
+ */
+ return (((uint32_t)reversed_byte[key & 0xff] << 24) |
+ ((uint32_t)reversed_byte[(key >> 8) & 0xff] << 16) |
+ ((uint32_t)reversed_byte[(key >> 16) & 0xff] << 8) |
+ ((uint32_t)reversed_byte[(key >> 24) & 0xff]));
+}
+
+/*
+ * Take the parent by discarding the highest bit that is set.
+ */
+static uint32_t parent_of(uint32_t key)
+{
+ if (key > 0x00ffffff)
+ return (key & 0x00ffffff) | (parent_byte[key >> 24] << 24);
+
+ if (key > 0x0000ffff)
+ return (key & 0x0000ffff) | (parent_byte[key >> 16] << 16);
+
+ if (key > 0x000000ff)
+ return (key & 0x000000ff) | (parent_byte[key >> 8] << 8);
+
+ return parent_byte[key];
+}
+
+
+static fr_hash_entry_t *list_find(fr_hash_table_t *ht,
+ fr_hash_entry_t *head,
+ uint32_t reversed,
+ void const *data)
+{
+ fr_hash_entry_t *cur;
+
+ for (cur = head; cur != &ht->null; cur = cur->next) {
+ if (cur->reversed == reversed) {
+ if (ht->cmp) {
+ int cmp = ht->cmp(data, cur->data);
+ if (cmp > 0) break;
+ if (cmp < 0) continue;
+ }
+ return cur;
+ }
+ if (cur->reversed > reversed) break;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Inserts a new entry into the list, in order.
+ */
+static int list_insert(fr_hash_table_t *ht,
+ fr_hash_entry_t **head, fr_hash_entry_t *node)
+{
+ fr_hash_entry_t **last, *cur;
+
+ last = head;
+
+ for (cur = *head; cur != &ht->null; cur = cur->next) {
+ if (cur->reversed > node->reversed) break;
+ last = &(cur->next);
+
+ if (cur->reversed == node->reversed) {
+ if (ht->cmp) {
+ int cmp = ht->cmp(node->data, cur->data);
+ if (cmp > 0) break;
+ if (cmp < 0) continue;
+ }
+ return 0;
+ }
+ }
+
+ node->next = *last;
+ *last = node;
+
+ return 1;
+}
+
+
+/*
+ * Delete an entry from the list.
+ */
+static int list_delete(fr_hash_table_t *ht,
+ fr_hash_entry_t **head, fr_hash_entry_t *node)
+{
+ fr_hash_entry_t **last, *cur;
+
+ last = head;
+
+ for (cur = *head; cur != &ht->null; cur = cur->next) {
+ if (cur == node) break;
+ last = &(cur->next);
+ }
+
+ *last = node->next;
+ return 1;
+}
+
+
+/*
+ * Create the table.
+ *
+ * Memory usage in bytes is (20/3) * number of entries.
+ */
+fr_hash_table_t *fr_hash_table_create(fr_hash_table_hash_t hashNode,
+ fr_hash_table_cmp_t cmpNode,
+ fr_hash_table_free_t freeNode)
+{
+ fr_hash_table_t *ht;
+
+ if (!hashNode) return NULL;
+
+ ht = malloc(sizeof(*ht));
+ if (!ht) return NULL;
+
+ memset(ht, 0, sizeof(*ht));
+ ht->free = freeNode;
+ ht->hash = hashNode;
+ ht->cmp = cmpNode;
+ ht->num_buckets = FR_HASH_NUM_BUCKETS;
+ ht->mask = ht->num_buckets - 1;
+
+ /*
+ * Have a default load factor of 2.5. In practice this
+ * means that the average load will hit 3 before the
+ * table grows.
+ */
+ ht->next_grow = (ht->num_buckets << 1) + (ht->num_buckets >> 1);
+
+ ht->buckets = malloc(sizeof(*ht->buckets) * ht->num_buckets);
+ if (!ht->buckets) {
+ free(ht);
+ return NULL;
+ }
+ memset(ht->buckets, 0, sizeof(*ht->buckets) * ht->num_buckets);
+
+ ht->null.reversed = ~0;
+ ht->null.key = ~0;
+ ht->null.next = &ht->null;
+
+ ht->buckets[0] = &ht->null;
+
+ return ht;
+}
+
+
+/*
+ * If the current bucket is uninitialized, initialize it
+ * by recursively copying information from the parent.
+ *
+ * We may have a situation where entry E is a parent to 2 other
+ * entries E' and E". If we split E into E and E', then the
+ * nodes meant for E" end up in E or E', either of which is
+ * wrong. To solve that problem, we walk down the whole chain,
+ * inserting the elements into the correct place.
+ */
+static void fr_hash_table_fixup(fr_hash_table_t *ht, uint32_t entry)
+{
+ uint32_t parent_entry;
+ fr_hash_entry_t **last, *cur;
+ uint32_t this;
+
+ parent_entry = parent_of(entry);
+
+ /* parent_entry == entry if and only if entry == 0 */
+
+ if (!ht->buckets[parent_entry]) {
+ fr_hash_table_fixup(ht, parent_entry);
+ }
+
+ /*
+ * Keep walking down cur, trying to find entries that
+ * don't belong here any more. There may be multiple
+ * ones, so we can't have a naive algorithm...
+ */
+ last = &ht->buckets[parent_entry];
+ this = parent_entry;
+
+ for (cur = *last; cur != &ht->null; cur = cur->next) {
+ uint32_t real_entry;
+
+ real_entry = cur->key & ht->mask;
+ if (real_entry != this) { /* ht->buckets[real_entry] == NULL */
+ *last = &ht->null;
+ ht->buckets[real_entry] = cur;
+ this = real_entry;
+ }
+
+ last = &(cur->next);
+ }
+
+ /*
+ * We may NOT have initialized this bucket, so do it now.
+ */
+ if (!ht->buckets[entry]) ht->buckets[entry] = &ht->null;
+}
+
+/*
+ * This should be a power of two. Changing it to 4 doesn't seem
+ * to make any difference.
+ */
+#define GROW_FACTOR (2)
+
+/*
+ * Grow the hash table.
+ */
+static void fr_hash_table_grow(fr_hash_table_t *ht)
+{
+ fr_hash_entry_t **buckets;
+
+ buckets = malloc(sizeof(*buckets) * GROW_FACTOR * ht->num_buckets);
+ if (!buckets) return;
+
+ memcpy(buckets, ht->buckets,
+ sizeof(*buckets) * ht->num_buckets);
+ memset(&buckets[ht->num_buckets], 0,
+ sizeof(*buckets) * ht->num_buckets);
+
+ free(ht->buckets);
+ ht->buckets = buckets;
+ ht->num_buckets *= GROW_FACTOR;
+ ht->next_grow *= GROW_FACTOR;
+ ht->mask = ht->num_buckets - 1;
+#ifdef TESTING
+ grow = 1;
+ fprintf(stderr, "GROW TO %d\n", ht->num_buckets);
+#endif
+}
+
+
+/*
+ * Insert data.
+ */
+int fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
+{
+ uint32_t key;
+ uint32_t entry;
+ uint32_t reversed;
+ fr_hash_entry_t *node;
+
+ if (!ht || !data) return 0;
+
+ key = ht->hash(data);
+ entry = key & ht->mask;
+ reversed = reverse(key);
+
+ if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
+
+ /*
+ * If we try to do our own memory allocation here, the
+ * speedup is only ~15% or so, which isn't worth it.
+ */
+ node = malloc(sizeof(*node));
+ if (!node) return 0;
+ memset(node, 0, sizeof(*node));
+
+ node->next = &ht->null;
+ node->reversed = reversed;
+ node->key = key;
+ node->data = data;
+
+ /* already in the table, can't insert it */
+ if (!list_insert(ht, &ht->buckets[entry], node)) {
+ free(node);
+ return 0;
+ }
+
+ /*
+ * Check the load factor, and grow the table if
+ * necessary.
+ */
+ ht->num_elements++;
+ if (ht->num_elements >= ht->next_grow) {
+ fr_hash_table_grow(ht);
+ }
+
+ return 1;
+}
+
+
+/*
+ * Internal find a node routine.
+ */
+static fr_hash_entry_t *fr_hash_table_find(fr_hash_table_t *ht, void const *data)
+{
+ uint32_t key;
+ uint32_t entry;
+ uint32_t reversed;
+
+ if (!ht) return NULL;
+
+ key = ht->hash(data);
+ entry = key & ht->mask;
+ reversed = reverse(key);
+
+ if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
+
+ return list_find(ht, ht->buckets[entry], reversed, data);
+}
+
+
+/*
+ * Replace old data with new data, OR insert if there is no old.
+ */
+int fr_hash_table_replace(fr_hash_table_t *ht, void const *data)
+{
+ fr_hash_entry_t *node;
+ void *tofree;
+
+ if (!ht || !data) return 0;
+
+ node = fr_hash_table_find(ht, data);
+ if (!node) {
+ return fr_hash_table_insert(ht, data);
+ }
+
+ if (ht->free) {
+ memcpy(&tofree, &node->data, sizeof(tofree));
+ ht->free(tofree);
+ }
+ node->data = data;
+
+ return 1;
+}
+
+
+/*
+ * Find data from a template
+ */
+void *fr_hash_table_finddata(fr_hash_table_t *ht, void const *data)
+{
+ fr_hash_entry_t *node;
+ void *out;
+
+ node = fr_hash_table_find(ht, data);
+ if (!node) return NULL;
+
+ memcpy(&out, &node->data, sizeof(out));
+
+ return out;
+}
+
+
+
+/*
+ * Yank an entry from the hash table, without freeing the data.
+ */
+void *fr_hash_table_yank(fr_hash_table_t *ht, void const *data)
+{
+ uint32_t key;
+ uint32_t entry;
+ uint32_t reversed;
+ void *old;
+ fr_hash_entry_t *node;
+
+ if (!ht) return NULL;
+
+ key = ht->hash(data);
+ entry = key & ht->mask;
+ reversed = reverse(key);
+
+ if (!ht->buckets[entry]) fr_hash_table_fixup(ht, entry);
+
+ node = list_find(ht, ht->buckets[entry], reversed, data);
+ if (!node) return NULL;
+
+ list_delete(ht, &ht->buckets[entry], node);
+ ht->num_elements--;
+
+ memcpy(&old, &node->data, sizeof(old));
+ free(node);
+
+ return old;
+}
+
+
+/*
+ * Delete a piece of data from the hash table.
+ */
+int fr_hash_table_delete(fr_hash_table_t *ht, void const *data)
+{
+ void *old;
+
+ old = fr_hash_table_yank(ht, data);
+ if (!old) return 0;
+
+ if (ht->free) ht->free(old);
+
+ return 1;
+}
+
+
+/*
+ * Free a hash table
+ */
+void fr_hash_table_free(fr_hash_table_t *ht)
+{
+ int i;
+ fr_hash_entry_t *node, *next;
+
+ if (!ht) return;
+
+ /*
+ * Walk over the buckets, freeing them all.
+ */
+ for (i = 0; i < ht->num_buckets; i++) {
+ if (ht->buckets[i]) for (node = ht->buckets[i];
+ node != &ht->null;
+ node = next) {
+ next = node->next;
+
+ if (node->data && ht->free) {
+ void *tofree;
+ memcpy(&tofree, &node->data, sizeof(tofree));
+ ht->free(tofree);
+ }
+
+ free(node);
+ }
+ }
+
+ free(ht->buckets);
+ free(ht);
+}
+
+
+/*
+ * Count number of elements
+ */
+int fr_hash_table_num_elements(fr_hash_table_t *ht)
+{
+ if (!ht) return 0;
+
+ return ht->num_elements;
+}
+
+
+/*
+ * Walk over the nodes, allowing deletes & inserts to happen.
+ */
+int fr_hash_table_walk(fr_hash_table_t *ht,
+ fr_hash_table_walk_t callback,
+ void *context)
+{
+ int i, rcode;
+
+ if (!ht || !callback) return 0;
+
+ for (i = ht->num_buckets - 1; i >= 0; i--) {
+ fr_hash_entry_t *node, *next;
+
+ /*
+ * Ensure that the current bucket is filled.
+ */
+ if (!ht->buckets[i]) fr_hash_table_fixup(ht, i);
+
+ for (node = ht->buckets[i]; node != &ht->null; node = next) {
+ void *arg;
+
+ next = node->next;
+
+ memcpy(&arg, &node->data, sizeof(arg));
+ rcode = callback(context, arg);
+
+ if (rcode != 0) return rcode;
+ }
+ }
+
+ return 0;
+}
+
+/** Iterate over entries in a hash table
+ *
+ * @note If the hash table is modified the iterator should be considered invalidated.
+ *
+ * @param[in] ht to iterate over.
+ * @param[in] iter Pointer to an iterator struct, used to maintain
+ * state between calls.
+ * @return
+ * - User data.
+ * - NULL if at the end of the list.
+ */
+void *fr_hash_table_iter_next(fr_hash_table_t *ht, fr_hash_iter_t *iter)
+{
+ fr_hash_entry_t *node;
+ uint32_t i;
+ void *out;
+
+ /*
+ * Return the next element in the bucket
+ */
+ if (iter->node != &ht->null) {
+ node = iter->node;
+ iter->node = node->next;
+
+ memcpy(&out, &node->data, sizeof(out)); /* const issues */
+ return out;
+ }
+
+ if (iter->bucket == 0) return NULL;
+
+ /*
+ * We might have to go through multiple empty
+ * buckets to find one that contains something
+ * we should return
+ */
+ i = iter->bucket - 1;
+ for (;;) {
+ if (!ht->buckets[i]) fr_hash_table_fixup(ht, i);
+
+ node = ht->buckets[i];
+ if (node == &ht->null) {
+ if (i == 0) break;
+ i--;
+ continue; /* This bucket was empty too... */
+ }
+
+ iter->node = node->next; /* Store the next one to examine */
+ iter->bucket = i;
+
+ memcpy(&out, &node->data, sizeof(out)); /* const issues */
+ return out;
+ }
+ iter->bucket = i;
+
+ return NULL;
+}
+
+/** Initialise an iterator
+ *
+ * @note If the hash table is modified the iterator should be considered invalidated.
+ *
+ * @param[in] ht to iterate over.
+ * @param[out] iter to initialise.
+ * @return
+ * - The first entry in the hash table.
+ * - NULL if the hash table is empty.
+ */
+void *fr_hash_table_iter_init(fr_hash_table_t *ht, fr_hash_iter_t *iter)
+{
+ iter->bucket = ht->num_buckets;
+ iter->node = &ht->null;
+
+ return fr_hash_table_iter_next(ht, iter);
+}
+
+
+#ifdef TESTING
+/*
+ * Show what the hash table is doing.
+ */
+int fr_hash_table_info(fr_hash_table_t *ht)
+{
+ int i, a, collisions, uninitialized;
+ int array[256];
+
+ if (!ht) return 0;
+
+ uninitialized = collisions = 0;
+ memset(array, 0, sizeof(array));
+
+ for (i = 0; i < ht->num_buckets; i++) {
+ uint32_t key;
+ int load;
+ fr_hash_entry_t *node, *next;
+
+ /*
+ * If we haven't inserted or looked up an entry
+ * in a bucket, it's uninitialized.
+ */
+ if (!ht->buckets[i]) {
+ uninitialized++;
+ continue;
+ }
+
+ load = 0;
+ key = ~0;
+ for (node = ht->buckets[i]; node != &ht->null; node = next) {
+ if (node->reversed == key) {
+ collisions++;
+ } else {
+ key = node->reversed;
+ }
+ next = node->next;
+ load++;
+ }
+
+ if (load > 255) load = 255;
+ array[load]++;
+ }
+
+ printf("HASH TABLE %p\tbuckets: %d\t(%d uninitialized)\n", ht,
+ ht->num_buckets, uninitialized);
+ printf("\tnum entries %d\thash collisions %d\n",
+ ht->num_elements, collisions);
+
+ a = 0;
+ for (i = 1; i < 256; i++) {
+ if (!array[i]) continue;
+ printf("%d\t%d\n", i, array[i]);
+
+ /*
+ * Since the entries are ordered, the lookup cost
+ * for any one element in a chain is (on average)
+ * the cost of walking half of the chain.
+ */
+ if (i > 1) {
+ a += array[i] * i;
+ }
+ }
+ a /= 2;
+ a += array[1];
+
+ printf("\texpected lookup cost = %d/%d or %f\n\n",
+ ht->num_elements, a,
+ (float) ht->num_elements / (float) a);
+
+ return 0;
+}
+#endif
+
+
+#define FNV_MAGIC_INIT (0x811c9dc5)
+#define FNV_MAGIC_PRIME (0x01000193)
+
+/*
+ * A fast hash function. For details, see:
+ *
+ * http://www.isthe.com/chongo/tech/comp/fnv/
+ *
+ * Which also includes public domain source. We've re-written
+ * it here for our purposes.
+ */
+uint32_t fr_hash(void const *data, size_t size)
+{
+ uint8_t const *p = data;
+ uint8_t const *q = p + size;
+ uint32_t hash = FNV_MAGIC_INIT;
+
+ /*
+ * FNV-1 hash each octet in the buffer
+ */
+ while (p != q) {
+ /*
+ * XOR the 8-bit quantity into the bottom of
+ * the hash.
+ */
+ hash ^= (uint32_t) (*p++);
+
+ /*
+ * Multiple by 32-bit magic FNV prime, mod 2^32
+ */
+ hash *= FNV_MAGIC_PRIME;
+#if 0
+ /*
+ * Potential optimization.
+ */
+ hash += (hash<<1) + (hash<<4) + (hash<<7) + (hash<<8) + (hash<<24);
+#endif
+ }
+
+ return hash;
+}
+
+/*
+ * Continue hashing data.
+ */
+uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
+{
+ uint8_t const *p = data;
+ uint8_t const *q = p + size;
+
+ while (p != q) {
+ hash *= FNV_MAGIC_PRIME;
+ hash ^= (uint32_t) (*p++);
+ }
+
+ return hash;
+
+}
+
+/*
+ * Hash a C string, so we loop over it once.
+ */
+uint32_t fr_hash_string(char const *p)
+{
+ uint32_t hash = FNV_MAGIC_INIT;
+
+ while (*p) {
+ hash *= FNV_MAGIC_PRIME;
+ hash ^= (uint32_t) (*p++);
+ }
+
+ return hash;
+}
+
+
+#ifdef TESTING
+/*
+ * cc -g -DTESTING -I ../include hash.c -o hash
+ *
+ * ./hash
+ */
+static uint32_t hash_int(void const *data)
+{
+ return fr_hash((int *) data, sizeof(int));
+}
+
+#define MAX 1024*1024
+int main(int argc, char **argv)
+{
+ int i, *p, *q, k;
+ fr_hash_table_t *ht;
+ int *array;
+
+ ht = fr_hash_table_create(hash_int, NULL, NULL);
+ if (!ht) {
+ fprintf(stderr, "Hash create failed\n");
+ fr_exit(1);
+ }
+
+ array = malloc(sizeof(int) * MAX);
+ if (!array) fr_exit(1);
+
+ for (i = 0; i < MAX; i++) {
+ p = array + i;
+ *p = i;
+
+ if (!fr_hash_table_insert(ht, p)) {
+ fprintf(stderr, "Failed insert %08x\n", i);
+ fr_exit(1);
+ }
+#ifdef TEST_INSERT
+ q = fr_hash_table_finddata(ht, p);
+ if (q != p) {
+ fprintf(stderr, "Bad data %d\n", i);
+ fr_exit(1);
+ }
+#endif
+ }
+
+ fr_hash_table_info(ht);
+
+ /*
+ * Build this to see how lookups result in shortening
+ * of the hash chains.
+ */
+ if (1) {
+ for (i = 0; i < MAX ; i++) {
+ q = fr_hash_table_finddata(ht, &i);
+ if (!q || *q != i) {
+ fprintf(stderr, "Failed finding %d\n", i);
+ fr_exit(1);
+ }
+
+#if 0
+ if (!fr_hash_table_delete(ht, &i)) {
+ fprintf(stderr, "Failed deleting %d\n", i);
+ fr_exit(1);
+ }
+ q = fr_hash_table_finddata(ht, &i);
+ if (q) {
+ fprintf(stderr, "Failed to delete %08x\n", i);
+ fr_exit(1);
+ }
+#endif
+ }
+
+ fr_hash_table_info(ht);
+ }
+
+ fr_hash_table_free(ht);
+ free(array);
+
+ fr_exit(0);
+}
+#endif
diff --git a/src/lib/heap.c b/src/lib/heap.c
new file mode 100644
index 0000000..a2e8f78
--- /dev/null
+++ b/src/lib/heap.c
@@ -0,0 +1,356 @@
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/heap.h>
+
+/*
+ * A heap entry is made of a pointer to the object, which
+ * contains the key. The heap itself is an array of pointers.
+ *
+ * Heaps normally support only ordered insert, and extraction
+ * of the minimum element. The heap entry can contain an "int"
+ * field that holds the entries position in the heap. The offset
+ * of the field is held inside of the heap structure.
+ */
+
+struct fr_heap_t {
+ int size;
+ int num_elements;
+ size_t offset;
+ fr_heap_cmp_t cmp;
+ void **p;
+};
+
+/*
+ * First node in a heap is element 0. Children of i are 2i+1 and
+ * 2i+2. These macros wrap the logic, so the code is more
+ * descriptive.
+ */
+#define HEAP_PARENT(x) ( ( (x) - 1 ) / 2 )
+#define HEAP_LEFT(x) ( 2*(x) + 1 )
+/* #define HEAP_RIGHT(x) ( 2*(x) + 2 ) */
+#define HEAP_SWAP(a, b) { void *_tmp = a; a = b; b = _tmp; }
+
+static int fr_heap_bubble(fr_heap_t *hp, int child);
+
+void fr_heap_delete(fr_heap_t *hp)
+{
+ if (!hp) return;
+
+ free(hp->p);
+ free(hp);
+}
+
+fr_heap_t *fr_heap_create(fr_heap_cmp_t cmp, size_t offset)
+{
+ fr_heap_t *fh;
+
+ if (!cmp) return NULL;
+
+ fh = malloc(sizeof(*fh));
+ if (!fh) return NULL;
+
+ memset(fh, 0, sizeof(*fh));
+
+ fh->size = 2048;
+ fh->p = malloc(sizeof(*(fh->p)) * fh->size);
+ if (!fh->p) {
+ free(fh);
+ return NULL;
+ }
+
+ fh->cmp = cmp;
+ fh->offset = offset;
+
+ return fh;
+}
+
+/*
+ * Insert element in heap. Normally, p != NULL, we insert p in a
+ * new position and bubble up. If p == NULL, then the element is
+ * already in place, and key is the position where to start the
+ * bubble-up.
+ *
+ * Returns 1 on failure (cannot allocate new heap entry)
+ *
+ * If offset > 0 the position (index, int) of the element in the
+ * heap is also stored in the element itself at the given offset
+ * in bytes.
+ */
+#define SET_OFFSET(heap, node) \
+ if (heap->offset) \
+ *((int *)(((uint8_t *)heap->p[node]) + heap->offset)) = node
+
+/*
+ * RESET_OFFSET is used for sanity checks. It sets offset to an
+ * invalid value.
+ */
+#define RESET_OFFSET(heap, node) \
+ if (heap->offset) \
+ *((int *)(((uint8_t *)heap->p[node]) + heap->offset)) = -1
+
+int fr_heap_insert(fr_heap_t *hp, void *data)
+{
+ int child = hp->num_elements;
+
+ /*
+ * Heap is full. Double it's size.
+ */
+ if (child == hp->size) {
+ void **p;
+
+ p = malloc(2 * hp->size * sizeof(*p));
+ if (!p) return 0;
+
+ memcpy(p, hp->p, sizeof(*p) * hp->size);
+ free(hp->p);
+ hp->p = p;
+ hp->size *= 2;
+ }
+
+ hp->p[child] = data;
+ hp->num_elements++;
+
+ return fr_heap_bubble(hp, child);
+}
+
+
+static int fr_heap_bubble(fr_heap_t *hp, int child)
+{
+ /*
+ * Bubble up the element.
+ */
+ while (child > 0) {
+ int parent = HEAP_PARENT(child);
+
+ /*
+ * Parent is smaller than the child. We're done.
+ */
+ if (hp->cmp(hp->p[parent], hp->p[child]) < 0) break;
+
+ /*
+ * Child is smaller than the parent, repeat.
+ */
+ HEAP_SWAP(hp->p[child], hp->p[parent]);
+ SET_OFFSET(hp, child);
+ child = parent;
+ }
+ SET_OFFSET(hp, child);
+
+ return 1;
+}
+
+
+/*
+ * Remove the top element, or object.
+ */
+int fr_heap_extract(fr_heap_t *hp, void *data)
+{
+ int child, parent;
+ int max;
+
+ if (!hp || (hp->num_elements == 0)) return 0;
+
+ max = hp->num_elements - 1;
+
+ /*
+ * Extract element. Default is the first one.
+ */
+ if (!data) {
+ parent = 0;
+
+ } else { /* extract from the middle */
+ if (!hp->offset) return 0;
+
+ parent = *((int *)(((uint8_t *)data) + hp->offset));
+
+ /*
+ * Out of bounds.
+ */
+ if (parent < 0 || parent >= hp->num_elements) return 0;
+ }
+
+ RESET_OFFSET(hp, parent);
+ child = HEAP_LEFT(parent);
+ while (child <= max) {
+ /*
+ * Maybe take the right child.
+ */
+ if ((child != max) &&
+ (hp->cmp(hp->p[child + 1], hp->p[child]) < 0)) {
+ child = child + 1;
+ }
+ hp->p[parent] = hp->p[child];
+ SET_OFFSET(hp, parent);
+ parent = child;
+ child = HEAP_LEFT(child);
+ }
+ hp->num_elements--;
+
+ /*
+ * We didn't end up at the last element in the heap.
+ * This element has to be re-inserted.
+ */
+ if (parent != max) {
+ /*
+ * Fill hole with last entry and bubble up,
+ * reusing the insert code
+ */
+ hp->p[parent] = hp->p[max];
+ return fr_heap_bubble(hp, parent);
+ }
+
+ return 1;
+}
+
+
+void *fr_heap_peek(fr_heap_t *hp)
+{
+ if (!hp || (hp->num_elements == 0)) return NULL;
+
+ /*
+ * If this is NULL, we have a problem.
+ */
+ return hp->p[0];
+}
+
+int fr_heap_num_elements(fr_heap_t *hp)
+{
+ if (!hp) return 0;
+
+ return hp->num_elements;
+}
+
+
+#ifdef TESTING
+static bool fr_heap_check(fr_heap_t *hp, void *data)
+{
+ int i;
+
+ if (!hp || (hp->num_elements == 0)) return false;
+
+ for (i = 0; i < hp->num_elements; i++) {
+ if (hp->p[i] == data) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+typedef struct heap_thing {
+ int data;
+ int heap; /* for the heap */
+} heap_thing;
+
+
+/*
+ * cc -g -DTESTING -I .. heap.c -o heap
+ *
+ * ./heap
+ */
+static int heap_cmp(void const *one, void const *two)
+{
+ heap_thing const *a;
+ heap_thing const *b;
+
+ a = (heap_thing const *) one;
+ b = (heap_thing const *) two;
+
+ return a->data - b->data;
+
+}
+
+#define ARRAY_SIZE (1024)
+
+int main(int argc, char **argv)
+{
+ fr_heap_t *hp;
+ int i;
+ heap_thing array[ARRAY_SIZE];
+ int skip = 0;
+ int left;
+
+ if (argc > 1) {
+ skip = atoi(argv[1]);
+ }
+
+ hp = fr_heap_create(heap_cmp, offsetof(heap_thing, heap));
+ if (!hp) {
+ fprintf(stderr, "Failed creating heap!\n");
+ fr_exit(1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE; i++) {
+ array[i].data = rand() % 65537;
+ if (!fr_heap_insert(hp, &array[i])) {
+ fprintf(stderr, "Failed inserting %d\n", i);
+ fr_exit(1);
+ }
+
+ if (!fr_heap_check(hp, &array[i])) {
+ fprintf(stderr, "Inserted but not in heap %d\n", i);
+ fr_exit(1);
+ }
+ }
+
+#if 0
+ for (i = 0; i < ARRAY_SIZE; i++) {
+ printf("Array %d has value %d at offset %d\n",
+ i, array[i].data, array[i].heap);
+ }
+#endif
+
+ if (skip) {
+ int entry;
+
+ printf("%d elements to remove\n", ARRAY_SIZE / skip);
+
+ for (i = 0; i < ARRAY_SIZE / skip; i++) {
+ entry = i * skip;
+
+ if (!fr_heap_extract(hp, &array[entry])) {
+ fprintf(stderr, "Failed removing %d\n", entry);
+ }
+
+ if (fr_heap_check(hp, &array[entry])) {
+ fprintf(stderr, "Deleted but still in heap %d\n", entry);
+ fr_exit(1);
+ }
+
+ if (array[entry].heap != -1) {
+ fprintf(stderr, "heap offset is wrong %d\n", entry);
+ fr_exit(1);
+ }
+ }
+ }
+
+ left = fr_heap_num_elements(hp);
+ printf("%d elements left in the heap\n", left);
+
+ for (i = 0; i < left; i++) {
+ heap_thing *t = fr_heap_peek(hp);
+
+ if (!t) {
+ fprintf(stderr, "Failed peeking %d\n", i);
+ fr_exit(1);
+ }
+
+ printf("%d\t%d\n", i, t->data);
+
+ if (!fr_heap_extract(hp, NULL)) {
+ fprintf(stderr, "Failed extracting %d\n", i);
+ fr_exit(1);
+ }
+ }
+
+ if (fr_heap_num_elements(hp) > 0) {
+ fprintf(stderr, "%d elements left at the end", fr_heap_num_elements(hp));
+ fr_exit(1);
+ }
+
+ fr_heap_delete(hp);
+
+ return 0;
+}
+#endif
diff --git a/src/lib/hmacmd5.c b/src/lib/hmacmd5.c
new file mode 100644
index 0000000..2aad490
--- /dev/null
+++ b/src/lib/hmacmd5.c
@@ -0,0 +1,197 @@
+/*
+ * hmac.c For the sake of illustration we provide the following
+ * sample code for the implementation of HMAC-MD5 as well
+ * as some corresponding test vectors (the code is based
+ * on MD5 code as described in [MD5]).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+/*
+** Function: fr_hmac_md5
+*/
+
+RCSID("$Id$")
+
+#ifdef HAVE_OPENSSL_EVP_H
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#endif
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/openssl3.h>
+
+#if defined(HAVE_OPENSSL_EVP_H) && !defined(WITH_FIPS)
+/** Calculate HMAC using OpenSSL's MD5 implementation
+ *
+ * @param digest Caller digest to be filled in.
+ * @param text Pointer to data stream.
+ * @param text_len length of data stream.
+ * @param key Pointer to authentication key.
+ * @param key_len Length of authentication key.
+ *
+ */
+void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len)
+{
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ unsigned int len = MD5_DIGEST_LENGTH;
+
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ /* Since MD5 is not allowed by FIPS, explicitly allow it. */
+ HMAC_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif /* EVP_MD_CTX_FLAG_NON_FIPS_ALLOW */
+
+ HMAC_Init_ex(ctx, key, key_len, EVP_md5(), NULL);
+ HMAC_Update(ctx, text, text_len);
+ HMAC_Final(ctx, digest, &len);
+ HMAC_CTX_free(ctx);
+}
+#else
+/** Calculate HMAC using internal MD5 implementation
+ *
+ * @param digest Caller digest to be filled in.
+ * @param text Pointer to data stream.
+ * @param text_len length of data stream.
+ * @param key Pointer to authentication key.
+ * @param key_len Length of authentication key.
+ *
+ */
+void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len)
+{
+ FR_MD5_CTX context;
+ uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
+ uint8_t k_opad[65]; /* outer padding - key XORd with opad */
+ uint8_t tk[16];
+ int i;
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+ FR_MD5_CTX tctx;
+
+ fr_md5_init(&tctx);
+ fr_md5_update(&tctx, key, key_len);
+ fr_md5_final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ memset( k_ipad, 0, sizeof(k_ipad));
+ memset( k_opad, 0, sizeof(k_opad));
+ memcpy( k_ipad, key, key_len);
+ memcpy( k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+ fr_md5_init(&context); /* init context for 1st
+ * pass */
+ fr_md5_update(&context, k_ipad, 64); /* start with inner pad */
+ fr_md5_update(&context, text, text_len); /* then text of datagram */
+ fr_md5_final(digest, &context); /* finish up 1st pass */
+ /*
+ * perform outer MD5
+ */
+ fr_md5_init(&context); /* init context for 2nd
+ * pass */
+ fr_md5_update(&context, k_opad, 64); /* start with outer pad */
+ fr_md5_update(&context, digest, 16); /* then results of 1st
+ * hash */
+ fr_md5_final(digest, &context); /* finish up 2nd pass */
+}
+#endif /* HAVE_OPENSSL_EVP_H */
+
+/*
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ key_len = 16 bytes
+ data = "Hi There"
+ data_len = 8 bytes
+ digest = 0x9294727a3638bb1c13f48ef8158bfc9d
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0x750c783e6ab0b503eaa86e310a5db738
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+*/
+
+#ifdef TESTING
+/*
+ * cc -DTESTING -I ../include/ hmac.c md5.c -o hmac
+ *
+ * ./hmac Jefe "what do ya want for nothing?"
+ */
+int main(int argc, char **argv)
+{
+ uint8_t digest[16];
+ char *key;
+ int key_len;
+ char *text;
+ int text_len;
+ int i;
+
+ key = argv[1];
+ key_len = strlen(key);
+
+ text = argv[2];
+ text_len = strlen(text);
+
+ fr_hmac_md5(digest, text, text_len, key, key_len);
+
+ for (i = 0; i < 16; i++) {
+ printf("%02x", digest[i]);
+ }
+ printf("\n");
+
+ exit(0);
+ return 0;
+}
+
+#endif
diff --git a/src/lib/hmacsha1.c b/src/lib/hmacsha1.c
new file mode 100644
index 0000000..8711f98
--- /dev/null
+++ b/src/lib/hmacsha1.c
@@ -0,0 +1,228 @@
+/*
+ * Adapted from hmac.c (HMAC-MD5) for use by SHA1.
+ * by <mcr@sandelman.ottawa.on.ca>. Test cases from RFC2202.
+ *
+ */
+
+/*
+** Function: hmac_sha1
+*/
+
+RCSID("$Id$")
+
+#ifdef HAVE_OPENSSL_EVP_H
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <freeradius-devel/openssl3.h>
+#endif
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef HMAC_SHA1_DATA_PROBLEMS
+unsigned int sha1_data_problems = 0;
+#endif
+
+#ifdef HAVE_OPENSSL_EVP_H
+/** Calculate HMAC using OpenSSL's SHA1 implementation
+ *
+ * @param digest Caller digest to be filled in.
+ * @param text Pointer to data stream.
+ * @param text_len length of data stream.
+ * @param key Pointer to authentication key.
+ * @param key_len Length of authentication key.
+
+ */
+void fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len)
+{
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ unsigned int len = SHA1_DIGEST_LENGTH;
+
+ HMAC_Init_ex(ctx, key, key_len, EVP_sha1(), NULL);
+ HMAC_Update(ctx, text, text_len);
+ HMAC_Final(ctx, digest, &len);
+ HMAC_CTX_free(ctx);
+}
+
+#else
+
+/** Calculate HMAC using internal SHA1 implementation
+ *
+ * @param digest Caller digest to be filled in.
+ * @param text Pointer to data stream.
+ * @param text_len length of data stream.
+ * @param key Pointer to authentication key.
+ * @param key_len Length of authentication key.
+ */
+void fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
+ uint8_t const *key, size_t key_len)
+{
+ fr_sha1_ctx context;
+ uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
+ uint8_t k_opad[65]; /* outer padding - key XORd with opad */
+ uint8_t tk[20];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=SHA1(key) */
+ if (key_len > 64) {
+
+ fr_sha1_ctx tctx;
+
+ fr_sha1_init(&tctx);
+ fr_sha1_update(&tctx, key, key_len);
+ fr_sha1_final(tk, &tctx);
+
+ key = tk;
+ key_len = 20;
+ }
+
+#ifdef HMAC_SHA1_DATA_PROBLEMS
+ if(sha1_data_problems)
+ {
+ int j,k;
+
+ printf("\nhmac-sha1 key(%d): ", key_len);
+ j=0; k=0;
+ for (i = 0; i < key_len; i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", key[i]);
+ }
+ printf("\nDATA: (%d) ",text_len);
+
+ j=0; k=0;
+ for (i = 0; i < text_len; i++) {
+ if(k==20) {
+ printf("\n ");
+ k=0;
+ j=0;
+ }
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ k++;
+ j++;
+
+ printf("%02x", text[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+
+ /*
+ * the HMAC_SHA1 transform looks like:
+ *
+ * SHA1(K XOR opad, SHA1(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner SHA1
+ */
+ fr_sha1_init(&context); /* init context for 1st pass */
+ fr_sha1_update(&context, k_ipad, 64); /* start with inner pad */
+ fr_sha1_update(&context, text, text_len); /* then text of datagram */
+ fr_sha1_final(digest, &context); /* finish up 1st pass */
+ /*
+ * perform outer SHA1
+ */
+ fr_sha1_init(&context); /* init context for 2nd pass */
+ fr_sha1_update(&context, k_opad, 64); /* start with outer pad */
+ fr_sha1_update(&context, digest, 20); /* then results of 1st hash */
+ fr_sha1_final(digest, &context); /* finish up 2nd pass */
+
+#ifdef HMAC_SHA1_DATA_PROBLEMS
+ if (sha1_data_problems) {
+ int j;
+
+ printf("\nhmac-sha1 mac(20): ");
+ j=0;
+ for (i = 0; i < 20; i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", digest[i]);
+ }
+ printf("\n");
+ }
+#endif
+}
+#endif /* HAVE_OPENSSL_EVP_H */
+
+/*
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+*/
+
+#ifdef TESTING
+/*
+ * cc -DTESTING -I ../include/ hmac.c sha1.c -o hmac
+ *
+ * ./hmac Jefe "what do ya want for nothing?"
+ */
+int main(int argc, char **argv)
+{
+ uint8_t digest[20];
+ char *key;
+ int key_len;
+ char *text;
+ int text_len;
+ int i;
+
+ key = argv[1];
+ key_len = strlen(key);
+
+ text = argv[2];
+ text_len = strlen(text);
+
+ fr_hmac_sha1(digest, text, text_len, key, key_len);
+
+ for (i = 0; i < 20; i++) {
+ printf("%02x", digest[i]);
+ }
+ printf("\n");
+
+ exit(0);
+ return 0;
+}
+
+#endif
diff --git a/src/lib/isaac.c b/src/lib/isaac.c
new file mode 100644
index 0000000..fff1a35
--- /dev/null
+++ b/src/lib/isaac.c
@@ -0,0 +1,133 @@
+/*
+------------------------------------------------------------------------------
+http://burtleburtle.net/bob/rand/isaac.html
+rand.c: By Bob Jenkins. My random number generator, ISAAC. Public Domain
+MODIFIED:
+ 960327: Creation (addition of randinit, really)
+ 970719: use context, not global variables, for internal state
+ 980324: make a portable version
+ 010626: Note this is public domain
+------------------------------------------------------------------------------
+*/
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#define RANDSIZL (8) /* I recommend 8 for crypto, 4 for simulations */
+#define RANDSIZ (1<<RANDSIZL)
+
+#define ind(mm,x) ((mm)[(x>>2)&(RANDSIZ-1)])
+#define rngstep(mix,a,b,mm,m,m2,r,x) \
+{ \
+ x = *m; \
+ a = ((a^(mix)) + *(m2++)) & 0xffffffff; \
+ *(m++) = y = (ind(mm,x) + a + b) & 0xffffffff; \
+ *(r++) = b = (ind(mm,y>>RANDSIZL) + x) & 0xffffffff; \
+}
+
+void fr_isaac(fr_randctx *ctx)
+{
+ register uint32_t a,b,x,y,*m,*mm,*m2,*r,*mend;
+ mm=ctx->randmem; r=ctx->randrsl;
+ a = ctx->randa; b = (ctx->randb + (++ctx->randc)) & 0xffffffff;
+ for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; )
+ {
+ rngstep( a<<13, a, b, mm, m, m2, r, x);
+ rngstep( a>>6 , a, b, mm, m, m2, r, x);
+ rngstep( a<<2 , a, b, mm, m, m2, r, x);
+ rngstep( a>>16, a, b, mm, m, m2, r, x);
+ }
+ for (m2 = mm; m2<mend; )
+ {
+ rngstep( a<<13, a, b, mm, m, m2, r, x);
+ rngstep( a>>6 , a, b, mm, m, m2, r, x);
+ rngstep( a<<2 , a, b, mm, m, m2, r, x);
+ rngstep( a>>16, a, b, mm, m, m2, r, x);
+ }
+ ctx->randb = b; ctx->randa = a;
+}
+
+
+#define mix(a,b,c,d,e,f,g,h) \
+{ \
+ a^=b<<11; d+=a; b+=c; \
+ b^=c>>2; e+=b; c+=d; \
+ c^=d<<8; f+=c; d+=e; \
+ d^=e>>16; g+=d; e+=f; \
+ e^=f<<10; h+=e; f+=g; \
+ f^=g>>4; a+=f; g+=h; \
+ g^=h<<8; b+=g; h+=a; \
+ h^=a>>9; c+=h; a+=b; \
+}
+
+/* if (flag==1), then use the contents of randrsl[] to initialize mm[]. */
+void fr_randinit(fr_randctx *ctx, int flag)
+{
+ int i;
+ uint32_t a,b,c,d,e,f,g,h;
+ uint32_t *m,*r;
+ ctx->randa = ctx->randb = ctx->randc = 0;
+ m=ctx->randmem;
+ r=ctx->randrsl;
+ a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */
+
+ for (i=0; i<4; ++i) { /* scramble it */
+ mix(a,b,c,d,e,f,g,h);
+ }
+
+ if (flag) {
+ /* initialize using the contents of r[] as the seed */
+ for (i=0; i<RANDSIZ; i+=8) {
+ a+=r[i ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
+ e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
+ mix(a,b,c,d,e,f,g,h);
+ m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
+ m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
+ }
+ /* do a second pass to make all of the seed affect all of m */
+ for (i=0; i<RANDSIZ; i+=8) {
+ a+=m[i ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
+ e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
+ mix(a,b,c,d,e,f,g,h);
+ m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
+ m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
+ }
+ } else {
+ for (i=0; i<RANDSIZ; i+=8) {
+ /* fill in mm[] with messy stuff */
+ mix(a,b,c,d,e,f,g,h);
+ m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
+ m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
+ }
+ }
+
+ fr_isaac(ctx); /* fill in the first set of results */
+ ctx->randcnt=RANDSIZ; /* prepare to use the first set of results */
+}
+
+
+#ifdef TEST
+/*
+ * For testing. Output should be the same as
+ *
+ * http://burtleburtle.net/bob/rand/randvect.txt
+ */
+int main()
+{
+ uint32_t i,j;
+ fr_randctx ctx;
+
+ ctx.randa = ctx.randb = ctx.randc = (uint32_t)0;
+
+ for (i=0; i<256; ++i) ctx.randrsl[i]=(uint32_t)0;
+ fr_randinit(&ctx, 1);
+ for (i=0; i<2; ++i) {
+ fr_isaac(&ctx);
+ for (j=0; j<256; ++j) {
+ printf("%.8lx",ctx.randrsl[j]);
+ if ((j&7)==7) printf("\n");
+ }
+ }
+}
+#endif
diff --git a/src/lib/log.c b/src/lib/log.c
new file mode 100644
index 0000000..c7e3256
--- /dev/null
+++ b/src/lib/log.c
@@ -0,0 +1,343 @@
+/*
+ * log.c Functions in the library call radlib_log() which
+ * does internal logging.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+/*
+ * Are we using glibc or a close relative?
+ */
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
+
+#define FR_STRERROR_BUFSIZE (2048)
+
+fr_thread_local_setup(char *, fr_strerror_buffer) /* macro */
+fr_thread_local_setup(char *, fr_syserror_buffer) /* macro */
+
+#ifndef NDEBUG
+/** POSIX-2008 errno macros
+ *
+ * Non-POSIX macros may be added, but you must check they're defined.
+ */
+static char const *fr_errno_macro_names[] = {
+ [E2BIG] = "E2BIG",
+ [EACCES] = "EACCES",
+ [EADDRINUSE] = "EADDRINUSE",
+ [EADDRNOTAVAIL] = "EADDRNOTAVAIL",
+ [EAFNOSUPPORT] = "EAFNOSUPPORT",
+#if EWOULDBLOCK == EAGAIN
+ [EWOULDBLOCK] = "EWOULDBLOCK or EAGAIN",
+#else
+ [EAGAIN] = "EAGAIN",
+ [EWOULDBLOCK] = "EWOULDBLOCK",
+#endif
+ [EALREADY] = "EALREADY",
+ [EBADF] = "EBADF",
+ [EBADMSG] = "EBADMSG",
+ [EBUSY] = "EBUSY",
+ [ECANCELED] = "ECANCELED",
+ [ECHILD] = "ECHILD",
+ [ECONNABORTED] = "ECONNABORTED",
+ [ECONNREFUSED] = "ECONNREFUSED",
+ [ECONNRESET] = "ECONNRESET",
+ [EDEADLK] = "EDEADLK",
+ [EDESTADDRREQ] = "EDESTADDRREQ",
+ [EDOM] = "EDOM",
+ [EDQUOT] = "EDQUOT",
+ [EEXIST] = "EEXIST",
+ [EFAULT] = "EFAULT",
+ [EFBIG] = "EFBIG",
+ [EHOSTUNREACH] = "EHOSTUNREACH",
+ [EIDRM] = "EIDRM",
+ [EILSEQ] = "EILSEQ",
+ [EINPROGRESS] = "EINPROGRESS",
+ [EINTR] = "EINTR",
+ [EINVAL] = "EINVAL",
+ [EIO] = "EIO",
+ [EISCONN] = "EISCONN",
+ [EISDIR] = "EISDIR",
+ [ELOOP] = "ELOOP",
+ [EMFILE] = "EMFILE",
+ [EMLINK] = "EMLINK",
+ [EMSGSIZE] = "EMSGSIZE",
+ [EMULTIHOP] = "EMULTIHOP",
+ [ENAMETOOLONG] = "ENAMETOOLONG",
+ [ENETDOWN] = "ENETDOWN",
+ [ENETRESET] = "ENETRESET",
+ [ENETUNREACH] = "ENETUNREACH",
+ [ENFILE] = "ENFILE",
+ [ENOBUFS] = "ENOBUFS",
+#ifdef ENODATA
+ [ENODATA] = "ENODATA",
+#endif
+ [ENODEV] = "ENODEV",
+ [ENOENT] = "ENOENT",
+ [ENOEXEC] = "ENOEXEC",
+ [ENOLCK] = "ENOLCK",
+ [ENOLINK] = "ENOLINK",
+ [ENOMEM] = "ENOMEM",
+ [ENOMSG] = "ENOMSG",
+ [ENOPROTOOPT] = "ENOPROTOOPT",
+ [ENOSPC] = "ENOSPC",
+#ifdef ENOSR
+ [ENOSR] = "ENOSR",
+#endif
+#ifdef ENOSTR
+ [ENOSTR] = "ENOSTR",
+#endif
+ [ENOSYS] = "ENOSYS",
+ [ENOTCONN] = "ENOTCONN",
+ [ENOTDIR] = "ENOTDIR",
+ [ENOTEMPTY] = "ENOTEMPTY",
+#ifdef ENOTRECOVERABLE
+ [ENOTRECOVERABLE] = "ENOTRECOVERABLE",
+#endif
+ [ENOTSOCK] = "ENOTSOCK",
+ [ENOTSUP] = "ENOTSUP",
+#if ENOTSUP != EOPNOTSUPP
+ [EOPNOTSUPP] = "EOPNOTSUPP",
+#endif
+ [ENOTTY] = "ENOTTY",
+ [ENXIO] = "ENXIO",
+ [EOVERFLOW] = "EOVERFLOW",
+#ifdef EOWNERDEAD
+ [EOWNERDEAD] = "EOWNERDEAD",
+#endif
+ [EPERM] = "EPERM",
+ [EPIPE] = "EPIPE",
+ [EPROTO] = "EPROTO",
+ [EPROTONOSUPPORT] = "EPROTONOSUPPORT",
+ [EPROTOTYPE] = "EPROTOTYPE",
+ [ERANGE] = "ERANGE",
+ [EROFS] = "EROFS",
+ [ESPIPE] = "ESPIPE",
+ [ESRCH] = "ESRCH",
+ [ESTALE] = "ESTALE",
+#ifdef ETIME
+ [ETIME] = "ETIME",
+#endif
+ [ETIMEDOUT] = "ETIMEDOUT",
+ [ETXTBSY] = "ETXTBSY",
+ [EXDEV] = "EXDEV"
+};
+#endif
+
+/*
+ * Explicitly cleanup the memory allocated to the error buffer,
+ * just in case valgrind complains about it.
+ */
+static void _fr_logging_free(void *arg)
+{
+ free(arg);
+}
+
+/** Log to thread local error buffer
+ *
+ * @param fmt printf style format string. If NULL sets the 'new' byte to false,
+ * effectively clearing the last message.
+ */
+void fr_strerror_printf(char const *fmt, ...)
+{
+ va_list ap;
+
+ char *buffer;
+
+ buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free);
+ if (!buffer) {
+ int ret;
+
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */
+ if (!buffer) {
+ fr_perror("Failed allocating memory for libradius error buffer");
+ return;
+ }
+
+ ret = fr_thread_local_set(fr_strerror_buffer, buffer);
+ if (ret != 0) {
+ fr_perror("Failed setting up thread-local storage for libradius error buffer: %s", fr_syserror(ret));
+ free(buffer);
+ return;
+ }
+ }
+
+ /*
+ * NULL has a special meaning, setting the new bit to false.
+ */
+ if (!fmt) {
+ buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06;
+ return;
+ }
+
+ va_start(ap, fmt);
+ /*
+ * Alternate where we write the message, so we can do:
+ * fr_strerror_printf("Additional error: %s", fr_strerror());
+ */
+ switch (buffer[FR_STRERROR_BUFSIZE * 2] & 0x06) {
+ default:
+ vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap);
+ buffer[FR_STRERROR_BUFSIZE * 2] = 0x05; /* Flip the 'new' bit to true */
+ break;
+
+ case 0x04:
+ vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap);
+ buffer[FR_STRERROR_BUFSIZE * 2] = 0x03; /* Flip the 'new' bit to true */
+ break;
+ }
+ va_end(ap);
+}
+
+/** Get the last library error
+ *
+ * Will only return the last library error once, after which it will return a zero length string.
+ *
+ * @return library error or zero length string
+ */
+char const *fr_strerror(void)
+{
+ char *buffer;
+
+ buffer = fr_thread_local_get(fr_strerror_buffer);
+ if (!buffer) return "";
+
+ switch (buffer[FR_STRERROR_BUFSIZE * 2]) {
+ default:
+ return "";
+
+ case 0x03:
+ buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; /* Flip the 'new' bit to false */
+ return buffer;
+
+ case 0x05:
+ buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; /* Flip the 'new' bit to false */
+ return buffer + FR_STRERROR_BUFSIZE;
+ }
+}
+
+/** Guaranteed to be thread-safe version of strerror
+ *
+ * @param num errno as returned by function or from global errno.
+ * @return local specific error string relating to errno.
+ */
+char const *fr_syserror(int num)
+{
+ char *buffer, *p, *end;
+ int ret;
+
+ buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free);
+ if (!buffer) {
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE);
+ if (!buffer) {
+ fr_perror("Failed allocating memory for system error buffer");
+ return NULL;
+ }
+
+ ret = fr_thread_local_set(fr_syserror_buffer, buffer);
+ if (ret != 0) {
+ fr_perror("Failed setting up thread-local storage for system error buffer");
+ free(buffer);
+ return NULL;
+ }
+ }
+
+ if (!num) return "No error";
+
+ p = buffer;
+ end = p + FR_STRERROR_BUFSIZE;
+
+#ifndef NDEBUG
+ /*
+ * Prefix system errors with the macro name and number
+ * if we're debugging.
+ */
+ if (num < (int)(sizeof(fr_errno_macro_names) / sizeof(*fr_errno_macro_names))) {
+ p += snprintf(p, end - p, "%s: ", fr_errno_macro_names[num]);
+ } else {
+ p += snprintf(p, end - p, "errno %i: ", num);
+ }
+ if (p >= end) return p;
+#endif
+
+ /*
+ * XSI-Compliant version
+ */
+#if !defined(HAVE_FEATURES_H) || !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE)
+ ret = strerror_r(num, p, end - p);
+ if (ret != 0) {
+# ifndef NDEBUG
+ fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), "
+ "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret));
+# endif
+ buffer[0] = '\0';
+ }
+ return buffer;
+ /*
+ * GNU Specific version
+ *
+ * The GNU Specific version returns a char pointer. That pointer may point
+ * the buffer you just passed in, or to an immutable static string.
+ */
+#else
+ {
+ p = strerror_r(num, p, end - p);
+ if (!p) {
+# ifndef NDEBUG
+ fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p "
+ "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno));
+# endif
+ buffer[0] = '\0';
+ return buffer;
+ }
+
+ return p;
+ }
+#endif
+
+}
+
+void fr_perror(char const *fmt, ...)
+{
+ char const *error;
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+
+ error = fr_strerror();
+ if (error && (error[0] != '\0')) {
+ fprintf(stderr, ": %s\n", error);
+ } else {
+ fputs("\n", stderr);
+ }
+
+ va_end(ap);
+}
diff --git a/src/lib/md4.c b/src/lib/md4.c
new file mode 100644
index 0000000..7169000
--- /dev/null
+++ b/src/lib/md4.c
@@ -0,0 +1,310 @@
+/**
+ * $Id$
+ *
+ * @note license is LGPL, but largely derived from a public domain source.
+ *
+ * @file md4.c
+ * @brief md4 digest functions.
+ */
+
+RCSID("$Id$")
+
+/*
+ * FORCE MD4 TO USE OUR MD4 HEADER FILE!
+ * If we don't do this, it might pick up the systems broken MD4.
+ */
+#include <freeradius-devel/md4.h>
+
+/** Calculate the MD4 hash of the contents of a buffer
+ *
+ * @param[out] out Where to write the MD4 digest. Must be a minimum of MD4_DIGEST_LENGTH.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md4_calc(uint8_t out[MD4_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
+{
+ FR_MD4_CTX ctx;
+
+ fr_md4_init(&ctx);
+ fr_md4_update(&ctx, in, inlen);
+ fr_md4_final(out, &ctx);
+ fr_md4_destroy(&ctx);
+}
+
+#ifndef HAVE_OPENSSL_MD4_H
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4Context structure, pass it to fr_md4_init, call fr_md4_update as
+ * needed on buffers full of bytes, and then call fr_md4_final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifdef FR_LITTLE_ENDIAN
+# define htole32_4(buf) /* Nothing */
+# define htole32_14(buf) /* Nothing */
+# define htole32_16(buf) /* Nothing */
+#else
+/* Sometimes defined by endian.h */
+# ifndef htole32
+# define htole32(x)\
+ (((((uint32_t)x) & 0xff000000) >> 24) |\
+ ((((uint32_t)x) & 0x00ff0000) >> 8) |\
+ ((((uint32_t)x) & 0x0000ff00) << 8) |\
+ ((((uint32_t)x) & 0x000000ff) << 24))
+# endif
+# define htole32_4(buf) do {\
+ (buf)[0] = htole32((buf)[0]);\
+ (buf)[1] = htole32((buf)[1]);\
+ (buf)[2] = htole32((buf)[2]);\
+ (buf)[3] = htole32((buf)[3]);\
+} while (0)
+
+# define htole32_14(buf) do {\
+ (buf)[0] = htole32((buf)[0]);\
+ (buf)[1] = htole32((buf)[1]);\
+ (buf)[2] = htole32((buf)[2]);\
+ (buf)[3] = htole32((buf)[3]);\
+ (buf)[4] = htole32((buf)[4]);\
+ (buf)[5] = htole32((buf)[5]);\
+ (buf)[6] = htole32((buf)[6]);\
+ (buf)[7] = htole32((buf)[7]);\
+ (buf)[8] = htole32((buf)[8]);\
+ (buf)[9] = htole32((buf)[9]);\
+ (buf)[10] = htole32((buf)[10]);\
+ (buf)[11] = htole32((buf)[11]);\
+ (buf)[12] = htole32((buf)[12]);\
+ (buf)[13] = htole32((buf)[13]);\
+} while (0)
+
+# define htole32_16(buf) do {\
+ (buf)[0] = htole32((buf)[0]);\
+ (buf)[1] = htole32((buf)[1]);\
+ (buf)[2] = htole32((buf)[2]);\
+ (buf)[3] = htole32((buf)[3]);\
+ (buf)[4] = htole32((buf)[4]);\
+ (buf)[5] = htole32((buf)[5]);\
+ (buf)[6] = htole32((buf)[6]);\
+ (buf)[7] = htole32((buf)[7]);\
+ (buf)[8] = htole32((buf)[8]);\
+ (buf)[9] = htole32((buf)[9]);\
+ (buf)[10] = htole32((buf)[10]);\
+ (buf)[11] = htole32((buf)[11]);\
+ (buf)[12] = htole32((buf)[12]);\
+ (buf)[13] = htole32((buf)[13]);\
+ (buf)[14] = htole32((buf)[14]);\
+ (buf)[15] = htole32((buf)[15]);\
+} while (0)
+#endif
+
+/** Initialise a new MD4 context
+ *
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ *
+ * @param[out] ctx to initialise.
+ */
+void fr_md4_init(FR_MD4_CTX *ctx)
+{
+ ctx->count[0] = 0;
+ ctx->count[1] = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/** Feed additional data into the MD4 hashing function
+ *
+ * @param[in,out] ctx to update.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md4_update(FR_MD4_CTX *ctx, uint8_t const *in, size_t inlen)
+{
+ uint32_t count;
+
+ /* Bytes already stored in ctx->buffer */
+ count = (uint32_t)((ctx->count[0] >> 3) & 0x3f);
+
+ /* Update bitcount */
+/* ctx->count += (uint64_t)inlen << 3;*/
+ if ((ctx->count[0] += ((uint32_t)inlen << 3)) < (uint32_t)inlen) {
+ /* Overflowed ctx->count[0] */
+ ctx->count[1]++;
+ }
+ ctx->count[1] += ((uint32_t)inlen >> 29);
+
+ /* Handle any leading odd-sized chunks */
+ if (count) {
+ unsigned char *p = (unsigned char *)ctx->buffer + count;
+
+ count = MD4_BLOCK_LENGTH - count;
+ if (inlen < count) {
+ memcpy(p, in, inlen);
+ return;
+ }
+ memcpy(p, in, count);
+ htole32_16((uint32_t *)ctx->buffer);
+ fr_md4_transform(ctx->state, ctx->buffer);
+ in += count;
+ inlen -= count;
+ }
+
+ /* Process data in MD4_BLOCK_LENGTH-byte chunks */
+ while (inlen >= MD4_BLOCK_LENGTH) {
+ memcpy(ctx->buffer, in, MD4_BLOCK_LENGTH);
+ htole32_16((uint32_t *)ctx->buffer);
+ fr_md4_transform(ctx->state, ctx->buffer);
+ in += MD4_BLOCK_LENGTH;
+ inlen -= MD4_BLOCK_LENGTH;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->buffer, in, inlen);
+}
+
+/** Finalise the MD4 context and write out the hash
+ *
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 1 0*
+ * (64-bit count of bits processed, MSB-first).
+ *
+ * @param[out] out Where to write the MD4 digest. Minimum length of MD4_DIGEST_LENGTH.
+ * @param[in,out] ctx to finalise.
+ */
+void fr_md4_final(uint8_t out[MD4_DIGEST_LENGTH], FR_MD4_CTX *ctx)
+{
+ uint32_t count;
+ unsigned char *p;
+
+ /* number of bytes mod 64 */
+ count = (uint32_t)(ctx->count[0] >> 3) & 0x3f;
+
+ /*
+ * Set the first char of padding to 0x80.
+ * This is safe since there is always at least one byte free.
+ */
+ p = ctx->buffer + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ htole32_16((uint32_t *)ctx->buffer);
+ fr_md4_transform(ctx->state, ctx->buffer);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->buffer, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ htole32_14((uint32_t *)ctx->buffer);
+
+ /* Append bit count and transform */
+ ((uint32_t *)ctx->buffer)[14] = ctx->count[0];
+ ((uint32_t *)ctx->buffer)[15] = ctx->count[1];
+
+ fr_md4_transform(ctx->state, ctx->buffer);
+ htole32_4(ctx->state);
+ memcpy(out, ctx->state, MD4_DIGEST_LENGTH);
+ memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */
+}
+
+/* The three core functions - F1 is optimized somewhat */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F3(x, y, z) (x ^ y ^ z)
+
+/* This is the central step in the MD4 algorithm. */
+#define MD4STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s))
+
+/** The core of the MD4 algorithm
+ *
+ * This alters an existing MD4 hash to reflect the addition of 16
+ * longwords of new data. fr_md4_update blocks the data and converts bytes
+ * into longwords for this routine.
+ *
+ * @param[in] state 16 bytes of data to feed into the hashing function.
+ * @param[in,out] block MD4 digest block to update.
+ */
+void fr_md4_transform(uint32_t state[4], uint8_t const block[MD4_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d;
+ uint32_t const *in = (uint32_t const *)block;
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD4STEP(F1, a, b, c, d, in[ 0], 3);
+ MD4STEP(F1, d, a, b, c, in[ 1], 7);
+ MD4STEP(F1, c, d, a, b, in[ 2], 11);
+ MD4STEP(F1, b, c, d, a, in[ 3], 19);
+ MD4STEP(F1, a, b, c, d, in[ 4], 3);
+ MD4STEP(F1, d, a, b, c, in[ 5], 7);
+ MD4STEP(F1, c, d, a, b, in[ 6], 11);
+ MD4STEP(F1, b, c, d, a, in[ 7], 19);
+ MD4STEP(F1, a, b, c, d, in[ 8], 3);
+ MD4STEP(F1, d, a, b, c, in[ 9], 7);
+ MD4STEP(F1, c, d, a, b, in[10], 11);
+ MD4STEP(F1, b, c, d, a, in[11], 19);
+ MD4STEP(F1, a, b, c, d, in[12], 3);
+ MD4STEP(F1, d, a, b, c, in[13], 7);
+ MD4STEP(F1, c, d, a, b, in[14], 11);
+ MD4STEP(F1, b, c, d, a, in[15], 19);
+
+ MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
+
+ MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+#endif
diff --git a/src/lib/md5.c b/src/lib/md5.c
new file mode 100644
index 0000000..b5c1729
--- /dev/null
+++ b/src/lib/md5.c
@@ -0,0 +1,276 @@
+/**
+ * $Id$
+ *
+ * @note license is LGPL, but largely derived from a public domain source.
+ *
+ * @file md5.c
+ * @brief md5 digest functions.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+/*
+ * FORCE MD5 TO USE OUR MD5 HEADER FILE!
+ * If we don't do this, it might pick up the systems broken MD5.
+ */
+#include <freeradius-devel/md5.h>
+
+/** Calculate the MD5 hash of the contents of a buffer
+ *
+ * @param[out] out Where to write the MD5 digest. Must be a minimum of MD5_DIGEST_LENGTH.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md5_calc(uint8_t *out, uint8_t const *in, size_t inlen)
+{
+ FR_MD5_CTX ctx;
+
+ fr_md5_init(&ctx);
+ fr_md5_update(&ctx, in, inlen);
+ fr_md5_final(out, &ctx);
+ fr_md5_destroy(&ctx);
+}
+
+#ifndef HAVE_OPENSSL_MD5_H
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to fr_md5_init, call fr_md5_update as
+ * needed on buffers full of bytes, and then call fr_md5_final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#define PUT_64BIT_LE(cp, value) do {\
+ (cp)[7] = (value)[1] >> 24;\
+ (cp)[6] = (value)[1] >> 16;\
+ (cp)[5] = (value)[1] >> 8;\
+ (cp)[4] = (value)[1];\
+ (cp)[3] = (value)[0] >> 24;\
+ (cp)[2] = (value)[0] >> 16;\
+ (cp)[1] = (value)[0] >> 8;\
+ (cp)[0] = (value)[0];\
+} while (0)
+
+#define PUT_32BIT_LE(cp, value) do {\
+ (cp)[3] = (value) >> 24;\
+ (cp)[2] = (value) >> 16;\
+ (cp)[1] = (value) >> 8;\
+ (cp)[0] = (value);\
+} while (0)
+
+static const uint8_t PADDING[MD5_BLOCK_LENGTH] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/** Initialise a new MD5 context
+ *
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ *
+ * @param[out] ctx to initialise.
+ */
+void fr_md5_init(FR_MD5_CTX *ctx)
+{
+ ctx->count[0] = 0;
+ ctx->count[1] = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/** Feed additional data into the MD5 hashing function
+ *
+ * @param[in,out] ctx to update.
+ * @param[in] in Data to hash.
+ * @param[in] inlen Length of the data.
+ */
+void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen)
+{
+ size_t have, need;
+
+ /* Check how many bytes we already have and how many more we need. */
+ have = (size_t)((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
+ need = MD5_BLOCK_LENGTH - have;
+
+ /* Update bitcount */
+/* ctx->count += (uint64_t)inlen << 3;*/
+ if ((ctx->count[0] += ((uint32_t)inlen << 3)) < (uint32_t)inlen) {
+ /* Overflowed ctx->count[0] */
+ ctx->count[1]++;
+ }
+ ctx->count[1] += ((uint32_t)inlen >> 29);
+
+ if (inlen >= need) {
+ if (have != 0) {
+ memcpy(ctx->buffer + have, in, need);
+ fr_md5_transform(ctx->state, ctx->buffer);
+ in += need;
+ inlen -= need;
+ have = 0;
+ }
+
+ /* Process data in MD5_BLOCK_LENGTH-byte chunks. */
+ while (inlen >= MD5_BLOCK_LENGTH) {
+ fr_md5_transform(ctx->state, in);
+ in += MD5_BLOCK_LENGTH;
+ inlen -= MD5_BLOCK_LENGTH;
+ }
+ }
+
+ /* Handle any remaining bytes of data. */
+ if (inlen != 0) memcpy(ctx->buffer + have, in, inlen);
+}
+
+/** Finalise the MD5 context and write out the hash
+ *
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 1 0*
+ * (64-bit count of bits processed, MSB-first).
+ *
+ * @param[out] out Where to write the MD5 digest. Minimum length of MD5_DIGEST_LENGTH.
+ * @param[in,out] ctx to finalise.
+ */
+void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx)
+{
+ uint8_t count[8];
+ size_t padlen;
+ int i;
+
+ /* Convert count to 8 bytes in little endian order. */
+ PUT_64BIT_LE(count, ctx->count);
+
+ /* Pad out to 56 mod 64. */
+ padlen = MD5_BLOCK_LENGTH -
+ ((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1));
+ if (padlen < 1 + 8)
+ padlen += MD5_BLOCK_LENGTH;
+ fr_md5_update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
+ fr_md5_update(ctx, count, 8);
+
+ if (out != NULL) {
+ for (i = 0; i < 4; i++)
+ PUT_32BIT_LE(out + i * 4, ctx->state[i]);
+ }
+ memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
+
+/** The core of the MD5 algorithm
+ *
+ * This alters an existing MD5 hash to reflect the addition of 16
+ * longwords of new data. fr_md5_update blocks the data and converts bytes
+ * into longwords for this routine.
+ *
+ * @param[in] state 16 bytes of data to feed into the hashing function.
+ * @param[in,out] block MD5 digest block to update.
+ */
+void fr_md5_transform(uint32_t state[4], uint8_t const block[MD5_BLOCK_LENGTH])
+{
+ uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
+
+ for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
+ in[a] = (uint32_t)(
+ (uint32_t)(block[a * 4 + 0]) |
+ (uint32_t)(block[a * 4 + 1]) << 8 |
+ (uint32_t)(block[a * 4 + 2]) << 16 |
+ (uint32_t)(block[a * 4 + 3]) << 24);
+ }
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+#endif
diff --git a/src/lib/misc.c b/src/lib/misc.c
new file mode 100644
index 0000000..b80b9ce
--- /dev/null
+++ b/src/lib/misc.c
@@ -0,0 +1,2192 @@
+/*
+ * misc.c Various miscellaneous functions.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/uio.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+
+/*
+ * Some versions of Linux don't have closefrom(), but they will
+ * have /proc.
+ *
+ * BSD systems will generally have closefrom(), but not proc.
+ *
+ * OSX doesn't have closefrom() or /proc/self/fd, but it does
+ * have /dev/fd
+ */
+#ifdef __linux__
+#define CLOSEFROM_DIR "/proc/self/fd"
+#elif defined(__APPLE__)
+#define CLOSEFROM_DIR "/dev/fd"
+#else
+#undef HAVE_DIRENT_H
+#endif
+
+#endif
+
+#define FR_PUT_LE16(a, val)\
+ do {\
+ a[1] = ((uint16_t) (val)) >> 8;\
+ a[0] = ((uint16_t) (val)) & 0xff;\
+ } while (0)
+
+bool fr_dns_lookups = false; /* IP -> hostname lookups? */
+bool fr_hostname_lookups = true; /* hostname -> IP lookups? */
+int fr_debug_lvl = 0;
+
+static char const *months[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec" };
+
+fr_thread_local_setup(char *, fr_inet_ntop_buffer) /* macro */
+
+typedef struct fr_talloc_link {
+ bool armed;
+ TALLOC_CTX *child;
+} fr_talloc_link_t;
+
+/** Sets a signal handler using sigaction if available, else signal
+ *
+ * @param sig to set handler for.
+ * @param func handler to set.
+ */
+DIAG_OPTIONAL
+DIAG_OFF(disabled-macro-expansion)
+int fr_set_signal(int sig, sig_t func)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = func;
+
+ if (sigaction(sig, &act, NULL) < 0) {
+ fr_strerror_printf("Failed setting signal %i handler via sigaction(): %s", sig, fr_syserror(errno));
+ return -1;
+ }
+#else
+ if (signal(sig, func) < 0) {
+ fr_strerror_printf("Failed setting signal %i handler via signal(): %s", sig, fr_syserror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+DIAG_ON(disabled-macro-expansion)
+
+/** Uninstall a signal for a specific handler
+ *
+ * man sigaction says these are fine to call from a signal handler.
+ *
+ * @param sig SIGNAL
+ */
+DIAG_OPTIONAL
+DIAG_OFF(disabled-macro-expansion)
+int fr_unset_signal(int sig)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+
+ return sigaction(sig, &act, NULL);
+#else
+ return signal(sig, SIG_DFL);
+#endif
+}
+DIAG_ON(disabled-macro-expansion)
+
+static int _fr_trigger_talloc_ctx_free(fr_talloc_link_t *trigger)
+{
+ if (trigger->armed) talloc_free(trigger->child);
+
+ return 0;
+}
+
+static int _fr_disarm_talloc_ctx_free(bool **armed)
+{
+ **armed = false;
+ return 0;
+}
+
+/** Link a parent and a child context, so the child is freed before the parent
+ *
+ * @note This is not thread safe. Do not free parent before threads are joined, do not call from a child thread.
+ * @note It's OK to free the child before threads are joined, but this will leak memory until the parent is freed.
+ *
+ * @param parent who's fate the child should share.
+ * @param child bound to parent's lifecycle.
+ * @return 0 on success -1 on failure.
+ */
+int fr_link_talloc_ctx_free(TALLOC_CTX *parent, TALLOC_CTX *child)
+{
+ fr_talloc_link_t *trigger;
+ bool **disarm;
+
+ trigger = talloc(parent, fr_talloc_link_t);
+ if (!trigger) return -1;
+
+ disarm = talloc(child, bool *);
+ if (!disarm) {
+ talloc_free(trigger);
+ return -1;
+ }
+
+ trigger->child = child;
+ trigger->armed = true;
+ *disarm = &trigger->armed;
+
+ talloc_set_destructor(trigger, _fr_trigger_talloc_ctx_free);
+ talloc_set_destructor(disarm, _fr_disarm_talloc_ctx_free);
+
+ return 0;
+}
+
+/*
+ * Explicitly cleanup the memory allocated to the error inet_ntop
+ * buffer.
+ */
+static void _fr_inet_ntop_free(void *arg)
+{
+ free(arg);
+}
+
+/** Wrapper around inet_ntop, prints IPv4/IPv6 addresses
+ *
+ * inet_ntop requires the caller pass in a buffer for the address.
+ * This would be annoying and cumbersome, seeing as quite often the ASCII
+ * address is only used for logging output.
+ *
+ * So as with lib/log.c use TLS to allocate thread specific buffers, and
+ * write the IP address there instead.
+ *
+ * @param af address family, either AF_INET or AF_INET6.
+ * @param src pointer to network address structure.
+ * @return NULL on error, else pointer to ASCII buffer containing text version of address.
+ */
+char const *fr_inet_ntop(int af, void const *src)
+{
+ char *buffer;
+
+ if (!src) {
+ return NULL;
+ }
+
+ buffer = fr_thread_local_init(fr_inet_ntop_buffer, _fr_inet_ntop_free);
+ if (!buffer) {
+ int ret;
+
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * INET6_ADDRSTRLEN);
+ if (!buffer) {
+ fr_perror("Failed allocating memory for inet_ntop buffer");
+ return NULL;
+ }
+
+ ret = fr_thread_local_set(fr_inet_ntop_buffer, buffer);
+ if (ret != 0) {
+ fr_perror("Failed setting up TLS for inet_ntop buffer: %s", fr_syserror(ret));
+ free(buffer);
+ return NULL;
+ }
+ }
+ buffer[0] = '\0';
+
+ return inet_ntop(af, src, buffer, INET6_ADDRSTRLEN);
+}
+
+/*
+ * Return an IP address in standard dot notation
+ *
+ * FIXME: DELETE THIS
+ */
+char const *ip_ntoa(char *buffer, uint32_t ipaddr)
+{
+ ipaddr = ntohl(ipaddr);
+
+ sprintf(buffer, "%d.%d.%d.%d",
+ (ipaddr >> 24) & 0xff,
+ (ipaddr >> 16) & 0xff,
+ (ipaddr >> 8) & 0xff,
+ (ipaddr ) & 0xff);
+ return buffer;
+}
+
+/*
+ * Parse decimal digits until we run out of decimal digits.
+ */
+static int ip_octet_from_str(char const *str, uint32_t *poctet)
+{
+ uint32_t octet;
+ char const *p = str;
+
+ if ((*p < '0') || (*p > '9')) {
+ return -1;
+ }
+
+ octet = 0;
+
+ while ((*p >= '0') && (*p <= '9')) {
+ octet *= 10;
+ octet += *p - '0';
+ p++;
+
+ if (octet > 255) return -1;
+ }
+
+
+ *poctet = octet;
+ return p - str;
+}
+
+static int ip_prefix_from_str(char const *str, uint32_t *paddr)
+{
+ int shift, length;
+ uint32_t octet;
+ uint32_t addr;
+ char const *p = str;
+
+ addr = 0;
+
+ for (shift = 24; shift >= 0; shift -= 8) {
+ length = ip_octet_from_str(p, &octet);
+ if (length <= 0) return -1;
+
+ addr |= octet << shift;
+ p += length;
+
+ /*
+ * EOS or / means we're done.
+ */
+ if (!*p || (*p == '/')) break;
+
+ /*
+ * We require dots between octets.
+ */
+ if (*p != '.') return -1;
+ p++;
+ }
+
+ *paddr = htonl(addr);
+ return p - str;
+}
+
+
+/**
+ * Parse an IPv4 address, IPv4 prefix in presentation format (and others), or
+ * a hostname.
+ *
+ * @param out Where to write the ip address value.
+ * @param value to parse, may be dotted quad [+ prefix], or integer, or octal number, or '*' (INADDR_ANY), or a hostname.
+ * @param inlen Length of value, if value is \0 terminated inlen may be -1.
+ * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
+ * @param fallback to IPv6 resolution if no A records can be found.
+ * @return 0 if ip address was parsed successfully, else -1 on error.
+ */
+int fr_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback)
+{
+ char *p;
+ unsigned int mask;
+ char *eptr;
+
+ /* Dotted quad + / + [0-9]{1,2} or a hostname (RFC1035 2.3.4 Size limits) */
+ char buffer[256];
+
+ /*
+ * Copy to intermediary buffer if we were given a length
+ */
+ if (inlen >= 0) {
+ if (inlen >= (ssize_t)sizeof(buffer)) {
+ fr_strerror_printf("Invalid IPv4 address string \"%s\"", value);
+ return -1;
+ }
+ memcpy(buffer, value, inlen);
+ buffer[inlen] = '\0';
+ value = buffer;
+ }
+
+ p = strchr(value, '/');
+
+ /*
+ * 192.0.2.2 is parsed as if it was /32
+ */
+ if (!p) {
+ out->prefix = 32;
+ out->af = AF_INET;
+
+ /*
+ * Allow '*' as the wildcard address usually 0.0.0.0
+ */
+ if ((value[0] == '*') && (value[1] == '\0')) {
+ out->ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
+
+ /*
+ * Convert things which are obviously integers to IP addresses
+ *
+ * We assume the number is the bigendian representation of the
+ * IP address.
+ */
+ } else if (is_integer(value) || ((value[0] == '0') && (value[1] == 'x'))) {
+ out->ipaddr.ip4addr.s_addr = htonl(strtoul(value, NULL, 0));
+
+ } else if (!resolve) {
+ if (inet_pton(AF_INET, value, &out->ipaddr.ip4addr.s_addr) <= 0) {
+ fr_strerror_printf("Failed to parse IPv4 addreess string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET, value, fallback) < 0) return -1;
+
+ return 0;
+ }
+
+ /*
+ * Copy the IP portion into a temporary buffer if we haven't already.
+ */
+ if (inlen < 0) memcpy(buffer, value, p - value);
+ buffer[p - value] = '\0';
+
+ if (ip_prefix_from_str(buffer, &out->ipaddr.ip4addr.s_addr) <= 0) {
+ fr_strerror_printf("Failed to parse IPv4 address string \"%s\"", value);
+ return -1;
+ }
+
+ mask = strtoul(p + 1, &eptr, 10);
+ if (mask > 32) {
+ fr_strerror_printf("Invalid IPv4 mask length \"%s\". Should be between 0-32", p);
+ return -1;
+ }
+
+ if (eptr[0] != '\0') {
+ fr_strerror_printf("Failed to parse IPv4 address string \"%s\", "
+ "got garbage after mask length \"%s\"", value, eptr);
+ return -1;
+ }
+
+ if (mask < 32) {
+ out->ipaddr.ip4addr = fr_inaddr_mask(&out->ipaddr.ip4addr, mask);
+ }
+
+ out->prefix = (uint8_t) mask;
+ out->af = AF_INET;
+
+ return 0;
+}
+
+/**
+ * Parse an IPv6 address or IPv6 prefix in presentation format (and others),
+ * or a hostname.
+ *
+ * @param out Where to write the ip address value.
+ * @param value to parse.
+ * @param inlen Length of value, if value is \0 terminated inlen may be -1.
+ * @param resolve If true and value doesn't look like an IP address, try and resolve value as a hostname.
+ * @param fallback to IPv4 resolution if no AAAA records can be found.
+ * @return 0 if ip address was parsed successfully, else -1 on error.
+ */
+int fr_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback)
+{
+ char const *p;
+ unsigned int prefix;
+ char *eptr;
+
+ /* IPv6 + / + [0-9]{1,3} or a hostname (RFC1035 2.3.4 Size limits) */
+ char buffer[256];
+
+ /*
+ * Copy to intermediary buffer if we were given a length
+ */
+ if (inlen >= 0) {
+ if (inlen >= (ssize_t)sizeof(buffer)) {
+ fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ memcpy(buffer, value, inlen);
+ buffer[inlen] = '\0';
+ value = buffer;
+ }
+
+ p = strchr(value, '/');
+ if (!p) {
+ out->prefix = 128;
+ out->af = AF_INET6;
+
+ /*
+ * Allow '*' as the wildcard address
+ */
+ if ((value[0] == '*') && (value[1] == '\0')) {
+ memset(out->ipaddr.ip6addr.s6_addr, 0, sizeof(out->ipaddr.ip6addr.s6_addr));
+ } else if (!resolve) {
+ if (inet_pton(AF_INET6, value, out->ipaddr.ip6addr.s6_addr) <= 0) {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET6, value, fallback) < 0) return -1;
+
+ return 0;
+ }
+
+ if ((p - value) >= INET6_ADDRSTRLEN) {
+ fr_strerror_printf("Invalid IPv6 address string \"%s\"", value);
+ return -1;
+ }
+
+ /*
+ * Copy string to temporary buffer if we didn't do it earlier
+ */
+ if (inlen < 0) memcpy(buffer, value, p - value);
+ buffer[p - value] = '\0';
+
+ if (!resolve) {
+ if (inet_pton(AF_INET6, buffer, out->ipaddr.ip6addr.s6_addr) <= 0) {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\"", value);
+ return -1;
+ }
+ } else if (ip_hton(out, AF_INET6, buffer, fallback) < 0) return -1;
+
+ prefix = strtoul(p + 1, &eptr, 10);
+ if (prefix > 128) {
+ fr_strerror_printf("Invalid IPv6 mask length \"%s\". Should be between 0-128", p);
+ return -1;
+ }
+ if (eptr[0] != '\0') {
+ fr_strerror_printf("Failed to parse IPv6 address string \"%s\", "
+ "got garbage after mask length \"%s\"", value, eptr);
+ return -1;
+ }
+
+ if (prefix < 128) {
+ struct in6_addr addr;
+
+ addr = fr_in6addr_mask(&out->ipaddr.ip6addr, prefix);
+ memcpy(out->ipaddr.ip6addr.s6_addr, addr.s6_addr, sizeof(out->ipaddr.ip6addr.s6_addr));
+ }
+
+ out->prefix = (uint8_t) prefix;
+ out->af = AF_INET6;
+
+ return 0;
+}
+
+/** Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
+ *
+ * @param[out] out Where to write the ip address value.
+ * @param[in] value to parse.
+ * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
+ * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a
+ * hostname.
+ * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS
+ * record (A or AAAA) we require. Also controls which parser we pass the address to if
+ * we have no idea what it is.
+ * @return
+ * - 0 if ip address was parsed successfully.
+ * - -1 on failure.
+ */
+int fr_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve)
+{
+ size_t len, i;
+ bool hostname = true;
+ bool ipv4 = true;
+ bool ipv6 = true;
+
+ len = (inlen >= 0) ? (size_t)inlen : strlen(value);
+
+ for (i = 0; i < len; i++) {
+ /*
+ * These are valid for IPv4, IPv6, and host names.
+ */
+ if ((value[i] >= '0') && (value[i] <= '9')) {
+ continue;
+ }
+
+ /*
+ * These are invalid for IPv4, but OK for IPv6
+ * and host names.
+ */
+ if ((value[i] >= 'a') && (value[i] <= 'f')) {
+ ipv4 = false;
+ continue;
+ }
+
+ /*
+ * These are invalid for IPv4, but OK for IPv6
+ * and host names.
+ */
+ if ((value[i] >= 'A') && (value[i] <= 'F')) {
+ ipv4 = false;
+ continue;
+ }
+
+ /*
+ * This is only valid for IPv6 addresses.
+ */
+ if (value[i] == ':') {
+ ipv4 = false;
+ hostname = false;
+ continue;
+ }
+
+ /*
+ * Valid for IPv4 and host names, not for IPv6.
+ */
+ if (value[i] == '.') {
+ ipv6 = false;
+ continue;
+ }
+
+ /*
+ * Netmasks are allowed by us, and MUST come at
+ * the end of the address.
+ */
+ if (value[i] == '/') {
+ break;
+ }
+
+ /*
+ * Any characters other than what are checked for
+ * above can't be IPv4 or IPv6 addresses.
+ */
+ ipv4 = false;
+ ipv6 = false;
+ }
+
+ /*
+ * It's not an IPv4 or IPv6 address. It MUST be a host
+ * name.
+ */
+ if (!ipv4 && !ipv6) {
+ /*
+ * Not an IPv4 or IPv6 address, and we weren't
+ * asked to do DNS resolution, we can't do it.
+ */
+ if (!resolve) {
+ fr_strerror_printf("Not IPv4/6 address, and asked not to resolve");
+ return -1;
+ }
+
+ /*
+ * It's not a hostname, either, so bail out
+ * early.
+ */
+ if (!hostname) {
+ fr_strerror_printf("Invalid address");
+ return -1;
+ }
+ }
+
+ /*
+ * The name has a ':' in it. Therefore it must be an
+ * IPv6 address. Error out if the caller specified IPv4.
+ * Otherwise, force IPv6.
+ */
+ if (ipv6 && !hostname) {
+ if (af == AF_INET) {
+ fr_strerror_printf("Invalid address");
+ return -1;
+ }
+
+ af = AF_INET6;
+ }
+
+ /*
+ * Use whatever the caller specified, OR what we
+ * insinuated above from looking at the name string.
+ */
+ switch (af) {
+ case AF_UNSPEC:
+ return fr_pton4(out, value, inlen, resolve, true);
+
+ case AF_INET:
+ return fr_pton4(out, value, inlen, resolve, false);
+
+ case AF_INET6:
+ return fr_pton6(out, value, inlen, resolve, false);
+
+ default:
+ break;
+ }
+
+ /*
+ * No idea what it is...
+ */
+ fr_strerror_printf("Invalid address family %i", af);
+ return -1;
+}
+
+/** Parses IPv4/6 address + port, to fr_ipaddr_t and integer
+ *
+ * @param[out] out Where to write the ip address value.
+ * @param[out] port_out Where to write the port (0 if no port found).
+ * @param[in] value to parse.
+ * @param[in] inlen Length of value, if value is \0 terminated inlen may be -1.
+ * @param[in] af If the address type is not obvious from the format, and resolve is true, the DNS
+ * record (A or AAAA) we require. Also controls which parser we pass the address to if
+ * we have no idea what it is.
+ * @param[in] resolve If true and value doesn't look like an IP address, try and resolve value as a
+ * hostname.
+ */
+int fr_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve)
+{
+ char const *p = value, *q;
+ char *end;
+ unsigned long port;
+ char buffer[6];
+ size_t len;
+
+ *port_out = 0;
+
+ len = (inlen >= 0) ? (size_t)inlen : strlen(value);
+
+ if (*p == '[') {
+ if (!(q = memchr(p + 1, ']', len - 1))) {
+ fr_strerror_printf("Missing closing ']' for IPv6 address");
+ return -1;
+ }
+
+ /*
+ * inet_pton doesn't like the address being wrapped in []
+ */
+ if (fr_pton6(out, p + 1, (q - p) - 1, false, false) < 0) return -1;
+
+ if (q[1] == ':') {
+ q++;
+ goto do_port;
+ }
+
+ return 0;
+ }
+
+ /*
+ * Host, IPv4 or IPv6 with no port
+ */
+ q = memchr(p, ':', len);
+ if (!q) return fr_pton(out, p, len, af, resolve);
+
+ /*
+ * IPv4 or host, with port
+ */
+ if (fr_pton(out, p, (q - p), af, resolve) < 0) return -1;
+
+do_port:
+ /*
+ * Valid ports are a maximum of 5 digits, so if the
+ * input length indicates there are more than 5 chars
+ * after the ':' then there's an issue.
+ */
+ if (len > (size_t) ((q + sizeof(buffer)) - value)) {
+ error:
+ fr_strerror_printf("IP string contains trailing garbage after port delimiter");
+ return -1;
+ }
+
+ p = q + 1; /* Move to first digit */
+
+ strlcpy(buffer, p, (len - (p - value)) + 1);
+ port = strtoul(buffer, &end, 10);
+ if (*end != '\0') goto error; /* Trailing garbage after integer */
+
+ if ((port > UINT16_MAX) || (port == 0)) {
+ fr_strerror_printf("Port %lu outside valid port range 1-" STRINGIFY(UINT16_MAX), port);
+ return -1;
+ }
+ *port_out = port;
+
+ return 0;
+}
+
+int fr_ntop(char *out, size_t outlen, fr_ipaddr_t const *addr)
+{
+ char buffer[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(addr->af, &(addr->ipaddr), buffer, sizeof(buffer)) == NULL) return -1;
+
+ return snprintf(out, outlen, "%s/%i", buffer, addr->prefix);
+}
+
+/*
+ * cppcheck apparently can't pick this up from the system headers.
+ */
+#ifdef CPPCHECK
+#define F_WRLCK
+#endif
+
+/*
+ * Internal wrapper for locking, to minimize the number of ifdef's
+ *
+ * Use fcntl or error
+ */
+int rad_lockfd(int fd, int lock_len)
+{
+#ifdef F_WRLCK
+ struct flock fl;
+
+ fl.l_start = 0;
+ fl.l_len = lock_len;
+ fl.l_pid = getpid();
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_CUR;
+
+ return fcntl(fd, F_SETLKW, (void *)&fl);
+#else
+#error "missing definition for F_WRLCK, all file locks will fail"
+
+ return -1;
+#endif
+}
+
+/*
+ * Internal wrapper for locking, to minimize the number of ifdef's
+ *
+ * Lock an fd, prefer lockf() over flock()
+ * Nonblocking version.
+ */
+int rad_lockfd_nonblock(int fd, int lock_len)
+{
+#ifdef F_WRLCK
+ struct flock fl;
+
+ fl.l_start = 0;
+ fl.l_len = lock_len;
+ fl.l_pid = getpid();
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_CUR;
+
+ return fcntl(fd, F_SETLK, (void *)&fl);
+#else
+#error "missing definition for F_WRLCK, all file locks will fail"
+
+ return -1;
+#endif
+}
+
+/*
+ * Internal wrapper for unlocking, to minimize the number of ifdef's
+ * in the source.
+ *
+ * Unlock an fd, prefer lockf() over flock()
+ */
+int rad_unlockfd(int fd, int lock_len)
+{
+#ifdef F_WRLCK
+ struct flock fl;
+
+ fl.l_start = 0;
+ fl.l_len = lock_len;
+ fl.l_pid = getpid();
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_CUR;
+
+ return fcntl(fd, F_SETLK, (void *)&fl);
+#else
+#error "missing definition for F_WRLCK, all file locks will fail"
+
+ return -1;
+#endif
+}
+
+/*
+ * Return an interface-id in standard colon notation
+ */
+char *ifid_ntoa(char *buffer, size_t size, uint8_t const *ifid)
+{
+ snprintf(buffer, size, "%x:%x:%x:%x",
+ (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
+ (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
+ return buffer;
+}
+
+
+/*
+ * Return an interface-id from
+ * one supplied in standard colon notation.
+ */
+uint8_t *ifid_aton(char const *ifid_str, uint8_t *ifid)
+{
+ static char const xdigits[] = "0123456789abcdef";
+ char const *p, *pch;
+ int num_id = 0, val = 0, idx = 0;
+
+ for (p = ifid_str; ; ++p) {
+ if (*p == ':' || *p == '\0') {
+ if (num_id <= 0)
+ return NULL;
+
+ /*
+ * Drop 'val' into the array.
+ */
+ ifid[idx] = (val >> 8) & 0xff;
+ ifid[idx + 1] = val & 0xff;
+ if (*p == '\0') {
+ /*
+ * Must have all entries before
+ * end of the string.
+ */
+ if (idx != 6)
+ return NULL;
+ break;
+ }
+ val = 0;
+ num_id = 0;
+ if ((idx += 2) > 6)
+ return NULL;
+ } else if ((pch = strchr(xdigits, tolower((uint8_t) *p))) != NULL) {
+ if (++num_id > 4)
+ return NULL;
+ /*
+ * Dumb version of 'scanf'
+ */
+ val <<= 4;
+ val |= (pch - xdigits);
+ } else
+ return NULL;
+ }
+ return ifid;
+}
+
+
+#ifndef HAVE_INET_PTON
+static int inet_pton4(char const *src, struct in_addr *dst)
+{
+ int octet;
+ unsigned int num;
+ char const *p, *off;
+ uint8_t tmp[4];
+ static char const digits[] = "0123456789";
+
+ octet = 0;
+ p = src;
+ while (1) {
+ num = 0;
+ while (*p && ((off = strchr(digits, *p)) != NULL)) {
+ num *= 10;
+ num += (off - digits);
+
+ if (num > 255) return 0;
+
+ p++;
+ }
+ if (!*p) break;
+
+ /*
+ * Not a digit, MUST be a dot, else we
+ * die.
+ */
+ if (*p != '.') {
+ return 0;
+ }
+
+ tmp[octet++] = num;
+ p++;
+ }
+
+ /*
+ * End of the string. At the fourth
+ * octet is OK, anything else is an
+ * error.
+ */
+ if (octet != 3) {
+ return 0;
+ }
+ tmp[3] = num;
+
+ memcpy(dst, &tmp, sizeof(tmp));
+ return 1;
+}
+
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+/** Convert presentation level address to network order binary form
+ *
+ * @note Does not touch dst unless it's returning 1.
+ * @note :: in a full address is silently ignored.
+ * @note Inspired by Mark Andrews.
+ * @author Paul Vixie, 1996.
+ *
+ * @param src presentation level address.
+ * @param dst where to write output address.
+ * @return 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ */
+static int inet_pton6(char const *src, unsigned char *dst)
+{
+ static char const xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ char const *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ char const *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, (struct in_addr *) tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ int const n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ /* bcopy(tmp, dst, IN6ADDRSZ); */
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+#endif
+
+/*
+ * Utility function, so that the rest of the server doesn't
+ * have ifdef's around IPv6 support
+ */
+int inet_pton(int af, char const *src, void *dst)
+{
+ if (af == AF_INET) {
+ return inet_pton4(src, dst);
+ }
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+
+ if (af == AF_INET6) {
+ return inet_pton6(src, dst);
+ }
+#endif
+
+ return -1;
+}
+#endif
+
+#ifndef HAVE_INET_NTOP
+/*
+ * Utility function, so that the rest of the server doesn't
+ * have ifdef's around IPv6 support
+ */
+char const *inet_ntop(int af, void const *src, char *dst, size_t cnt)
+{
+ if (af == AF_INET) {
+ uint8_t const *ipaddr = src;
+
+ if (cnt <= INET_ADDRSTRLEN) return NULL;
+
+ snprintf(dst, cnt, "%d.%d.%d.%d",
+ ipaddr[0], ipaddr[1],
+ ipaddr[2], ipaddr[3]);
+ return dst;
+ }
+
+ /*
+ * If the system doesn't define this, we define it
+ * in missing.h
+ */
+ if (af == AF_INET6) {
+ struct in6_addr const *ipaddr = src;
+
+ if (cnt <= INET6_ADDRSTRLEN) return NULL;
+
+ snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
+ (ipaddr->s6_addr[0] << 8) | ipaddr->s6_addr[1],
+ (ipaddr->s6_addr[2] << 8) | ipaddr->s6_addr[3],
+ (ipaddr->s6_addr[4] << 8) | ipaddr->s6_addr[5],
+ (ipaddr->s6_addr[6] << 8) | ipaddr->s6_addr[7],
+ (ipaddr->s6_addr[8] << 8) | ipaddr->s6_addr[9],
+ (ipaddr->s6_addr[10] << 8) | ipaddr->s6_addr[11],
+ (ipaddr->s6_addr[12] << 8) | ipaddr->s6_addr[13],
+ (ipaddr->s6_addr[14] << 8) | ipaddr->s6_addr[15]);
+ return dst;
+ }
+
+ return NULL; /* don't support IPv6 */
+}
+#endif
+
+/** Wrappers for IPv4/IPv6 host to IP address lookup
+ *
+ * This function returns only one IP address, of the specified address family,
+ * or the first address (of whatever family), if AF_UNSPEC is used.
+ *
+ * If fallback is specified and af is AF_INET, but no AF_INET records were
+ * found and a record for AF_INET6 exists that record will be returned.
+ *
+ * If fallback is specified and af is AF_INET6, and a record with AF_INET4 exists
+ * that record will be returned instead.
+ *
+ * @param out Where to write result.
+ * @param af To search for in preference.
+ * @param hostname to search for.
+ * @param fallback to the other adress family, if no records matching af, found.
+ * @return 0 on success, else -1 on failure.
+ */
+int ip_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
+{
+ int rcode;
+ struct addrinfo hints, *ai = NULL, *alt = NULL, *res = NULL;
+
+ /*
+ * Avoid malloc for IP addresses. This helps us debug
+ * memory errors when using talloc.
+ */
+#ifdef TALLOC_DEBUG
+ if (true) {
+#else
+ if (!fr_hostname_lookups) {
+#endif
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ if (af == AF_UNSPEC) {
+ char const *p;
+
+ for (p = hostname; *p != '\0'; p++) {
+ if ((*p == ':') ||
+ (*p == '[') ||
+ (*p == ']')) {
+ af = AF_INET6;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (af == AF_UNSPEC) af = AF_INET;
+
+ if (!inet_pton(af, hostname, &(out->ipaddr))) return -1;
+
+ out->af = af;
+ return 0;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+
+ /*
+ * If we're falling back we need both IPv4 and IPv6 records
+ */
+ if (fallback) {
+ hints.ai_family = AF_UNSPEC;
+ } else {
+ hints.ai_family = af;
+ }
+
+ if ((rcode = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
+ switch (af) {
+ default:
+ case AF_UNSPEC:
+ fr_strerror_printf("Failed resolving \"%s\" to IP address: %s",
+ hostname, gai_strerror(rcode));
+ return -1;
+
+ case AF_INET:
+ fr_strerror_printf("Failed resolving \"%s\" to IPv4 address: %s",
+ hostname, gai_strerror(rcode));
+ return -1;
+
+ case AF_INET6:
+ fr_strerror_printf("Failed resolving \"%s\" to IPv6 address: %s",
+ hostname, gai_strerror(rcode));
+ return -1;
+ }
+ }
+
+ for (ai = res; ai; ai = ai->ai_next) {
+ if ((af == ai->ai_family) || (af == AF_UNSPEC)) break;
+ if (!alt && fallback && ((ai->ai_family == AF_INET) || (ai->ai_family == AF_INET6))) alt = ai;
+ }
+
+ if (!ai) ai = alt;
+ if (!ai) {
+ fr_strerror_printf("ip_hton failed to find requested information for host %.100s", hostname);
+ freeaddrinfo(res);
+ return -1;
+ }
+
+ rcode = fr_sockaddr2ipaddr((struct sockaddr_storage *)ai->ai_addr,
+ ai->ai_addrlen, out, NULL);
+ freeaddrinfo(res);
+ if (!rcode) {
+ fr_strerror_printf("Failed converting sockaddr to ipaddr");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Look IP addresses up, and print names (depending on DNS config)
+ */
+char const *ip_ntoh(fr_ipaddr_t const *src, char *dst, size_t cnt)
+{
+ struct sockaddr_storage ss;
+ int error;
+ socklen_t salen;
+
+ /*
+ * No DNS lookups
+ */
+ if (!fr_dns_lookups) {
+ return inet_ntop(src->af, &(src->ipaddr), dst, cnt);
+ }
+
+ if (!fr_ipaddr2sockaddr(src, 0, &ss, &salen)) {
+ return NULL;
+ }
+
+ if ((error = getnameinfo((struct sockaddr *)&ss, salen, dst, cnt, NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+ fr_strerror_printf("ip_ntoh: %s", gai_strerror(error));
+ return NULL;
+ }
+ return dst;
+}
+
+/** Mask off a portion of an IPv4 address
+ *
+ * @param ipaddr to mask.
+ * @param prefix Number of contiguous bits to mask.
+ * @return an ipv4 address with the host portion zeroed out.
+ */
+struct in_addr fr_inaddr_mask(struct in_addr const *ipaddr, uint8_t prefix)
+{
+ uint32_t ret;
+
+ if (prefix > 32) prefix = 32;
+
+ /* Short circuit */
+ if (prefix == 32) return *ipaddr;
+
+ if (prefix == 0) ret = 0;
+ else ret = htonl(~((0x00000001UL << (32 - prefix)) - 1)) & ipaddr->s_addr;
+
+ return (*(struct in_addr *)&ret);
+}
+
+/** Mask off a portion of an IPv6 address
+ *
+ * @param ipaddr to mask.
+ * @param prefix Number of contiguous bits to mask.
+ * @return an ipv6 address with the host portion zeroed out.
+ */
+struct in6_addr fr_in6addr_mask(struct in6_addr const *ipaddr, uint8_t prefix)
+{
+ uint64_t const *p = (uint64_t const *) ipaddr;
+ uint64_t addr; /* Needed for alignment */
+ uint64_t ret[2], *o = ret;
+
+ if (prefix > 128) prefix = 128;
+
+ /* Short circuit */
+ if (prefix == 128) return *ipaddr;
+
+ if (prefix >= 64) {
+ prefix -= 64;
+ memcpy(&addr, p, sizeof(addr)); /* Needed for aligned access (ubsan) */
+ *o++ = 0xffffffffffffffffULL & addr; /* lhs portion masked */
+ p++;
+ } else {
+ ret[1] = 0; /* rhs portion zeroed */
+ }
+
+ /* Max left shift is 63 else we get overflow */
+ if (prefix > 0) {
+ memcpy(&addr, p, sizeof(addr)); /* Needed for aligned access (ubsan) */
+ *o = htonll(~((uint64_t)(0x0000000000000001ULL << (64 - prefix)) - 1)) & addr;
+ } else {
+ *o = 0;
+ }
+
+ return *(struct in6_addr *) &ret;
+}
+
+/** Zeroes out the host portion of an fr_ipaddr_t
+ *
+ * @param[in,out] addr to mask
+ * @param[in] prefix Length of the network portion.
+ */
+void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
+{
+
+ switch (addr->af) {
+ case AF_INET:
+ addr->ipaddr.ip4addr = fr_inaddr_mask(&addr->ipaddr.ip4addr, prefix);
+ break;
+
+ case AF_INET6:
+ addr->ipaddr.ip6addr = fr_in6addr_mask(&addr->ipaddr.ip6addr, prefix);
+ break;
+
+ default:
+ return;
+ }
+ addr->prefix = prefix;
+}
+
+static char const hextab[] = "0123456789abcdef";
+
+/** Convert hex strings to binary data
+ *
+ * @param bin Buffer to write output to.
+ * @param outlen length of output buffer (or length of input string / 2).
+ * @param hex input string.
+ * @param inlen length of the input string
+ * @return length of data written to buffer.
+ */
+size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
+{
+ size_t i;
+ size_t len;
+ char *c1, *c2;
+
+ /*
+ * Smartly truncate output, caller should check number of bytes
+ * written.
+ */
+ len = inlen >> 1;
+ if (len > outlen) len = outlen;
+
+ for (i = 0; i < len; i++) {
+ if(!(c1 = memchr(hextab, tolower((uint8_t) hex[i << 1]), sizeof(hextab))) ||
+ !(c2 = memchr(hextab, tolower((uint8_t) hex[(i << 1) + 1]), sizeof(hextab))))
+ break;
+ bin[i] = ((c1-hextab)<<4) + (c2-hextab);
+ }
+
+ return i;
+}
+
+/** Convert binary data to a hex string
+ *
+ * Ascii encoded hex string will not be prefixed with '0x'
+ *
+ * @warning If the output buffer isn't long enough, we have a buffer overflow.
+ *
+ * @param[out] hex Buffer to write hex output.
+ * @param[in] bin input.
+ * @param[in] inlen of bin input.
+ * @return length of data written to buffer.
+ */
+size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
+{
+ size_t i;
+
+ for (i = 0; i < inlen; i++) {
+ hex[0] = hextab[((*bin) >> 4) & 0x0f];
+ hex[1] = hextab[*bin & 0x0f];
+ hex += 2;
+ bin++;
+ }
+
+ *hex = '\0';
+ return inlen * 2;
+}
+
+/** Convert binary data to a hex string
+ *
+ * Ascii encoded hex string will not be prefixed with '0x'
+ *
+ * @param[in] ctx to alloc buffer in.
+ * @param[in] bin input.
+ * @param[in] inlen of bin input.
+ * @return length of data written to buffer.
+ */
+char *fr_abin2hex(TALLOC_CTX *ctx, uint8_t const *bin, size_t inlen)
+{
+ char *buff;
+
+ buff = talloc_array(ctx, char, (inlen << 2));
+ if (!buff) return NULL;
+
+ fr_bin2hex(buff, bin, inlen);
+
+ return buff;
+}
+
+/** Consume the integer (or hex) portion of a value string
+ *
+ * @param value string to parse.
+ * @param end pointer to the first non numeric char.
+ * @return integer value.
+ */
+uint32_t fr_strtoul(char const *value, char **end)
+{
+ if ((value[0] == '0') && (value[1] == 'x')) {
+ return strtoul(value, end, 16);
+ }
+
+ return strtoul(value, end, 10);
+}
+
+/** Check whether the string is all whitespace
+ *
+ * @return true if the entirety of the string is whitespace, else false.
+ */
+bool is_whitespace(char const *value)
+{
+ do {
+ if (!isspace((uint8_t) *value)) return false;
+ value++;
+ } while (*value);
+
+ return true;
+}
+
+/** Check whether the string is made up of printable UTF8 chars
+ *
+ * @param value to check.
+ * @param len of value.
+ *
+ * @return
+ * - true if the string is printable.
+ * - false if the string contains non printable chars
+ */
+ bool is_printable(void const *value, size_t len)
+ {
+ uint8_t const *p = value;
+ int clen;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ clen = fr_utf8_char(p, len - i);
+ if (clen == 0) return false;
+ i += (size_t)clen;
+ p += clen;
+ }
+ return true;
+ }
+
+/** Check whether the string is all numbers
+ *
+ * @return true if the entirety of the string is all numbers, else false.
+ */
+bool is_integer(char const *value)
+{
+#ifndef __clang_analyzer__
+ do {
+ if (!isdigit((uint8_t) *value)) return false;
+ value++;
+ } while (*value);
+
+ /*
+ * Clang analyzer complains about the above line: "Branch
+ * depends on a garbage value", even though that's
+ * clearly not true. And, it doesn't complain about the
+ * other functions doing similar things.
+ */
+#else
+ if (!isdigit((uint8_t) *value)) return false;
+#endif
+
+ return true;
+}
+
+/** Check whether the string is allzeros
+ *
+ * @return true if the entirety of the string is all zeros, else false.
+ */
+bool is_zero(char const *value)
+{
+ do {
+ if (*value != '0') return false;
+ value++;
+ } while (*value);
+
+ return true;
+}
+
+/*
+ * So we don't have ifdef's in the rest of the code
+ */
+#ifndef HAVE_CLOSEFROM
+int closefrom(int fd)
+{
+ int i;
+ int maxfd = 256;
+#ifdef HAVE_DIRENT_H
+ DIR *dir;
+#endif
+
+#ifdef F_CLOSEM
+ if (fcntl(fd, F_CLOSEM) == 0) {
+ return 0;
+ }
+#endif
+
+#ifdef F_MAXFD
+ maxfd = fcntl(fd, F_F_MAXFD);
+ if (maxfd >= 0) goto do_close;
+#endif
+
+#ifdef _SC_OPEN_MAX
+ maxfd = sysconf(_SC_OPEN_MAX);
+ if (maxfd < 0) {
+ maxfd = 256;
+ }
+#endif
+
+#ifdef HAVE_DIRENT_H
+ /*
+ * Use /proc/self/fd directory if it exists.
+ */
+ dir = opendir(CLOSEFROM_DIR);
+ if (dir != NULL) {
+ long my_fd;
+ char *endp;
+ struct dirent *dp;
+
+ while ((dp = readdir(dir)) != NULL) {
+ my_fd = strtol(dp->d_name, &endp, 10);
+ if (my_fd <= 0) continue;
+
+ if (*endp) continue;
+
+ if (my_fd == dirfd(dir)) continue;
+
+ if ((my_fd >= fd) && (my_fd <= maxfd)) {
+ (void) close((int) my_fd);
+ }
+ }
+ (void) closedir(dir);
+ return 0;
+ }
+#endif
+
+#ifdef F_MAXFD
+do_close:
+#endif
+
+ if (fd > maxfd) return 0;
+
+ /*
+ * FIXME: return EINTR?
+ */
+ for (i = fd; i < maxfd; i++) {
+ close(i);
+ }
+
+ return 0;
+}
+#endif
+
+int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
+{
+ if (a->af < b->af) return -1;
+ if (a->af > b->af) return +1;
+
+ if (a->prefix < b->prefix) return -1;
+ if (a->prefix > b->prefix) return +1;
+
+ switch (a->af) {
+ case AF_INET:
+ return memcmp(&a->ipaddr.ip4addr,
+ &b->ipaddr.ip4addr,
+ sizeof(a->ipaddr.ip4addr));
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ case AF_INET6:
+ if (a->scope < b->scope) return -1;
+ if (a->scope > b->scope) return +1;
+
+ return memcmp(&a->ipaddr.ip6addr,
+ &b->ipaddr.ip6addr,
+ sizeof(a->ipaddr.ip6addr));
+#endif
+
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+int fr_ipaddr2sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port,
+ struct sockaddr_storage *sa, socklen_t *salen)
+{
+ memset(sa, 0, sizeof(*sa));
+
+ if (ipaddr->af == AF_INET) {
+ struct sockaddr_in s4;
+
+ *salen = sizeof(s4);
+
+ memset(&s4, 0, sizeof(s4));
+ s4.sin_family = AF_INET;
+ s4.sin_addr = ipaddr->ipaddr.ip4addr;
+ s4.sin_port = htons(port);
+ memset(sa, 0, sizeof(*sa));
+ memcpy(sa, &s4, sizeof(s4));
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (ipaddr->af == AF_INET6) {
+ struct sockaddr_in6 s6;
+
+ *salen = sizeof(s6);
+
+ memset(&s6, 0, sizeof(s6));
+ s6.sin6_family = AF_INET6;
+ s6.sin6_addr = ipaddr->ipaddr.ip6addr;
+ s6.sin6_port = htons(port);
+ s6.sin6_scope_id = ipaddr->scope;
+ memset(sa, 0, sizeof(*sa));
+ memcpy(sa, &s6, sizeof(s6));
+#endif
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int fr_sockaddr2ipaddr(struct sockaddr_storage const *sa, socklen_t salen,
+ fr_ipaddr_t *ipaddr, uint16_t *port)
+{
+ memset(ipaddr, 0, sizeof(*ipaddr));
+
+ if (sa->ss_family == AF_INET) {
+ struct sockaddr_in s4;
+
+ if (salen < sizeof(s4)) {
+ fr_strerror_printf("IPv4 address is too small");
+ return 0;
+ }
+
+ memcpy(&s4, sa, sizeof(s4));
+ ipaddr->af = AF_INET;
+ ipaddr->prefix = 32;
+ ipaddr->ipaddr.ip4addr = s4.sin_addr;
+ if (port) *port = ntohs(s4.sin_port);
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (sa->ss_family == AF_INET6) {
+ struct sockaddr_in6 s6;
+
+ if (salen < sizeof(s6)) {
+ fr_strerror_printf("IPv6 address is too small");
+ return 0;
+ }
+
+ memcpy(&s6, sa, sizeof(s6));
+ ipaddr->af = AF_INET6;
+ ipaddr->prefix = 128;
+ ipaddr->ipaddr.ip6addr = s6.sin6_addr;
+ if (port) *port = ntohs(s6.sin6_port);
+ ipaddr->scope = s6.sin6_scope_id;
+#endif
+
+ } else {
+ fr_strerror_printf("Unsupported address famility %d",
+ sa->ss_family);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef O_NONBLOCK
+/** Set O_NONBLOCK on a socket
+ *
+ * @note O_NONBLOCK is POSIX.
+ *
+ * @param fd to set nonblocking flag on.
+ * @return flags set on the socket, or -1 on error.
+ */
+int fr_nonblock(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL, NULL);
+ if (flags < 0) {
+ fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) < 0) {
+ fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ return flags;
+}
+
+/** Unset O_NONBLOCK on a socket
+ *
+ * @note O_NONBLOCK is POSIX.
+ *
+ * @param fd to set nonblocking flag on.
+ * @return flags set on the socket, or -1 on error.
+ */
+int fr_blocking(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL, NULL);
+ if (flags < 0) {
+ fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ flags ^= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) < 0) {
+ fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ return flags;
+}
+#else
+int fr_nonblock(UNUSED int fd)
+{
+ fr_strerror_printf("Non blocking sockets are not supported");
+ return -1;
+}
+int fr_blocking(UNUSED int fd)
+{
+ fr_strerror_printf("Non blocking sockets are not supported");
+ return -1;
+}
+#endif
+
+/** Write out a vector to a file descriptor
+ *
+ * Wraps writev, calling it as necessary. If timeout is not NULL,
+ * timeout is applied to each call that returns EAGAIN or EWOULDBLOCK
+ *
+ * @note Should only be used on nonblocking file descriptors.
+ * @note Socket should likely be closed on timeout.
+ * @note iovec may be modified in such a way that it's not re-usable.
+ * @note Leaves errno set to the last error that ocurred.
+ *
+ * @param fd to write to.
+ * @param vector to write.
+ * @param iovcnt number of elements in iovec.
+ * @param timeout how long to wait for fd to become writeable before timing out.
+ * @return number of bytes written, -1 on error.
+ */
+ssize_t fr_writev(int fd, struct iovec vector[], int iovcnt, struct timeval *timeout)
+{
+ struct iovec *vector_p = vector;
+ ssize_t total = 0;
+
+ while (iovcnt > 0) {
+ ssize_t wrote;
+
+ wrote = writev(fd, vector_p, iovcnt);
+ if (wrote > 0) {
+ total += wrote;
+ while (wrote > 0) {
+ /*
+ * An entire vector element was written
+ */
+ if (wrote >= (ssize_t)vector_p->iov_len) {
+ iovcnt--;
+ wrote -= vector_p->iov_len;
+ vector_p++;
+ continue;
+ }
+
+ /*
+ * Partial vector element was written
+ */
+ vector_p->iov_len -= wrote;
+ vector_p->iov_base = ((char *)vector_p->iov_base) + wrote;
+ break;
+ }
+ continue;
+ } else if (wrote == 0) return total;
+
+ switch (errno) {
+ /* Write operation would block, use select() to implement a timeout */
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+ case EAGAIN:
+#else
+ case EAGAIN:
+#endif
+ {
+ int ret;
+ fd_set write_set;
+
+ FD_ZERO(&write_set);
+ FD_SET(fd, &write_set);
+
+ /* Don't let signals mess up the select */
+ do {
+ ret = select(fd + 1, NULL, &write_set, NULL, timeout);
+ } while ((ret == -1) && (errno == EINTR));
+
+ /* Select returned 0 which means it reached the timeout */
+ if (ret == 0) {
+ fr_strerror_printf("Write timed out");
+ return -1;
+ }
+
+ /* Other select error */
+ if (ret < 0) {
+ fr_strerror_printf("Failed waiting on socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /* select said a file descriptor was ready for writing */
+ if (!fr_assert(FD_ISSET(fd, &write_set))) return -1;
+
+ break;
+ }
+
+ default:
+ return -1;
+ }
+ }
+
+ return total;
+}
+
+/** Convert UTF8 string to UCS2 encoding
+ *
+ * @note Borrowed from src/crypto/ms_funcs.c of wpa_supplicant project (http://hostap.epitest.fi/wpa_supplicant/)
+ *
+ * @param[out] out Where to write the ucs2 string.
+ * @param[in] outlen Size of output buffer.
+ * @param[in] in UTF8 string to convert.
+ * @param[in] inlen length of UTF8 string.
+ * @return the size of the UCS2 string written to the output buffer (in bytes).
+ */
+ssize_t fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen)
+{
+ size_t i;
+ uint8_t *start = out;
+
+ for (i = 0; i < inlen; i++) {
+ uint8_t c, c2, c3;
+
+ c = in[i];
+ if ((size_t)(out - start) >= outlen) {
+ /* input too long */
+ return -1;
+ }
+
+ /* One-byte encoding */
+ if (c <= 0x7f) {
+ FR_PUT_LE16(out, c);
+ out += 2;
+ continue;
+ } else if ((i == (inlen - 1)) || ((size_t)(out - start) >= (outlen - 1))) {
+ /* Incomplete surrogate */
+ return -1;
+ }
+
+ c2 = in[++i];
+ /* Two-byte encoding */
+ if ((c & 0xe0) == 0xc0) {
+ FR_PUT_LE16(out, ((c & 0x1f) << 6) | (c2 & 0x3f));
+ out += 2;
+ continue;
+ }
+ if ((i == inlen) || ((size_t)(out - start) >= (outlen - 1))) {
+ /* Incomplete surrogate */
+ return -1;
+ }
+
+ /* Three-byte encoding */
+ c3 = in[++i];
+ FR_PUT_LE16(out, ((c & 0xf) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f));
+ out += 2;
+ }
+
+ return out - start;
+}
+
+/** Write 128bit unsigned integer to buffer
+ *
+ * @author Alexey Frunze
+ *
+ * @param out where to write result to.
+ * @param outlen size of out.
+ * @param num 128 bit integer.
+ */
+size_t fr_prints_uint128(char *out, size_t outlen, uint128_t const num)
+{
+ char buff[128 / 3 + 1 + 1];
+ uint64_t n[2];
+ char *p = buff;
+ int i;
+#ifdef FR_LITTLE_ENDIAN
+ const size_t l = 0;
+ const size_t h = 1;
+#else
+ const size_t l = 1;
+ const size_t h = 0;
+#endif
+
+ memset(buff, '0', sizeof(buff) - 1);
+ buff[sizeof(buff) - 1] = '\0';
+
+ memcpy(n, &num, sizeof(n));
+
+ for (i = 0; i < 128; i++) {
+ ssize_t j;
+ int carry;
+
+ carry = (n[h] >= 0x8000000000000000);
+
+ // Shift n[] left, doubling it
+ n[h] = ((n[h] << 1) & 0xffffffffffffffff) + (n[l] >= 0x8000000000000000);
+ n[l] = ((n[l] << 1) & 0xffffffffffffffff);
+
+ // Add s[] to itself in decimal, doubling it
+ for (j = sizeof(buff) - 2; j >= 0; j--) {
+ buff[j] += buff[j] - '0' + carry;
+ carry = (buff[j] > '9');
+ if (carry) {
+ buff[j] -= 10;
+ }
+ }
+ }
+
+ while ((*p == '0') && (p < &buff[sizeof(buff) - 2])) {
+ p++;
+ }
+
+ return strlcpy(out, p, outlen);
+}
+
+/*
+ * Sort of strtok/strsep function.
+ */
+static char *mystrtok(char **ptr, char const *sep)
+{
+ char *res;
+
+ if (**ptr == 0) {
+ return NULL;
+ }
+
+ while (**ptr && strchr(sep, **ptr)) {
+ (*ptr)++;
+ }
+ if (**ptr == 0) {
+ return NULL;
+ }
+
+ res = *ptr;
+ while (**ptr && strchr(sep, **ptr) == NULL) {
+ (*ptr)++;
+ }
+
+ if (**ptr != 0) {
+ *(*ptr)++ = 0;
+ }
+ return res;
+}
+
+/** Convert string in various formats to a time_t
+ *
+ * @param date_str input date string.
+ * @param date time_t to write result to.
+ * @return 0 on success or -1 on error.
+ */
+int fr_get_time(char const *date_str, time_t *date)
+{
+ int i, j;
+ time_t t;
+ struct tm *tm, s_tm;
+ char buf[64];
+ char *p;
+ char *f[4];
+ char *tail = NULL;
+
+ /*
+ * Test for unix timestamp date
+ */
+ *date = strtoul(date_str, &tail, 10);
+ if (*tail == '\0') {
+ return 0;
+ }
+
+ tm = &s_tm;
+ memset(tm, 0, sizeof(*tm));
+ tm->tm_isdst = -1; /* don't know, and don't care about DST */
+
+ strlcpy(buf, date_str, sizeof(buf));
+
+ p = buf;
+ f[0] = mystrtok(&p, " \t");
+ f[1] = mystrtok(&p, " \t");
+ f[2] = mystrtok(&p, " \t");
+ f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
+ if (!f[0] || !f[1] || !f[2]) return -1;
+
+ /*
+ * The time has a colon, where nothing else does.
+ * So if we find it, bubble it to the back of the list.
+ */
+ if (f[3]) {
+ for (i = 0; i < 3; i++) {
+ if (strchr(f[i], ':')) {
+ p = f[3];
+ f[3] = f[i];
+ f[i] = p;
+ break;
+ }
+ }
+ }
+
+ /*
+ * The month is text, which allows us to find it easily.
+ */
+ tm->tm_mon = 12;
+ for (i = 0; i < 3; i++) {
+ if (isalpha( (int) *f[i])) {
+ /*
+ * Bubble the month to the front of the list
+ */
+ p = f[0];
+ f[0] = f[i];
+ f[i] = p;
+
+ for (j = 0; j < 12; j++) {
+ if (strncasecmp(months[j], f[0], 3) == 0) {
+ tm->tm_mon = j;
+ break;
+ }
+ }
+ }
+ }
+
+ /* month not found? */
+ if (tm->tm_mon == 12) return -1;
+
+ /*
+ * The year may be in f[1], or in f[2]
+ */
+ tm->tm_year = atoi(f[1]);
+ tm->tm_mday = atoi(f[2]);
+
+ if (tm->tm_year >= 1900) {
+ tm->tm_year -= 1900;
+
+ } else {
+ /*
+ * We can't use 2-digit years any more, they make it
+ * impossible to tell what's the day, and what's the year.
+ */
+ if (tm->tm_mday < 1900) return -1;
+
+ /*
+ * Swap the year and the day.
+ */
+ i = tm->tm_year;
+ tm->tm_year = tm->tm_mday - 1900;
+ tm->tm_mday = i;
+ }
+
+ /*
+ * If the day is out of range, die.
+ */
+ if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
+ return -1;
+ }
+
+ /*
+ * There may be %H:%M:%S. Parse it in a hacky way.
+ */
+ if (f[3]) {
+ f[0] = f[3]; /* HH */
+ f[1] = strchr(f[0], ':'); /* find : separator */
+ if (!f[1]) return -1;
+
+ *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
+
+ f[2] = strchr(f[1], ':'); /* find : separator */
+ if (f[2]) {
+ *(f[2]++) = '\0'; /* nuke it, and point to SS */
+ tm->tm_sec = atoi(f[2]);
+ } /* else leave it as zero */
+
+ tm->tm_hour = atoi(f[0]);
+ tm->tm_min = atoi(f[1]);
+ }
+
+ /*
+ * Returns -1 on error.
+ */
+ t = mktime(tm);
+ if (t == (time_t) -1) return -1;
+
+ *date = t;
+
+ return 0;
+}
+
+/** Compares two pointers
+ *
+ * @param a first pointer to compare.
+ * @param b second pointer to compare.
+ * @return -1 if a < b, +1 if b > a, or 0 if both equal.
+ */
+int8_t fr_pointer_cmp(void const *a, void const *b)
+{
+ if (a < b) return -1;
+ if (a == b) return 0;
+
+ return 1;
+}
+
+static int _quick_partition(void const *to_sort[], int min, int max, fr_cmp_t cmp) {
+ void const *pivot = to_sort[min];
+ int i = min;
+ int j = max + 1;
+ void const *tmp;
+
+ for (;;) {
+ do ++i; while((cmp(to_sort[i], pivot) <= 0) && i <= max);
+ do --j; while(cmp(to_sort[j], pivot) > 0);
+
+ if (i >= j) break;
+
+ tmp = to_sort[i];
+ to_sort[i] = to_sort[j];
+ to_sort[j] = tmp;
+ }
+
+ tmp = to_sort[min];
+ to_sort[min] = to_sort[j];
+ to_sort[j] = tmp;
+
+ return j;
+}
+
+/** Quick sort an array of pointers using a comparator
+ *
+ * @param to_sort array of pointers to sort.
+ * @param min_idx the lowest index (usually 0).
+ * @param max_idx the highest index (usually length of array - 1).
+ * @param cmp the comparison function to use to sort the array elements.
+ */
+void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp)
+{
+ int part;
+
+ if (min_idx >= max_idx) return;
+
+ part = _quick_partition(to_sort, min_idx, max_idx, cmp);
+ fr_quick_sort(to_sort, min_idx, part - 1, cmp);
+ fr_quick_sort(to_sort, part + 1, max_idx, cmp);
+}
+
+#define USEC 1000000
+
+/** Convert a time specified in milliseconds to a timeval
+ *
+ * @param[out] out Where to write the result.
+ * @param[in] ms To convert to a timeval struct.
+ */
+void fr_timeval_from_ms(struct timeval *out, uint64_t ms)
+{
+ out->tv_sec = ms / 1000;
+ out->tv_usec = (ms % 1000) * 1000;
+}
+
+/** Convert a time specified in microseconds to a timeval
+ *
+ * @param[out] out Where to write the result.
+ * @param[in] usec To convert to a timeval struct.
+ */
+void fr_timeval_from_usec(struct timeval *out, uint64_t usec)
+{
+ out->tv_sec = usec / USEC;
+ out->tv_usec = usec % USEC;
+}
+
+#ifdef TALLOC_DEBUG
+void fr_talloc_verify_cb(UNUSED const void *ptr, UNUSED int depth,
+ UNUSED int max_depth, UNUSED int is_ref,
+ UNUSED void *private_data)
+{
+ /* do nothing */
+}
+#endif
diff --git a/src/lib/missing.c b/src/lib/missing.c
new file mode 100644
index 0000000..95b8c54
--- /dev/null
+++ b/src/lib/missing.c
@@ -0,0 +1,443 @@
+/*
+ * missing.c Replacements for functions that are or can be
+ * missing on some platforms.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+
+#ifndef HAVE_CRYPT
+char *crypt(UNUSED char *key, char *salt)
+{
+ /*log(L_ERR, "crypt() called but not implemented");*/
+ return salt;
+}
+#endif
+
+#ifndef HAVE_STRNCASECMP
+int strncasecmp(char *s1, char *s2, int n)
+{
+ int dif;
+ unsigned char *p1, *p2;
+ int c1, c2;
+
+ p1 = (unsigned char *)s1;
+ p2 = (unsigned char *)s2;
+ dif = 0;
+
+ while (n != 0) {
+ if (*p1 == 0 && *p2 == 0)
+ break;
+ c1 = *p1;
+ c2 = *p2;
+
+ if (islower(c1)) c1 = toupper(c1);
+ if (islower(c2)) c2 = toupper(c2);
+
+ if ((dif = c1 - c2) != 0)
+ break;
+ p1++;
+ p2++;
+ n--;
+ }
+ return dif;
+}
+#endif
+
+#ifndef HAVE_STRCASECMP
+int strcasecmp(char *s1, char *s2)
+{
+ int l1, l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+ if (l2 > l1) l1 = l2;
+
+ return strncasecmp(s1, s2, l1);
+}
+#endif
+
+#ifndef HAVE_INET_ATON
+int inet_aton(char const *cp, struct in_addr *inp)
+{
+ int a1, a2, a3, a4;
+
+ if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
+ return 0;
+
+ inp->s_addr = htonl((a1 << 24) + (a2 << 16) + (a3 << 8) + a4);
+ return 1;
+}
+#endif
+
+#ifndef HAVE_STRSEP
+/*
+ * Get next token from string *stringp, where tokens are
+ * possibly-empty strings separated by characters from delim.
+ *
+ * Writes NULs into the string at *stringp to end tokens.
+ * delim need not remain constant from call to call. On
+ * return, *stringp points past the last NUL written (if there
+ * might be further tokens), or is NULL (if there are
+ * definitely no more tokens).
+ *
+ * If *stringp is NULL, strsep returns NULL.
+ */
+char *
+strsep(char **stringp, char const *delim)
+{
+ char *s;
+ char const *spanp;
+ int c, sc;
+ char *tok;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+
+ return NULL; /* NOTREACHED, but the compiler complains */
+}
+#endif
+
+#ifndef HAVE_LOCALTIME_R
+/*
+ * We use localtime_r() by default in the server.
+ *
+ * For systems which do NOT have localtime_r(), we make the
+ * assumption that localtime() is re-entrant, and returns a
+ * per-thread data structure.
+ *
+ * Even if localtime is NOT re-entrant, this function will
+ * lower the possibility of race conditions.
+ */
+struct tm *localtime_r(time_t const *l_clock, struct tm *result)
+{
+ memcpy(result, localtime(l_clock), sizeof(*result));
+
+ return result;
+}
+#endif
+
+#ifndef HAVE_CTIME_R
+/*
+ * We use ctime_r() by default in the server.
+ *
+ * For systems which do NOT have ctime_r(), we make the
+ * assumption that ctime() is re-entrant, and returns a
+ * per-thread data structure.
+ *
+ * Even if ctime is NOT re-entrant, this function will
+ * lower the possibility of race conditions.
+ */
+char *ctime_r(time_t const *l_clock, char *l_buf)
+{
+ strcpy(l_buf, ctime(l_clock));
+
+ return l_buf;
+}
+#endif
+
+#ifndef HAVE_GMTIME_R
+/*
+ * We use gmtime_r() by default in the server.
+ *
+ * For systems which do NOT have gmtime_r(), we make the
+ * assumption that gmtime() is re-entrant, and returns a
+ * per-thread data structure.
+ *
+ * Even if gmtime is NOT re-entrant, this function will
+ * lower the possibility of race conditions.
+ */
+struct tm *gmtime_r(time_t const *l_clock, struct tm *result)
+{
+ memcpy(result, gmtime(l_clock), sizeof(*result));
+
+ return result;
+}
+#endif
+
+#ifndef HAVE_VDPRINTF
+int vdprintf (int fd, char const *format, va_list args)
+{
+ int ret;
+ FILE *fp;
+ int dup_fd;
+
+ dup_fd = dup(fd);
+ if (dup_fd < 0) return -1;
+
+ fp = fdopen(fd, "w");
+ if (!fp) {
+ close(dup_fd);
+ return -1;
+ }
+
+ ret = vfprintf(fp, format, args);
+ fclose(fp); /* Also closes dup_fd */
+
+ return ret;
+}
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+#ifdef WIN32
+/*
+ * Number of micro-seconds between the beginning of the Windows epoch
+ * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
+ *
+ * This assumes all Win32 compilers have 64-bit support.
+ */
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
+#define DELTA_EPOCH_IN_USEC 11644473600000000Ui64
+#else
+#define DELTA_EPOCH_IN_USEC 11644473600000000ULL
+#endif
+
+static uint64_t filetime_to_unix_epoch (FILETIME const *ft)
+{
+ uint64_t res = (uint64_t) ft->dwHighDateTime << 32;
+
+ res |= ft->dwLowDateTime;
+ res /= 10; /* from 100 nano-sec periods to usec */
+ res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */
+ return (res);
+}
+
+int gettimeofday (struct timeval *tv, UNUSED void *tz)
+{
+ FILETIME ft;
+ uint64_t tim;
+
+ if (!tv) {
+ errno = EINVAL;
+ return (-1);
+ }
+ GetSystemTimeAsFileTime (&ft);
+ tim = filetime_to_unix_epoch (&ft);
+ tv->tv_sec = (long) (tim / 1000000L);
+ tv->tv_usec = (long) (tim % 1000000L);
+ return (0);
+}
+#endif
+#endif
+
+#define NTP_EPOCH_OFFSET 2208988800ULL
+
+/*
+ * Convert 'struct timeval' into NTP format (32-bit integer
+ * of seconds, 32-bit integer of fractional seconds)
+ */
+void
+timeval2ntp(struct timeval const *tv, uint8_t *ntp)
+{
+ uint32_t sec, usec;
+
+ sec = tv->tv_sec + NTP_EPOCH_OFFSET;
+ usec = tv->tv_usec * 4295; /* close enough to 2^32 / USEC */
+ usec -= ((tv->tv_usec * 2143) >> 16); /* */
+
+ sec = htonl(sec);
+ usec = htonl(usec);
+
+ memcpy(ntp, &sec, sizeof(sec));
+ memcpy(ntp + sizeof(sec), &usec, sizeof(usec));
+}
+
+/*
+ * Inverse of timeval2ntp
+ */
+void
+ntp2timeval(struct timeval *tv, char const *ntp)
+{
+ uint32_t sec, usec;
+
+ memcpy(&sec, ntp, sizeof(sec));
+ memcpy(&usec, ntp + sizeof(sec), sizeof(usec));
+
+ sec = ntohl(sec);
+ usec = ntohl(usec);
+
+ tv->tv_sec = sec - NTP_EPOCH_OFFSET;
+ tv->tv_usec = usec / 4295; /* close enough */
+}
+
+#if !defined(HAVE_128BIT_INTEGERS) && defined(FR_LITTLE_ENDIAN)
+/** Swap byte order of 128 bit integer
+ *
+ * @param num 128bit integer to swap.
+ * @return 128bit integer reversed.
+ */
+uint128_t ntohlll(uint128_t const num)
+{
+ uint64_t const *p = (uint64_t const *) &num;
+ uint64_t ret[2];
+
+ /* swapsies */
+ ret[1] = ntohll(p[0]);
+ ret[0] = ntohll(p[1]);
+
+ return *(uint128_t *)ret;
+}
+#endif
+
+#ifdef HAVE_OPENSSL_HMAC_H
+# ifndef HAVE_HMAC_CTX_NEW
+HMAC_CTX *HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx;
+ ctx = OPENSSL_malloc(sizeof(*ctx));
+ if (!ctx) return NULL;
+
+ memset(ctx, 0, sizeof(*ctx));
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+# endif
+# ifndef HAVE_HMAC_CTX_FREE
+void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+ HMAC_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+# endif
+#endif
+
+#ifdef HAVE_OPENSSL_SSL_H
+# ifndef HAVE_SSL_GET_CLIENT_RANDOM
+size_t SSL_get_client_random(const SSL *s, unsigned char *out, size_t outlen)
+{
+ if (!outlen) return sizeof(s->s3->client_random);
+
+ if (outlen > sizeof(s->s3->client_random)) outlen = sizeof(s->s3->client_random);
+
+ memcpy(out, s->s3->client_random, outlen);
+ return outlen;
+}
+# endif
+# ifndef HAVE_SSL_GET_SERVER_RANDOM
+size_t SSL_get_server_random(const SSL *s, unsigned char *out, size_t outlen)
+{
+ if (!outlen) return sizeof(s->s3->server_random);
+
+ if (outlen > sizeof(s->s3->server_random)) outlen = sizeof(s->s3->server_random);
+
+ memcpy(out, s->s3->server_random, outlen);
+ return outlen;
+}
+# endif
+# ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *s,
+ unsigned char *out, size_t outlen)
+{
+ if (!outlen) return s->master_key_length;
+
+ if (outlen > (size_t)s->master_key_length) outlen = (size_t)s->master_key_length;
+
+ memcpy(out, s->master_key, outlen);
+ return outlen;
+}
+# endif
+#endif
+
+/** Call talloc strdup, setting the type on the new chunk correctly
+ *
+ * For some bizarre reason the talloc string functions don't set the
+ * memory chunk type to char, which causes all kinds of issues with
+ * verifying VALUE_PAIRs.
+ *
+ * @param[in] t The talloc context to hang the result off.
+ * @param[in] p The string you want to duplicate.
+ * @return The duplicated string, NULL on error.
+ */
+char *talloc_typed_strdup(void const *t, char const *p)
+{
+ char *n;
+
+ n = talloc_strdup(t, p);
+ if (!n) return NULL;
+ talloc_set_type(n, char);
+
+ return n;
+}
+
+/** Call talloc vasprintf, setting the type on the new chunk correctly
+ *
+ * For some bizarre reason the talloc string functions don't set the
+ * memory chunk type to char, which causes all kinds of issues with
+ * verifying VALUE_PAIRs.
+ *
+ * @param[in] t The talloc context to hang the result off.
+ * @param[in] fmt The format string.
+ * @return The formatted string, NULL on error.
+ */
+char *talloc_typed_asprintf(void const *t, char const *fmt, ...)
+{
+ char *n;
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = talloc_vasprintf(t, fmt, ap);
+ va_end(ap);
+ if (!n) return NULL;
+ talloc_set_type(n, char);
+
+ return n;
+}
+
+/** Binary safe strndup function
+ *
+ * @param[in] t The talloc context o allocate new buffer in.
+ * @param[in] in String to dup, may contain embedded '\0'.
+ * @param[in] inlen Number of bytes to dup.
+ * @return duped string.
+ */
+char *talloc_bstrndup(void const *t, char const *in, size_t inlen)
+{
+ char *p;
+
+ p = talloc_array(t, char, inlen + 1);
+ if (!p) return NULL;
+ memcpy(p, in, inlen);
+ p[inlen] = '\0';
+
+ return p;
+}
+
diff --git a/src/lib/net.c b/src/lib/net.c
new file mode 100644
index 0000000..7c899d7
--- /dev/null
+++ b/src/lib/net.c
@@ -0,0 +1,94 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file net.c
+ * @brief Functions to parse raw packets.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+ #include <freeradius-devel/libradius.h>
+ #include <freeradius-devel/net.h>
+
+/** Calculate UDP checksum
+ *
+ * Zero out UDP checksum in UDP header before calling fr_udp_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the UDP header
+ * @param len value of udp length field in host byte order. Must be validated to make
+ * sure it won't overrun data buffer.
+ * @param checksum current checksum, leave as 0 to just enable validation.
+ * @param src_addr in network byte order.
+ * @param dst_addr in network byte order.
+ * @return 0 if the checksum is correct, else another number.
+ */
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr)
+{
+ uint64_t sum = 0; /* using 64bits avoids overflow check */
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint16_t const *ip_src = (void const *) &src_addr.s_addr;
+ uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
+ uint16_t i;
+
+ sum += *(ip_src++);
+ sum += *ip_src;
+ sum += *(ip_dst++);
+ sum += *ip_dst;
+
+ sum += htons(IPPROTO_UDP);
+ sum += htons(len);
+
+ for (i = len; i > 1; i -= 2) {
+ sum += *p++;
+ }
+
+ if (i) {
+ sum += (0xff & *(uint8_t const *)p) << 8;
+ }
+
+ sum -= checksum;
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ return ((uint16_t) ~sum);
+}
+
+/** Calculate IP header checksum.
+ *
+ * Zero out IP header checksum in IP header before calling fr_iph_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the IP header
+ * @param ihl value of ip header length field (number of 32 bit words)
+ */
+uint16_t fr_iph_checksum(uint8_t const *data, uint8_t ihl)
+{
+ uint64_t sum = 0;
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint8_t nwords = (ihl << 1); /* number of 16-bit words */
+
+ for (sum = 0; nwords > 0; nwords--) {
+ sum += *p++;
+ }
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ((uint16_t) ~sum);
+}
diff --git a/src/lib/packet.c b/src/lib/packet.c
new file mode 100644
index 0000000..971980b
--- /dev/null
+++ b/src/lib/packet.c
@@ -0,0 +1,1116 @@
+/*
+ * packet.c Generic packet manipulation functions.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef WITH_UDPFROMTO
+#include <freeradius-devel/udpfromto.h>
+#endif
+
+#include <fcntl.h>
+
+/*
+ * See if two packets are identical.
+ *
+ * Note that we do NOT compare the authentication vectors.
+ * That's because if the authentication vector is different,
+ * it means that the NAS has given up on the earlier request.
+ */
+int fr_packet_cmp(RADIUS_PACKET const *a, RADIUS_PACKET const *b)
+{
+ int rcode;
+
+ if (a->sockfd < b->sockfd) return -1;
+ if (a->sockfd > b->sockfd) return +1;
+
+ /*
+ * IDs should be spread effectively randomly
+ */
+ if (a->id < b->id) return -1;
+ if (a->id > b->id) return +1;
+
+#ifdef WITH_TCP
+ /*
+ * TCP sockets have (by definition) the same src/dst
+ * IP/port combos. We we can just ignore those fields.
+ */
+ if (a->proto == IPPROTO_TCP) {
+ return 0;
+ }
+#endif
+
+ /*
+ * RADIUS can have unconnected UDP sockets, in which case
+ * the socket FD is the same, but the src/dst IP/ports
+ * may be different.
+ */
+
+ /*
+ * Source ports are pretty much random.
+ */
+ rcode = (int) a->src_port - (int) b->src_port;
+ if (rcode != 0) return rcode;
+
+ /*
+ * Usually many client IPs, and few server IPs
+ */
+ rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ /*
+ * One socket can receive packets for multiple
+ * destination IPs, so we check that before checking the
+ * file descriptor.
+ */
+ rcode = fr_ipaddr_cmp(&a->dst_ipaddr, &b->dst_ipaddr);
+ if (rcode != 0) return rcode;
+
+ /*
+ * At this point, the order of comparing socket FDs
+ * and/or destination ports doesn't matter. One of those
+ * fields will make the socket unique, and the other is
+ * pretty much redundant.
+ */
+ rcode = (int) a->dst_port - (int) b->dst_port;
+ return rcode;
+}
+
+int fr_inaddr_any(fr_ipaddr_t *ipaddr)
+{
+
+ if (ipaddr->af == AF_INET) {
+ if (ipaddr->ipaddr.ip4addr.s_addr == INADDR_ANY) {
+ return 1;
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (ipaddr->af == AF_INET6) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->ipaddr.ip6addr))) {
+ return 1;
+ }
+#endif
+
+ } else {
+ fr_strerror_printf("Unknown address family");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Create a fake "request" from a reply, for later lookup.
+ */
+void fr_request_from_reply(RADIUS_PACKET *request,
+ RADIUS_PACKET const *reply)
+{
+ request->sockfd = reply->sockfd;
+ request->id = reply->id;
+#ifdef WITH_TCP
+ request->proto = reply->proto;
+
+#ifdef WITH_RADIUSV11
+ if (reply->radiusv11) {
+ memcpy(request->vector, reply->vector, sizeof(request->vector));
+ }
+#endif
+#endif
+ request->src_port = reply->dst_port;
+ request->dst_port = reply->src_port;
+ request->src_ipaddr = reply->dst_ipaddr;
+ request->dst_ipaddr = reply->src_ipaddr;
+}
+
+/*
+ * Open a socket on the given IP and port.
+ */
+int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
+{
+ int sockfd;
+ struct sockaddr_storage salocal;
+ socklen_t salen;
+
+ sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
+ return sockfd;
+ }
+
+#ifdef WITH_UDPFROMTO
+ /*
+ * Initialize udpfromto for all sockets.
+ */
+ if (udpfromto_init(sockfd) != 0) {
+ close(sockfd);
+ fr_strerror_printf("cannot initialize udpfromto: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+
+ if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
+ return sockfd;
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ if (ipaddr->af == AF_INET6) {
+ /*
+ * Listening on '::' does NOT get you IPv4 to
+ * IPv6 mapping. You've got to listen on an IPv4
+ * address, too. This makes the rest of the server
+ * design a little simpler.
+ */
+#ifdef IPV6_V6ONLY
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
+ int on = 1;
+
+ if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&on, sizeof(on)) < 0) {
+ close(sockfd);
+ fr_strerror_printf("Failed setting sockopt "
+ "IPPROTO_IPV6 - IPV6_V6ONLY"
+ ": %s", fr_syserror(errno));
+ return -1;
+ }
+ }
+#endif /* IPV6_V6ONLY */
+ }
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+
+#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
+ if (ipaddr->af == AF_INET) {
+ int flag;
+
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+
+ /*
+ * Disable PMTU discovery. On Linux, this
+ * also makes sure that the "don't fragment"
+ * flag is zero.
+ */
+ flag = IP_PMTUDISC_DONT;
+ if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
+ &flag, sizeof(flag)) < 0) {
+ close(sockfd);
+ fr_strerror_printf("Failed setting sockopt "
+ "IPPROTO_IP - IP_MTU_DISCOVER: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+#endif
+
+#if defined(IP_DONTFRAG)
+ /*
+ * Ensure that the "don't fragment" flag is zero.
+ */
+ flag = 0;
+ if (setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
+ &flag, sizeof(flag)) < 0) {
+ close(sockfd);
+ fr_strerror_printf("Failed setting sockopt "
+ "IPPROTO_IP - IP_DONTFRAG: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+#endif
+ }
+#endif
+
+ if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
+ close(sockfd);
+ fr_strerror_printf("cannot bind socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ return sockfd;
+}
+
+
+/*
+ * We need to keep track of the socket & it's IP/port.
+ */
+typedef struct fr_packet_socket_t {
+ int sockfd;
+ void *ctx;
+
+ uint32_t num_outgoing;
+
+ int src_any;
+ fr_ipaddr_t src_ipaddr;
+ uint16_t src_port;
+
+ int dst_any;
+ fr_ipaddr_t dst_ipaddr;
+ uint16_t dst_port;
+
+ bool dont_use;
+
+#ifdef WITH_TCP
+ int proto;
+#endif
+
+#ifdef WITH_RADIUSV11
+ bool radiusv11;
+
+ uint32_t counter;
+#endif
+
+ uint8_t id[32];
+} fr_packet_socket_t;
+
+
+#define FNV_MAGIC_PRIME (0x01000193)
+#define MAX_SOCKETS (1024)
+#define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
+#define SOCK2OFFSET(sockfd) ((sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
+
+/*
+ * Structure defining a list of packets (incoming or outgoing)
+ * that should be managed.
+ */
+struct fr_packet_list_t {
+ rbtree_t *tree;
+
+ int alloc_id;
+ uint32_t num_outgoing;
+ int last_recv;
+ int num_sockets;
+
+ fr_packet_socket_t sockets[MAX_SOCKETS];
+};
+
+
+/*
+ * Ugh. Doing this on every sent/received packet is not nice.
+ */
+static fr_packet_socket_t *fr_socket_find(fr_packet_list_t *pl,
+ int sockfd)
+{
+ int i, start;
+
+ i = start = SOCK2OFFSET(sockfd);
+
+ do { /* make this hack slightly more efficient */
+ if (pl->sockets[i].sockfd == sockfd) return &pl->sockets[i];
+
+ i = (i + 1) & SOCKOFFSET_MASK;
+ } while (i != start);
+
+ return NULL;
+}
+
+bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
+{
+ fr_packet_socket_t *ps;
+
+ if (!pl) {
+ fr_strerror_printf("Invalid argument");
+ return false;
+ }
+
+ ps = fr_socket_find(pl, sockfd);
+ if (!ps) {
+ fr_strerror_printf("No such socket");
+ return false;
+ }
+
+ ps->dont_use = true;
+ return true;
+}
+
+bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
+{
+ fr_packet_socket_t *ps;
+
+ if (!pl) return false;
+
+ ps = fr_socket_find(pl, sockfd);
+ if (!ps) return false;
+
+ ps->dont_use = false;
+ return true;
+}
+
+
+bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
+{
+ fr_packet_socket_t *ps;
+
+ if (!pl) return false;
+
+ ps = fr_socket_find(pl, sockfd);
+ if (!ps) return false;
+
+ if (ps->num_outgoing != 0) {
+ fr_strerror_printf("socket is still in use");
+ return false;
+ }
+
+ ps->sockfd = -1;
+ pl->num_sockets--;
+
+ return true;
+}
+
+
+bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
+#ifdef WITH_RADIUSV11
+ bool radiusv11,
+#endif
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
+ void *ctx)
+{
+ int i, start;
+ struct sockaddr_storage src;
+ socklen_t sizeof_src;
+ fr_packet_socket_t *ps;
+
+ if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
+ fr_strerror_printf("Invalid argument");
+ return false;
+ }
+
+ if (pl->num_sockets >= MAX_SOCKETS) {
+ fr_strerror_printf("Too many open sockets");
+ return false;
+ }
+
+#ifndef WITH_TCP
+ if (proto != IPPROTO_UDP) {
+ fr_strerror_printf("only UDP is supported");
+ return false;
+ }
+#endif
+
+ ps = NULL;
+ i = start = SOCK2OFFSET(sockfd);
+
+ do {
+ if (pl->sockets[i].sockfd == -1) {
+ ps = &pl->sockets[i];
+ break;
+ }
+
+ i = (i + 1) & SOCKOFFSET_MASK;
+ } while (i != start);
+
+ if (!ps) {
+ fr_strerror_printf("All socket entries are full");
+ return false;
+ }
+
+ memset(ps, 0, sizeof(*ps));
+ ps->ctx = ctx;
+#ifdef WITH_TCP
+ ps->proto = proto;
+#ifdef WITH_RADIUSV11
+ ps->radiusv11 = radiusv11;
+
+ /*
+ * Start our packet counter at a random 64-bit number.
+ */
+ if (radiusv11) {
+ ps->counter = fr_rand();
+ }
+#endif
+#endif
+
+ /*
+ * Get address family, etc. first, so we know if we
+ * need to do udpfromto.
+ *
+ * FIXME: udpfromto also does this, but it's not
+ * a critical problem.
+ */
+ sizeof_src = sizeof(src);
+ memset(&src, 0, sizeof_src);
+ if (getsockname(sockfd, (struct sockaddr *) &src,
+ &sizeof_src) < 0) {
+ fr_strerror_printf("%s", fr_syserror(errno));
+ return false;
+ }
+
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->src_ipaddr,
+ &ps->src_port)) {
+ fr_strerror_printf("Failed to get IP");
+ return false;
+ }
+
+ ps->dst_ipaddr = *dst_ipaddr;
+ ps->dst_port = dst_port;
+
+ ps->src_any = fr_inaddr_any(&ps->src_ipaddr);
+ if (ps->src_any < 0) return false;
+
+ ps->dst_any = fr_inaddr_any(&ps->dst_ipaddr);
+ if (ps->dst_any < 0) return false;
+
+ /*
+ * As the last step before returning.
+ */
+ ps->sockfd = sockfd;
+ pl->num_sockets++;
+
+ return true;
+}
+
+static int packet_entry_cmp(void const *one, void const *two)
+{
+ RADIUS_PACKET const * const *a = one;
+ RADIUS_PACKET const * const *b = two;
+
+ return fr_packet_cmp(*a, *b);
+}
+
+void fr_packet_list_free(fr_packet_list_t *pl)
+{
+ if (!pl) return;
+
+ rbtree_free(pl->tree);
+ free(pl);
+}
+
+
+/*
+ * Caller is responsible for managing the packet entries.
+ */
+fr_packet_list_t *fr_packet_list_create(int alloc_id)
+{
+ int i;
+ fr_packet_list_t *pl;
+
+ pl = malloc(sizeof(*pl));
+ if (!pl) return NULL;
+ memset(pl, 0, sizeof(*pl));
+
+ pl->tree = rbtree_create(NULL, packet_entry_cmp, NULL, 0);
+ if (!pl->tree) {
+ fr_packet_list_free(pl);
+ return NULL;
+ }
+
+ for (i = 0; i < MAX_SOCKETS; i++) {
+ pl->sockets[i].sockfd = -1;
+ }
+
+ pl->alloc_id = alloc_id;
+
+ return pl;
+}
+
+
+/*
+ * If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
+ * be called before inserting the packet into the list!
+ */
+bool fr_packet_list_insert(fr_packet_list_t *pl,
+ RADIUS_PACKET **request_p)
+{
+ if (!pl || !request_p || !*request_p) return 0;
+
+ VERIFY_PACKET(*request_p);
+
+ return rbtree_insert(pl->tree, request_p);
+}
+
+RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,
+ RADIUS_PACKET *request)
+{
+ if (!pl || !request) return 0;
+
+ VERIFY_PACKET(request);
+
+ return rbtree_finddata(pl->tree, &request);
+}
+
+
+/*
+ * This presumes that the reply has dst_ipaddr && dst_port set up
+ * correctly (i.e. real IP, or "*").
+ */
+RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
+ RADIUS_PACKET *reply)
+{
+ RADIUS_PACKET my_request, *request;
+ fr_packet_socket_t *ps;
+
+ if (!pl || !reply) return NULL;
+
+ VERIFY_PACKET(reply);
+
+ ps = fr_socket_find(pl, reply->sockfd);
+ if (!ps) return NULL;
+
+ /*
+ * Initialize request from reply, AND from the source
+ * IP & port of this socket. The client may have bound
+ * the socket to 0, in which case it's some random port,
+ * that is NOT in the original request->src_port.
+ */
+ my_request.sockfd = reply->sockfd;
+ my_request.id = reply->id;
+
+#ifdef WITH_TCP
+ /*
+ * TCP sockets are always bound to the correct src/dst IP/port
+ */
+ if (ps->proto == IPPROTO_TCP) {
+ reply->dst_ipaddr = ps->src_ipaddr;
+ reply->dst_port = ps->src_port;
+ reply->src_ipaddr = ps->dst_ipaddr;
+ reply->src_port = ps->dst_port;
+
+ my_request.src_ipaddr = ps->src_ipaddr;
+ my_request.src_port = ps->src_port;
+ my_request.dst_ipaddr = ps->dst_ipaddr;
+ my_request.dst_port = ps->dst_port;
+
+ } else
+#endif
+ {
+ if (ps->src_any) {
+ my_request.src_ipaddr = ps->src_ipaddr;
+ } else {
+ my_request.src_ipaddr = reply->dst_ipaddr;
+ }
+ my_request.src_port = ps->src_port;
+
+ my_request.dst_ipaddr = reply->src_ipaddr;
+ my_request.dst_port = reply->src_port;
+ }
+
+#ifdef WITH_TCP
+ my_request.proto = reply->proto;
+#endif
+
+#ifdef WITH_RADIUSV11
+ my_request.radiusv11 = reply->radiusv11;
+#endif
+
+ request = &my_request;
+
+ return rbtree_finddata(pl->tree, &request);
+}
+
+
+bool fr_packet_list_yank(fr_packet_list_t *pl, RADIUS_PACKET *request)
+{
+ rbnode_t *node;
+
+ if (!pl || !request) return false;
+
+ VERIFY_PACKET(request);
+
+ node = rbtree_find(pl->tree, &request);
+ if (!node) return false;
+
+ rbtree_delete(pl->tree, node);
+ return true;
+}
+
+uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
+{
+ if (!pl) return 0;
+
+ return rbtree_num_elements(pl->tree);
+}
+
+
+/*
+ * 1 == ID was allocated & assigned
+ * 0 == couldn't allocate ID.
+ *
+ * Note that this ALSO assigns a socket to use, and updates
+ * packet->request->src_ipaddr && packet->request->src_port
+ *
+ * In multi-threaded systems, the calls to id_alloc && id_free
+ * should be protected by a mutex. This does NOT have to be
+ * the same mutex as the one protecting the insert/find/yank
+ * calls!
+ *
+ * We assume that the packet has dst_ipaddr && dst_port
+ * already initialized. We will use those to find an
+ * outgoing socket. The request MAY also have src_ipaddr set.
+ *
+ * We also assume that the sender doesn't care which protocol
+ * should be used.
+ */
+bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
+ RADIUS_PACKET **request_p, void **pctx)
+{
+ int i, j, k, fd, id, start_i, start_j, start_k;
+ int src_any = 0;
+ fr_packet_socket_t *ps= NULL;
+ RADIUS_PACKET *request = *request_p;
+
+ VERIFY_PACKET(request);
+
+ if ((request->dst_ipaddr.af == AF_UNSPEC) ||
+ (request->dst_port == 0)) {
+ fr_strerror_printf("No destination address/port specified");
+ return false;
+ }
+
+#ifndef WITH_TCP
+ if ((proto != 0) && (proto != IPPROTO_UDP)) {
+ fr_strerror_printf("Invalid destination protocol");
+ return false;
+ }
+#endif
+
+ /*
+ * Special case: unspec == "don't care"
+ */
+ if (request->src_ipaddr.af == AF_UNSPEC) {
+ memset(&request->src_ipaddr, 0, sizeof(request->src_ipaddr));
+ request->src_ipaddr.af = request->dst_ipaddr.af;
+ }
+
+ src_any = fr_inaddr_any(&request->src_ipaddr);
+ if (src_any < 0) {
+ fr_strerror_printf("Can't check src_ipaddr");
+ return false;
+ }
+
+ /*
+ * MUST specify a destination address.
+ */
+ if (fr_inaddr_any(&request->dst_ipaddr) != 0) {
+ fr_strerror_printf("Must specify a dst_ipaddr");
+ return false;
+ }
+
+ /*
+ * FIXME: Go to an LRU system. This prevents ID re-use
+ * for as long as possible. The main problem with that
+ * approach is that it requires us to populate the
+ * LRU/FIFO when we add a new socket, or a new destination,
+ * which can be expensive.
+ *
+ * The LRU can be avoided if the caller takes care to free
+ * Id's only when all responses have been received, OR after
+ * a timeout.
+ *
+ * Right now, the random approach is almost OK... it's
+ * brute-force over all of the available ID's, BUT using
+ * random numbers for everything spreads the load a bit.
+ *
+ * The old method had a hash lookup on allocation AND
+ * on free. The new method has brute-force on allocation,
+ * and near-zero cost on free.
+ */
+
+ id = fd = -1;
+ start_i = fr_rand() & SOCKOFFSET_MASK;
+
+#define ID_i ((i + start_i) & SOCKOFFSET_MASK)
+ for (i = 0; i < MAX_SOCKETS; i++) {
+ if (pl->sockets[ID_i].sockfd == -1) continue; /* paranoia */
+
+ ps = &(pl->sockets[ID_i]);
+
+ /*
+ * This socket is marked as "don't use for new
+ * packets". But we can still receive packets
+ * that are outstanding.
+ */
+ if (ps->dont_use) continue;
+
+#ifdef WITH_TCP
+ if (ps->proto != proto) continue;
+#endif
+
+ /*
+ * Address families don't match, skip it.
+ */
+ if (ps->src_ipaddr.af != request->dst_ipaddr.af) continue;
+
+ /*
+ * MUST match dst port, if we have one.
+ */
+ if ((ps->dst_port != 0) &&
+ (ps->dst_port != request->dst_port)) continue;
+
+ /*
+ * MUST match requested src port, if one has been given.
+ */
+ if ((request->src_port != 0) &&
+ (ps->src_port != request->src_port)) continue;
+
+ /*
+ * We don't care about the source IP, but this
+ * socket is link local, and the requested
+ * destination is not link local. Ignore it.
+ */
+ if (src_any && (ps->src_ipaddr.af == AF_INET) &&
+ (((ps->src_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) == 127) &&
+ (((request->dst_ipaddr.ipaddr.ip4addr.s_addr >> 24) & 0xff) != 127)) continue;
+
+ /*
+ * We're sourcing from *, and they asked for a
+ * specific source address: ignore it.
+ */
+ if (ps->src_any && !src_any) continue;
+
+ /*
+ * We're sourcing from a specific IP, and they
+ * asked for a source IP that isn't us: ignore
+ * it.
+ */
+ if (!ps->src_any && !src_any &&
+ (fr_ipaddr_cmp(&request->src_ipaddr,
+ &ps->src_ipaddr) != 0)) continue;
+
+ /*
+ * UDP sockets are allowed to match
+ * destination IPs exactly, OR a socket
+ * with destination * is allowed to match
+ * any requested destination.
+ *
+ * TCP sockets must match the destination
+ * exactly. They *always* have dst_any=0,
+ * so the first check always matches.
+ */
+ if (!ps->dst_any &&
+ (fr_ipaddr_cmp(&request->dst_ipaddr,
+ &ps->dst_ipaddr) != 0)) continue;
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 matches on src/dst IP/port, but
+ * doesn't care about num_outgoing or ID allocation.
+ */
+ if (ps->radiusv11) {
+ request->radiusv11 = true;
+
+ fd = ps->sockfd;
+
+ /*
+ * Increment the counter. It has to be
+ * unique, but its exact value doesn't
+ * matter. i.e. the receiver doesn't
+ * care if it's a counter or a random
+ * number.
+ */
+ ps->counter++;
+ id = 0;
+ memcpy(request->vector, &ps->counter, sizeof(ps->counter));
+ memset(request->vector + sizeof(ps->counter), 0, sizeof(request->vector) - sizeof(ps->counter));
+ break;
+ }
+#endif
+
+ /*
+ * All IDs are allocated: ignore it.
+ */
+ if (ps->num_outgoing == 256) continue;
+
+ /*
+ * Otherwise, this socket is OK to use.
+ */
+
+ /*
+ * Look for a free Id, starting from a random number.
+ */
+ start_j = fr_rand() & 0x1f;
+#define ID_j ((j + start_j) & 0x1f)
+ for (j = 0; j < 32; j++) {
+ if (ps->id[ID_j] == 0xff) continue;
+
+
+ start_k = fr_rand() & 0x07;
+#define ID_k ((k + start_k) & 0x07)
+ for (k = 0; k < 8; k++) {
+ if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
+
+ ps->id[ID_j] |= (1 << ID_k);
+ id = (ID_j * 8) + ID_k;
+ fd = i;
+ break;
+ }
+ if (fd >= 0) break;
+ }
+#undef ID_i
+#undef ID_j
+#undef ID_k
+ if (fd >= 0) break;
+ }
+
+ /*
+ * Ask the caller to allocate a new ID.
+ */
+ if (fd < 0) {
+ fr_strerror_printf("Failed finding socket, caller must allocate a new one");
+ return false;
+ }
+
+ /*
+ * Set the ID, source IP, and source port.
+ */
+ request->id = id;
+#ifdef WITH_RADIUSV11
+ if (ps->radiusv11) request->id = ps->counter;
+#endif
+
+ request->sockfd = ps->sockfd;
+ request->src_ipaddr = ps->src_ipaddr;
+ request->src_port = ps->src_port;
+
+ /*
+ * If we managed to insert it, we're done.
+ */
+ if (fr_packet_list_insert(pl, request_p)) {
+ if (pctx) *pctx = ps->ctx;
+ ps->num_outgoing++;
+ pl->num_outgoing++;
+ return true;
+ }
+
+ /*
+ * Mark the ID as free. This is the one line from
+ * id_free() that we care about here.
+ */
+ ps->id[(id >> 3) & 0x1f] &= ~(1 << (id & 0x07));
+
+ request->id = -1;
+ request->sockfd = -1;
+ request->src_ipaddr.af = AF_UNSPEC;
+ request->src_port = 0;
+
+ return false;
+}
+
+/*
+ * Should be called AFTER yanking it from the list, so that
+ * any newly inserted entries don't collide with this one.
+ */
+bool fr_packet_list_id_free(fr_packet_list_t *pl,
+ RADIUS_PACKET *request, bool yank)
+{
+ fr_packet_socket_t *ps;
+
+ if (!pl || !request) return false;
+
+ VERIFY_PACKET(request);
+
+ if (yank && !fr_packet_list_yank(pl, request)) return false;
+
+ ps = fr_socket_find(pl, request->sockfd);
+ if (!ps) return false;
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 packets don't track individual IDs.
+ */
+ if (!ps->radiusv11)
+#endif
+ ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
+
+ ps->num_outgoing--;
+ pl->num_outgoing--;
+
+ request->id = -1;
+ request->src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
+ request->src_port = 0;
+
+ return true;
+}
+
+/*
+ * We always walk RBTREE_DELETE_ORDER, which is like RBTREE_IN_ORDER, except that
+ * <0 means error, stop
+ * 0 means OK, continue
+ * 1 means delete current node and stop
+ * 2 means delete current node and continue
+ */
+int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx, rb_walker_t callback)
+{
+ if (!pl || !callback) return 0;
+
+ return rbtree_walk(pl->tree, RBTREE_DELETE_ORDER, callback, ctx);
+}
+
+int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
+{
+ int i, maxfd;
+
+ if (!pl || !set) return 0;
+
+ maxfd = -1;
+
+ for (i = 0; i < MAX_SOCKETS; i++) {
+ if (pl->sockets[i].sockfd == -1) continue;
+ FD_SET(pl->sockets[i].sockfd, set);
+ if (pl->sockets[i].sockfd > maxfd) {
+ maxfd = pl->sockets[i].sockfd;
+ }
+ }
+
+ if (maxfd < 0) return -1;
+
+ return maxfd + 1;
+}
+
+/*
+ * Round-robins the receivers, without priority.
+ *
+ * FIXME: Add sockfd, if -1, do round-robin, else do sockfd
+ * IF in fdset.
+ */
+RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
+{
+ int start;
+ RADIUS_PACKET *packet;
+
+ if (!pl || !set) return NULL;
+
+ start = pl->last_recv;
+ do {
+ start++;
+ start &= SOCKOFFSET_MASK;
+
+ if (pl->sockets[start].sockfd == -1) continue;
+
+ if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue;
+
+#ifdef WITH_TCP
+ if (pl->sockets[start].proto == IPPROTO_TCP) {
+ packet = fr_tcp_recv(pl->sockets[start].sockfd, 0);
+ if (!packet) {
+ fr_strerror_printf("TCP connection has been closed");
+ return NULL;
+ }
+
+ /*
+ * We always know src/dst ip/port for TCP
+ * sockets. So just fill them in. Since
+ * we read the packet from the TCP
+ * socket, we invert src/dst.
+ */
+ packet->dst_ipaddr = pl->sockets[start].src_ipaddr;
+ packet->dst_port = pl->sockets[start].src_port;
+ packet->src_ipaddr = pl->sockets[start].dst_ipaddr;
+ packet->src_port = pl->sockets[start].dst_port;
+
+ } else
+#endif
+
+ /*
+ * Rely on rad_recv() to fill in the required
+ * fields.
+ */
+ packet = rad_recv(NULL, pl->sockets[start].sockfd, 0);
+ if (!packet) continue;
+
+ /*
+ * Call fr_packet_list_find_byreply(). If it
+ * doesn't find anything, discard the reply.
+ */
+
+ pl->last_recv = start;
+#ifdef WITH_TCP
+ packet->proto = pl->sockets[start].proto;
+#endif
+ return packet;
+ } while (start != pl->last_recv);
+
+ return NULL;
+}
+
+uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
+{
+ uint32_t num_elements;
+
+ if (!pl) return 0;
+
+ num_elements = rbtree_num_elements(pl->tree);
+ if (num_elements < pl->num_outgoing) return 0; /* panic! */
+
+ return num_elements - pl->num_outgoing;
+}
+
+uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
+{
+ if (!pl) return 0;
+
+ return pl->num_outgoing;
+}
+
+/*
+ * Debug the packet if requested.
+ */
+void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
+{
+ char src_ipaddr[128];
+ char dst_ipaddr[128];
+
+ if (!fp) return;
+ if (!packet) return;
+
+ /*
+ * Client-specific debugging re-prints the input
+ * packet into the client log.
+ *
+ * This really belongs in a utility library
+ */
+ if (is_radius_code(packet->code)) {
+ fprintf(fp, "%s %s Id %i from %s%s%s:%x to %s%s%s:%u length %zu\n",
+ received ? "Received" : "Sent",
+ fr_packet_codes[packet->code],
+ packet->id,
+ packet->src_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ipaddr, sizeof(src_ipaddr)),
+ packet->src_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->src_port,
+ packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->dst_port,
+ packet->data_len);
+ } else {
+ fprintf(fp, "%s code %u Id %i from %s%s%s:%u to %s%s%s:%i length %zu\n",
+ received ? "Received" : "Sent",
+ packet->code,
+ packet->id,
+ packet->src_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ipaddr, sizeof(src_ipaddr)),
+ packet->src_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->src_port,
+ packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->dst_port,
+ packet->data_len);
+ }
+}
+
diff --git a/src/lib/pair.c b/src/lib/pair.c
new file mode 100644
index 0000000..449e0e1
--- /dev/null
+++ b/src/lib/pair.c
@@ -0,0 +1,2520 @@
+/*
+ * pair.c Functions to handle VALUE_PAIRs
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/regex.h>
+
+#include <ctype.h>
+
+/** Free a VALUE_PAIR
+ *
+ * @note Do not call directly, use talloc_free instead.
+ *
+ * @param vp to free.
+ * @return 0
+ */
+static int _fr_pair_free(VALUE_PAIR *vp) {
+#ifndef NDEBUG
+ vp->vp_integer = 0xf4eef4ee;
+#endif
+
+#ifdef TALLOC_DEBUG
+ talloc_report_depth_cb(NULL, 0, -1, fr_talloc_verify_cb, NULL);
+#endif
+ return 0;
+}
+
+VALUE_PAIR *fr_pair_alloc(TALLOC_CTX *ctx)
+{
+ VALUE_PAIR *vp;
+
+ vp = talloc_zero(ctx, VALUE_PAIR);
+ if (!vp) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+
+ vp->op = T_OP_EQ;
+ vp->tag = TAG_ANY;
+ vp->type = VT_NONE;
+
+ talloc_set_destructor(vp, _fr_pair_free);
+
+ return vp;
+}
+
+
+/** Dynamically allocate a new attribute
+ *
+ * Allocates a new attribute and a new dictionary attr if no DA is provided.
+ *
+ * @param[in] ctx for allocated memory, usually a pointer to a RADIUS_PACKET
+ * @param[in] da Specifies the dictionary attribute to build the VP from.
+ * @return a new value pair or NULL if an error occurred.
+ */
+VALUE_PAIR *fr_pair_afrom_da(TALLOC_CTX *ctx, DICT_ATTR const *da)
+{
+ VALUE_PAIR *vp;
+
+ /*
+ * Caller must specify a da else we don't know what the attribute type is.
+ */
+ if (!da) {
+ fr_strerror_printf("Invalid arguments");
+ return NULL;
+ }
+
+ vp = fr_pair_alloc(ctx);
+ if (!vp) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+
+ /*
+ * Use the 'da' to initialize more fields.
+ */
+ vp->da = da;
+ vp->vp_length = da->flags.length;
+
+ return vp;
+}
+
+/** Create a new valuepair
+ *
+ * If attr and vendor match a dictionary entry then a VP with that DICT_ATTR
+ * will be returned.
+ *
+ * If attr or vendor are uknown will call dict_attruknown to create a dynamic
+ * DICT_ATTR of PW_TYPE_OCTETS.
+ *
+ * Which type of DICT_ATTR the VALUE_PAIR was created with can be determined by
+ * checking @verbatim vp->da->flags.is_unknown @endverbatim.
+ *
+ * @param[in] ctx for allocated memory, usually a pointer to a RADIUS_PACKET
+ * @param[in] attr number.
+ * @param[in] vendor number.
+ * @return the new valuepair or NULL on error.
+ */
+VALUE_PAIR *fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor)
+{
+ DICT_ATTR const *da;
+
+ da = dict_attrbyvalue(attr, vendor);
+ if (!da) return NULL;
+
+ return fr_pair_afrom_da(ctx, da);
+}
+
+/** Free memory used by a valuepair list.
+ *
+ * @todo TLV: needs to free all dependents of each VP freed.
+ */
+void fr_pair_list_free(VALUE_PAIR **vps)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ if (!vps || !*vps) {
+ return;
+ }
+
+ for (vp = fr_cursor_init(&cursor, vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VERIFY_VP(vp);
+ talloc_free(vp);
+ }
+
+ *vps = NULL;
+}
+
+/** Mark malformed or unrecognised attributed as unknown
+ *
+ * @param vp to change DICT_ATTR of.
+ * @return 0 on success (or if already unknown) else -1 on error.
+ */
+int fr_pair_to_unknown(VALUE_PAIR *vp)
+{
+ DICT_ATTR const *da;
+
+ VERIFY_VP(vp);
+ if (vp->da->flags.is_unknown) {
+ return 0;
+ }
+
+ da = dict_unknown_afrom_fields(vp, vp->da->attr, vp->da->vendor);
+ if (!da) {
+ return -1;
+ }
+
+ vp->da = da;
+
+ return 0;
+}
+
+/** Find the pair with the matching DAs
+ *
+ */
+VALUE_PAIR *fr_pair_find_by_da(VALUE_PAIR *vp, DICT_ATTR const *da, int8_t tag)
+{
+ vp_cursor_t cursor;
+
+ if(!fr_assert(da)) {
+ return NULL;
+ }
+
+ (void) fr_cursor_init(&cursor, &vp);
+ return fr_cursor_next_by_da(&cursor, da, tag);
+}
+
+
+/** Find the pair with the matching attribute
+ *
+ * @todo should take DAs and do a pointer comparison.
+ */
+VALUE_PAIR *fr_pair_find_by_num(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ vp_cursor_t cursor;
+
+ /* List head may be NULL if it contains no VPs */
+ if (!vp) return NULL;
+
+ VERIFY_LIST(vp, "");
+
+ (void) fr_cursor_init(&cursor, &vp);
+ return fr_cursor_next_by_num(&cursor, attr, vendor, tag);
+}
+
+/** Delete matching pairs
+ *
+ * Delete matching pairs from the attribute list.
+ *
+ * @param[in,out] first VP in list.
+ * @param[in] attr to match.
+ * @param[in] vendor to match.
+ * @param[in] tag to match. TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
+ *
+ * @todo should take DAs and do a point comparison.
+ */
+void fr_pair_delete_by_num(VALUE_PAIR **first, unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ VALUE_PAIR *i, *next;
+ VALUE_PAIR **last = first;
+
+ for(i = *first; i; i = next) {
+ VERIFY_VP(i);
+ next = i->next;
+ if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
+ (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
+ *last = next;
+ talloc_free(i);
+ } else {
+ last = &i->next;
+ }
+ }
+}
+
+/** Delete matching pairs by da
+ *
+ * Delete matching pairs from the attribute list.
+ *
+ * @param[in,out] first VP in list.
+ * @param[in] da to match.
+ */
+void fr_pair_delete_by_da(VALUE_PAIR **first, DICT_ATTR const *da)
+{
+ VALUE_PAIR *i, *next;
+ VALUE_PAIR **last = first;
+
+ for(i = *first; i; i = next) {
+ VERIFY_VP(i);
+ next = i->next;
+ if (i->da == da) {
+ *last = next;
+ talloc_free(i);
+ } else {
+ last = &i->next;
+ }
+ }
+}
+
+/** Add a VP to the end of the list.
+ *
+ * Locates the end of 'first', and links an additional VP 'add' at the end.
+ *
+ * @param[in] first VP in linked list. Will add new VP to the end of this list.
+ * @param[in] add VP to add to list.
+ */
+void fr_pair_add(VALUE_PAIR **first, VALUE_PAIR *add)
+{
+ VALUE_PAIR *i;
+
+ if (!add) return;
+
+ VERIFY_VP(add);
+
+ if (*first == NULL) {
+ *first = add;
+ return;
+ }
+
+ for (i = *first; i->next; i = i->next) {
+#ifdef WITH_VERIFY_PTR
+ VERIFY_VP(i);
+ /*
+ * The same VP should never by added multiple times
+ * to the same list.
+ */
+ fr_assert(i != add);
+#endif
+ }
+
+ i->next = add;
+}
+
+/** Add a VP to the start of the list.
+ *
+ * Links the new VP to 'first', then points 'first' at the new VP.
+ *
+ * @param[in] first VP in linked list. Will add new VP to the start of this list.
+ * @param[in] add VP to add to list.
+ */
+void fr_pair_prepend(VALUE_PAIR **first, VALUE_PAIR *add)
+{
+ VALUE_PAIR *i;
+
+ if (!add) return;
+
+ VERIFY_VP(add);
+
+ if (*first == NULL) {
+ *first = add;
+ return;
+ }
+
+ /*
+ * Find the end of the list to be prepended
+ */
+ for (i = add; i->next; i = i->next) {
+#ifdef WITH_VERIFY_PTR
+ VERIFY_VP(i);
+ /*
+ * The same VP should never by added multiple times
+ * to the same list.
+ */
+ fr_assert(*first != i);
+#endif
+ }
+ i->next = *first;
+ *first = add;
+}
+
+/** Replace all matching VPs
+ *
+ * Walks over 'first', and replaces the first VP that matches 'replace'.
+ *
+ * @note Memory used by the VP being replaced will be freed.
+ * @note Will not work with unknown attributes.
+ *
+ * @param[in,out] first VP in linked list. Will search and replace in this list.
+ * @param[in] replace VP to replace.
+ */
+void fr_pair_replace(VALUE_PAIR **first, VALUE_PAIR *replace)
+{
+ VALUE_PAIR *i, *next;
+ VALUE_PAIR **prev = first;
+
+ VERIFY_VP(replace);
+
+ if (*first == NULL) {
+ *first = replace;
+ return;
+ }
+
+ /*
+ * Not an empty list, so find item if it is there, and
+ * replace it. Note, we always replace the first one, and
+ * we ignore any others that might exist.
+ */
+ for(i = *first; i; i = next) {
+ VERIFY_VP(i);
+ next = i->next;
+
+ /*
+ * Found the first attribute, replace it,
+ * and return.
+ */
+ if ((i->da == replace->da) && (!i->da->flags.has_tag || TAG_EQ(replace->tag, i->tag))) {
+ *prev = replace;
+
+ /*
+ * Should really assert that replace->next == NULL
+ */
+ replace->next = next;
+ talloc_free(i);
+ return;
+ }
+
+ /*
+ * Point to where the attribute should go.
+ */
+ prev = &i->next;
+ }
+
+ /*
+ * If we got here, we didn't find anything to replace, so
+ * stopped at the last item, which we just append to.
+ */
+ *prev = replace;
+}
+
+int8_t fr_pair_cmp_by_da_tag(void const *a, void const *b)
+{
+ VALUE_PAIR const *my_a = a;
+ VALUE_PAIR const *my_b = b;
+
+ VERIFY_VP(my_a);
+ VERIFY_VP(my_b);
+
+ uint8_t cmp;
+
+ cmp = fr_pointer_cmp(my_a->da, my_b->da);
+ if (cmp != 0) return cmp;
+
+ if (my_a->tag < my_b->tag) return -1;
+
+ if (my_a->tag > my_b->tag) return 1;
+
+ return 0;
+}
+
+static void fr_pair_list_sort_split(VALUE_PAIR *source, VALUE_PAIR **front, VALUE_PAIR **back)
+{
+ VALUE_PAIR *fast;
+ VALUE_PAIR *slow;
+
+ /*
+ * Stopping condition - no more elements left to split
+ */
+ if (!source || !source->next) {
+ *front = source;
+ *back = NULL;
+
+ return;
+ }
+
+ /*
+ * Fast advances twice as fast as slow, so when it gets to the end,
+ * slow will point to the middle of the linked list.
+ */
+ slow = source;
+ fast = source->next;
+
+ while (fast) {
+ fast = fast->next;
+ if (fast) {
+ slow = slow->next;
+ fast = fast->next;
+ }
+ }
+
+ *front = source;
+ *back = slow->next;
+ slow->next = NULL;
+}
+
+static VALUE_PAIR *fr_pair_list_sort_merge(VALUE_PAIR *a, VALUE_PAIR *b, fr_cmp_t cmp)
+{
+ VALUE_PAIR *result = NULL;
+
+ if (!a) return b;
+ if (!b) return a;
+
+ /*
+ * Compare the DICT_ATTRs and tags
+ */
+ if (cmp(a, b) <= 0) {
+ result = a;
+ result->next = fr_pair_list_sort_merge(a->next, b, cmp);
+ } else {
+ result = b;
+ result->next = fr_pair_list_sort_merge(a, b->next, cmp);
+ }
+
+ return result;
+}
+
+/** Sort a linked list of VALUE_PAIRs using merge sort
+ *
+ * @param[in,out] vps List of VALUE_PAIRs to sort.
+ * @param[in] cmp to sort with
+ */
+void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp)
+{
+ VALUE_PAIR *head = *vps;
+ VALUE_PAIR *a;
+ VALUE_PAIR *b;
+
+ /*
+ * If there's 0-1 elements it must already be sorted.
+ */
+ if (!head || !head->next) {
+ return;
+ }
+
+ fr_pair_list_sort_split(head, &a, &b); /* Split into sublists */
+ fr_pair_list_sort(&a, cmp); /* Traverse left */
+ fr_pair_list_sort(&b, cmp); /* Traverse right */
+
+ /*
+ * merge the two sorted lists together
+ */
+ *vps = fr_pair_list_sort_merge(a, b, cmp);
+}
+
+/** Write an error to the library errorbuff detailing the mismatch
+ *
+ * Retrieve output with fr_strerror();
+ *
+ * @todo add thread specific talloc contexts.
+ *
+ * @param ctx a hack until we have thread specific talloc contexts.
+ * @param failed pair of attributes which didn't match.
+ */
+void fr_pair_validate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
+{
+ VALUE_PAIR const *filter = failed[0];
+ VALUE_PAIR const *list = failed[1];
+
+ char *value, *str;
+
+ (void) fr_strerror(); /* Clear any existing messages */
+
+ if (!fr_assert(!(!filter && !list))) return;
+
+ if (!list) {
+ if (!filter) return;
+ fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
+ return;
+ }
+
+ if (!filter || (filter->da != list->da)) {
+ fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
+ return;
+ }
+
+ if (!TAG_EQ(filter->tag, list->tag)) {
+ fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
+ list->da->name, list->tag, filter->tag);
+ return;
+ }
+
+
+ value = vp_aprints_value(ctx, list, '"');
+ str = vp_aprints(ctx, filter, '"');
+
+ fr_strerror_printf("Attribute value \"%s\" didn't match filter: %s", value, str);
+
+ talloc_free(str);
+ talloc_free(value);
+
+ return;
+}
+
+/** Uses fr_pair_cmp to verify all VALUE_PAIRs in list match the filter defined by check
+ *
+ * @note will sort both filter and list in place.
+ *
+ * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
+ * May be NULL.
+ * @param filter attributes to check list against.
+ * @param list attributes, probably a request or reply
+ */
+bool fr_pair_validate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
+{
+ vp_cursor_t filter_cursor;
+ vp_cursor_t list_cursor;
+
+ VALUE_PAIR *check, *match;
+
+ if (!filter && !list) {
+ return true;
+ }
+
+ /*
+ * This allows us to verify the sets of validate and reply are equal
+ * i.e. we have a validate rule which matches every reply attribute.
+ *
+ * @todo this should be removed one we have sets and lists
+ */
+ fr_pair_list_sort(&filter, fr_pair_cmp_by_da_tag);
+ fr_pair_list_sort(&list, fr_pair_cmp_by_da_tag);
+
+ check = fr_cursor_init(&filter_cursor, &filter);
+ match = fr_cursor_init(&list_cursor, &list);
+ while (match || check) {
+ /*
+ * Lists are of different lengths
+ */
+ if (!match || !check) goto mismatch;
+
+ /*
+ * The lists are sorted, so if the first
+ * attributes aren't of the same type, then we're
+ * done.
+ */
+ if (!ATTRIBUTE_EQ(check, match)) goto mismatch;
+
+ /*
+ * They're of the same type, but don't have the
+ * same values. This is a problem.
+ *
+ * Note that the RFCs say that for attributes of
+ * the same type, order is important.
+ */
+ if (fr_pair_cmp(check, match) != 1) goto mismatch;
+
+ check = fr_cursor_next(&filter_cursor);
+ match = fr_cursor_next(&list_cursor);
+ }
+
+ return true;
+
+mismatch:
+ if (failed) {
+ failed[0] = check;
+ failed[1] = match;
+ }
+ return false;
+}
+
+/** Uses fr_pair_cmp to verify all VALUE_PAIRs in list match the filter defined by check
+ *
+ * @note will sort both filter and list in place.
+ *
+ * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
+ * May be NULL.
+ * @param filter attributes to check list against.
+ * @param list attributes, probably a request or reply
+ */
+bool fr_pair_validate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
+{
+ vp_cursor_t filter_cursor;
+ vp_cursor_t list_cursor;
+
+ VALUE_PAIR *check, *last_check = NULL, *match = NULL;
+
+ if (!filter && !list) {
+ return true;
+ }
+
+ /*
+ * This allows us to verify the sets of validate and reply are equal
+ * i.e. we have a validate rule which matches every reply attribute.
+ *
+ * @todo this should be removed one we have sets and lists
+ */
+ fr_pair_list_sort(&filter, fr_pair_cmp_by_da_tag);
+ fr_pair_list_sort(&list, fr_pair_cmp_by_da_tag);
+
+ fr_cursor_init(&list_cursor, &list);
+ for (check = fr_cursor_init(&filter_cursor, &filter);
+ check;
+ check = fr_cursor_next(&filter_cursor)) {
+ /*
+ * Were processing check attributes of a new type.
+ */
+ if (!ATTRIBUTE_EQ(last_check, check)) {
+ /*
+ * Record the start of the matching attributes in the pair list
+ * For every other operator we require the match to be present
+ */
+ match = fr_cursor_next_by_da(&list_cursor, check->da, check->tag);
+ if (!match) {
+ if (check->op == T_OP_CMP_FALSE) continue;
+ goto mismatch;
+ }
+
+ fr_cursor_init(&list_cursor, &match);
+ last_check = check;
+ }
+
+ /*
+ * Now iterate over all attributes of the same type.
+ */
+ for (match = fr_cursor_first(&list_cursor);
+ ATTRIBUTE_EQ(match, check);
+ match = fr_cursor_next(&list_cursor)) {
+ /*
+ * This attribute passed the filter
+ */
+ if (!fr_pair_cmp(check, match)) goto mismatch;
+ }
+ }
+
+ return true;
+
+mismatch:
+ if (failed) {
+ failed[0] = check;
+ failed[1] = match;
+ }
+ return false;
+}
+
+/** Copy a single valuepair
+ *
+ * Allocate a new valuepair and copy the da from the old vp.
+ *
+ * @param[in] ctx for talloc
+ * @param[in] vp to copy.
+ * @return a copy of the input VP or NULL on error.
+ */
+VALUE_PAIR *fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
+{
+ VALUE_PAIR *n;
+
+ if (!vp) return NULL;
+
+ VERIFY_VP(vp);
+
+ n = fr_pair_afrom_da(ctx, vp->da);
+ if (!n) return NULL;
+
+ memcpy(n, vp, sizeof(*n));
+
+ /*
+ * If the DA is unknown, steal "n" to "ctx". This does
+ * nothing for "n", but will also copy the unknown "da".
+ */
+ if (n->da->flags.is_unknown) {
+ fr_pair_steal(ctx, n);
+ }
+
+ n->next = NULL;
+
+ /*
+ * If it's an xlat, copy the raw string and return early,
+ * so we don't pre-expand or otherwise mangle the VALUE_PAIR.
+ */
+ if (vp->type == VT_XLAT) {
+ n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
+ return n;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ n->vp_octets = NULL; /* else fr_pair_value_memcpy will free vp's value */
+ fr_pair_value_memcpy(n, vp->vp_octets, n->vp_length);
+ break;
+
+ case PW_TYPE_STRING:
+ n->vp_strvalue = NULL; /* else pairstrnpy will free vp's value */
+ fr_pair_value_bstrncpy(n, vp->vp_strvalue, n->vp_length);
+ break;
+
+ default:
+ break;
+ }
+
+ return n;
+}
+
+/** Copy a pairlist.
+ *
+ * Copy all pairs from 'from' regardless of tag, attribute or vendor.
+ *
+ * @param[in] ctx for new VALUE_PAIRs to be allocated in.
+ * @param[in] from whence to copy VALUE_PAIRs.
+ * @return the head of the new VALUE_PAIR list or NULL on error.
+ */
+VALUE_PAIR *fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
+{
+ vp_cursor_t src, dst;
+
+ VALUE_PAIR *out = NULL, *vp;
+
+ fr_cursor_init(&dst, &out);
+ for (vp = fr_cursor_init(&src, &from);
+ vp;
+ vp = fr_cursor_next(&src)) {
+ VERIFY_VP(vp);
+ vp = fr_pair_copy(ctx, vp);
+ if (!vp) {
+ fr_pair_list_free(&out);
+ return NULL;
+ }
+ fr_cursor_insert(&dst, vp); /* fr_pair_list_copy sets next pointer to NULL */
+ }
+
+ return out;
+}
+
+/** Copy matching pairs
+ *
+ * Copy pairs of a matching attribute number, vendor number and tag from the
+ * the input list to a new list, and returns the head of this list.
+ *
+ * @param[in] ctx for talloc
+ * @param[in] from whence to copy VALUE_PAIRs.
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ * will match (and therefore copy) only VSAs.
+ * If attribute 0 and vendor 0 will match (and therefore copy) all
+ * attributes.
+ * @param[in] vendor to match.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
+ * @return the head of the new VALUE_PAIR list or NULL on error.
+ */
+VALUE_PAIR *fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from,
+ unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ vp_cursor_t src, dst;
+
+ VALUE_PAIR *out = NULL, *vp;
+
+ fr_cursor_init(&dst, &out);
+ for (vp = fr_cursor_init(&src, &from);
+ vp;
+ vp = fr_cursor_next(&src)) {
+ VERIFY_VP(vp);
+
+ if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) {
+ continue;
+ }
+
+ /*
+ * Attr/vendor of 0 means "move them all".
+ * It's better than "fr_pair_copy(foo,bar);bar=NULL"
+ */
+ if ((attr == 0) && (vendor == 0)) {
+ goto do_copy;
+ }
+
+ /*
+ * vendor=0, attr = PW_VENDOR_SPECIFIC means
+ * "match any vendor attribute".
+ */
+ if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
+ /*
+ * It's a VSA: copy it over.
+ */
+ if (vp->da->vendor != 0) goto do_copy;
+
+ /*
+ * It's Vendor-Specific: copy it over.
+ */
+ if (vp->da->attr == attr) goto do_copy;
+
+ /*
+ * It's not a VSA: ignore it.
+ */
+ continue;
+ }
+
+ if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
+ continue;
+ }
+
+ do_copy:
+ vp = fr_pair_copy(ctx, vp);
+ if (!vp) {
+ fr_pair_list_free(&out);
+ return NULL;
+ }
+ fr_cursor_insert(&dst, vp);
+ }
+
+ return out;
+}
+
+/** Steal one VP
+ *
+ * @param[in] ctx to move VALUE_PAIR into
+ * @param[in] vp VALUE_PAIR to move into the new context.
+ */
+void fr_pair_steal(TALLOC_CTX *ctx, VALUE_PAIR *vp)
+{
+ (void) talloc_steal(ctx, vp);
+
+ /*
+ * The DA may be unknown. If we're stealing the VPs to a
+ * different context, copy the unknown DA. We use the VP
+ * as a context here instead of "ctx", so that when the
+ * VP is freed, so is the DA.
+ *
+ * Since we have no introspection into OTHER VPs using
+ * the same DA, we can't have multiple VPs use the same
+ * DA. So we might as well tie it to this VP.
+ */
+ if (vp->da->flags.is_unknown) {
+ DICT_ATTR *da;
+ char *p;
+ size_t size;
+
+ size = talloc_get_size(vp->da);
+
+ p = talloc_zero_array(vp, char, size);
+ da = (DICT_ATTR *) p;
+ talloc_set_type(p, DICT_ATTR);
+ memcpy(da, vp->da, size);
+ vp->da = da;
+ }
+}
+
+/** Move pairs from source list to destination list respecting operator
+ *
+ * @note This function does some additional magic that's probably not needed
+ * in most places. Consider using radius_pairmove in server code.
+ *
+ * @note fr_pair_list_free should be called on the head of the source list to free
+ * unmoved attributes (if they're no longer needed).
+ *
+ * @note Does not respect tags when matching.
+ *
+ * @param[in] ctx for talloc
+ * @param[in,out] to destination list.
+ * @param[in,out] from source list.
+ * @param[in] op operator for move.
+ *
+ * @see radius_pairmove
+ */
+void fr_pair_list_move(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, FR_TOKEN op)
+{
+ VALUE_PAIR *i, *found;
+ VALUE_PAIR *head_new, **tail_new;
+ VALUE_PAIR *head_prepend;
+ VALUE_PAIR **tail_from;
+
+ if (!to || !from || !*from) return;
+
+ /*
+ * We're editing the "to" list while we're adding new
+ * attributes to it. We don't want the new attributes to
+ * be edited, so we create an intermediate list to hold
+ * them during the editing process.
+ */
+ head_new = NULL;
+ tail_new = &head_new;
+
+ /*
+ * Any attributes that are requested to be prepended
+ * are added to a temporary list here
+ */
+ head_prepend = NULL;
+
+ /*
+ * We're looping over the "from" list, moving some
+ * attributes out, but leaving others in place.
+ */
+ tail_from = from;
+ while ((i = *tail_from) != NULL) {
+ VALUE_PAIR *j;
+
+ VERIFY_VP(i);
+
+ /*
+ * We never move Fall-Through.
+ */
+ if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
+ tail_from = &(i->next);
+ continue;
+ }
+
+ /*
+ * Unlike previous versions, we treat all other
+ * attributes as normal. i.e. there's no special
+ * treatment for passwords or Hint.
+ */
+
+ switch (i->op) {
+ /*
+ * Anything else are operators which
+ * shouldn't occur. We ignore them, and
+ * leave them in place.
+ */
+ default:
+ tail_from = &(i->next);
+ continue;
+
+ /*
+ * Add it to the "to" list, but only if
+ * it doesn't already exist.
+ */
+ case T_OP_EQ:
+ found = fr_pair_find_by_da(*to, i->da, TAG_ANY);
+ if (!found) goto do_add;
+
+ tail_from = &(i->next);
+ continue;
+
+ /*
+ * Add it to the "to" list, and delete any attribute
+ * of the same vendor/attr which already exists.
+ */
+ case T_OP_SET:
+ found = fr_pair_find_by_da(*to, i->da, TAG_ANY);
+ if (!found) goto do_add;
+
+ /*
+ * Do NOT call fr_pair_delete_by_num() here,
+ * due to issues with re-writing
+ * "request->username".
+ *
+ * Everybody calls fr_pair_move, and
+ * expects it to work. We can't
+ * update request->username here,
+ * so instead we over-write the
+ * vp that it's pointing to.
+ */
+ switch (found->da->type) {
+ default:
+ j = found->next;
+ memcpy(found, i, sizeof(*found));
+ found->next = j;
+ break;
+
+ case PW_TYPE_OCTETS:
+ fr_pair_value_memsteal(found, i->vp_octets);
+ i->vp_octets = NULL;
+ break;
+
+ case PW_TYPE_STRING:
+ fr_pair_value_strsteal(found, i->vp_strvalue);
+ i->vp_strvalue = NULL;
+ found->tag = i->tag;
+ break;
+ }
+
+ /*
+ * Delete *all* of the attributes
+ * of the same number.
+ */
+ fr_pair_delete_by_num(&found->next,
+ found->da->attr,
+ found->da->vendor, TAG_ANY);
+
+ /*
+ * Remove this attribute from the
+ * "from" list.
+ */
+ *tail_from = i->next;
+ i->next = NULL;
+ fr_pair_list_free(&i);
+ continue;
+
+ /*
+ * Move it from the old list and add it
+ * to the new list.
+ */
+ case T_OP_ADD:
+ do_add:
+ *tail_from = i->next;
+ i->next = NULL;
+ *tail_new = i;
+ fr_pair_steal(ctx, i);
+ tail_new = &(i->next);
+ continue;
+ case T_OP_PREPEND:
+ i->next = head_prepend;
+ head_prepend = i;
+ fr_pair_steal(ctx, i);
+ continue;
+ }
+ } /* loop over the "from" list. */
+
+ /*
+ * If the op parameter was prepend, add the "new" list
+ * attributes first as those whose individual operator
+ * is prepend should be prepended to the resulting list
+ */
+ if (op == T_OP_PREPEND) {
+ fr_pair_prepend(to, head_new);
+ }
+
+ /*
+ * If there are any items in the prepend list prepend
+ * it to the "to" list
+ */
+ fr_pair_prepend(to, head_prepend);
+
+ /*
+ * If the op parameter was not prepend, take the "new"
+ * list, and append it to the "to" list.
+ */
+ if (op != T_OP_PREPEND) {
+ fr_pair_add(to, head_new);
+ }
+}
+
+/** Move matching pairs between VALUE_PAIR lists
+ *
+ * Move pairs of a matching attribute number, vendor number and tag from the
+ * the input list to the output list.
+ *
+ * @note fr_pair_list_free should be called on the head of the old list to free unmoved
+ attributes (if they're no longer needed).
+ *
+ * @param[in] ctx for talloc
+ * @param[in,out] to destination list.
+ * @param[in,out] from source list.
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ * will match (and therefore copy) only VSAs.
+ * If attribute 0 and vendor 0 will match (and therefore copy) all
+ * attributes.
+ * @param[in] vendor to match.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
+ * @param[in] move if set to "true", VPs are moved. If set to "false", VPs are copied, and the old one deleted.
+ */
+static void fr_pair_list_move_by_num_internal(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
+ unsigned int attr, unsigned int vendor, int8_t tag,
+ bool move)
+{
+ VALUE_PAIR *to_tail, *i, *next, *this;
+ VALUE_PAIR *iprev = NULL;
+
+ /*
+ * Find the last pair in the "to" list and put it in "to_tail".
+ *
+ * @todo: replace the "if" with "VALUE_PAIR **tail"
+ */
+ if (*to != NULL) {
+ to_tail = *to;
+ for(i = *to; i; i = i->next) {
+ VERIFY_VP(i);
+ to_tail = i;
+ }
+ } else
+ to_tail = NULL;
+
+ /*
+ * Attr/vendor of 0 means "move them all".
+ * It's better than "fr_pair_add(foo,bar);bar=NULL"
+ */
+ if ((vendor == 0) && (attr == 0)) {
+ if (*to) {
+ to_tail->next = *from;
+ } else {
+ *to = *from;
+ }
+
+ for (i = *from; i; i = i->next) {
+ fr_pair_steal(ctx, i);
+ }
+
+ *from = NULL;
+ return;
+ }
+
+ for(i = *from; i; i = next) {
+ VERIFY_VP(i);
+ next = i->next;
+
+ if (i->da->flags.has_tag && !TAG_EQ(tag, i->tag)) {
+ iprev = i;
+ continue;
+ }
+
+ /*
+ * vendor=0, attr = PW_VENDOR_SPECIFIC means
+ * "match any vendor attribute".
+ */
+ if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
+ /*
+ * It's a VSA: move it over.
+ */
+ if (i->da->vendor != 0) goto move;
+
+ /*
+ * It's Vendor-Specific: move it over.
+ */
+ if (i->da->attr == attr) goto move;
+
+ /*
+ * It's not a VSA: ignore it.
+ */
+ iprev = i;
+ continue;
+ }
+
+ /*
+ * If it isn't an exact match, ignore it.
+ */
+ if (!((i->da->vendor == vendor) && (i->da->attr == attr))) {
+ iprev = i;
+ continue;
+ }
+
+ move:
+ /*
+ * Remove the attribute from the "from" list.
+ */
+ if (iprev)
+ iprev->next = next;
+ else
+ *from = next;
+
+ if (move) {
+ this = i;
+ } else {
+ this = fr_pair_copy(ctx, i);
+ }
+
+ /*
+ * Add the attribute to the "to" list.
+ */
+ if (to_tail)
+ to_tail->next = this;
+ else
+ *to = this;
+ to_tail = this;
+ this->next = NULL;
+
+ if (move) {
+ fr_pair_steal(ctx, i);
+ } else {
+ talloc_free(i);
+ }
+ }
+}
+
+
+/** Move matching pairs between VALUE_PAIR lists
+ *
+ * Move pairs of a matching attribute number, vendor number and tag from the
+ * the input list to the output list.
+ *
+ * @note pairs which are moved have their parent changed to ctx.
+ *
+ * @note fr_pair_list_free should be called on the head of the old list to free unmoved
+ attributes (if they're no longer needed).
+ *
+ * @param[in] ctx for talloc
+ * @param[in,out] to destination list.
+ * @param[in,out] from source list.
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ * will match (and therefore copy) only VSAs.
+ * If attribute 0 and vendor 0 will match (and therefore copy) all
+ * attributes.
+ * @param[in] vendor to match.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
+ */
+void fr_pair_list_move_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
+ unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ fr_pair_list_move_by_num_internal(ctx, to, from, attr, vendor, tag, true);
+}
+
+
+/** Copy / delete matching pairs between VALUE_PAIR lists
+ *
+ * Move pairs of a matching attribute number, vendor number and tag from the
+ * the input list to the output list. Like fr_pair_list_move_by_num(), but
+ * instead does copy / delete.
+ *
+ * @note The pair is NOT reparented. It is copied and deleted.
+ *
+ * @note fr_pair_list_free should be called on the head of the old list to free unmoved
+ attributes (if they're no longer needed).
+ *
+ * @param[in] ctx for talloc
+ * @param[in,out] to destination list.
+ * @param[in,out] from source list.
+ * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
+ * will match (and therefore copy) only VSAs.
+ * If attribute 0 and vendor 0 will match (and therefore copy) all
+ * attributes.
+ * @param[in] vendor to match.
+ * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
+ */
+void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
+ unsigned int attr, unsigned int vendor, int8_t tag)
+{
+ fr_pair_list_move_by_num_internal(ctx, to, from, attr, vendor, tag, false);
+}
+
+
+/** Convert string value to native attribute value
+ *
+ * @param vp to assign value to.
+ * @param value string to convert. Binary safe for variable length values if len is provided.
+ * @param inlen may be < 0 in which case strlen(len) is used to determine length, else inline
+ * should be the length of the string or sub string to parse.
+ * @return 0 on success -1 on error.
+ */
+int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t inlen)
+{
+ ssize_t ret;
+ PW_TYPE type;
+ VERIFY_VP(vp);
+
+ if (!value) return -1;
+
+ type = vp->da->type;
+
+ /*
+ * We presume that the input data is from a double quoted
+ * string, and needs escaping
+ */
+ ret = value_data_from_str(vp, &vp->data, &type, vp->da, value, inlen, '"');
+ if (ret < 0) return -1;
+
+ /*
+ * If we parsed to a different type than the DA associated with
+ * the VALUE_PAIR we now need to fixup the DA.
+ */
+ if (type != vp->da->type) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbytype(vp->da->attr, vp->da->vendor, type);
+ if (!da) {
+ fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
+ fr_int2str(dict_attr_types, type, "<INVALID>"), vp->da->name);
+ return -1;
+ }
+ vp->da = da;
+ }
+
+ vp->vp_length = ret;
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
+
+ return 0;
+}
+
+/** Use simple heuristics to create an VALUE_PAIR from an unknown address string
+ *
+ * If a DICT_ATTR is not provided for the address type, parsing will fail with
+ * and error.
+ *
+ * @param ctx to allocate VP in.
+ * @param value IPv4/IPv6 address/prefix string.
+ * @param ipv4 dictionary attribute to use for an IPv4 address.
+ * @param ipv6 dictionary attribute to use for an IPv6 address.
+ * @param ipv4_prefix dictionary attribute to use for an IPv4 prefix.
+ * @param ipv6_prefix dictionary attribute to use for an IPv6 prefix.
+ * @return NULL on error, or new VALUE_PAIR.
+ */
+VALUE_PAIR *fr_pair_afrom_ip_str(TALLOC_CTX *ctx, char const *value, DICT_ATTR *ipv4, DICT_ATTR *ipv6,
+ DICT_ATTR *ipv4_prefix, DICT_ATTR *ipv6_prefix)
+{
+ VALUE_PAIR *vp;
+ DICT_ATTR *da = NULL;
+
+ if (!fr_assert(ipv4 || ipv6 || ipv4_prefix || ipv6_prefix)) {
+ return NULL;
+ }
+
+ /* No point in repeating the work of fr_pair_value_from_str */
+ if (strchr(value, ':')) {
+ if (strchr(value, '/')) {
+ da = ipv6_prefix;
+ goto finish;
+ }
+
+ da = ipv6;
+ goto finish;
+ }
+
+ if (strchr(value, '/')) {
+ da = ipv4_prefix;
+ goto finish;
+ }
+
+ if (ipv4) {
+ da = ipv4;
+ goto finish;
+ }
+
+ fr_strerror_printf("Invalid IP value specified, allowed types are %s%s%s%s",
+ ipv4 ? "ipaddr " : "", ipv6 ? "ipv6addr " : "",
+ ipv4_prefix ? "ipv4prefix " : "", ipv6_prefix ? "ipv6prefix" : "");
+
+finish:
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return NULL;
+ if (fr_pair_value_from_str(vp, value, -1) < 0) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ return vp;
+}
+
+
+/** Create a valuepair from an ASCII attribute and value
+ *
+ * Where the attribute name is in the form:
+ * - Attr-%d
+ * - Attr-%d.%d.%d...
+ * - Vendor-%d-Attr-%d
+ * - VendorName-Attr-%d
+ *
+ * @param ctx for talloc
+ * @param attribute name to parse.
+ * @param value to parse (must be a hex string).
+ * @param op to assign to new valuepair.
+ * @return new valuepair or NULL on error.
+ */
+static VALUE_PAIR *fr_pair_make_unknown(TALLOC_CTX *ctx,
+ char const *attribute, char const *value,
+ FR_TOKEN op)
+{
+ VALUE_PAIR *vp, *vp2;
+ DICT_ATTR const *da;
+
+ uint8_t *data;
+ size_t size;
+ ssize_t len;
+
+ vp = fr_pair_alloc(ctx);
+ if (!vp) return NULL;
+
+ vp->da = dict_unknown_afrom_str(vp, attribute);
+ if (!vp->da) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ /*
+ * No value. Nothing more to do.
+ */
+ if (!value) return vp;
+
+ /*
+ * Unknown attributes MUST be of type 'octets'
+ */
+ if (strncasecmp(value, "0x", 2) != 0) {
+ fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
+ "string, not \"%s\"", attribute, value);
+ talloc_free(vp);
+ return NULL;
+ }
+
+ /*
+ * Convert the hex data to binary.
+ */
+ size = strlen(value + 2);
+
+ vp->vp_length = size >> 1;
+ vp->vp_octets = data = talloc_array(vp, uint8_t, vp->vp_length);
+ vp->type = VT_DATA;
+ vp->op = (op == 0) ? T_OP_EQ : op;
+
+ if (fr_hex2bin(data, vp->vp_length, value + 2, size) != vp->vp_length) {
+ fr_strerror_printf("Invalid hex string");
+ talloc_free(vp);
+ return NULL;
+ }
+
+ /*
+ * It's still unknown, return it as-is.
+ */
+ da = dict_attrbyvalue(vp->da->attr, vp->da->vendor);
+ if (!da) return vp;
+
+ /*
+ * It MIGHT be known. See if we can decode the raw data
+ * into a valid attribute.
+ */
+ len = data2vp(ctx, NULL, NULL, NULL, da,
+ vp->vp_octets, vp->vp_length, vp->vp_length,
+ &vp2);
+ if (len <= 0) return vp;
+
+ /*
+ * It's still unknown. Return the original VP.
+ */
+ if (vp2->da->flags.is_unknown) {
+ fr_pair_list_free(&vp2);
+ return vp;
+ }
+
+ /*
+ * Didn't parse all of it. Return the "unknown" one.
+ *
+ * FIXME: it COULD have parsed 2 attributes and
+ * then not the third, so returning 2 "knowns"
+ * and 1 "unknown" is likely preferable.
+ */
+ if ((size_t) len < vp->vp_length) {
+ fr_pair_list_free(&vp2);
+ return vp;
+ }
+
+ fr_pair_list_free(&vp);
+ return vp2;
+}
+
+
+/** Create a VALUE_PAIR from ASCII strings
+ *
+ * Converts an attribute string identifier (with an optional tag qualifier)
+ * and value string into a VALUE_PAIR.
+ *
+ * The string value is parsed according to the type of VALUE_PAIR being created.
+ *
+ * @param[in] ctx for talloc
+ * @param[in] vps list where the attribute will be added (optional)
+ * @param[in] attribute name.
+ * @param[in] value attribute value (may be NULL if value will be set later).
+ * @param[in] op to assign to new VALUE_PAIR.
+ * @return a new VALUE_PAIR.
+ */
+VALUE_PAIR *fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps,
+ char const *attribute, char const *value, FR_TOKEN op)
+{
+ DICT_ATTR const *da;
+ VALUE_PAIR *vp;
+ char *tc, *ts;
+ int8_t tag;
+ bool found_tag;
+ char buffer[256];
+ char const *attrname = attribute;
+
+ /*
+ * Check for tags in 'Attribute:Tag' format.
+ */
+ found_tag = false;
+ tag = TAG_ANY;
+
+ ts = strrchr(attribute, ':');
+ if (ts && !ts[1]) {
+ fr_strerror_printf("Invalid tag for attribute %s", attribute);
+ return NULL;
+ }
+
+ if (ts && ts[1]) {
+ strlcpy(buffer, attribute, sizeof(buffer));
+ attrname = buffer;
+ ts = strrchr(attrname, ':');
+ if (!ts) return NULL;
+
+ /* Colon found with something behind it */
+ if (ts[1] == '*' && ts[2] == 0) {
+ /* Wildcard tag for check items */
+ tag = TAG_ANY;
+ *ts = '\0';
+ } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
+ /* It's not a wild card tag */
+ tag = strtol(ts + 1, &tc, 0);
+ if (tc && !*tc && TAG_VALID_ZERO(tag))
+ *ts = '\0';
+ else tag = TAG_ANY;
+ } else {
+ fr_strerror_printf("Invalid tag for attribute %s", attribute);
+ return NULL;
+ }
+ found_tag = true;
+ }
+
+ /*
+ * It's not found in the dictionary, so we use
+ * another method to create the attribute.
+ */
+ da = dict_attrbyname(attrname);
+ if (!da) {
+ vp = fr_pair_make_unknown(ctx, attrname, value, op);
+ if (vp && vps) fr_pair_add(vps, vp);
+ return vp;
+ }
+
+ /* Check for a tag in the 'Merit' format of:
+ * :Tag:Value. Print an error if we already found
+ * a tag in the Attribute.
+ */
+
+ if (value && (*value == ':' && da->flags.has_tag)) {
+ /* If we already found a tag, this is invalid */
+ if(found_tag) {
+ fr_strerror_printf("Duplicate tag %s for attribute %s",
+ value, da->name);
+ DEBUG("Duplicate tag %s for attribute %s\n",
+ value, da->name);
+ return NULL;
+ }
+ /* Colon found and attribute allows a tag */
+ if (value[1] == '*' && value[2] == ':') {
+ /* Wildcard tag for check items */
+ tag = TAG_ANY;
+ value += 3;
+ } else {
+ /* Real tag */
+ tag = strtol(value + 1, &tc, 0);
+ if (tc && *tc==':' && TAG_VALID_ZERO(tag))
+ value = tc + 1;
+ else tag = 0;
+ }
+ }
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return NULL;
+ vp->op = (op == 0) ? T_OP_EQ : op;
+ vp->tag = tag;
+
+ switch (vp->op) {
+ case T_OP_CMP_TRUE:
+ case T_OP_CMP_FALSE:
+ vp->vp_strvalue = NULL;
+ vp->vp_length = 0;
+ value = NULL; /* ignore it! */
+ break;
+
+ /*
+ * Regular expression comparison of integer attributes
+ * does a STRING comparison of the names of their
+ * integer attributes.
+ */
+ case T_OP_REG_EQ: /* =~ */
+ case T_OP_REG_NE: /* !~ */
+ {
+#ifndef HAVE_REGEX
+ fr_strerror_printf("Regular expressions are not supported");
+ return NULL;
+#else
+ ssize_t slen;
+ regex_t *preg;
+
+ /*
+ * Someone else will fill in the value.
+ */
+ if (!value) break;
+
+ talloc_free(vp);
+
+ slen = regex_compile(ctx, &preg, value, strlen(value), false, false, false, true);
+ if (slen <= 0) {
+ fr_strerror_printf("Error at offset %zu compiling regex for %s: %s", -slen,
+ attribute, fr_strerror());
+ return NULL;
+ }
+ talloc_free(preg);
+
+ vp = fr_pair_make(ctx, NULL, attribute, NULL, op);
+ if (!vp) return NULL;
+
+ if (fr_pair_mark_xlat(vp, value) < 0) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ value = NULL; /* ignore it */
+ break;
+#endif
+ }
+ default:
+ break;
+ }
+
+ /*
+ * We allow this for stupidity, but it's really a bad idea.
+ */
+ if (vp->da->type == PW_TYPE_TLV) {
+ ssize_t len;
+ DICT_ATTR const *unknown;
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR **tail = &head;
+
+ if (!value) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ unknown = dict_unknown_afrom_fields(vp, vp->da->attr, vp->da->vendor);
+ if (!unknown) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ vp->da = unknown;
+
+ /*
+ * Parse it as an unknown type, i.e. octets.
+ */
+ if (fr_pair_value_from_str(vp, value, -1) < 0) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+ /*
+ * It's badly formatted. Treat it as unknown.
+ */
+ if (rad_tlv_ok(vp->vp_octets, vp->vp_length, 1, 1) < 0) {
+ goto do_add;
+ }
+
+ /*
+ * Decode the TLVs
+ */
+ len = rad_data2vp_tlvs(ctx, NULL, NULL, NULL, da, vp->vp_octets,
+ vp->vp_length, tail);
+ if (len < 0) {
+ goto do_add;
+ }
+
+ talloc_free(vp);
+ vp = head;
+ goto do_add;
+ }
+
+ /*
+ * FIXME: if (strcasecmp(attribute, vp->da->name) != 0)
+ * then the user MAY have typed in the attribute name
+ * as Vendor-%d-Attr-%d, and the value MAY be octets.
+ *
+ * We probably want to fix fr_pair_value_from_str to accept
+ * octets as values for any attribute.
+ */
+ if (value && (fr_pair_value_from_str(vp, value, -1) < 0)) {
+ talloc_free(vp);
+ return NULL;
+ }
+
+do_add:
+ if (vps) fr_pair_add(vps, vp);
+ return vp;
+}
+
+/** Mark a valuepair for xlat expansion
+ *
+ * Copies xlat source (unprocessed) string to valuepair value,
+ * and sets value type.
+ *
+ * @param vp to mark for expansion.
+ * @param value to expand.
+ * @return 0 if marking succeeded or -1 if vp already had a value, or OOM.
+ */
+int fr_pair_mark_xlat(VALUE_PAIR *vp, char const *value)
+{
+ char *raw;
+
+ /*
+ * valuepair should not already have a value.
+ */
+ if (vp->type != VT_NONE) {
+ fr_strerror_printf("Pair already has a value");
+ return -1;
+ }
+
+ raw = talloc_typed_strdup(vp, value);
+ if (!raw) {
+ fr_strerror_printf("Out of memory");
+ return -1;
+ }
+
+ vp->type = VT_XLAT;
+ vp->value.xlat = raw;
+ vp->vp_length = 0;
+
+ return 0;
+}
+
+
+/** Read a single valuepair from a buffer, and advance the pointer
+ *
+ * Returns T_EOL if end of line was encountered.
+ *
+ * @param[in,out] ptr to read from and update.
+ * @param[out] raw The struct to write the raw VALUE_PAIR to.
+ * @return the last token read.
+ */
+FR_TOKEN fr_pair_raw_from_str(char const **ptr, VALUE_PAIR_RAW *raw)
+{
+ char const *p;
+ char *q;
+ FR_TOKEN ret = T_INVALID, next, quote;
+ char buf[8];
+
+ if (!ptr || !*ptr || !raw) {
+ fr_strerror_printf("Invalid arguments");
+ return T_INVALID;
+ }
+
+ /*
+ * Skip leading spaces
+ */
+ p = *ptr;
+ while ((*p == ' ') || (*p == '\t')) p++;
+
+ if (!*p) {
+ fr_strerror_printf("No token read where we expected "
+ "an attribute name");
+ return T_INVALID;
+ }
+
+ if (*p == '#') return T_HASH;
+
+ /*
+ * Try to get the attribute name.
+ */
+ q = raw->l_opand;
+ *q = '\0';
+ while (*p) {
+ uint8_t const *t = (uint8_t const *) p;
+
+ if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
+ too_long:
+ fr_strerror_printf("Attribute name too long");
+ return T_INVALID;
+ }
+
+ /*
+ * This is arguably easier than trying to figure
+ * out which operators come after the attribute
+ * name. Yes, our "lexer" is bad.
+ */
+ if (!dict_attr_allowed_chars[(unsigned int) *t]) {
+ break;
+ }
+
+ /*
+ * Attribute:=value is NOT
+ *
+ * Attribute:
+ * =
+ * value
+ */
+ if ((*p == ':') && (!isdigit((uint8_t) p[1]))) {
+ break;
+ }
+
+ *(q++) = *(p++);
+ }
+
+ /*
+ * Haven't found any valid characters in the name.
+ */
+ if (!*raw->l_opand) {
+ fr_strerror_printf("Invalid attribute name");
+ return T_INVALID;
+ }
+
+ /*
+ * Look for tag (:#). This is different from :=, which
+ * is an operator.
+ */
+ if ((*p == ':') && (isdigit((uint8_t) p[1]))) {
+ if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
+ goto too_long;
+ }
+ *(q++) = *(p++);
+
+ while (isdigit((uint8_t) *p)) {
+ if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
+ goto too_long;
+ }
+ *(q++) = *(p++);
+ }
+ }
+
+ *q = '\0';
+ *ptr = p;
+
+ /* Now we should have an operator here. */
+ raw->op = gettoken(ptr, buf, sizeof(buf), false);
+ if (raw->op < T_EQSTART || raw->op > T_EQEND) {
+ fr_strerror_printf("Expecting operator");
+
+ return T_INVALID;
+ }
+
+ /*
+ * Read value. Note that empty string values are allowed
+ */
+ quote = gettoken(ptr, raw->r_opand, sizeof(raw->r_opand), false);
+ if (quote == T_EOL) {
+ fr_strerror_printf("Failed to get value");
+
+ return T_INVALID;
+ }
+
+ /*
+ * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
+ */
+ p = *ptr;
+
+ next = gettoken(&p, buf, sizeof(buf), false);
+ switch (next) {
+ case T_HASH:
+ next = T_EOL;
+ break;
+
+ case T_EOL:
+ break;
+
+ case T_COMMA:
+ *ptr = p;
+ break;
+
+ default:
+ fr_strerror_printf("Expected end of line or comma");
+ return T_INVALID;
+ }
+ ret = next;
+
+ switch (quote) {
+ /*
+ * Perhaps do xlat's
+ */
+ case T_DOUBLE_QUOTED_STRING:
+ /*
+ * Only report as double quoted if it contained valid
+ * a valid xlat expansion.
+ */
+ p = strchr(raw->r_opand, '%');
+ if (p && (p[1] == '{')) {
+ raw->quote = quote;
+ } else {
+ raw->quote = T_SINGLE_QUOTED_STRING;
+ }
+
+ break;
+
+ case T_SINGLE_QUOTED_STRING:
+ case T_BACK_QUOTED_STRING:
+ case T_BARE_WORD:
+ raw->quote = quote;
+ break;
+
+ default:
+ fr_strerror_printf("Failed to find expected value on right hand side in %s", raw->l_opand);
+ return T_INVALID;
+ }
+
+ return ret;
+}
+
+/** Read one line of attribute/value pairs into a list.
+ *
+ * The line may specify multiple attributes separated by commas.
+ *
+ * @note If the function returns T_INVALID, an error has occurred and
+ * @note the valuepair list should probably be freed.
+ *
+ * @param ctx for talloc
+ * @param buffer to read valuepairs from.
+ * @param list where the parsed VALUE_PAIRs will be appended.
+ * @return the last token parsed, or T_INVALID
+ */
+FR_TOKEN fr_pair_list_afrom_str(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **list)
+{
+ VALUE_PAIR *vp, *head, **tail;
+ char const *p;
+ FR_TOKEN last_token = T_INVALID;
+ VALUE_PAIR_RAW raw;
+
+ /*
+ * We allow an empty line.
+ */
+ if (buffer[0] == 0) {
+ return T_EOL;
+ }
+
+ head = NULL;
+ tail = &head;
+
+ p = buffer;
+ do {
+ raw.l_opand[0] = '\0';
+ raw.r_opand[0] = '\0';
+
+ last_token = fr_pair_raw_from_str(&p, &raw);
+
+ /*
+ * JUST a hash. Don't try to create a VP.
+ * Let the caller determine if an empty list is OK.
+ */
+ if (last_token == T_HASH) {
+ last_token = T_EOL;
+ break;
+ }
+ if (last_token == T_INVALID) break;
+
+ if (raw.quote == T_DOUBLE_QUOTED_STRING) {
+ vp = fr_pair_make(ctx, NULL, raw.l_opand, NULL, raw.op);
+ if (!vp) {
+ last_token = T_INVALID;
+ break;
+ }
+ if (fr_pair_mark_xlat(vp, raw.r_opand) < 0) {
+ talloc_free(vp);
+ last_token = T_INVALID;
+ break;
+ }
+ } else {
+ vp = fr_pair_make(ctx, NULL, raw.l_opand, raw.r_opand, raw.op);
+ if (!vp) {
+ last_token = T_INVALID;
+ break;
+ }
+ }
+
+ *tail = vp;
+ tail = &((*tail)->next);
+ } while (*p && (last_token == T_COMMA));
+
+ if (last_token == T_INVALID) {
+ fr_pair_list_free(&head);
+ } else {
+ fr_pair_add(list, head);
+ }
+
+ /*
+ * And return the last token which we read.
+ */
+ return last_token;
+}
+
+/*
+ * Read valuepairs from the fp up to End-Of-File.
+ */
+int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone)
+{
+ char buf[8192];
+ FR_TOKEN last_token = T_EOL;
+
+ vp_cursor_t cursor;
+
+ VALUE_PAIR *vp = NULL;
+ fr_cursor_init(&cursor, out);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /*
+ * If we get a '\n' by itself, we assume that's
+ * the end of that VP
+ */
+ if (buf[0] == '\n') {
+ if (vp) {
+ *pfiledone = false;
+ return 0;
+ }
+ continue;
+ }
+
+ /*
+ * Comments get ignored
+ */
+ if (buf[0] == '#') continue;
+
+ /*
+ * Read all of the attributes on the current line.
+ */
+ vp = NULL;
+ last_token = fr_pair_list_afrom_str(ctx, buf, &vp);
+ if (!vp) {
+ if (last_token != T_EOL) goto error;
+ break;
+ }
+
+ fr_cursor_merge(&cursor, vp);
+ buf[0] = '\0';
+ }
+ *pfiledone = true;
+
+ return 0;
+
+error:
+ *pfiledone = false;
+ vp = fr_cursor_first(&cursor);
+ if (vp) fr_pair_list_free(&vp);
+
+ return -1;
+}
+
+/** Compare two pairs, using the operator from "a"
+ *
+ * i.e. given two attributes, it does:
+ *
+ * (b->data) (a->operator) (a->data)
+ *
+ * e.g. "foo" != "bar"
+ *
+ * @param[in] a the first attribute
+ * @param[in] b the second attribute
+ * @return 1 if true, 0 if false, -1 on error.
+ */
+int fr_pair_cmp(VALUE_PAIR *a, VALUE_PAIR *b)
+{
+ if (!a) return -1;
+
+ VERIFY_VP(a);
+ if (b) VERIFY_VP(b);
+
+ switch (a->op) {
+ case T_OP_CMP_TRUE:
+ return (b != NULL);
+
+ case T_OP_CMP_FALSE:
+ return (b == NULL);
+
+ /*
+ * a is a regex, compile it, print b to a string,
+ * and then do string comparisons.
+ */
+ case T_OP_REG_EQ:
+ case T_OP_REG_NE:
+#ifndef HAVE_REGEX
+ return -1;
+#else
+ if (!b) return false;
+
+ {
+ ssize_t slen;
+ regex_t *preg;
+ char *value;
+
+ if (!fr_assert(a->da->type == PW_TYPE_STRING)) return -1;
+
+ slen = regex_compile(NULL, &preg, a->value.xlat, talloc_array_length(a->value.xlat) - 1, false, false, false, true);
+ if (slen <= 0) {
+ fr_strerror_printf("Error at offset %zu compiling regex for %s: %s",
+ -slen, a->da->name, fr_strerror());
+ return -1;
+ }
+ value = vp_aprints_value(NULL, b, '\0');
+ if (!value) {
+ talloc_free(preg);
+ return -1;
+ }
+
+ /*
+ * Don't care about substring matches, oh well...
+ */
+ slen = regex_exec(preg, value, talloc_array_length(value) - 1, NULL, NULL);
+ talloc_free(preg);
+ talloc_free(value);
+
+ if (slen < 0) return -1;
+ if (a->op == T_OP_REG_EQ) return (int)slen;
+ return !slen;
+ }
+#endif
+
+ default: /* we're OK */
+ if (!b) return false;
+ break;
+ }
+
+ return fr_pair_cmp_op(a->op, b, a);
+}
+
+/** Determine equality of two lists
+ *
+ * This is useful for comparing lists of attributes inserted into a binary tree.
+ *
+ * @param a first list of VALUE_PAIRs.
+ * @param b second list of VALUE_PAIRs.
+ * @return -1 if a < b, 0 if the two lists are equal, 1 if a > b, -2 on error.
+ */
+int fr_pair_list_cmp(VALUE_PAIR *a, VALUE_PAIR *b)
+{
+ vp_cursor_t a_cursor, b_cursor;
+ VALUE_PAIR *a_p, *b_p;
+ int ret;
+
+ for (a_p = fr_cursor_init(&a_cursor, &a), b_p = fr_cursor_init(&b_cursor, &b);
+ a_p && b_p;
+ a_p = fr_cursor_next(&a_cursor), b_p = fr_cursor_next(&b_cursor)) {
+ /* Same VP, no point doing expensive checks */
+ if (a_p == b_p) {
+ continue;
+ }
+
+ if (a_p->da < b_p->da) {
+ return -1;
+ }
+ if (a_p->da > b_p->da) {
+ return 1;
+ }
+
+ if (a_p->tag < b_p->tag) {
+ return -1;
+ }
+ if (a_p->tag > b_p->tag) {
+ return 1;
+ }
+
+ ret = value_data_cmp(a_p->da->type, &a_p->data, a_p->vp_length,
+ b_p->da->type, &b_p->data, b_p->vp_length);
+ if (ret != 0) {
+ fr_assert(ret >= -1); /* Comparison error */
+ return ret;
+ }
+ }
+
+ if (!a_p && !b_p) {
+ return 0;
+ }
+
+ if (!a_p) {
+ return -1;
+ }
+
+ /* if(!b_p) */
+ return 1;
+}
+
+/** Set the type of the VALUE_PAIR value buffer to match it's DICT_ATTR
+ *
+ * @param vp to fixup.
+ */
+static void fr_pair_value_set_type(VALUE_PAIR *vp)
+{
+ if (!vp->data.ptr) return;
+
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ talloc_set_type(vp->data.ptr, uint8_t);
+ return;
+
+ case PW_TYPE_STRING:
+ talloc_set_type(vp->data.ptr, char);
+ return;
+
+ default:
+ return;
+ }
+}
+
+/** Copy data into an "octets" data type.
+ *
+ * @param[in,out] vp to update
+ * @param[in] src data to copy
+ * @param[in] size of the data, may be 0 in which case previous value will be freed.
+ */
+void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t size)
+{
+ uint8_t *p = NULL, *q;
+
+ VERIFY_VP(vp);
+
+ if (size > 0) {
+ p = talloc_memdup(vp, src, size);
+ if (!p) return;
+ talloc_set_type(p, uint8_t);
+ }
+
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ TALLOC_FREE(q);
+
+ vp->vp_octets = p;
+ vp->vp_length = size;
+
+ if (size > 0) fr_pair_value_set_type(vp);
+}
+
+/** Reparent an allocated octet buffer to a VALUE_PAIR
+ *
+ * @param[in,out] vp to update
+ * @param[in] src buffer to steal.
+ */
+void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
+{
+ uint8_t *q;
+
+ VERIFY_VP(vp);
+
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, src);
+ vp->type = VT_DATA;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue);
+ fr_pair_value_set_type(vp);
+}
+
+/** Reparent an allocated char buffer to a VALUE_PAIR
+ *
+ * @param[in,out] vp to update
+ * @param[in] src buffer to steal.
+ */
+void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
+{
+ uint8_t *q;
+
+ VERIFY_VP(vp);
+
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_strvalue = talloc_steal(vp, src);
+ vp->type = VT_DATA;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ fr_pair_value_set_type(vp);
+}
+
+/** Copy data into an "string" data type.
+ *
+ * @param[in,out] vp to update
+ * @param[in] src data to copy
+ */
+void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
+{
+ char *p, *q;
+
+ VERIFY_VP(vp);
+
+ p = talloc_strdup(vp, src);
+
+ if (!p) return;
+
+ memcpy(&q, &vp->vp_strvalue, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_strvalue = p;
+ vp->type = VT_DATA;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ fr_pair_value_set_type(vp);
+}
+
+/** Copy data into an "string" data type.
+ *
+ * @note unlike the original strncpy, this function does not stop
+ * if it finds \0 bytes embedded in the string.
+ *
+ * @param[in,out] vp to update.
+ * @param[in] src data to copy.
+ * @param[in] len of data to copy.
+ */
+void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
+{
+ char *p, *q;
+
+ VERIFY_VP(vp);
+
+ if (!src) return;
+
+ p = talloc_array(vp, char, len + 1);
+ if (!p) return;
+
+ memcpy(p, src, len); /* embdedded \0 safe */
+ p[len] = '\0';
+
+ memcpy(&q, &vp->vp_strvalue, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_strvalue = p;
+ vp->type = VT_DATA;
+ vp->vp_length = len;
+ fr_pair_value_set_type(vp);
+}
+
+/** Print data into an "string" data type.
+ *
+ * @param[in,out] vp to update
+ * @param[in] fmt the format string
+ */
+void fr_pair_value_sprintf(VALUE_PAIR *vp, char const *fmt, ...)
+{
+ va_list ap;
+ char *p, *q;
+
+ VERIFY_VP(vp);
+
+ va_start(ap, fmt);
+ p = talloc_vasprintf(vp, fmt, ap);
+ va_end(ap);
+
+ if (!p) return;
+
+ memcpy(&q, &vp->vp_strvalue, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_strvalue = p;
+ vp->type = VT_DATA;
+
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ fr_pair_value_set_type(vp);
+}
+
+#ifdef WITH_VERIFY_PTR
+/*
+ * Verify a VALUE_PAIR
+ */
+inline void fr_pair_verify(char const *file, int line, VALUE_PAIR const *vp)
+{
+ if (!vp) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR pointer was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ (void) talloc_get_type_abort(vp, VALUE_PAIR);
+
+ if (!vp->da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR da pointer was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vp->data.ptr) switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ {
+ size_t len;
+ TALLOC_CTX *parent;
+
+ if (!talloc_get_type(vp->data.ptr, uint8_t)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
+ "uint8_t but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
+ (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
+ }
+
+ len = talloc_array_length(vp->vp_octets);
+ if (vp->vp_length > len) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
+ "uint8_t data buffer length %zu\n", file, line, vp->da->name, vp->vp_length, len);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ parent = talloc_parent(vp->data.ptr);
+ if (parent != vp) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
+ "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
+ file, line, vp->da->name,
+ vp, parent, parent ? talloc_get_name(parent) : "NULL");
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+ break;
+
+ case PW_TYPE_STRING:
+ {
+ size_t len;
+ TALLOC_CTX *parent;
+
+ if (!talloc_get_type(vp->data.ptr, char)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
+ "char but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
+ (void) talloc_get_type_abort(vp->data.ptr, char);
+ }
+
+ len = (talloc_array_length(vp->vp_strvalue) - 1);
+ if (vp->vp_length > len) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
+ "char buffer length %zu\n", file, line, vp->da->name, vp->vp_length, len);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vp->vp_strvalue[vp->vp_length] != '\0') {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer not \\0 "
+ "terminated\n", file, line, vp->da->name);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ parent = talloc_parent(vp->data.ptr);
+ if (parent != vp) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
+ "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
+ file, line, vp->da->name,
+ vp, parent, parent ? talloc_get_name(parent) : "NULL");
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (vp->da->flags.is_unknown) {
+ (void) talloc_get_type_abort(vp->da, DICT_ATTR);
+ } else {
+ DICT_ATTR const *da;
+
+ /*
+ * Attribute may be present with multiple names
+ */
+ da = dict_attrbyname(vp->da->name);
+ if (!da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR attribute %p \"%s\" (%s) "
+ "not found in global dictionary",
+ file, line, vp->da, vp->da->name,
+ fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (da->type == PW_TYPE_COMBO_IP_ADDR) {
+ da = dict_attrbytype(vp->da->attr, vp->da->vendor, vp->da->type);
+ if (!da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR attribute %p \"%s\" "
+ "variant (%s) not found in global dictionary",
+ file, line, vp->da, vp->da->name,
+ fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+
+
+ if (da != vp->da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR "
+ "dictionary pointer %p \"%s\" (%s) "
+ "and global dictionary pointer %p \"%s\" (%s) differ",
+ file, line, vp->da, vp->da->name,
+ fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"),
+ da, da->name, fr_int2str(dict_attr_types, da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+}
+
+/*
+ * Verify a pair list
+ */
+void fr_pair_list_verify(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps, char const *name)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ TALLOC_CTX *parent;
+
+ for (vp = fr_cursor_init(&cursor, &vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VERIFY_VP(vp);
+
+ parent = talloc_parent(vp);
+ if (expected && (parent != expected)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Expected VALUE_PAIR \"%s\" to be parented "
+ "by %p (%s) name %s, instead parented by %p (%s)\n",
+ file, line, vp->da->name,
+ expected, talloc_get_name(expected), name,
+ parent, parent ? talloc_get_name(parent) : "NULL");
+
+ fr_log_talloc_report(expected);
+ if (parent) fr_log_talloc_report(parent);
+
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ }
+}
+#endif
diff --git a/src/lib/pcap.c b/src/lib/pcap.c
new file mode 100644
index 0000000..987a8ea
--- /dev/null
+++ b/src/lib/pcap.c
@@ -0,0 +1,474 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file pcap.c
+ * @brief Wrappers around libpcap functions
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#ifdef HAVE_LIBPCAP
+
+#include <sys/ioctl.h>
+#include <freeradius-devel/pcap.h>
+
+const FR_NAME_NUMBER pcap_types[] = {
+ { "interface", PCAP_INTERFACE_IN },
+ { "file", PCAP_FILE_IN },
+ { "stdio", PCAP_STDIO_IN },
+ { "interface", PCAP_INTERFACE_OUT },
+ { "file", PCAP_FILE_OUT },
+ { "stdio", PCAP_STDIO_OUT },
+
+ { NULL, 0}
+};
+
+/** Talloc destructor to free pcap resources associated with a handle.
+ *
+ * @param pcap to free.
+ * @return 0
+ */
+static int _free_pcap(fr_pcap_t *pcap) {
+ switch (pcap->type) {
+ case PCAP_INTERFACE_IN:
+ case PCAP_INTERFACE_OUT:
+ case PCAP_FILE_IN:
+ case PCAP_STDIO_IN:
+ if (pcap->handle) {
+ pcap_close(pcap->handle);
+
+ if (pcap->fd > 0) {
+ close(pcap->fd);
+ }
+ }
+
+ break;
+
+ case PCAP_FILE_OUT:
+ case PCAP_STDIO_OUT:
+ if (pcap->dumper) {
+ pcap_dump_flush(pcap->dumper);
+ pcap_dump_close(pcap->dumper);
+ }
+
+ break;
+ case PCAP_INVALID:
+ break;
+ }
+
+ return 0;
+}
+
+/** Get data link from pcap_if_t
+ *
+ * libpcap requires an open pcap handle to get data_link type
+ * unfortunately when we're trying to find useful interfaces
+ * this is too late.
+ *
+ * @param errbuff Error message.
+ * @param dev to get link layer for.
+ * @return datalink layer or -1 on failure.
+ */
+int fr_pcap_if_link_layer(char *errbuff, pcap_if_t *dev)
+{
+ pcap_t *pcap;
+ int data_link;
+
+ pcap = pcap_open_live(dev->name, 0, 0, 0, errbuff);
+ if (!pcap) return -1;
+
+ data_link = pcap_datalink(pcap);
+ pcap_close(pcap);
+
+ return data_link;
+}
+
+/** Initialise a pcap handle abstraction
+ *
+ * @param ctx talloc TALLOC_CTX to allocate handle in.
+ * @param name of interface or file to open.
+ * @param type of handle to initialise.
+ * @return new handle or NULL on error.
+ */
+fr_pcap_t *fr_pcap_init(TALLOC_CTX *ctx, char const *name, fr_pcap_type_t type)
+{
+ fr_pcap_t *this = talloc_zero(ctx, fr_pcap_t);
+ if (!this) {
+ return NULL;
+ }
+
+ talloc_set_destructor(this, _free_pcap);
+ this->name = talloc_typed_strdup(this, name);
+ this->type = type;
+ this->link_layer = -1;
+
+ return this;
+}
+
+/** Open a PCAP handle abstraction
+ *
+ * This opens interfaces for capture or injection, or files/streams for reading/writing.
+ * @param pcap created with fr_pcap_init.
+ * @return 0 on success, -1 on error.
+ */
+int fr_pcap_open(fr_pcap_t *pcap)
+{
+ switch (pcap->type) {
+ case PCAP_INTERFACE_OUT:
+ case PCAP_INTERFACE_IN:
+ {
+#if defined(HAVE_PCAP_CREATE) && defined(HAVE_PCAP_ACTIVATE)
+ pcap->handle = pcap_create(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+ if (pcap_set_snaplen(pcap->handle, SNAPLEN) != 0) {
+ create_error:
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+ if (pcap_set_timeout(pcap->handle, PCAP_NONBLOCK_TIMEOUT) != 0) {
+ goto create_error;
+ }
+ if (pcap_set_promisc(pcap->handle, pcap->promiscuous) != 0) {
+ goto create_error;
+ }
+
+ if (pcap_set_buffer_size(pcap->handle, SNAPLEN *
+ (pcap->buffer_pkts ? pcap->buffer_pkts : PCAP_BUFFER_DEFAULT)) != 0) {
+ goto create_error;
+ }
+ if (pcap_activate(pcap->handle) != 0) {
+ goto create_error;
+ }
+#else
+ /*
+ * Alternative functions for libpcap < 1.0
+ */
+ pcap->handle = pcap_open_live(pcap->name, SNAPLEN, pcap->promiscuous, PCAP_NONBLOCK_TIMEOUT,
+ pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+ return -1;
+ }
+#endif
+ /*
+ * Despite accepting an errbuff, pcap_setnonblock doesn't seem to write
+ * error message there in newer versions.
+ */
+ if (pcap_setnonblock(pcap->handle, true, pcap->errbuf) != 0) {
+ fr_strerror_printf("%s", *pcap->errbuf != '\0' ?
+ pcap->errbuf : pcap_geterr(pcap->handle));
+ pcap_close(pcap->handle);
+ pcap->handle = NULL;
+ return -1;
+ }
+
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_layer = pcap_datalink(pcap->handle);
+#ifndef __linux__
+ {
+ int value = 1;
+ if (ioctl(pcap->fd, BIOCIMMEDIATE, &value) < 0) {
+ fr_strerror_printf("Failed setting BIOCIMMEDIATE: %s", fr_syserror(errno));
+ }
+ }
+#endif
+ }
+ break;
+
+ case PCAP_FILE_IN:
+ pcap->handle = pcap_open_offline(pcap->name, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_layer = pcap_datalink(pcap->handle);
+ break;
+
+ case PCAP_FILE_OUT:
+ if (pcap->link_layer < 0) {
+ pcap->link_layer = DLT_EN10MB;
+ }
+ pcap->handle = pcap_open_dead(pcap->link_layer, SNAPLEN);
+ if (!pcap->handle) {
+ fr_strerror_printf("Unknown error occurred opening dead PCAP handle");
+
+ return -1;
+ }
+ pcap->dumper = pcap_dump_open(pcap->handle, pcap->name);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+
+#ifdef HAVE_PCAP_FOPEN_OFFLINE
+ case PCAP_STDIO_IN:
+ pcap->handle = pcap_fopen_offline(stdin, pcap->errbuf);
+ if (!pcap->handle) {
+ fr_strerror_printf("%s", pcap->errbuf);
+
+ return -1;
+ }
+ pcap->fd = pcap_get_selectable_fd(pcap->handle);
+ pcap->link_layer = pcap_datalink(pcap->handle);
+ break;
+#else
+ case PCAP_STDIO_IN:
+ fr_strerror_printf("This version of libpcap does not support reading pcap data from streams");
+
+ return -1;
+#endif
+#ifdef HAVE_PCAP_DUMP_FOPEN
+ case PCAP_STDIO_OUT:
+ pcap->handle = pcap_open_dead(DLT_EN10MB, SNAPLEN);
+ pcap->dumper = pcap_dump_fopen(pcap->handle, stdout);
+ if (!pcap->dumper) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+ break;
+#else
+ case PCAP_STDIO_OUT:
+ fr_strerror_printf("This version of libpcap does not support writing pcap data to streams");
+
+ return -1;
+#endif
+ case PCAP_INVALID:
+ default:
+ fr_assert(0);
+ fr_strerror_printf("Bad handle type (%i)", pcap->type);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Apply capture filter to an interface
+ *
+ * @param pcap handle to apply filter to.
+ * @param expression PCAP expression to use as a filter.
+ * @return 0 on success, 1 can't apply to interface, -1 on error.
+ */
+int fr_pcap_apply_filter(fr_pcap_t *pcap, char const *expression)
+{
+ bpf_u_int32 mask = 0; /* Our netmask */
+ bpf_u_int32 net = 0; /* Our IP */
+ struct bpf_program fp;
+
+ /*
+ * nflog devices are in the set of devices selected by default.
+ * Unfortunately there's a bug in all released version of libpcap (as of 2/1/2014)
+ * which triggers an abort if pcap_setfilter is called on an nflog interface.
+ *
+ * See here:
+ * https://github.com/the-tcpdump-group/libpcap/commit/676cf8a61ed240d0a86d471ef419f45ba35dba80
+ */
+#ifdef DLT_NFLOG
+ if (pcap->link_layer == DLT_NFLOG) {
+ fr_strerror_printf("NFLOG link-layer type filtering not implemented");
+
+ return 1;
+ }
+#endif
+
+ if (pcap->type == PCAP_INTERFACE_IN) {
+ if (pcap_lookupnet(pcap->name, &net, &mask, pcap->errbuf) < 0) {
+ fr_strerror_printf("Failed getting IP for interface \"%s\", using defaults: %s",
+ pcap->name, pcap->errbuf);
+ }
+ }
+
+ if (pcap_compile(pcap->handle, &fp, expression, 0, net) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ if (pcap_setfilter(pcap->handle, &fp) < 0) {
+ fr_strerror_printf("%s", pcap_geterr(pcap->handle));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+char *fr_pcap_device_names(TALLOC_CTX *ctx, fr_pcap_t *pcap, char c)
+{
+ fr_pcap_t *pcap_p;
+ char *buff, *p;
+ size_t len = 0, left = 0, wrote;
+
+ if (!pcap) {
+ goto null;
+ }
+
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ len += talloc_array_length(pcap_p->name); // Talloc array length includes the \0
+ }
+
+ if (!len) {
+ null:
+ return talloc_zero_array(ctx, char, 1);
+ }
+
+ left = len + 1;
+ buff = p = talloc_zero_array(ctx, char, left);
+ for (pcap_p = pcap;
+ pcap_p;
+ pcap_p = pcap_p->next) {
+ wrote = snprintf(p, left, "%s%c", pcap_p->name, c);
+ left -= wrote;
+ p += wrote;
+ }
+ buff[len - 1] = '\0';
+
+ return buff;
+}
+
+/** Check whether fr_pcap_link_layer_offset can process a link_layer
+ *
+ * @param link_layer to check.
+ * @return true if supported, else false.
+ */
+bool fr_pcap_link_layer_supported(int link_layer)
+{
+ switch (link_layer) {
+ case DLT_EN10MB:
+ case DLT_RAW:
+ case DLT_NULL:
+ case DLT_LOOP:
+#ifdef DLT_LINUX_SLL
+ case DLT_LINUX_SLL:
+#endif
+ case DLT_PFLOG:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/** Returns the length of the link layer header
+ *
+ * Libpcap does not include a decoding function to skip the L2 header, but it does
+ * at least inform us of the type.
+ *
+ * Unfortunately some headers are of variable length (like ethernet), so additional
+ * decoding logic is required.
+ *
+ * @note No header data is returned, this is only meant to be used to determine how
+ * data to consume before attempting to parse the IP header.
+ *
+ * @param data start of packet data.
+ * @param len caplen.
+ * @param link_layer value returned from pcap_linktype.
+ * @return the length of the header, or -1 on error.
+ */
+ssize_t fr_pcap_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
+{
+ uint8_t const *p = data;
+
+ switch (link_layer) {
+ case DLT_RAW:
+ break;
+
+ case DLT_NULL:
+ case DLT_LOOP:
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ ood:
+ fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes",
+ (size_t)(p - data), len);
+ return -1;
+ }
+ break;
+
+ case DLT_EN10MB:
+ {
+ uint16_t ether_type; /* Ethernet type */
+ int i;
+
+ p += 12; /* SRC/DST Mac-Addresses */
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+
+ for (i = 0; i < 3; i++) {
+ ether_type = ntohs(*((uint16_t const *) p));
+ switch (ether_type) {
+ /*
+ * There are a number of devices out there which
+ * double tag with 0x8100 *sigh*
+ */
+ case 0x8100: /* CVLAN */
+ case 0x9100: /* SVLAN */
+ case 0x9200: /* SVLAN */
+ case 0x9300: /* SVLAN */
+ p += 4;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ p += 2;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ goto done;
+ }
+ }
+ fr_strerror_printf("Exceeded maximum level of VLAN tag nesting (2)");
+ return -1;
+ }
+
+#ifdef DLT_LINUX_SLL
+ case DLT_LINUX_SLL:
+ p += 16;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+#endif
+
+ case DLT_PFLOG:
+ p += 28;
+ if (((size_t)(p - data)) > len) {
+ goto ood;
+ }
+ break;
+
+ default:
+ fr_strerror_printf("Unsupported link layer type %i", link_layer);
+ }
+
+done:
+ return p - data;
+}
+#endif /* HAVE_LIBPCAP */
diff --git a/src/lib/print.c b/src/lib/print.c
new file mode 100644
index 0000000..57455b6
--- /dev/null
+++ b/src/lib/print.c
@@ -0,0 +1,790 @@
+/*
+ * print.c Routines to print stuff.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+
+/** Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8
+ *
+ * @param str input string.
+ * @param inlen length of input string. May be -1 if str is \0 terminated.
+ */
+int fr_utf8_char(uint8_t const *str, ssize_t inlen)
+{
+ if (inlen == 0) return 0;
+
+ if (inlen < 0) inlen = 4; /* longest char */
+
+ if (*str < 0x20) return 0;
+
+ if (*str <= 0x7e) return 1; /* 1 */
+
+ if (*str <= 0xc1) return 0;
+
+ if (inlen < 2) return 0;
+
+ if ((str[0] >= 0xc2) && /* 2 */
+ (str[0] <= 0xdf) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf)) {
+ return 2;
+ }
+
+ if (inlen < 3) return 0;
+
+ if ((str[0] == 0xe0) && /* 3 */
+ (str[1] >= 0xa0) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] >= 0xe1) && /* 4a */
+ (str[0] <= 0xec) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] >= 0xee) && /* 4b */
+ (str[0] <= 0xef) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] == 0xed) && /* 5 */
+ (str[1] >= 0x80) &&
+ (str[1] <= 0x9f) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if (inlen < 4) return 0;
+
+ if ((str[0] == 0xf0) && /* 6 */
+ (str[1] >= 0x90) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf) &&
+ (str[3] >= 0x80) &&
+ (str[3] <= 0xbf)) {
+ return 4;
+ }
+
+ if ((str[0] >= 0xf1) && /* 6 */
+ (str[0] <= 0xf3) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf) &&
+ (str[3] >= 0x80) &&
+ (str[3] <= 0xbf)) {
+ return 4;
+ }
+
+
+ if ((str[0] == 0xf4) && /* 7 */
+ (str[1] >= 0x80) &&
+ (str[1] <= 0x8f) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf) &&
+ (str[3] >= 0x80) &&
+ (str[3] <= 0xbf)) {
+ return 4;
+ }
+
+ /*
+ * Invalid UTF-8 Character
+ */
+ return 0;
+}
+
+/** Return a pointer to the first UTF8 char in a string.
+ *
+ * @param[out] chr_len Where to write the length of the multibyte char passed in chr (may be NULL).
+ * @param[in] str Haystack.
+ * @param[in] chr Multibyte needle.
+ * @return The position of chr in str or NULL if not found.
+ */
+char const *fr_utf8_strchr(int *chr_len, char const *str, char const *chr)
+{
+ int cchr;
+
+ cchr = fr_utf8_char((uint8_t const *)chr, -1);
+ if (cchr == 0) cchr = 1;
+ if (chr_len) *chr_len = cchr;
+
+ while (*str) {
+ int schr;
+
+ schr = fr_utf8_char((uint8_t const *) str, -1);
+ if (schr == 0) schr = 1;
+ if (schr != cchr) goto next;
+
+ if (memcmp(str, chr, schr) == 0) {
+ return (char const *) str;
+ }
+ next:
+ str += schr;
+ }
+
+ return NULL;
+}
+
+/** Escape any non printable or non-UTF8 characters in the input string
+ *
+ * @note Return value should be checked with is_truncated
+ * @note Will always \0 terminate unless outlen == 0.
+ *
+ * @param[in] in string to escape.
+ * @param[in] inlen length of string to escape (lets us deal with embedded NULs)
+ * @param[out] out where to write the escaped string.
+ * @param[out] outlen the length of the buffer pointed to by out.
+ * @param[in] quote the quotation character
+ * @return the number of bytes it WOULD HAVE written to the buffer, not including the trailing NUL
+ */
+size_t fr_prints(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
+{
+ uint8_t const *p = (uint8_t const *) in;
+ size_t utf8;
+ size_t used;
+ size_t freespace;
+
+ /* No input, so no output... */
+ if (!in) {
+ if (out && outlen) *out = '\0';
+ return 0;
+ }
+
+ /* Figure out the length of the input string */
+ if (inlen < 0) inlen = strlen(in);
+
+ /*
+ * No quotation character, just use memcpy, ensuring we
+ * don't overflow the output buffer.
+ */
+ if (!quote) {
+ if (!out) return inlen;
+
+ if ((size_t)inlen >= outlen) {
+ memcpy(out, in, outlen - 1);
+ out[outlen - 1] = '\0';
+ } else {
+ memcpy(out, in, inlen);
+ out[inlen] = '\0';
+ }
+
+ return inlen;
+ }
+
+ /*
+ * Check the output buffer and length. Zero both of them
+ * out if either are zero.
+ */
+ freespace = outlen;
+ if (freespace == 0) out = NULL;
+ if (!out) freespace = 0;
+
+ used = 0;
+
+ while (inlen > 0) {
+ int sp = 0;
+
+ /*
+ * Hack: never print trailing zero.
+ * Some clients send pings with an off-by-one
+ * length (confused with strings in C).
+ */
+ if ((inlen == 1) && (*p == '\0')) {
+ inlen--;
+ break;
+ }
+
+ /*
+ * Always escape the quotation character.
+ */
+ if (*p == quote) {
+ sp = quote;
+ goto do_escape;
+ }
+
+ /*
+ * Escape the backslash ONLY for single quoted strings.
+ */
+ if (quote == '\'') {
+ if (*p == '\\') {
+ sp = '\\';
+ }
+ goto do_escape;
+ }
+
+ /*
+ * Try to convert 0x0a --> \r, etc.
+ * Backslashes get handled specially.
+ */
+ switch (*p) {
+ case '\r':
+ sp = 'r';
+ break;
+
+ case '\n':
+ sp = 'n';
+ break;
+
+ case '\t':
+ sp = 't';
+ break;
+
+ case '\\':
+ sp = '\\';
+ break;
+
+ default:
+ sp = '\0';
+ break;
+ } /* escape the character at *p */
+
+ do_escape:
+ if (sp) {
+ if ((freespace > 0) && (freespace <= 2)) {
+ if (out) out[used] = '\0';
+ out = NULL;
+ freespace = 0;
+
+ } else if (freespace > 2) { /* room for char AND trailing zero */
+ if (out) {
+ out[used] = '\\';
+ out[used + 1] = sp;
+ }
+ freespace -= 2;
+ }
+
+ used += 2;
+ p++;
+ inlen--;
+ continue;
+ }
+
+ /*
+ * All strings are UTF-8 clean.
+ */
+ utf8 = fr_utf8_char(p, inlen);
+
+ /*
+ * If we have an invalid UTF-8 character, it gets
+ * copied over as a 1-byte character for single
+ * quoted strings. Which means that the output
+ * isn't strictly UTF-8, but oh well...
+ *
+ * For double quoted strints, the invalid
+ * characters get escaped as octal encodings.
+ */
+ if (utf8 == 0) {
+ if (quote == '\'') {
+ utf8 = 1;
+
+ } else {
+ if ((freespace > 0) && (freespace <= 4)) {
+ if (out) out[used] = '\0';
+ out = NULL;
+ freespace = 0;
+
+ } else if (freespace > 4) { /* room for char AND trailing zero */
+ if (out) snprintf(out + used, freespace, "\\%03o", *p);
+ freespace -= 4;
+ }
+
+ used += 4;
+ p++;
+ inlen--;
+ continue;
+ }
+ }
+
+ if ((freespace > 0) && (freespace <= utf8)) {
+ if (out) out[used] = '\0';
+ out = NULL;
+ freespace = 0;
+
+ } else if (freespace > utf8) { /* room for char AND trailing zero */
+ if (out) memcpy(out + used, p, utf8);
+ freespace -= utf8;
+ }
+
+ used += utf8;
+ p += utf8;
+ inlen -= utf8;
+ }
+
+ /*
+ * Ensure that the output buffer is always zero terminated.
+ */
+ if (out && freespace) out[used] = '\0';
+
+ return used;
+}
+
+/** Find the length of the buffer required to fully escape a string with fr_prints
+ *
+ * Were assuming here that's it's cheaper to figure out the length and do one
+ * alloc than repeatedly expand the buffer when we find extra chars which need
+ * to be added.
+ *
+ * @param in string to calculate the escaped length for.
+ * @param inlen length of the input string, if < 0 strlen will be used to check the length.
+ * @param[in] quote the quotation character.
+ * @return the size of buffer required to hold the escaped string including the NUL byte.
+ */
+size_t fr_prints_len(char const *in, ssize_t inlen, char quote)
+{
+ return fr_prints(NULL, 0, in, inlen, quote) + 1;
+}
+
+/** Escape string that may contain binary data, and write it to a new buffer
+ *
+ * This is useful in situations where we expect printable strings as input,
+ * but under some conditions may get binary data. A good example is libldap
+ * and the arrays of struct berval ldap_get_values_len returns.
+ *
+ * @param[in] ctx To allocate new buffer in.
+ * @param[in] in String to escape.
+ * @param[in] inlen Length of string. Should be >= 0 if the data may contain
+ * embedded \0s. Must be >= 0 if data may not be \0 terminated.
+ * If < 0 inlen will be calculated using strlen.
+ * @param[in] quote the quotation character.
+ * @return new buffer holding the escaped string.
+ */
+char *fr_aprints(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
+{
+ size_t len, ret;
+ char *out;
+
+ len = fr_prints_len(in, inlen, quote);
+
+ out = talloc_array(ctx, char, len);
+ ret = fr_prints(out, len, in, inlen, quote);
+
+ /*
+ * This is a fatal error, but fr_assert is the strongest
+ * assert we're allowed to use in library functions.
+ */
+ if (!fr_assert(ret == (len - 1))) {
+ talloc_free(out);
+ return NULL;
+ }
+
+ return out;
+}
+
+/** Print the value of an attribute to a string
+ *
+ * @param[out] out Where to write the string.
+ * @param[in] outlen Size of outlen (must be at least 3 bytes).
+ * @param[in] vp to print.
+ * @param[in] quote Char to add before and after printed value, if 0 no char will be added, if < 0 raw string will be
+ * added.
+ * @return the length of data written to out, or a value >= outlen on truncation.
+ */
+size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
+{
+ VERIFY_VP(vp);
+
+ if (vp->type == VT_XLAT) {
+ return snprintf(out, outlen, "%c%s%c", quote, vp->value.xlat, quote);
+ }
+
+ return value_data_prints(out, outlen, vp->da->type, vp->da, &vp->data, vp->vp_length, quote);
+}
+
+/** Print one attribute value to a string
+ *
+ * @param ctx to allocate string in.
+ * @param vp to print.
+ * @param[in] quote the quotation character
+ * @return a talloced buffer with the attribute operator and value.
+ */
+char *vp_aprints_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
+{
+ VERIFY_VP(vp);
+
+ if (vp->type == VT_XLAT) {
+ return fr_aprints(ctx, vp->value.xlat, talloc_array_length(vp->value.xlat) - 1, quote);
+ }
+
+ return value_data_aprints(ctx, vp->da->type, vp->da, &vp->data, vp->vp_length, quote);
+}
+
+char *vp_aprints_type(TALLOC_CTX *ctx, PW_TYPE type)
+{
+ switch (type) {
+ case PW_TYPE_STRING :
+ return talloc_typed_strdup(ctx, "_");
+
+ case PW_TYPE_INTEGER64:
+ case PW_TYPE_SIGNED:
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE :
+ return talloc_typed_strdup(ctx, "0");
+
+ case PW_TYPE_IPV4_ADDR :
+ return talloc_typed_strdup(ctx, "?.?.?.?");
+
+ case PW_TYPE_IPV4_PREFIX:
+ return talloc_typed_strdup(ctx, "?.?.?.?/?");
+
+ case PW_TYPE_IPV6_ADDR:
+ return talloc_typed_strdup(ctx, "[:?:]");
+
+ case PW_TYPE_IPV6_PREFIX:
+ return talloc_typed_strdup(ctx, "[:?:]/?");
+
+ case PW_TYPE_OCTETS:
+ return talloc_typed_strdup(ctx, "??");
+
+ case PW_TYPE_ETHERNET:
+ return talloc_typed_strdup(ctx, "??:??:??:??:??:??:??:??");
+
+#ifdef WITH_ASCEND_BINARY
+ case PW_TYPE_ABINARY:
+ return talloc_typed_strdup(ctx, "??");
+#endif
+
+ default :
+ break;
+ }
+
+ return talloc_typed_strdup(ctx, "<UNKNOWN-TYPE>");
+}
+
+/** Prints attribute enumv escaped suitably for use as JSON enumv
+ *
+ * Returns < 0 if the buffer may be (or have been) too small to write the encoded
+ * JSON value to.
+ *
+ * @param out Where to write the string.
+ * @param outlen Length of output buffer.
+ * @param vp to print.
+ * @param raw_value if true, the raw value is printed and not the enumerated attribute value
+ * @return the length of data written to out, or a value >= outlen on truncation.
+ */
+size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp, bool raw_value)
+{
+ char const *q;
+ size_t len, freespace = outlen;
+ /* attempt to print raw_value when has_value is false, or raw_value is false, but only
+ if has_tag is also false */
+ bool raw = (raw_value || !vp->da->flags.has_value) && !vp->da->flags.has_tag;
+
+ if (raw) {
+ switch (vp->da->type) {
+ case PW_TYPE_INTEGER:
+ return snprintf(out, freespace, "%u", vp->vp_integer);
+
+ case PW_TYPE_SHORT:
+ return snprintf(out, freespace, "%u", (unsigned int) vp->vp_short);
+
+ case PW_TYPE_BYTE:
+ return snprintf(out, freespace, "%u", (unsigned int) vp->vp_byte);
+
+ default:
+ break;
+ }
+ }
+
+ /* Indicate truncation */
+ if (freespace < 2) return outlen + 1;
+ *out++ = '"';
+ freespace--;
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->vp_length; q++) {
+ /* Indicate truncation */
+ if (freespace < 3) return outlen + 1;
+
+ if (*q == '"') {
+ *out++ = '\\';
+ *out++ = '"';
+ freespace -= 2;
+ } else if (*q == '\\') {
+ *out++ = '\\';
+ *out++ = '\\';
+ freespace -= 2;
+ } else if (*q == '/') {
+ *out++ = '\\';
+ *out++ = '/';
+ freespace -= 2;
+ } else if (*q >= ' ') {
+ *out++ = *q;
+ freespace--;
+ } else {
+ *out++ = '\\';
+ freespace--;
+
+ switch (*q) {
+ 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) *q);
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
+ out += len;
+ freespace -= len;
+ }
+ }
+ }
+ break;
+
+ default:
+ len = vp_prints_value(out, freespace, vp, 0);
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
+ out += len;
+ freespace -= len;
+ break;
+ }
+
+ /* Indicate truncation */
+ if (freespace < 2) return outlen + 1;
+ *out++ = '"';
+ freespace--;
+ *out = '\0'; // We don't increment out, because the nul byte should not be included in the length
+
+ return outlen - freespace;
+}
+
+/*
+ * This is a hack, and has to be kept in sync with tokens.h
+ */
+static char const *vp_tokens[] = {
+ "?", /* T_INVALID */
+ "EOL", /* T_EOL */
+ "{",
+ "}",
+ "(",
+ ")",
+ ",",
+ ";",
+ "++",
+ "+=",
+ "-=",
+ ":=",
+ "=",
+ "!=",
+ ">=",
+ ">",
+ "<=",
+ "<",
+ "=~",
+ "!~",
+ "=*",
+ "!*",
+ "==",
+ "#",
+ "<BARE-WORD>",
+ "<\"STRING\">",
+ "<'STRING'>",
+ "<`STRING`>"
+};
+
+/** Print one attribute and value to a string
+ *
+ * Print a VALUE_PAIR in the format:
+@verbatim
+ <attribute_name>[:tag] <op> <value>
+@endverbatim
+ * to a string.
+ *
+ * @param out Where to write the string.
+ * @param outlen Length of output buffer.
+ * @param vp to print.
+ * @return the length of data written to out, or a value >= outlen on truncation.
+ */
+size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp)
+{
+ char const *token = NULL;
+ size_t len, freespace = outlen;
+
+ if (!out) return 0;
+
+ *out = '\0';
+ if (!vp || !vp->da) return 0;
+
+ VERIFY_VP(vp);
+
+ if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) {
+ token = vp_tokens[vp->op];
+ } else {
+ token = "<INVALID-TOKEN>";
+ }
+
+ if (vp->da->flags.has_tag && (vp->tag != TAG_ANY)) {
+ len = snprintf(out, freespace, "%s:%d %s ", vp->da->name, vp->tag, token);
+ } else {
+ len = snprintf(out, freespace, "%s %s ", vp->da->name, token);
+ }
+
+ if (is_truncated(len, freespace)) return len;
+ out += len;
+ freespace -= len;
+
+ len = vp_prints_value(out, freespace, vp, '"');
+ if (is_truncated(len, freespace)) return (outlen - freespace) + len;
+ freespace -= len;
+
+ return (outlen - freespace);
+}
+
+/** Print one attribute and value to FP
+ *
+ * Complete string with '\\t' and '\\n' is written to buffer before printing to
+ * avoid issues when running with multiple threads.
+ *
+ * @param fp to output to.
+ * @param vp to print.
+ */
+void vp_print(FILE *fp, VALUE_PAIR const *vp)
+{
+ char buf[1024];
+ char *p = buf;
+ size_t len;
+
+ VERIFY_VP(vp);
+
+ *p++ = '\t';
+ len = vp_prints(p, sizeof(buf) - 1, vp);
+ if (!len) {
+ return;
+ }
+ p += len;
+
+ /*
+ * Deal with truncation gracefully
+ */
+ if (((size_t) (p - buf)) >= (sizeof(buf) - 2)) {
+ p = buf + (sizeof(buf) - 2);
+ }
+
+ *p++ = '\n';
+ *p = '\0';
+
+ fputs(buf, fp);
+}
+
+
+/** Print a list of attributes and enumv
+ *
+ * @param fp to output to.
+ * @param const_vp to print.
+ */
+void vp_printlist(FILE *fp, VALUE_PAIR const *const_vp)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ memcpy(&vp, &const_vp, sizeof(vp)); /* const work-arounds */
+
+ for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) {
+ vp_print(fp, vp);
+ }
+}
+
+/** Print one attribute and value to a string
+ *
+ * Print a VALUE_PAIR in the format:
+@verbatim
+ <attribute_name>[:tag] <op> <value>
+@endverbatim
+ * to a string.
+ *
+ * @param ctx to allocate string in.
+ * @param vp to print.
+ * @param[in] quote the quotation character
+ * @return a talloced buffer with the attribute operator and value.
+ */
+char *vp_aprints(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
+{
+ char const *token = NULL;
+ char *str, *value;
+
+ if (!vp || !vp->da) return 0;
+
+ VERIFY_VP(vp);
+
+ if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) {
+ token = vp_tokens[vp->op];
+ } else {
+ token = "<INVALID-TOKEN>";
+ }
+
+ value = vp_aprints_value(ctx, vp, quote);
+
+ if (vp->da->flags.has_tag && (vp->tag != TAG_ANY)) {
+ if (quote && (vp->da->type == PW_TYPE_STRING)) {
+ str = talloc_asprintf(ctx, "%s:%d %s %c%s%c", vp->da->name, vp->tag, token, quote, value, quote);
+ } else {
+ str = talloc_asprintf(ctx, "%s:%d %s %s", vp->da->name, vp->tag, token, value);
+ }
+ } else {
+ if (quote && (vp->da->type == PW_TYPE_STRING)) {
+ str = talloc_asprintf(ctx, "%s %s %c%s%c", vp->da->name, token, quote, value, quote);
+ } else {
+ str = talloc_asprintf(ctx, "%s %s %s", vp->da->name, token, value);
+ }
+ }
+
+ talloc_free(value);
+
+ return str;
+}
diff --git a/src/lib/radius.c b/src/lib/radius.c
new file mode 100644
index 0000000..b2de15b
--- /dev/null
+++ b/src/lib/radius.c
@@ -0,0 +1,5354 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file radius.c
+ * @brief Functions to send/receive radius packets.
+ *
+ * @copyright 2000-2003,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/rfc4849.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef WITH_UDPFROMTO
+#include <freeradius-devel/udpfromto.h>
+#endif
+
+/*
+ * Some messages get printed out only in debugging mode.
+ */
+#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
+
+#if 0
+#define VP_TRACE printf
+
+static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
+{
+ size_t i;
+
+ printf("--- %s ---\n", msg);
+ for (i = 0; i < len; i++) {
+ if ((i & 0x0f) == 0) printf("%04x: ", (unsigned int) i);
+ printf("%02x ", data[i]);
+ if ((i & 0x0f) == 0x0f) printf("\n");
+ }
+ if ((len == 0x0f) || ((len & 0x0f) != 0x0f)) printf("\n");
+ fflush(stdout);
+}
+
+#else
+#define VP_TRACE(_x, ...)
+#define VP_HEXDUMP(_x, _y, _z)
+#endif
+
+
+/*
+ * The maximum number of attributes which we allow in an incoming
+ * request. If there are more attributes than this, the request
+ * is rejected.
+ *
+ * This helps to minimize the potential for a DoS, when an
+ * attacker spoofs Access-Request packets, which don't have a
+ * Message-Authenticator attribute. This means that the packet
+ * is unsigned, and the attacker can use resources on the server,
+ * even if the end request is rejected.
+ */
+uint32_t fr_max_attributes = 0;
+FILE *fr_log_fp = NULL;
+
+typedef struct radius_packet_t {
+ uint8_t code;
+ uint8_t id;
+ uint8_t length[2];
+ uint8_t vector[AUTH_VECTOR_LEN];
+ uint8_t data[1];
+} radius_packet_t;
+
+static fr_randctx fr_rand_pool; /* across multiple calls */
+static int fr_rand_initialized = 0;
+#ifndef WITH_RADIUSV11_ONLY
+static unsigned int salt_offset = 0;
+static uint8_t nullvector[AUTH_VECTOR_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* for CoA decode */
+#endif
+
+char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
+ "", //!< 0
+ "Access-Request",
+ "Access-Accept",
+ "Access-Reject",
+ "Accounting-Request",
+ "Accounting-Response",
+ "Accounting-Status",
+ "Password-Request",
+ "Password-Accept",
+ "Password-Reject",
+ "Accounting-Message", //!< 10
+ "Access-Challenge",
+ "Status-Server",
+ "Status-Client",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "20", //!< 20
+ "Resource-Free-Request",
+ "Resource-Free-Response",
+ "Resource-Query-Request",
+ "Resource-Query-Response",
+ "Alternate-Resource-Reclaim-Request",
+ "NAS-Reboot-Request",
+ "NAS-Reboot-Response",
+ "28",
+ "Next-Passcode",
+ "New-Pin", //!< 30
+ "Terminate-Session",
+ "Password-Expired",
+ "Event-Request",
+ "Event-Response",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "Disconnect-Request", //!< 40
+ "Disconnect-ACK",
+ "Disconnect-NAK",
+ "CoA-Request",
+ "CoA-ACK",
+ "CoA-NAK",
+ "46",
+ "47",
+ "48",
+ "49",
+ "IP-Address-Allocate",
+ "IP-Address-Release", //!< 50
+};
+
+
+void fr_printf_log(char const *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if ((fr_debug_lvl == 0) || !fr_log_fp) {
+ va_end(ap);
+ return;
+ }
+
+ vfprintf(fr_log_fp, fmt, ap);
+ va_end(ap);
+
+ return;
+}
+
+static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+static void print_hex_data(uint8_t const *ptr, int attrlen, int depth)
+{
+ int i;
+
+ for (i = 0; i < attrlen; i++) {
+ if ((i > 0) && ((i & 0x0f) == 0x00))
+ fprintf(fr_log_fp, "%.*s", depth, tabs);
+ fprintf(fr_log_fp, "%02x ", ptr[i]);
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ if ((i & 0x0f) != 0) fprintf(fr_log_fp, "\n");
+}
+
+
+void rad_print_hex(RADIUS_PACKET const *packet)
+{
+ int i;
+
+ if (!packet->data || !fr_log_fp) return;
+
+ fprintf(fr_log_fp, " Socket:\t%d\n", packet->sockfd);
+#ifdef WITH_TCP
+ fprintf(fr_log_fp, " Proto:\t%d\n", packet->proto);
+#endif
+
+ if (packet->src_ipaddr.af == AF_INET) {
+ char buffer[32];
+
+ fprintf(fr_log_fp, " Src IP:\t%s\n",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ fprintf(fr_log_fp, " port:\t%u\n", packet->src_port);
+
+ fprintf(fr_log_fp, " Dst IP:\t%s\n",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ fprintf(fr_log_fp, " port:\t%u\n", packet->dst_port);
+ }
+
+ if (packet->data[0] < FR_MAX_PACKET_CODE) {
+ fprintf(fr_log_fp, " Code:\t\t(%d) %s\n", packet->data[0], fr_packet_codes[packet->data[0]]);
+ } else {
+ fprintf(fr_log_fp, " Code:\t\t%u\n", packet->data[0]);
+ }
+ fprintf(fr_log_fp, " Id:\t\t%u\n", packet->data[1]);
+ fprintf(fr_log_fp, " Length:\t%u\n", ((packet->data[2] << 8) |
+ (packet->data[3])));
+ fprintf(fr_log_fp, " Vector:\t");
+ for (i = 4; i < 20; i++) {
+ fprintf(fr_log_fp, "%02x", packet->data[i]);
+ }
+ fprintf(fr_log_fp, "\n");
+
+ if (packet->data_len > 20) {
+ int total;
+ uint8_t const *ptr;
+ fprintf(fr_log_fp, " Data:");
+
+ total = packet->data_len - 20;
+ ptr = packet->data + 20;
+
+ while (total > 0) {
+ int attrlen;
+ unsigned int vendor = 0;
+
+ fprintf(fr_log_fp, "\t\t");
+ if (total < 2) { /* too short */
+ fprintf(fr_log_fp, "%02x\n", *ptr);
+ break;
+ }
+
+ if (ptr[1] > total) { /* too long */
+ for (i = 0; i < total; i++) {
+ fprintf(fr_log_fp, "%02x ", ptr[i]);
+ }
+ break;
+ }
+
+ fprintf(fr_log_fp, "%02x %02x ", ptr[0], ptr[1]);
+ attrlen = ptr[1] - 2;
+
+ if ((ptr[0] == PW_VENDOR_SPECIFIC) &&
+ (attrlen > 4)) {
+ vendor = (ptr[3] << 16) | (ptr[4] << 8) | ptr[5];
+ fprintf(fr_log_fp, "%02x%02x%02x%02x (%u) ",
+ ptr[2], ptr[3], ptr[4], ptr[5], vendor);
+ attrlen -= 4;
+ ptr += 6;
+ total -= 6;
+
+ } else {
+ ptr += 2;
+ total -= 2;
+ }
+
+ print_hex_data(ptr, attrlen, 3);
+
+ ptr += attrlen;
+ total -= attrlen;
+ }
+ }
+ fflush(stdout);
+}
+
+/** Wrapper for sendto which handles sendfromto, IPv6, and all possible combinations
+ *
+ */
+static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
+#ifdef WITH_UDPFROMTO
+ fr_ipaddr_t *src_ipaddr, uint16_t src_port,
+#else
+ UNUSED fr_ipaddr_t *src_ipaddr, UNUSED uint16_t src_port,
+#endif
+ fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
+{
+ int rcode;
+ struct sockaddr_storage dst;
+ socklen_t sizeof_dst;
+
+#ifdef WITH_UDPFROMTO
+ struct sockaddr_storage src;
+ socklen_t sizeof_src;
+
+ fr_ipaddr2sockaddr(src_ipaddr, src_port, &src, &sizeof_src);
+#endif
+
+ if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) {
+ return -1;
+ }
+
+#ifdef WITH_UDPFROMTO
+ /*
+ * And if they don't specify a source IP address, don't
+ * use udpfromto.
+ */
+ if (((dst_ipaddr->af == AF_INET) || (dst_ipaddr->af == AF_INET6)) &&
+ (src_ipaddr->af != AF_UNSPEC) &&
+ !fr_inaddr_any(src_ipaddr)) {
+ rcode = sendfromto(sockfd, data, data_len, flags,
+ (struct sockaddr *)&src, sizeof_src,
+ (struct sockaddr *)&dst, sizeof_dst);
+ goto done;
+ }
+#endif
+
+ /*
+ * No udpfromto, fail gracefully.
+ */
+ rcode = sendto(sockfd, data, data_len, flags,
+ (struct sockaddr *) &dst, sizeof_dst);
+#ifdef WITH_UDPFROMTO
+done:
+#endif
+ if (rcode < 0) {
+ fr_strerror_printf("sendto failed: %s", fr_syserror(errno));
+ }
+
+ return rcode;
+}
+
+
+void rad_recv_discard(int sockfd)
+{
+ uint8_t header[4];
+ struct sockaddr_storage src;
+ socklen_t sizeof_src = sizeof(src);
+
+ (void) recvfrom(sockfd, header, sizeof(header), 0,
+ (struct sockaddr *)&src, &sizeof_src);
+}
+
+/** Basic validation of RADIUS packet header
+ *
+ * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
+ * consumed when discarding malformed packet.
+ *
+ * @param[in] sockfd we're reading from.
+ * @param[out] src_ipaddr of the packet.
+ * @param[out] src_port of the packet.
+ * @param[out] code Pointer to where to write the packet code.
+ * @return
+ * - -1 on failure.
+ * - 1 on decode error.
+ * - >= RADIUS_HDR_LEN on success. This is the packet length as specified in the header.
+ */
+ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code)
+{
+ ssize_t data_len, packet_len;
+ uint8_t header[4];
+ struct sockaddr_storage src;
+ socklen_t sizeof_src = sizeof(src);
+
+ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
+ if (data_len < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR)) return 0;
+ return -1;
+ }
+
+ /*
+ * Convert AF. If unknown, discard packet.
+ */
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
+ FR_DEBUG_STRERROR_PRINTF("Unknown address family");
+ rad_recv_discard(sockfd);
+
+ return 1;
+ }
+
+ /*
+ * Too little data is available, discard the packet.
+ */
+ if (data_len < 4) {
+ FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zu bytes", data_len);
+invalid:
+ FR_DEBUG_STRERROR_PRINTF("Invalid data from %s: %s",
+ fr_inet_ntop(src_ipaddr->af, &src_ipaddr->ipaddr),
+ fr_strerror());
+ rad_recv_discard(sockfd);
+
+ return 1;
+ }
+
+ /*
+ * See how long the packet says it is.
+ */
+ packet_len = (header[2] * 256) + header[3];
+
+ /*
+ * The length in the packet says it's less than
+ * a RADIUS header length: discard it.
+ */
+ if (packet_len < RADIUS_HDR_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HDR_LEN) " bytes of packet "
+ "data, got %zu bytes", packet_len);
+ goto invalid;
+ }
+
+ /*
+ * Enforce RFC requirements, for sanity.
+ * Anything after 4k will be discarded.
+ */
+ if (packet_len > MAX_PACKET_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
+ STRINGIFY(MAX_PACKET_LEN) " bytes, got %zu bytes", packet_len);
+ goto invalid;
+ }
+
+ *code = header[0];
+
+ /*
+ * The packet says it's this long, but the actual UDP
+ * size could still be smaller.
+ */
+ return packet_len;
+}
+
+
+/** Wrapper for recvfrom, which handles recvfromto, IPv6, and all possible combinations
+ *
+ */
+static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
+ fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
+ fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port)
+{
+ struct sockaddr_storage src;
+ struct sockaddr_storage dst;
+ socklen_t sizeof_src = sizeof(src);
+ socklen_t sizeof_dst = sizeof(dst);
+ ssize_t data_len;
+ size_t len;
+ uint16_t port;
+ uint8_t buffer[MAX_PACKET_LEN];
+
+ memset(&src, 0, sizeof_src);
+ memset(&dst, 0, sizeof_dst);
+
+ /*
+ * Receive the packet. The OS will discard any data in the
+ * packet after "len" bytes.
+ */
+#ifdef WITH_UDPFROMTO
+ data_len = recvfromto(sockfd, buffer, sizeof(buffer), flags,
+ (struct sockaddr *)&src, &sizeof_src,
+ (struct sockaddr *)&dst, &sizeof_dst);
+#else
+ data_len = recvfrom(sockfd, buffer, sizeof(buffer), flags,
+ (struct sockaddr *)&src, &sizeof_src);
+
+ /*
+ * Get the destination address, too.
+ */
+ if (getsockname(sockfd, (struct sockaddr *)&dst,
+ &sizeof_dst) < 0) return -1;
+#endif
+ if (data_len <= 0) {
+ return data_len;
+ }
+
+ /*
+ * See how long the packet says it is.
+ */
+ len = (buffer[2] * 256) + buffer[3];
+
+ /*
+ * Header says it's smaller than a RADIUS header, *or*
+ * the RADIUS header says that the RADIUS packet islarger
+ * than our buffer. Discard it.
+ */
+ if ((len < RADIUS_HDR_LEN) || (len > (size_t) data_len)) return 0;
+
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, &port)) {
+ return -1; /* Unknown address family, Die Die Die! */
+ }
+ *src_port = port;
+
+ fr_sockaddr2ipaddr(&dst, sizeof_dst, dst_ipaddr, &port);
+ *dst_port = port;
+
+ /*
+ * Different address families should never happen.
+ */
+ if (src.ss_family != dst.ss_family) {
+ return -1;
+ }
+
+ packet->data = talloc_memdup(packet, buffer, len);
+ if (!packet->data) return -1;
+
+ packet->data_len = len;
+
+ /*
+ * Return the length of the RADIUS packet. There may be
+ * stuff after the end of the RADIUS packet, so we don't
+ * want to parse that as RADIUS.
+ */
+ return len;
+}
+
+
+#ifndef WITH_RADIUSV11_ONLY
+#define AUTH_PASS_LEN (AUTH_VECTOR_LEN)
+/** Build an encrypted secret value to return in a reply packet
+ *
+ * The secret is hidden by xoring with a MD5 digest created from
+ * the shared secret and the authentication vector.
+ * We put them into MD5 in the reverse order from that used when
+ * encrypting passwords to RADIUS.
+ */
+static void make_secret(uint8_t *digest, uint8_t const *vector,
+ char const *secret, uint8_t const *value, size_t length)
+{
+ FR_MD5_CTX context;
+ size_t i;
+
+ fr_md5_init(&context);
+ fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+ fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+ fr_md5_final(digest, &context);
+
+ for ( i = 0; i < length; i++ ) {
+ digest[i] ^= value[i];
+ }
+
+ fr_md5_destroy(&context);
+}
+
+#define MAX_PASS_LEN (128)
+static void make_passwd(uint8_t *output, ssize_t *outlen,
+ uint8_t const *input, size_t inlen,
+ char const *secret, uint8_t const *vector)
+{
+ FR_MD5_CTX context, old;
+ uint8_t digest[AUTH_VECTOR_LEN];
+ uint8_t passwd[MAX_PASS_LEN];
+ size_t i, n;
+ size_t len;
+
+ /*
+ * If the length is zero, round it up.
+ */
+ len = inlen;
+
+ if (len > MAX_PASS_LEN) len = MAX_PASS_LEN;
+
+ memcpy(passwd, input, len);
+ if (len < sizeof(passwd)) memset(passwd + len, 0, sizeof(passwd) - len);
+
+ if (len == 0) {
+ len = AUTH_PASS_LEN;
+ }
+
+ else if ((len & 0x0f) != 0) {
+ len += 0x0f;
+ len &= ~0x0f;
+ }
+ *outlen = len;
+
+ fr_md5_init(&context);
+ fr_md5_init(&old);
+ fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+ fr_md5_copy(old, context);
+
+ /*
+ * Do first pass.
+ */
+ fr_md5_update(&context, vector, AUTH_PASS_LEN);
+
+ for (n = 0; n < len; n += AUTH_PASS_LEN) {
+ if (n > 0) {
+ fr_md5_copy(context, old);
+ fr_md5_update(&context,
+ passwd + n - AUTH_PASS_LEN,
+ AUTH_PASS_LEN);
+ }
+
+ fr_md5_final(digest, &context);
+ for (i = 0; i < AUTH_PASS_LEN; i++) {
+ passwd[i + n] ^= digest[i];
+ }
+ }
+
+ memcpy(output, passwd, len);
+
+ fr_md5_destroy(&old);
+ fr_md5_destroy(&context);
+}
+
+
+static void make_tunnel_passwd(uint8_t *output, ssize_t *outlen,
+ uint8_t const *input, size_t inlen, size_t room,
+ char const *secret, uint8_t const *vector)
+{
+ FR_MD5_CTX context, old;
+ uint8_t digest[AUTH_VECTOR_LEN];
+ size_t i, n;
+ size_t encrypted_len;
+
+ /*
+ * The password gets encoded with a 1-byte "length"
+ * field. Ensure that it doesn't overflow.
+ */
+ if (room > 253) room = 253;
+
+ /*
+ * Limit the maximum size of the input password. 2 bytes
+ * are taken up by the salt, and one by the encoded
+ * "length" field. Note that if we have a tag, the
+ * "room" will be 252 octets, not 253 octets.
+ */
+ if (inlen > (room - 3)) inlen = room - 3;
+
+ /*
+ * Length of the encrypted data is the clear-text
+ * password length plus one byte which encodes the length
+ * of the password. We round up to the nearest encoding
+ * block. Note that this can result in the encoding
+ * length being more than 253 octets.
+ */
+ encrypted_len = inlen + 1;
+ if ((encrypted_len & 0x0f) != 0) {
+ encrypted_len += 0x0f;
+ encrypted_len &= ~0x0f;
+ }
+
+ /*
+ * We need 2 octets for the salt, followed by the actual
+ * encrypted data.
+ */
+ if (encrypted_len > (room - 2)) encrypted_len = room - 2;
+
+ *outlen = encrypted_len + 2; /* account for the salt */
+
+ /*
+ * Copy the password over, and zero-fill the remainder.
+ */
+ memcpy(output + 3, input, inlen);
+ memset(output + 3 + inlen, 0, *outlen - 3 - inlen);
+
+ /*
+ * Generate salt. The RFCs say:
+ *
+ * The high bit of salt[0] must be set, each salt in a
+ * packet should be unique, and they should be random
+ *
+ * So, we set the high bit, add in a counter, and then
+ * add in some CSPRNG data. should be OK..
+ */
+ output[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
+ (fr_rand() & 0x07));
+ output[1] = fr_rand();
+ output[2] = inlen; /* length of the password string */
+
+ fr_md5_init(&context);
+ fr_md5_init(&old);
+ fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+ fr_md5_copy(old, context);
+
+ fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+ fr_md5_update(&context, &output[0], 2);
+
+ for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+ size_t block_len;
+
+ if (n > 0) {
+ fr_md5_copy(context, old);
+ fr_md5_update(&context,
+ output + 2 + n - AUTH_PASS_LEN,
+ AUTH_PASS_LEN);
+ }
+
+ fr_md5_final(digest, &context);
+
+ if ((2 + n + AUTH_PASS_LEN) < room) {
+ block_len = AUTH_PASS_LEN;
+ } else {
+ block_len = room - 2 - n;
+ }
+
+ for (i = 0; i < block_len; i++) {
+ output[i + 2 + n] ^= digest[i];
+ }
+ }
+ fr_md5_destroy(&old);
+ fr_md5_destroy(&context);
+}
+#endif /* WITH_RADIUSV11_ONLY */
+
+static int do_next_tlv(VALUE_PAIR const *vp, VALUE_PAIR const *next, int nest)
+{
+ unsigned int tlv1, tlv2;
+
+ if (nest > fr_attr_max_tlv) return 0;
+
+ if (!vp) return 0;
+
+ /*
+ * Keep encoding TLVs which have the same scope.
+ * e.g. two attributes of:
+ * ATTR.TLV1.TLV2.TLV3 = data1
+ * ATTR.TLV1.TLV2.TLV4 = data2
+ * both get put into a container of "ATTR.TLV1.TLV2"
+ */
+
+ /*
+ * Nothing to follow, we're done.
+ */
+ if (!next) return 0;
+
+ /*
+ * Not from the same vendor, skip it.
+ */
+ if (vp->da->vendor != next->da->vendor) return 0;
+
+ /*
+ * In a different TLV space, skip it.
+ */
+ tlv1 = vp->da->attr;
+ tlv2 = next->da->attr;
+
+ tlv1 &= ((1 << fr_attr_shift[nest]) - 1);
+ tlv2 &= ((1 << fr_attr_shift[nest]) - 1);
+
+ if (tlv1 != tlv2) return 0;
+
+ return 1;
+}
+
+
+static ssize_t vp2data_any(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, int nest,
+ VALUE_PAIR const **pvp,
+ uint8_t *start, size_t room);
+
+static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ unsigned int attribute, uint8_t *ptr, size_t room);
+
+/** Encode the *data* portion of the TLV
+ *
+ * This is really a sub-function of vp2data_any(). It encodes the *data* portion
+ * of the TLV, and assumes that the encapsulating attribute has already been encoded.
+ */
+static ssize_t vp2data_tlvs(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, int nest,
+ VALUE_PAIR const **pvp,
+ uint8_t *start, size_t room)
+{
+ ssize_t len;
+ size_t my_room;
+ uint8_t *ptr = start;
+ VALUE_PAIR const *vp = *pvp;
+ VALUE_PAIR const *svp = vp;
+
+ if (!svp) return 0;
+
+#ifndef NDEBUG
+ if (nest > fr_attr_max_tlv) {
+ fr_strerror_printf("vp2data_tlvs: attribute nesting overflow");
+ return -1;
+ }
+#endif
+
+ while (vp) {
+ VERIFY_VP(vp);
+
+ if (room <= 2) return ptr - start;
+
+ ptr[0] = (vp->da->attr >> fr_attr_shift[nest]) & fr_attr_mask[nest];
+ ptr[1] = 2;
+
+ my_room = room;
+ if (room > 255) my_room = 255;
+
+ len = vp2data_any(packet, original, secret, nest,
+ &vp, ptr + 2, my_room - 2);
+ if (len < 0) return len;
+ if (len == 0) return ptr - start;
+ /* len can NEVER be more than 253 */
+
+ ptr[1] += len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
+ print_hex_data(ptr + 2, len, 3);
+ }
+#endif
+
+ room -= ptr[1];
+ ptr += ptr[1];
+ *pvp = vp;
+
+ if (!do_next_tlv(svp, vp, nest)) break;
+ }
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbyvalue(svp->da->attr & ((1 << fr_attr_shift[nest ]) - 1), svp->da->vendor);
+ if (da) fprintf(fr_log_fp, "\t%s = ...\n", da->name);
+ }
+#endif
+
+ return ptr - start;
+}
+
+/** Encodes the data portion of an attribute
+ *
+ * @return -1 on error, or the length of the data portion.
+ */
+static ssize_t vp2data_any(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, int nest,
+ VALUE_PAIR const **pvp,
+ uint8_t *start, size_t room)
+{
+ uint32_t lvalue;
+ ssize_t len;
+ uint8_t const *data;
+ uint8_t *ptr = start;
+ uint8_t array[4];
+ uint64_t lvalue64;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ /*
+ * See if we need to encode a TLV. The low portion of
+ * the attribute has already been placed into the packer.
+ * If there are still attribute bytes left, then go
+ * encode them as TLVs.
+ *
+ * If we cared about the stack, we could unroll the loop.
+ */
+ if (vp->da->flags.is_tlv && (nest < fr_attr_max_tlv) &&
+ ((vp->da->attr >> fr_attr_shift[nest + 1]) != 0)) {
+ return vp2data_tlvs(packet, original, secret, nest + 1, pvp,
+ start, room);
+ }
+
+ /*
+ * Set up the default sources for the data.
+ */
+ len = vp->vp_length;
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ data = vp->data.ptr;
+ if (!data) return 0;
+ break;
+
+ case PW_TYPE_IFID:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_ABINARY:
+ case PW_TYPE_ETHERNET: /* just in case */
+ data = (uint8_t const *) &vp->data;
+ break;
+
+ case PW_TYPE_BYTE:
+ len = 1; /* just in case */
+ array[0] = vp->vp_byte;
+ data = array;
+ break;
+
+ case PW_TYPE_SHORT:
+ len = 2; /* just in case */
+ array[0] = (vp->vp_short >> 8) & 0xff;
+ array[1] = vp->vp_short & 0xff;
+ data = array;
+ break;
+
+ case PW_TYPE_INTEGER:
+ len = 4; /* just in case */
+ lvalue = htonl(vp->vp_integer);
+ memcpy(array, &lvalue, sizeof(lvalue));
+ data = array;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ len = 8; /* just in case */
+ lvalue64 = htonll(vp->vp_integer64);
+ data = (uint8_t *) &lvalue64;
+ break;
+
+ /*
+ * There are no tagged date attributes.
+ */
+ case PW_TYPE_DATE:
+ lvalue = htonl(vp->vp_date);
+ data = (uint8_t const *) &lvalue;
+ len = 4; /* just in case */
+ break;
+
+ case PW_TYPE_SIGNED:
+ {
+ int32_t slvalue;
+
+ len = 4; /* just in case */
+ slvalue = htonl(vp->vp_signed);
+ memcpy(array, &slvalue, sizeof(slvalue));
+ data = array;
+ break;
+ }
+
+ default: /* unknown type: ignore it */
+ fr_strerror_printf("ERROR: Unknown attribute type %d", vp->da->type);
+ return -1;
+ }
+
+ /*
+ * No data: skip it.
+ */
+ if (len == 0) {
+ *pvp = vp->next;
+ return 0;
+ }
+
+ /*
+ * Bound the data to the calling size
+ */
+ if (len > (ssize_t) room) len = room;
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encrypt any attributes.
+ */
+ if (packet->radiusv11) goto tag;
+#endif
+
+ /*
+ * Encrypt the various password styles
+ *
+ * Attributes with encrypted values MUST be less than
+ * 128 bytes long.
+ */
+ switch (vp->da->flags.encrypt) {
+#ifndef WITH_RADIUSV11_ONLY
+ case FLAG_ENCRYPT_USER_PASSWORD:
+ make_passwd(ptr, &len, data, len,
+ secret, packet->vector);
+ break;
+
+ case FLAG_ENCRYPT_TUNNEL_PASSWORD:
+ lvalue = 0;
+ if (vp->da->flags.has_tag) lvalue = 1;
+
+ /*
+ * Check if there's enough room. If there isn't,
+ * we discard the attribute.
+ *
+ * This is ONLY a problem if we have multiple VSA's
+ * in one Vendor-Specific, though.
+ */
+ if (room < (18 + lvalue)) return 0;
+
+ switch (packet->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ default:
+ if (!original) {
+ fr_strerror_printf("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->da->name);
+ return -1;
+ }
+
+ make_tunnel_passwd(ptr + lvalue, &len, data, len,
+ room - lvalue,
+ secret, original->vector);
+ break;
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ make_tunnel_passwd(ptr + lvalue, &len, data, len,
+ room - lvalue,
+ secret, packet->vector);
+ break;
+ }
+ if (lvalue) ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
+ len += lvalue;
+ break;
+
+ /*
+ * The code above ensures that this attribute
+ * always fits.
+ */
+ case FLAG_ENCRYPT_ASCEND_SECRET:
+ if (len > AUTH_VECTOR_LEN) len = AUTH_VECTOR_LEN;
+ make_secret(ptr, packet->vector, secret, data, len);
+ len = AUTH_VECTOR_LEN;
+ break;
+#endif /* WITH_RADIUSV11_ONLY */
+
+ default:
+#ifdef WITH_RADIUSV11
+ tag:
+#endif
+ if (vp->da->flags.has_tag && TAG_VALID(vp->tag)) {
+ if (vp->da->type == PW_TYPE_STRING) {
+ if (len > ((ssize_t) (room - 1))) len = room - 1;
+ ptr[0] = vp->tag;
+ ptr++;
+ } else if (vp->da->type == PW_TYPE_INTEGER) {
+ array[0] = vp->tag;
+ } /* else it can't be any other type */
+ }
+ memcpy(ptr, data, len);
+ break;
+ } /* switch over encryption flags */
+
+ *pvp = vp->next;
+ return len + (ptr - start);
+}
+
+static ssize_t attr_shift(uint8_t const *start, uint8_t const *end,
+ uint8_t *ptr, int hdr_len, ssize_t len,
+ int flag_offset, int vsa_offset)
+{
+ int check_len = len - ptr[1];
+ int total = len + hdr_len;
+
+ /*
+ * Pass 1: Check if the addition of the headers
+ * overflows the available room. If so, return
+ * what we were capable of encoding.
+ */
+
+ while (check_len > (255 - hdr_len)) {
+ total += hdr_len;
+ check_len -= (255 - hdr_len);
+ }
+
+ /*
+ * Note that this results in a number of attributes maybe
+ * being marked as "encoded", but which aren't in the
+ * packet. Oh well. The solution is to fix the
+ * "vp2data_any" function to take into account the header
+ * lengths.
+ */
+ if ((ptr + ptr[1] + total) > end) {
+ return (ptr + ptr[1]) - start;
+ }
+
+ /*
+ * Pass 2: Now that we know there's enough room,
+ * re-arrange the data to form a set of valid
+ * RADIUS attributes.
+ */
+ while (1) {
+ int sublen = 255 - ptr[1];
+
+ if (len <= sublen) {
+ break;
+ }
+
+ len -= sublen;
+ memmove(ptr + 255 + hdr_len, ptr + 255, sublen);
+ memmove(ptr + 255, ptr, hdr_len);
+ ptr[1] += sublen;
+ if (vsa_offset) ptr[vsa_offset] += sublen;
+ ptr[flag_offset] |= 0x80;
+
+ ptr += 255;
+ ptr[1] = hdr_len;
+ if (vsa_offset) ptr[vsa_offset] = 3;
+ }
+
+ ptr[1] += len;
+ if (vsa_offset) ptr[vsa_offset] += len;
+
+ return (ptr + ptr[1]) - start;
+}
+
+
+/** Encode an "extended" attribute
+ */
+int rad_vp2extended(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room)
+{
+ int len;
+ int hdr_len;
+ uint8_t *start = ptr;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ if (!vp->da->flags.extended) {
+ fr_strerror_printf("rad_vp2extended called for non-extended attribute");
+ return -1;
+ }
+
+ /*
+ * The attribute number is encoded into the upper 8 bits
+ * of the vendor ID.
+ */
+ ptr[0] = (vp->da->vendor / FR_MAX_VENDOR) & 0xff;
+
+ if (!vp->da->flags.long_extended) {
+ if (room < 3) return 0;
+
+ ptr[1] = 3;
+ ptr[2] = vp->da->attr & fr_attr_mask[0];
+
+ } else {
+ if (room < 4) return 0;
+
+ ptr[1] = 4;
+ ptr[2] = vp->da->attr & fr_attr_mask[0];
+ ptr[3] = 0;
+ }
+
+ /*
+ * Only "flagged" attributes can be longer than one
+ * attribute.
+ */
+ if (!vp->da->flags.long_extended && (room > 255)) {
+ room = 255;
+ }
+
+ /*
+ * Handle EVS VSAs.
+ */
+ if (vp->da->flags.evs) {
+ uint8_t *evs = ptr + ptr[1];
+
+ if (room < (size_t) (ptr[1] + 5)) return 0;
+
+ ptr[2] = 26;
+
+ evs[0] = 0; /* always zero */
+ evs[1] = (vp->da->vendor >> 16) & 0xff;
+ evs[2] = (vp->da->vendor >> 8) & 0xff;
+ evs[3] = vp->da->vendor & 0xff;
+ evs[4] = vp->da->attr & fr_attr_mask[0];
+
+ ptr[1] += 5;
+ }
+ hdr_len = ptr[1];
+
+ len = vp2data_any(packet, original, secret, 0,
+ pvp, ptr + ptr[1], room - hdr_len);
+ if (len <= 0) return len;
+
+ /*
+ * There may be more than 252 octets of data encoded in
+ * the attribute. If so, move the data up in the packet,
+ * and copy the existing header over. Set the "M" flag ONLY
+ * after copying the rest of the data.
+ */
+ if (vp->da->flags.long_extended && (len > (255 - ptr[1]))) {
+ return attr_shift(start, start + room, ptr, 4, len, 3, 0);
+ }
+
+ ptr[1] += len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ int jump = 3;
+
+ fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
+ if (!vp->da->flags.long_extended) {
+ fprintf(fr_log_fp, "%02x ", ptr[2]);
+
+ } else {
+ fprintf(fr_log_fp, "%02x %02x ", ptr[2], ptr[3]);
+ jump = 4;
+ }
+
+ if (vp->da->flags.evs) {
+ fprintf(fr_log_fp, "%02x%02x%02x%02x (%u) %02x ",
+ ptr[jump], ptr[jump + 1],
+ ptr[jump + 2], ptr[jump + 3],
+ ((ptr[jump + 1] << 16) |
+ (ptr[jump + 2] << 8) |
+ ptr[jump + 3]),
+ ptr[jump + 4]);
+ jump += 5;
+ }
+
+ print_hex_data(ptr + jump, len, 3);
+ }
+#endif
+
+ return (ptr + ptr[1]) - start;
+}
+
+
+/** Encode a WiMAX attribute
+ *
+ */
+int rad_vp2wimax(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room)
+{
+ int len;
+ uint32_t lvalue;
+ int hdr_len;
+ uint8_t *start = ptr;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ /*
+ * Double-check for WiMAX format.
+ */
+ if (!vp->da->flags.wimax) {
+ fr_strerror_printf("rad_vp2wimax called for non-WIMAX VSA");
+ return -1;
+ }
+
+ /*
+ * Not enough room for:
+ * attr, len, vendor-id, vsa, vsalen, continuation
+ */
+ if (room < 9) return 0;
+
+ /*
+ * Build the Vendor-Specific header
+ */
+ ptr = start;
+ ptr[0] = PW_VENDOR_SPECIFIC;
+ ptr[1] = 9;
+ lvalue = htonl(vp->da->vendor);
+ memcpy(ptr + 2, &lvalue, 4);
+ ptr[6] = (vp->da->attr & fr_attr_mask[1]);
+ ptr[7] = 3;
+ ptr[8] = 0; /* continuation byte */
+
+ hdr_len = 9;
+
+ len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1],
+ room - hdr_len);
+ if (len <= 0) return len;
+
+ /*
+ * There may be more than 252 octets of data encoded in
+ * the attribute. If so, move the data up in the packet,
+ * and copy the existing header over. Set the "C" flag
+ * ONLY after copying the rest of the data.
+ */
+ if (len > (255 - ptr[1])) {
+ return attr_shift(start, start + room, ptr, hdr_len, len, 8, 7);
+ }
+
+ ptr[1] += len;
+ ptr[7] += len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) %02x %02x %02x ",
+ ptr[0], ptr[1],
+ ptr[2], ptr[3], ptr[4], ptr[5],
+ (ptr[3] << 16) | (ptr[4] << 8) | ptr[5],
+ ptr[6], ptr[7], ptr[8]);
+ print_hex_data(ptr + 9, len, 3);
+ }
+#endif
+
+ return (ptr + ptr[1]) - start;
+}
+
+/** Encode an RFC format attribute, with the "concat" flag set
+ *
+ * If there isn't enough room in the packet, the data is
+ * truncated to fit.
+ */
+static ssize_t vp2attr_concat(UNUSED RADIUS_PACKET const *packet,
+ UNUSED RADIUS_PACKET const *original,
+ UNUSED char const *secret, VALUE_PAIR const **pvp,
+ unsigned int attribute, uint8_t *start, size_t room)
+{
+ uint8_t *ptr = start;
+ uint8_t const *p;
+ size_t len, left;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ p = vp->vp_octets;
+ len = vp->vp_length;
+
+ while (len > 0) {
+ if (room <= 2) break;
+
+ ptr[0] = attribute;
+ ptr[1] = 2;
+
+ left = len;
+
+ /* no more than 253 octets */
+ if (left > 253) left = 253;
+
+ /* no more than "room" octets */
+ if (room < (left + 2)) left = room - 2;
+
+ memcpy(ptr + 2, p, left);
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
+ print_hex_data(ptr + 2, len, 3);
+ }
+#endif
+ ptr[1] += left;
+ ptr += ptr[1];
+ p += left;
+ room -= left;
+ len -= left;
+ }
+
+ *pvp = vp->next;
+ return ptr - start;
+}
+
+/** Encode an RFC format TLV.
+ *
+ * This could be a standard attribute, or a TLV data type.
+ * If it's a standard attribute, then vp->da->attr == attribute.
+ * Otherwise, attribute may be something else.
+ */
+static ssize_t vp2attr_rfc(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ unsigned int attribute, uint8_t *ptr, size_t room)
+{
+ ssize_t len;
+
+ if (room <= 2) return 0;
+
+ ptr[0] = attribute & 0xff;
+ ptr[1] = 2;
+
+ if (room > 255) room = 255;
+
+ len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room - ptr[1]);
+ if (len <= 0) return len;
+
+ ptr[1] += len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
+ print_hex_data(ptr + 2, len, 3);
+ }
+#endif
+
+ return ptr[1];
+}
+
+
+/** Encode a VSA which is a TLV
+ *
+ * If it's in the RFC format, call vp2attr_rfc. Otherwise, encode it here.
+ */
+static ssize_t vp2attr_vsa(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ unsigned int attribute, unsigned int vendor,
+ uint8_t *ptr, size_t room)
+{
+ ssize_t len;
+ DICT_VENDOR *dv;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+ /*
+ * Unknown vendor: RFC format.
+ * Known vendor and RFC format: go do that.
+ */
+ dv = dict_vendorbyvalue(vendor);
+ if (!dv ||
+ (!vp->da->flags.is_tlv && (dv->type == 1) && (dv->length == 1))) {
+ return vp2attr_rfc(packet, original, secret, pvp,
+ attribute, ptr, room);
+ }
+
+ switch (dv->type) {
+ default:
+ fr_strerror_printf("vp2attr_vsa: Internal sanity check failed,"
+ " type %u", (unsigned) dv->type);
+ return -1;
+
+ case 4:
+ ptr[0] = 0; /* attr must be 24-bit */
+ ptr[1] = (attribute >> 16) & 0xff;
+ ptr[2] = (attribute >> 8) & 0xff;
+ ptr[3] = attribute & 0xff;
+ break;
+
+ case 2:
+ ptr[0] = (attribute >> 8) & 0xff;
+ ptr[1] = attribute & 0xff;
+ break;
+
+ case 1:
+ ptr[0] = attribute & 0xff;
+ break;
+ }
+
+ switch (dv->length) {
+ default:
+ fr_strerror_printf("vp2attr_vsa: Internal sanity check failed,"
+ " length %u", (unsigned) dv->length);
+ return -1;
+
+ case 0:
+ break;
+
+ case 2:
+ ptr[dv->type] = 0;
+ ptr[dv->type + 1] = dv->type + 2;
+ break;
+
+ case 1:
+ ptr[dv->type] = dv->type + 1;
+ break;
+
+ }
+
+ if (room > 255) room = 255;
+
+ len = vp2data_any(packet, original, secret, 0, pvp,
+ ptr + dv->type + dv->length, room - (dv->type + dv->length));
+ if (len <= 0) return len;
+
+ if (dv->length) ptr[dv->type + dv->length - 1] += len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ switch (dv->type) {
+ default:
+ break;
+
+ case 4:
+ if ((fr_debug_lvl > 3) && fr_log_fp)
+ fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ",
+ ptr[0], ptr[1], ptr[2], ptr[3]);
+ break;
+
+ case 2:
+ if ((fr_debug_lvl > 3) && fr_log_fp)
+ fprintf(fr_log_fp, "\t\t%02x%02x ",
+ ptr[0], ptr[1]);
+ break;
+
+ case 1:
+ if ((fr_debug_lvl > 3) && fr_log_fp)
+ fprintf(fr_log_fp, "\t\t%02x ", ptr[0]);
+ break;
+ }
+
+ switch (dv->length) {
+ default:
+ break;
+
+ case 0:
+ fprintf(fr_log_fp, " ");
+ break;
+
+ case 1:
+ fprintf(fr_log_fp, "%02x ",
+ ptr[dv->type]);
+ break;
+
+ case 2:
+ fprintf(fr_log_fp, "%02x%02x ",
+ ptr[dv->type], ptr[dv->type] + 1);
+ break;
+ }
+
+ print_hex_data(ptr + dv->type + dv->length, len, 3);
+ }
+#endif
+
+ return dv->type + dv->length + len;
+}
+
+
+/** Encode a Vendor-Specific attribute
+ *
+ */
+int rad_vp2vsa(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp, uint8_t *ptr,
+ size_t room)
+{
+ ssize_t len;
+ uint32_t lvalue;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ if (vp->da->vendor == 0) {
+ fr_strerror_printf("rad_vp2vsa called with rfc attribute");
+ return -1;
+ }
+
+ /*
+ * Double-check for WiMAX format.
+ */
+ if (vp->da->flags.wimax) {
+ return rad_vp2wimax(packet, original, secret, pvp, ptr, room);
+ }
+
+ if (vp->da->vendor > FR_MAX_VENDOR) {
+ fr_strerror_printf("rad_vp2vsa: Invalid arguments");
+ return -1;
+ }
+
+ /*
+ * Not enough room for:
+ * attr, len, vendor-id
+ */
+ if (room < 6) return 0;
+
+ /*
+ * Build the Vendor-Specific header
+ */
+ ptr[0] = PW_VENDOR_SPECIFIC;
+ ptr[1] = 6;
+ lvalue = htonl(vp->da->vendor);
+ memcpy(ptr + 2, &lvalue, 4);
+
+ if (room > 255) room = 255;
+
+ len = vp2attr_vsa(packet, original, secret, pvp,
+ vp->da->attr, vp->da->vendor,
+ ptr + ptr[1], room - ptr[1]);
+ if (len < 0) return len;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) ",
+ ptr[0], ptr[1],
+ ptr[2], ptr[3], ptr[4], ptr[5],
+ (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
+ print_hex_data(ptr + 6, len, 3);
+ }
+#endif
+
+ ptr[1] += len;
+
+ return ptr[1];
+}
+
+
+/** Encode an RFC standard attribute 1..255
+ *
+ */
+int rad_vp2rfc(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *ptr, size_t room)
+{
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ if (room < 2) return -1;
+
+ if (vp->da->vendor != 0) {
+ fr_strerror_printf("rad_vp2rfc called with VSA");
+ return -1;
+ }
+
+ if ((vp->da->attr == 0) || (vp->da->attr > 255)) {
+ fr_strerror_printf("rad_vp2rfc called with non-standard attribute %u", vp->da->attr);
+ return -1;
+ }
+
+ /*
+ * Only CUI is allowed to have zero length.
+ * Thank you, WiMAX!
+ */
+ if ((vp->vp_length == 0) &&
+ (vp->da->attr == PW_CHARGEABLE_USER_IDENTITY)) {
+ ptr[0] = PW_CHARGEABLE_USER_IDENTITY;
+ ptr[1] = 2;
+
+ *pvp = vp->next;
+ return 2;
+ }
+
+ /*
+ * Message-Authenticator is hard-coded.
+ */
+ if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) {
+ *pvp = (*pvp)->next;
+ return 0;
+ }
+#endif
+
+ if (room < 18) return -1;
+
+ ptr[0] = PW_MESSAGE_AUTHENTICATOR;
+ ptr[1] = 18;
+ memset(ptr + 2, 0, 16);
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
+ fprintf(fr_log_fp, "\t\t50 12 ...\n");
+ }
+#endif
+
+ *pvp = (*pvp)->next;
+ return 18;
+ }
+
+ /*
+ * Hacks for NAS-Filter-Rule. They all get concatenated
+ * with 0x00 bytes in between the values. We rely on the
+ * decoder to do the opposite transformation on incoming
+ * packets.
+ */
+ if (vp->da->attr == PW_NAS_FILTER_RULE) {
+ uint8_t const *end = ptr + room;
+ uint8_t *p, *attr = ptr;
+ bool zero = false;
+
+ attr[0] = PW_NAS_FILTER_RULE;
+ attr[1] = 2;
+ p = ptr + 2;
+
+ while (vp && !vp->da->vendor && (vp->da->attr == PW_NAS_FILTER_RULE)) {
+ if ((p + zero + vp->vp_length) > end) {
+ break;
+ }
+
+ if (zero) {
+ if (attr[1] == 255) {
+ attr = p;
+ if ((attr + 3) >= end) break;
+
+ attr[0] = PW_NAS_FILTER_RULE;
+ attr[1] = 2;
+ p = attr + 2;
+ }
+
+ *(p++) = 0;
+ attr[1]++;
+ }
+
+ /*
+ * Check for overflow
+ */
+ if ((attr[1] + vp->vp_length) < 255) {
+ memcpy(p, vp->vp_strvalue, vp->vp_length);
+ attr[1] += vp->vp_length;
+ p += vp->vp_length;
+
+ } else if (attr + (attr[1] + 2 + vp->vp_length) > end) {
+ break;
+
+ } else if (vp->vp_length > 253) {
+ /*
+ * Drop VPs which are too long.
+ * We don't (yet) split one VP
+ * across multiple attributes.
+ */
+ vp = vp->next;
+ continue;
+
+ } else {
+ size_t first, second;
+
+ first = 255 - attr[1];
+ second = vp->vp_length - first;
+
+ memcpy(p, vp->vp_strvalue, first);
+ p += first;
+ attr[1] = 255;
+ attr = p;
+
+ attr[0] = PW_NAS_FILTER_RULE;
+ attr[1] = 2;
+ p = attr + 2;
+
+ memcpy(p, vp->vp_strvalue + first, second);
+ attr[1] += second;
+ p += second;
+ }
+
+ vp = vp->next;
+ zero = true;
+ }
+
+ *pvp = vp;
+ return p - ptr;
+ }
+
+ /*
+ * EAP-Message is special.
+ */
+ if (vp->da->flags.concat && (vp->vp_length > 253)) {
+ return vp2attr_concat(packet, original, secret, pvp, vp->da->attr,
+ ptr, room);
+ }
+
+ return vp2attr_rfc(packet, original, secret, pvp, vp->da->attr,
+ ptr, room);
+}
+
+static ssize_t rad_vp2rfctlv(RADIUS_PACKET const *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp,
+ uint8_t *start, size_t room)
+{
+ ssize_t len;
+ VALUE_PAIR const *vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ if (!vp->da->flags.is_tlv) {
+ fr_strerror_printf("rad_vp2rfctlv: attr is not a TLV");
+ return -1;
+ }
+
+ if ((vp->da->vendor & (FR_MAX_VENDOR - 1)) != 0) {
+ fr_strerror_printf("rad_vp2rfctlv: attr is not an RFC TLV");
+ return -1;
+ }
+
+ if (room < 5) return 0;
+
+ /*
+ * Encode the first level of TLVs
+ */
+ start[0] = (vp->da->vendor / FR_MAX_VENDOR) & 0xff;
+ start[1] = 4;
+ start[2] = vp->da->attr & fr_attr_mask[0];
+ start[3] = 2;
+
+ len = vp2data_any(packet, original, secret, 0, pvp,
+ start + 4, room - 4);
+ if (len <= 0) return len;
+
+ if (len > 253) {
+ return -1;
+ }
+
+ start[1] += len;
+ start[3] += len;
+
+ return start[1];
+}
+
+/** Parse a data structure into a RADIUS attribute
+ *
+ */
+int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
+ char const *secret, VALUE_PAIR const **pvp, uint8_t *start,
+ size_t room)
+{
+ VALUE_PAIR const *vp;
+
+ if (!pvp || !*pvp || !start || (room <= 2)) return -1;
+
+ vp = *pvp;
+
+ VERIFY_VP(vp);
+
+ /*
+ * RFC format attributes take the fast path.
+ */
+ if (!vp->da->vendor) {
+ if (vp->da->attr > 255) {
+ *pvp = vp->next;
+ return 0;
+ }
+
+ return rad_vp2rfc(packet, original, secret, pvp,
+ start, room);
+ }
+
+ if (vp->da->flags.extended) {
+ return rad_vp2extended(packet, original, secret, pvp,
+ start, room);
+ }
+
+ /*
+ * The upper 8 bits of the vendor number are the standard
+ * space attribute which is a TLV.
+ */
+ if ((vp->da->vendor & (FR_MAX_VENDOR - 1)) == 0) {
+ return rad_vp2rfctlv(packet, original, secret, pvp,
+ start, room);
+ }
+
+ if (vp->da->flags.wimax) {
+ return rad_vp2wimax(packet, original, secret, pvp,
+ start, room);
+ }
+
+ return rad_vp2vsa(packet, original, secret, pvp, start, room);
+}
+
+
+/** Encode a packet
+ *
+ */
+int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret)
+{
+ radius_packet_t *hdr;
+ uint8_t *ptr;
+ uint16_t total_length;
+ int len;
+ VALUE_PAIR const *reply;
+
+ /*
+ * A 4K packet, aligned on 64-bits.
+ */
+ uint64_t data[MAX_PACKET_LEN / sizeof(uint64_t)];
+
+ /*
+ * Double-check some things based on packet code.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ if (!original) {
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
+ return -1;
+ }
+ break;
+
+ /*
+ * These packet vectors start off as all zero.
+ */
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ memset(packet->vector, 0, sizeof(packet->vector));
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Use memory on the stack, until we know how
+ * large the packet will be.
+ */
+ hdr = (radius_packet_t *) data;
+
+ /*
+ * Build standard header
+ */
+ hdr->code = packet->code;
+
+#ifdef WITH_RADIUSV11
+ if (packet->radiusv11) {
+ uint32_t id = packet->id;
+
+ hdr->id = 0;
+
+ id = htonl(id);
+ memcpy(hdr->vector, &id, sizeof(id));
+ memset(hdr->vector + sizeof(id), 0, sizeof(hdr->vector) - sizeof(id));
+ } else
+#endif
+ {
+ hdr->id = packet->id;
+
+ memcpy(hdr->vector, packet->vector, sizeof(hdr->vector));
+ }
+
+ total_length = RADIUS_HDR_LEN;
+
+ /*
+ * Load up the configuration values for the user
+ */
+ ptr = hdr->data;
+ packet->offset = 0;
+
+ /*
+ * FIXME: Loop twice over the reply list. The first time,
+ * calculate the total length of data. The second time,
+ * allocate the memory, and fill in the VP's.
+ *
+ * Hmm... this may be slower than just doing a small
+ * memcpy.
+ */
+
+ /*
+ * Loop over the reply attributes for the packet.
+ */
+ reply = packet->vps;
+ while (reply) {
+ size_t last_len, room;
+ char const *last_name = NULL;
+
+ VERIFY_VP(reply);
+
+ /*
+ * Ignore non-wire attributes, but allow extended
+ * attributes.
+ */
+ if ((reply->da->vendor == 0) &&
+ ((reply->da->attr & 0xFFFF) >= 256) &&
+ !reply->da->flags.extended && !reply->da->flags.long_extended) {
+#ifndef NDEBUG
+ /*
+ * Permit the admin to send BADLY formatted
+ * attributes with a debug build.
+ */
+ if (reply->da->attr == PW_RAW_ATTRIBUTE) {
+ memcpy(ptr, reply->vp_octets, reply->vp_length);
+ len = reply->vp_length;
+ reply = reply->next;
+ goto next;
+ }
+#endif
+ reply = reply->next;
+ continue;
+ }
+
+#ifdef WITH_RADIUSV11
+ /*
+ * Do not encode Message-Authenticator for RADIUS/1.1
+ */
+ if ((reply->da->vendor == 0) && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
+ reply = reply->next;
+ continue;
+ }
+
+
+ /*
+ * Do not encode Original-Packet-Code for RADIUS/1.1
+ */
+ if (reply->da->vendor == ((unsigned int) PW_EXTENDED_ATTRIBUTE_1 << 24) && (reply->da->attr == 4)) {
+ reply = reply->next;
+ continue;
+ }
+#endif
+
+ /*
+ * We allow zero-length strings in "unlang", but
+ * skip them (except for CUI, thanks WiMAX!) on
+ * all other attributes.
+ */
+ if (reply->vp_length == 0) {
+ if ((reply->da->vendor != 0) ||
+ ((reply->da->attr != PW_CHARGEABLE_USER_IDENTITY) &&
+ (reply->da->attr != PW_MESSAGE_AUTHENTICATOR))) {
+ reply = reply->next;
+ continue;
+ }
+ }
+
+ /*
+ * How much room do we have left?
+ */
+ room = ((uint8_t *) data) + sizeof(data) - ptr;
+
+ /*
+ * Set the Message-Authenticator to the correct
+ * length and initial value.
+ */
+ if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) {
+ reply = reply->next;
+ continue;
+ }
+#endif
+
+ if (room < 18) break;
+
+ /*
+ * Cache the offset to the
+ * Message-Authenticator
+ */
+ packet->offset = total_length;
+ last_len = 16;
+ } else {
+ if (room < (2 + reply->vp_length)) break;
+
+ last_len = reply->vp_length;
+ }
+ last_name = reply->da->name;
+
+ /*
+ * Note that this also checks "room", as the
+ * attribute may be a VSA, etc.
+ */
+ len = rad_vp2attr(packet, original, secret, &reply, ptr, room);
+ if (len < 0) return -1;
+
+ /*
+ * Failed to encode the attribute, likely because
+ * the packet is full.
+ */
+ if (len == 0) {
+ if (last_len != 0) {
+ fr_strerror_printf("WARNING: Failed encoding attribute %s\n", last_name);
+ break;
+ } else {
+ fr_strerror_printf("WARNING: Skipping zero-length attribute %s\n", last_name);
+ }
+ }
+
+#ifndef NDEBUG
+ next: /* Used only for Raw-Attribute */
+#endif
+ ptr += len;
+ total_length += len;
+ } /* done looping over all attributes */
+
+ /*
+ * Fill in the rest of the fields, and copy the data over
+ * from the local stack to the newly allocated memory.
+ *
+ * Yes, all this 'memcpy' is slow, but it means
+ * that we only allocate the minimum amount of
+ * memory for a request.
+ */
+ packet->data_len = total_length;
+ packet->data = talloc_array(packet, uint8_t, packet->data_len);
+ if (!packet->data) {
+ fr_strerror_printf("Out of memory");
+ return -1;
+ }
+
+ memcpy(packet->data, hdr, packet->data_len);
+ hdr = (radius_packet_t *) packet->data;
+
+ total_length = htons(total_length);
+ memcpy(hdr->length, &total_length, sizeof(total_length));
+
+ return 0;
+}
+
+#ifdef WITH_RADIUSV11_ONLY
+#define RADIUSV11_UNUSED UNUSED
+#else
+#define RADIUSV11_UNUSED
+#endif
+
+/** Sign a previously encoded packet
+ *
+ */
+int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ RADIUSV11_UNUSED char const *secret)
+{
+ radius_packet_t *hdr = (radius_packet_t *)packet->data;
+
+ if (!packet->data || (packet->data_len < RADIUS_HDR_LEN) ||
+ (packet->offset < 0)) {
+ fr_strerror_printf("ERROR: You must call rad_encode() before rad_sign()");
+ return -1;
+ }
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) {
+ return 0;
+ }
+#endif
+
+ /*
+ * It wasn't assigned an Id, this is bad!
+ */
+ if (packet->id < 0) {
+ fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id");
+ return -1;
+ }
+
+ /*
+ * Set up the authentication vector with zero, or with
+ * the original vector, prior to signing.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ memset(packet->vector, 0, AUTH_VECTOR_LEN);
+ break;
+
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ if (!original) {
+ fr_strerror_printf("ERROR: Cannot sign response packet without a request packet");
+ return -1;
+ }
+ memcpy(packet->vector, original->vector, AUTH_VECTOR_LEN);
+ break;
+
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ default:
+ break; /* packet->vector is already random bytes */
+ }
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * If there's a Message-Authenticator, update it
+ * now.
+ */
+ if ((packet->offset > 0) && ((size_t) (packet->offset + 18) <= packet->data_len)) {
+ uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
+
+ switch (packet->code) {
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ if (original && original->code == PW_CODE_STATUS_SERVER) {
+ goto do_ack;
+ }
+ /* FALL-THROUGH */
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ memset(hdr->vector, 0, AUTH_VECTOR_LEN);
+ break;
+
+ do_ack:
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Set the authentication vector to zero,
+ * calculate the HMAC, and put it
+ * into the Message-Authenticator
+ * attribute.
+ */
+ fr_hmac_md5(calc_auth_vector, packet->data, packet->data_len,
+ (uint8_t const *) secret, strlen(secret));
+ memcpy(packet->data + packet->offset + 2,
+ calc_auth_vector, AUTH_VECTOR_LEN);
+ }
+#endif /* WITH_RADIUSV11_ONLY */
+
+ /*
+ * Copy the request authenticator over to the packet.
+ */
+ memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
+
+#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * Switch over the packet code, deciding how to
+ * sign the packet.
+ */
+ switch (packet->code) {
+ /*
+ * Request packets are not signed, but
+ * have a random authentication vector.
+ */
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ break;
+
+ /*
+ * Reply packets are signed with the
+ * authentication vector of the request.
+ */
+ default:
+ {
+ uint8_t digest[16];
+
+ FR_MD5_CTX context;
+ fr_md5_init(&context);
+ fr_md5_update(&context, packet->data, packet->data_len);
+ fr_md5_update(&context, (uint8_t const *) secret,
+ strlen(secret));
+ fr_md5_final(digest, &context);
+ fr_md5_destroy(&context);
+
+ memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);
+ memcpy(packet->vector, digest, AUTH_VECTOR_LEN);
+ break;
+ }
+ }/* switch over packet codes */
+#endif /* WITH_RADIUSV11_ONLY */
+
+ return 0;
+}
+
+/** Reply to the request
+ *
+ * Also attach reply attribute value pairs and any user message provided.
+ */
+int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret)
+{
+ /*
+ * Maybe it's a fake packet. Don't send it.
+ */
+ if (!packet || (packet->sockfd < 0)) {
+ return 0;
+ }
+
+ /*
+ * First time through, allocate room for the packet
+ */
+ if (!packet->data) {
+ /*
+ * Encode the packet.
+ */
+ if (rad_encode(packet, original, secret) < 0) {
+ return -1;
+ }
+
+ /*
+ * Re-sign it, including updating the
+ * Message-Authenticator.
+ */
+ if (rad_sign(packet, original, secret) < 0) {
+ return -1;
+ }
+
+ /*
+ * If packet->data points to data, then we print out
+ * the VP list again only for debugging.
+ */
+ }
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+#ifdef WITH_TCP
+ /*
+ * If the socket is TCP, call write(). Calling sendto()
+ * is allowed on some platforms, but it's not nice. Even
+ * worse, if UDPFROMTO is defined, we *can't* use it on
+ * TCP sockets. So... just call write().
+ */
+ if (packet->proto == IPPROTO_TCP) {
+ ssize_t rcode;
+
+ rcode = write(packet->sockfd, packet->data, packet->data_len);
+ if (rcode >= 0) return rcode;
+
+ fr_strerror_printf("sendto failed: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+
+ /*
+ * And send it on it's way.
+ */
+ return rad_sendto(packet->sockfd, packet->data, packet->data_len, 0,
+ &packet->src_ipaddr, packet->src_port,
+ &packet->dst_ipaddr, packet->dst_port);
+}
+
+/** Do a comparison of two authentication digests by comparing the FULL digest
+ *
+ * Otherwise, the server can be subject to timing attacks that allow attackers
+ * find a valid message authenticator.
+ *
+ * http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf
+ */
+int rad_digest_cmp(uint8_t const *a, uint8_t const *b, size_t length)
+{
+ int result = 0;
+ size_t i;
+
+ for (i = 0; i < length; i++) {
+ result |= a[i] ^ b[i];
+ }
+
+ return result; /* 0 is OK, !0 is !OK, just like memcmp */
+}
+
+#ifndef WITH_RADIUSV11_ONLY
+/** Validates the requesting client NAS
+ *
+ * Calculates the request Authenticator based on the clients private key.
+ */
+static int calc_acctdigest(RADIUS_PACKET *packet, char const *secret)
+{
+ uint8_t digest[AUTH_VECTOR_LEN];
+ FR_MD5_CTX context;
+
+ /*
+ * Zero out the auth_vector in the received packet.
+ * Then append the shared secret to the received packet,
+ * and calculate the MD5 sum. This must be the same
+ * as the original MD5 sum (packet->vector).
+ */
+ memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
+
+ /*
+ * MD5(packet + secret);
+ */
+ fr_md5_init(&context);
+ fr_md5_update(&context, packet->data, packet->data_len);
+ fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+ fr_md5_final(digest, &context);
+ fr_md5_destroy(&context);
+
+ /*
+ * Return 0 if OK, 2 if not OK.
+ */
+ if (rad_digest_cmp(digest, packet->vector, AUTH_VECTOR_LEN) != 0) return 2;
+ return 0;
+}
+
+
+/** Validates the requesting client NAS
+ *
+ * Calculates the response Authenticator based on the clients
+ * private key.
+ */
+static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
+ char const *secret)
+{
+ uint8_t calc_digest[AUTH_VECTOR_LEN];
+ FR_MD5_CTX context;
+
+ /*
+ * Very bad!
+ */
+ if (original == NULL) {
+ return 3;
+ }
+
+ /*
+ * Copy the original vector in place.
+ */
+ memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
+
+ /*
+ * MD5(packet + secret);
+ */
+ fr_md5_init(&context);
+ fr_md5_update(&context, packet->data, packet->data_len);
+ fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
+ fr_md5_final(calc_digest, &context);
+ fr_md5_destroy(&context);
+
+ /*
+ * Copy the packet's vector back to the packet.
+ */
+ memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);
+
+ /*
+ * Return 0 if OK, 2 if not OK.
+ */
+ if (rad_digest_cmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) != 0) return 2;
+ return 0;
+}
+#endif /* WITH_RADIUSV11_ONLY */
+
+/** Check if a set of RADIUS formatted TLVs are OK
+ *
+ */
+int rad_tlv_ok(uint8_t const *data, size_t length,
+ size_t dv_type, size_t dv_length)
+{
+ uint8_t const *end = data + length;
+
+ VP_TRACE("checking TLV %u/%u\n", (unsigned int) dv_type, (unsigned int) dv_length);
+
+ VP_HEXDUMP("tlv_ok", data, length);
+
+ if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
+ fr_strerror_printf("rad_tlv_ok: Invalid arguments");
+ return -1;
+ }
+
+ while (data < end) {
+ size_t attrlen;
+
+ if ((data + dv_type + dv_length) > end) {
+ fr_strerror_printf("Attribute header overflow");
+ return -1;
+ }
+
+ switch (dv_type) {
+ case 4:
+ if ((data[0] == 0) && (data[1] == 0) &&
+ (data[2] == 0) && (data[3] == 0)) {
+ zero:
+ fr_strerror_printf("Invalid attribute 0");
+ return -1;
+ }
+
+ if (data[0] != 0) {
+ fr_strerror_printf("Invalid attribute > 2^24");
+ return -1;
+ }
+ break;
+
+ case 2:
+ if ((data[0] == 0) && (data[1] == 0)) goto zero;
+ break;
+
+ case 1:
+ /*
+ * Zero is allowed, because the Colubris
+ * people are dumb and use it.
+ */
+ break;
+
+ default:
+ fr_strerror_printf("Internal sanity check failed");
+ return -1;
+ }
+
+ switch (dv_length) {
+ case 0:
+ return 0;
+
+ case 2:
+ if (data[dv_type] != 0) {
+ fr_strerror_printf("Attribute is longer than 256 octets");
+ return -1;
+ }
+ /* FALL-THROUGH */
+ case 1:
+ attrlen = data[dv_type + dv_length - 1];
+ break;
+
+
+ default:
+ fr_strerror_printf("Internal sanity check failed");
+ return -1;
+ }
+
+ if (attrlen < (dv_type + dv_length)) {
+ fr_strerror_printf("Attribute header has invalid length");
+ return -1;
+ }
+
+ if (attrlen > length) {
+ fr_strerror_printf("Attribute overflows container");
+ return -1;
+ }
+
+ data += attrlen;
+ length -= attrlen;
+ }
+
+ return 0;
+}
+
+
+/** See if the data pointed to by PTR is a valid RADIUS packet.
+ *
+ * Packet is not 'const * const' because we may update data_len, if there's more data
+ * in the UDP packet than in the RADIUS packet.
+ *
+ * @param packet to check
+ * @param flags to control decoding
+ * @param reason if not NULL, will have the failure reason written to where it points.
+ * @return bool, true on success, false on failure.
+ */
+bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
+{
+ uint8_t *attr;
+ size_t totallen;
+ int count;
+ radius_packet_t *hdr;
+ char host_ipaddr[128];
+#ifndef WITH_RADIUSV11_ONLY
+ bool require_ma = false;
+ bool seen_ma = false;
+ bool eap = false;
+ bool non_eap = false;
+#endif
+ uint32_t num_attributes;
+ decode_fail_t failure = DECODE_FAIL_NONE;
+
+ /*
+ * Check for packets smaller than the packet header.
+ *
+ * RFC 2865, Section 3., subsection 'length' says:
+ *
+ * "The minimum length is 20 ..."
+ */
+ if (packet->data_len < RADIUS_HDR_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (received %zu < minimum %d)",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ packet->data_len, RADIUS_HDR_LEN);
+ failure = DECODE_FAIL_MIN_LENGTH_PACKET;
+ goto finish;
+ }
+
+
+ /*
+ * Check for packets with mismatched size.
+ * i.e. We've received 128 bytes, and the packet header
+ * says it's 256 bytes long.
+ */
+ totallen = (packet->data[2] << 8) | packet->data[3];
+ hdr = (radius_packet_t *)packet->data;
+
+ /*
+ * Code of 0 is not understood.
+ * Code of 16 or greate is not understood.
+ */
+ if ((hdr->code == 0) ||
+ (hdr->code >= FR_MAX_PACKET_CODE)) {
+ FR_DEBUG_STRERROR_PRINTF("Bad RADIUS packet from host %s: unknown packet code %d",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ hdr->code);
+ failure = DECODE_FAIL_UNKNOWN_PACKET_CODE;
+ goto finish;
+ }
+
+ /*
+ * Message-Authenticator is required in Status-Server
+ * packets, otherwise they can be trivially forged.
+ */
+ if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true;
+
+ /*
+ * It's also required if the caller asks for it.
+ */
+ if (flags) require_ma = true;
+
+ /*
+ * Repeat the length checks. This time, instead of
+ * looking at the data we received, look at the value
+ * of the 'length' field inside of the packet.
+ *
+ * Check for packets smaller than the packet header.
+ *
+ * RFC 2865, Section 3., subsection 'length' says:
+ *
+ * "The minimum length is 20 ..."
+ */
+ if (totallen < RADIUS_HDR_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (length %zu < minimum %d)",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ totallen, RADIUS_HDR_LEN);
+ failure = DECODE_FAIL_MIN_LENGTH_FIELD;
+ goto finish;
+ }
+
+ /*
+ * And again, for the value of the 'length' field.
+ *
+ * RFC 2865, Section 3., subsection 'length' says:
+ *
+ * " ... and maximum length is 4096."
+ *
+ * HOWEVER. This requirement is for the network layer.
+ * If the code gets here, we assume that a well-formed
+ * packet is an OK packet.
+ *
+ * We allow both the UDP data length, and the RADIUS
+ * "length" field to contain up to 64K of data.
+ */
+
+ /*
+ * RFC 2865, Section 3., subsection 'length' says:
+ *
+ * "If the packet is shorter than the Length field
+ * indicates, it MUST be silently discarded."
+ *
+ * i.e. No response to the NAS.
+ */
+ if (packet->data_len < totallen) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: received %zu octets, packet length says %zu",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ packet->data_len, totallen);
+ failure = DECODE_FAIL_MIN_LENGTH_MISMATCH;
+ goto finish;
+ }
+
+ /*
+ * RFC 2865, Section 3., subsection 'length' says:
+ *
+ * "Octets outside the range of the Length field MUST be
+ * treated as padding and ignored on reception."
+ */
+ if (packet->data_len > totallen) {
+ /*
+ * We're shortening the packet below, but just
+ * to be paranoid, zero out the extra data.
+ */
+ memset(packet->data + totallen, 0, packet->data_len - totallen);
+ packet->data_len = totallen;
+ }
+
+ /*
+ * Walk through the packet's attributes, ensuring that
+ * they add up EXACTLY to the size of the packet.
+ *
+ * If they don't, then the attributes either under-fill
+ * or over-fill the packet. Any parsing of the packet
+ * is impossible, and will result in unknown side effects.
+ *
+ * This would ONLY happen with buggy RADIUS implementations,
+ * or with an intentional attack. Either way, we do NOT want
+ * to be vulnerable to this problem.
+ */
+ attr = hdr->data;
+ count = totallen - RADIUS_HDR_LEN;
+ num_attributes = 0;
+
+ while (count > 0) {
+ /*
+ * We need at least 2 bytes to check the
+ * attribute header.
+ */
+ if (count < 2) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute header overflows the packet",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_HEADER_OVERFLOW;
+ goto finish;
+ }
+
+ /*
+ * Attribute number zero is NOT defined.
+ */
+ if (attr[0] == 0) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Invalid attribute 0",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_INVALID_ATTRIBUTE;
+ goto finish;
+ }
+
+ /*
+ * Attributes are at LEAST as long as the ID & length
+ * fields. Anything shorter is an invalid attribute.
+ */
+ if (attr[1] < 2) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute %u too short",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ attr[0]);
+ failure = DECODE_FAIL_ATTRIBUTE_TOO_SHORT;
+ goto finish;
+ }
+
+ /*
+ * If there are fewer bytes in the packet than in the
+ * attribute, it's a bad packet.
+ */
+ if (count < attr[1]) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: attribute %u data overflows the packet",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ attr[0]);
+ failure = DECODE_FAIL_ATTRIBUTE_OVERFLOW;
+ goto finish;
+ }
+
+#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * Sanity check the attributes for length.
+ */
+ switch (attr[0]) {
+ default: /* don't do anything by default */
+ break;
+
+ /*
+ * If there's an EAP-Message, we require
+ * a Message-Authenticator.
+ */
+ case PW_EAP_MESSAGE:
+ require_ma = true;
+ eap = true;
+ break;
+
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_ARAP_PASSWORD:
+ non_eap = true;
+ break;
+
+ case PW_MESSAGE_AUTHENTICATOR:
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) break;
+#endif
+
+ if (attr[1] != 2 + AUTH_VECTOR_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ attr[1] - 2);
+ failure = DECODE_FAIL_MA_INVALID_LENGTH;
+ goto finish;
+ }
+ seen_ma = true;
+ break;
+ }
+#endif
+
+ /*
+ * FIXME: Look up the base 255 attributes in the
+ * dictionary, and switch over their type. For
+ * integer/date/ip, the attribute length SHOULD
+ * be 6.
+ */
+ count -= attr[1]; /* grab the attribute length */
+ attr += attr[1];
+ num_attributes++; /* seen one more attribute */
+ }
+
+ /*
+ * If the attributes add up to a packet, it's allowed.
+ *
+ * If not, we complain, and throw the packet away.
+ */
+ if (count != 0) {
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_ATTRIBUTE_UNDERFLOW;
+ goto finish;
+ }
+
+ /*
+ * If we're configured to look for a maximum number of
+ * attributes, and we've seen more than that maximum,
+ * then throw the packet away, as a possible DoS.
+ */
+ if ((fr_max_attributes > 0) &&
+ (num_attributes > fr_max_attributes)) {
+ FR_DEBUG_STRERROR_PRINTF("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ num_attributes, fr_max_attributes);
+ failure = DECODE_FAIL_TOO_MANY_ATTRIBUTES;
+ goto finish;
+ }
+
+ /*
+ * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
+ *
+ * A packet with an EAP-Message attribute MUST also have
+ * a Message-Authenticator attribute.
+ *
+ * A Message-Authenticator all by itself is OK, though.
+ *
+ * Similarly, Status-Server packets MUST contain
+ * Message-Authenticator attributes.
+ */
+ if (require_ma &&
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ !packet->radiusv11 &&
+#endif
+ !seen_ma) {
+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_MA_MISSING;
+ goto finish;
+ }
+
+#ifndef WITH_RADIUSV11_ONLY
+ if (eap && non_eap) {
+ FR_DEBUG_STRERROR_PRINTF("Bad packet from host %s: Packet contains EAP-Message and non-EAP authentication attribute",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_TOO_MANY_AUTH;
+ goto finish;
+ }
+#endif
+
+ /*
+ * Fill RADIUS header fields
+ */
+ packet->code = hdr->code;
+ packet->id = hdr->id;
+#ifdef WITH_RADIUSV11
+ if (packet->radiusv11) {
+ uint32_t id;
+
+ memcpy(&id, hdr->vector, sizeof(id));
+ packet->id = ntohl(id);
+ }
+#endif
+ memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
+
+
+ finish:
+
+ if (reason) {
+ *reason = failure;
+ }
+ return (failure == DECODE_FAIL_NONE);
+}
+
+
+/** Receive UDP client requests, and fill in the basics of a RADIUS_PACKET structure
+ *
+ */
+RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags)
+{
+ int sock_flags = 0;
+ ssize_t data_len;
+ RADIUS_PACKET *packet;
+
+ /*
+ * Allocate the new request data structure
+ */
+ packet = rad_alloc(ctx, false);
+ if (!packet) {
+ fr_strerror_printf("out of memory");
+ return NULL;
+ }
+
+ if (flags & 0x02) {
+ sock_flags = MSG_PEEK;
+ flags &= ~0x02;
+ }
+
+ data_len = rad_recvfrom(fd, packet, sock_flags,
+ &packet->src_ipaddr, &packet->src_port,
+ &packet->dst_ipaddr, &packet->dst_port);
+
+ /*
+ * Check for socket errors.
+ */
+ if (data_len < 0) {
+ FR_DEBUG_STRERROR_PRINTF("Error receiving packet: %s", fr_syserror(errno));
+ /* packet->data is NULL */
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * No data read from the network.
+ */
+ if (data_len == 0) {
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * See if it's a well-formed RADIUS packet.
+ */
+ if (!rad_packet_ok(packet, flags, NULL)) {
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * Remember which socket we read the packet from.
+ */
+ packet->sockfd = fd;
+
+ /*
+ * FIXME: Do even more filtering by only permitting
+ * certain IP's. The problem is that we don't know
+ * how to do this properly for all possible clients...
+ */
+
+ /*
+ * Explicitely set the VP list to empty.
+ */
+ packet->vps = NULL;
+
+#ifndef NDEBUG
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
+#endif
+
+ return packet;
+}
+
+
+/** Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet
+ *
+ */
+int rad_verify(RADIUS_PACKET *packet, RADIUSV11_UNUSED RADIUS_PACKET *original, RADIUSV11_UNUSED char const *secret)
+{
+ uint8_t *ptr;
+ int length;
+ int attrlen;
+#ifndef WITH_RADIUSV11_ONLY
+ int rcode;
+#endif
+ char buffer[32];
+
+ if (!packet || !packet->data) return -1;
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) {
+ return 0;
+ }
+#endif
+
+ /*
+ * Before we allocate memory for the attributes, do more
+ * sanity checking.
+ */
+ ptr = packet->data + RADIUS_HDR_LEN;
+ length = packet->data_len - RADIUS_HDR_LEN;
+ while (length > 0) {
+#ifndef WITH_RADIUSV11_ONLY
+ uint8_t msg_auth_vector[AUTH_VECTOR_LEN];
+ uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
+#endif
+
+ attrlen = ptr[1];
+
+#ifndef WITH_RADIUSV11_ONLY
+ switch (ptr[0]) {
+ default: /* don't do anything. */
+ break;
+
+ /*
+ * Note that more than one Message-Authenticator
+ * attribute is invalid.
+ */
+ case PW_MESSAGE_AUTHENTICATOR:
+#ifdef WITH_RADIUSV11
+ /*
+ * Ignore Message-Authenticator for RADIUSV11 packets.
+ */
+ if (packet->radiusv11) break;
+#endif
+
+ memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector));
+ memset(&ptr[2], 0, AUTH_VECTOR_LEN);
+
+ switch (packet->code) {
+ default:
+ break;
+
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ if (original &&
+ (original->code == PW_CODE_STATUS_SERVER)) {
+ goto do_ack;
+ }
+ /* FALL-THROUGH */
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
+ break;
+
+ do_ack:
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ if (!original) {
+ fr_strerror_printf("Cannot validate Message-Authenticator in response "
+ "packet without a request packet");
+ return -1;
+ }
+ memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
+ break;
+ }
+
+ fr_hmac_md5(calc_auth_vector, packet->data, packet->data_len,
+ (uint8_t const *) secret, strlen(secret));
+ if (rad_digest_cmp(calc_auth_vector, msg_auth_vector,
+ sizeof(calc_auth_vector)) != 0) {
+ fr_strerror_printf("Received packet from %s with invalid Message-Authenticator! "
+ "(Shared secret is incorrect.)",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ /* Silently drop packet, according to RFC 3579 */
+ return -1;
+ } /* else the message authenticator was good */
+
+ /*
+ * Reinitialize Authenticators.
+ */
+ memcpy(&ptr[2], msg_auth_vector, AUTH_VECTOR_LEN);
+ memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);
+ break;
+ } /* switch over the attributes */
+#endif /* WITH_RADIUSV11_ONLY */
+
+ ptr += attrlen;
+ length -= attrlen;
+ } /* loop over the packet, sanity checking the attributes */
+
+ /*
+ * It looks like a RADIUS packet, but we don't know what it is
+ * so can't validate the authenticators.
+ */
+ if ((packet->code == 0) || (packet->code >= FR_MAX_PACKET_CODE)) {
+ fr_strerror_printf("Received Unknown packet code %d "
+ "from client %s port %d: Cannot validate Request/Response Authenticator.",
+ packet->code,
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
+ return -1;
+ }
+
+#ifndef WITH_RADIUSV11_ONLY
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) return 0;
+#endif
+
+ /*
+ * Calculate and/or verify Request or Response Authenticator.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ /*
+ * The authentication vector is random
+ * nonsense, invented by the client.
+ */
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (calc_acctdigest(packet, secret) > 1) {
+ fr_strerror_printf("Received %s packet "
+ "from client %s with invalid Request Authenticator! "
+ "(Shared secret is incorrect.)",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ return -1;
+ }
+ break;
+
+ /* Verify the reply digest */
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ rcode = calc_replydigest(packet, original, secret);
+ if (rcode > 1) {
+ fr_strerror_printf("Received %s packet "
+ "from home server %s port %d with invalid Response Authenticator! "
+ "(Shared secret is incorrect.)",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
+ return -1;
+ }
+ break;
+
+ default:
+ fr_strerror_printf("Received Unknown packet code %d "
+ "from client %s port %d: Cannot validate Request/Response Authenticator",
+ packet->code,
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+/** Convert one or more NAS-Filter-Rule attributes to one or more
+ * attributes.
+ *
+ */
+static ssize_t data2vp_nas_filter_rule(TALLOC_CTX *ctx,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const packetlen, VALUE_PAIR **pvp)
+{
+ uint8_t const *p = start;
+ uint8_t const *attr = start;
+ uint8_t const *end = start + packetlen;
+ uint8_t const *attr_end;
+ uint8_t *q;
+ VALUE_PAIR *vp;
+ uint8_t buffer[253];
+
+ q = buffer;
+
+ /*
+ * The packet has already been sanity checked, so we
+ * don't care about walking off of the end of it.
+ */
+ while (attr < end) {
+ if ((attr + 2) > end) {
+ fr_strerror_printf("decode NAS-Filter-Rule: Failure (1) to call rad_packet_ok");
+ return -1;
+ }
+
+ if (attr[1] < 2) {
+ fr_strerror_printf("decode NAS-Filter-Rule: Failure (2) to call rad_packet_ok");
+ return -1;
+ }
+ if (attr[0] != PW_NAS_FILTER_RULE) break;
+
+ /*
+ * Now decode one, or part of one rule.
+ */
+ p = attr + 2;
+ attr_end = attr + attr[1];
+
+ if (attr_end > end) {
+ fr_strerror_printf("decode NAS-Filter-Rule: Failure (3) to call rad_packet_ok");
+ return -1;
+ }
+
+ /*
+ * Coalesce data until the zero byte.
+ */
+ while (p < attr_end) {
+ /*
+ * Once we hit the zero byte, create the
+ * VP, skip the zero byte, and reset the
+ * counters.
+ */
+ if (*p == 0) {
+ /*
+ * Discard consecutive zeroes.
+ */
+ if (q > buffer) {
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_strerror_printf("decode NAS-Filter-Rule: Out of memory");
+ return -1;
+ }
+
+ fr_pair_value_bstrncpy(vp, buffer, q - buffer);
+
+ *pvp = vp;
+ pvp = &(vp->next);
+ q = buffer;
+ }
+
+ p++;
+ continue;
+ }
+ *(q++) = *(p++);
+
+ /*
+ * Not much reason to have rules which
+ * are too long.
+ */
+ if ((size_t) (q - buffer) > sizeof(buffer)) {
+ fr_strerror_printf("decode NAS-Filter-Rule: decoded attribute is too long");
+ return -1;
+ }
+ }
+
+ /*
+ * Done this attribute. There MAY be things left
+ * in the buffer.
+ */
+ attr = attr_end;
+ }
+
+ if (q == buffer) return attr + attr[2] - start;
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_strerror_printf("decode NAS-Filter-Rule: Out of memory");
+ return -1;
+ }
+
+ fr_pair_value_bstrncpy(vp, buffer, q - buffer);
+
+ *pvp = vp;
+
+ return p - start;
+}
+
+/** Convert a "concatenated" attribute to one long VP
+ *
+ */
+static ssize_t data2vp_concat(TALLOC_CTX *ctx,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const packetlen, VALUE_PAIR **pvp)
+{
+ size_t total;
+ uint8_t attr;
+ uint8_t const *ptr = start;
+ uint8_t const *end = start + packetlen;
+ uint8_t *p;
+ VALUE_PAIR *vp;
+
+ total = 0;
+ attr = ptr[0];
+
+ /*
+ * The packet has already been sanity checked, so we
+ * don't care about walking off of the end of it.
+ */
+ while (ptr < end) {
+ if (ptr[1] < 2) return -1;
+ if ((ptr + ptr[1]) > end) return -1;
+
+ total += ptr[1] - 2;
+
+ ptr += ptr[1];
+
+ if (ptr == end) break;
+
+ /*
+ * Attributes MUST be consecutive.
+ */
+ if (ptr[0] != attr) break;
+ }
+
+ end = ptr;
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return -1;
+
+ vp->vp_length = total;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+ if (!p) {
+ fr_pair_list_free(&vp);
+ return -1;
+ }
+
+ total = 0;
+ ptr = start;
+ while (ptr < end) {
+ memcpy(p, ptr + 2, ptr[1] - 2);
+ p += ptr[1] - 2;
+ total += ptr[1] - 2;
+ ptr += ptr[1];
+ }
+
+ *pvp = vp;
+
+ return ptr - start;
+}
+
+
+/** Convert TLVs to one or more VPs
+ *
+ */
+ssize_t rad_data2vp_tlvs(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret, DICT_ATTR const *da,
+ uint8_t const *start, size_t length,
+ VALUE_PAIR **pvp)
+{
+ uint8_t const *data = start;
+ DICT_ATTR const *child;
+ VALUE_PAIR *head, **tail;
+
+ if (length < 3) return -1; /* type, length, value */
+
+ VP_HEXDUMP("tlvs", data, length);
+
+ if (rad_tlv_ok(data, length, 1, 1) < 0) return -1;
+
+ head = NULL;
+ tail = &head;
+
+ while (data < (start + length)) {
+ ssize_t tlv_len;
+
+ child = dict_attrbyparent(da, data[0], da->vendor);
+ if (!child) {
+ unsigned int my_attr, my_vendor;
+
+ VP_TRACE("Failed to find child %u of TLV %s\n",
+ data[0], da->name);
+
+ /*
+ * Get child attr/vendor so that
+ * we can call unknown attr.
+ */
+ my_attr = data[0];
+ my_vendor = da->vendor;
+
+ if (!dict_attr_child(da, &my_attr, &my_vendor)) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ child = dict_unknown_afrom_fields(ctx, my_attr, my_vendor);
+ if (!child) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ }
+
+ tlv_len = data2vp(ctx, packet, original, secret, child,
+ data + 2, data[1] - 2, data[1] - 2, tail);
+ if (tlv_len < 0) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ if (*tail) tail = &((*tail)->next);
+ data += data[1];
+ }
+
+ *pvp = head;
+ return length;
+}
+
+/** Convert a top-level VSA to a VP.
+ *
+ * "length" can be LONGER than just this sub-vsa.
+ */
+static ssize_t data2vp_vsa(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, DICT_VENDOR *dv,
+ uint8_t const *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ unsigned int attribute;
+ ssize_t attrlen, my_len;
+ DICT_ATTR const *da;
+
+ VP_TRACE("data2vp_vsa: length %u\n", (unsigned int) length);
+
+#ifndef NDEBUG
+ if (length <= (dv->type + dv->length)) {
+ fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
+ return -1;
+ }
+#endif
+
+ switch (dv->type) {
+ case 4:
+ /* data[0] must be zero */
+ attribute = data[1] << 16;
+ attribute |= data[2] << 8;
+ attribute |= data[3];
+ break;
+
+ case 2:
+ attribute = data[0] << 8;
+ attribute |= data[1];
+ break;
+
+ case 1:
+ attribute = data[0];
+ break;
+
+ default:
+ fr_strerror_printf("data2vp_vsa: Internal sanity check failed");
+ return -1;
+ }
+
+ switch (dv->length) {
+ case 2:
+ /* data[dv->type] must be zero, from rad_tlv_ok() */
+ attrlen = data[dv->type + 1];
+ break;
+
+ case 1:
+ attrlen = data[dv->type];
+ break;
+
+ case 0:
+ attrlen = length;
+ break;
+
+ default:
+ fr_strerror_printf("data2vp_vsa: Internal sanity check failed");
+ return -1;
+ }
+
+ /*
+ * See if the VSA is known.
+ */
+ da = dict_attrbyvalue(attribute, dv->vendorpec);
+ if (!da) da = dict_unknown_afrom_fields(ctx, attribute, dv->vendorpec);
+ if (!da) return -1;
+
+ my_len = data2vp(ctx, packet, original, secret, da,
+ data + dv->type + dv->length,
+ attrlen - (dv->type + dv->length),
+ attrlen - (dv->type + dv->length),
+ pvp);
+ if (my_len < 0) return my_len;
+
+ return attrlen;
+}
+
+
+/** Convert a fragmented extended attr to a VP
+ *
+ * Format is:
+ *
+ * attr
+ * length
+ * extended-attr
+ * flag
+ * data...
+ *
+ * But for the first fragment, we get passed a pointer to the "extended-attr"
+ */
+static ssize_t data2vp_extended(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, DICT_ATTR const *da,
+ uint8_t const *data,
+ size_t attrlen, size_t packetlen,
+ VALUE_PAIR **pvp)
+{
+ ssize_t rcode;
+ size_t ext_len;
+ bool more;
+ uint8_t *head, *tail;
+ uint8_t const *attr, *end;
+ DICT_ATTR const *child;
+
+ /*
+ * data = Ext-Attr Flag ...
+ */
+
+ /*
+ * Not enough room for Ext-Attr + Flag + data, it's a bad
+ * attribute.
+ */
+ if (attrlen < 3) {
+ raw:
+ /*
+ * It's not an Extended attribute, it's unknown...
+ */
+ child = dict_unknown_afrom_fields(ctx, (da->vendor/ FR_MAX_VENDOR) & 0xff, 0);
+ if (!child) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data, attrlen, attrlen, pvp);
+ if (rcode < 0) return rcode;
+ return attrlen;
+ }
+
+ /*
+ * No continued data, just decode the attribute in place.
+ */
+ if ((data[1] & 0x80) == 0) {
+ rcode = data2vp(ctx, packet, original, secret, da,
+ data + 2, attrlen - 2, attrlen - 2,
+ pvp);
+
+ if ((rcode < 0) || (((size_t) rcode + 2) != attrlen)) goto raw; /* didn't decode all of the data */
+ return attrlen;
+ }
+
+ /*
+ * It's continued, but there are no subsequent fragments,
+ * it's bad.
+ */
+ if (attrlen >= packetlen) goto raw;
+
+ /*
+ * Calculate the length of all of the fragments. For
+ * now, they MUST be contiguous in the packet, and they
+ * MUST be all of the same Type and Ext-Type
+ *
+ * We skip the first fragment, which doesn't have a
+ * RADIUS attribute header.
+ */
+ ext_len = attrlen - 2;
+ attr = data + attrlen;
+ end = data + packetlen;
+
+ while (attr < end) {
+ /*
+ * Not enough room for Attr + length + Ext-Attr
+ * continuation, it's bad.
+ */
+ if ((end - attr) < 4) goto raw;
+
+ if (attr[1] < 4) goto raw;
+
+ /*
+ * If the attribute overflows the packet, it's
+ * bad.
+ */
+ if ((attr + attr[1]) > end) goto raw;
+
+ if (attr[0] != ((da->vendor / FR_MAX_VENDOR) & 0xff)) goto raw; /* not the same Extended-Attribute-X */
+
+ if (attr[2] != data[0]) goto raw; /* Not the same Ext-Attr */
+
+ /*
+ * Check the continuation flag.
+ */
+ more = ((attr[2] & 0x80) != 0);
+
+ /*
+ * Or, there's no more data, in which case we
+ * shorten "end" to finish at this attribute.
+ */
+ if (!more) end = attr + attr[1];
+
+ /*
+ * There's more data, but we're at the end of the
+ * packet. The attribute is malformed!
+ */
+ if (more && ((attr + attr[1]) == end)) goto raw;
+
+ /*
+ * Add in the length of the data we need to
+ * concatenate together.
+ */
+ ext_len += attr[1] - 4;
+
+ /*
+ * Go to the next attribute, and stop if there's
+ * no more.
+ */
+ attr += attr[1];
+ if (!more) break;
+ }
+
+ if (!ext_len) goto raw;
+
+ head = tail = malloc(ext_len);
+ if (!head) goto raw;
+
+ /*
+ * Copy the data over, this time trusting the attribute
+ * contents.
+ */
+ attr = data;
+ memcpy(tail, attr + 2, attrlen - 2);
+ tail += attrlen - 2;
+ attr += attrlen;
+
+ while (attr < end) {
+ if (attr[1] > 4) memcpy(tail, attr + 4, attr[1] - 4);
+ tail += attr[1] - 4;
+ attr += attr[1]; /* skip VID+WiMax header */
+ }
+
+ VP_HEXDUMP("long-extended fragments", head, ext_len);
+
+ rcode = data2vp(ctx, packet, original, secret, da,
+ head, ext_len, ext_len, pvp);
+ free(head);
+ if (rcode < 0) goto raw;
+
+ return end - data;
+}
+
+/** Convert a Vendor-Specific WIMAX to VPs
+ *
+ * @note Called ONLY for Vendor-Specific
+ */
+static ssize_t data2vp_wimax(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret, uint32_t vendor,
+ uint8_t const *data,
+ size_t attrlen, size_t packetlen,
+ VALUE_PAIR **pvp)
+{
+ ssize_t rcode;
+ size_t wimax_len;
+ bool more;
+ uint8_t *head, *tail;
+ uint8_t const *attr, *end;
+ DICT_ATTR const *child;
+
+ /*
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ */
+
+ /*
+ * Not enough room for WiMAX Vendor + Wimax attr + length
+ * + continuation, it's a bad attribute.
+ */
+ if (attrlen < 8) {
+ raw:
+ /*
+ * It's not a Vendor-Specific, it's unknown...
+ */
+ child = dict_unknown_afrom_fields(ctx, PW_VENDOR_SPECIFIC, 0);
+ if (!child) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data, attrlen, attrlen, pvp);
+ if (rcode < 0) return rcode;
+ return attrlen;
+ }
+
+ if (data[5] < 3) goto raw; /* WiMAX-Length is too small */
+
+ child = dict_attrbyvalue(data[4], vendor);
+ if (!child) goto raw;
+
+ /*
+ * No continued data, just decode the attribute in place.
+ */
+ if ((data[6] & 0x80) == 0) {
+ if (((size_t) (data[5] + 4)) != attrlen) goto raw; /* WiMAX attribute doesn't fill Vendor-Specific */
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data + 7, data[5] - 3, data[5] - 3,
+ pvp);
+
+ if ((rcode < 0) || (((size_t) rcode + 7) != attrlen)) goto raw; /* didn't decode all of the data */
+ return attrlen;
+ }
+
+ /*
+ * Calculate the length of all of the fragments. For
+ * now, they MUST be contiguous in the packet, and they
+ * MUST be all of the same VSA, WiMAX, and WiMAX-attr.
+ *
+ * The first fragment doesn't have a RADIUS attribute
+ * header.
+ */
+ wimax_len = 0;
+ attr = data + 4;
+ end = data + packetlen;
+
+ while (attr < end) {
+ /*
+ * Not enough room for Attribute + length +
+ * continuation, it's bad.
+ */
+ if ((end - attr) < 3) goto raw;
+
+ /*
+ * Must have non-zero data in the attribute.
+ */
+ if (attr[1] <= 3) goto raw;
+
+ /*
+ * If the WiMAX attribute overflows the packet,
+ * it's bad.
+ */
+ if ((attr + attr[1]) > end) goto raw;
+
+ /*
+ * Check the continuation flag.
+ */
+ more = ((attr[2] & 0x80) != 0);
+
+ /*
+ * Or, there's no more data, in which case we
+ * shorten "end" to finish at this attribute.
+ */
+ if (!more) end = attr + attr[1];
+
+ /*
+ * There's more data, but we're at the end of the
+ * packet. The attribute is malformed!
+ */
+ if (more && ((attr + attr[1]) == end)) goto raw;
+
+ /*
+ * Add in the length of the data we need to
+ * concatenate together.
+ */
+ wimax_len += attr[1] - 3;
+
+ /*
+ * Go to the next attribute, and stop if there's
+ * no more.
+ */
+ attr += attr[1];
+ if (!more) break;
+
+ /*
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ *
+ * attr = Vendor-Specific VSA-Length VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ *
+ */
+
+ /*
+ * No room for Vendor-Specific + length +
+ * Vendor(4) + attr + length + continuation + data
+ */
+ if ((end - attr) < 9) goto raw;
+
+ if (attr[0] != PW_VENDOR_SPECIFIC) goto raw;
+ if (attr[1] < 9) goto raw;
+ if ((attr + attr[1]) > end) goto raw;
+ if (memcmp(data, attr + 2, 4) != 0) goto raw; /* not WiMAX Vendor ID */
+
+ if (attr[1] != (attr[7] + 6)) goto raw; /* WiMAX attr doesn't exactly fill the VSA */
+
+ if (data[4] != attr[6]) goto raw; /* different WiMAX attribute */
+
+ /*
+ * Skip over the Vendor-Specific header, and
+ * continue with the WiMAX attributes.
+ */
+ attr += 6;
+ }
+
+ /*
+ * No data in the WiMAX attribute, make a "raw" one.
+ */
+ if (!wimax_len) goto raw;
+
+ head = tail = malloc(wimax_len);
+ if (!head) return -1;
+
+ /*
+ * Copy the data over, this time trusting the attribute
+ * contents.
+ */
+ attr = data;
+ while (attr < end) {
+ memcpy(tail, attr + 4 + 3, attr[4 + 1] - 3);
+ tail += attr[4 + 1] - 3;
+ attr += 4 + attr[4 + 1]; /* skip VID+WiMax header */
+ attr += 2; /* skip Vendor-Specific header */
+ }
+
+ VP_HEXDUMP("wimax fragments", head, wimax_len);
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ head, wimax_len, wimax_len, pvp);
+ free(head);
+ if (rcode < 0) goto raw;
+
+ return end - data;
+}
+
+
+/** Convert a top-level VSA to one or more VPs
+ *
+ */
+static ssize_t data2vp_vsas(TALLOC_CTX *ctx, RADIUS_PACKET *packet,
+ RADIUS_PACKET const *original,
+ char const *secret, uint8_t const *data,
+ size_t attrlen, size_t packetlen,
+ VALUE_PAIR **pvp)
+{
+ size_t total;
+ ssize_t rcode;
+ uint32_t vendor;
+ DICT_VENDOR *dv;
+ VALUE_PAIR *head, **tail;
+ DICT_VENDOR my_dv;
+
+ if (attrlen > packetlen) return -1;
+ if (attrlen < 5) return -1; /* vid, value */
+ if (data[0] != 0) return -1; /* we require 24-bit VIDs */
+
+ VP_TRACE("data2vp_vsas\n");
+
+ memcpy(&vendor, data, 4);
+ vendor = ntohl(vendor);
+ dv = dict_vendorbyvalue(vendor);
+ if (!dv) {
+ /*
+ * RFC format is 1 octet type, 1 octet length
+ */
+ if (rad_tlv_ok(data + 4, attrlen - 4, 1, 1) < 0) {
+ VP_TRACE("data2vp_vsas: unknown tlvs not OK: %s\n", fr_strerror());
+ return -1;
+ }
+
+ /*
+ * It's a known unknown.
+ */
+ memset(&my_dv, 0, sizeof(my_dv));
+ dv = &my_dv;
+
+ /*
+ * Fill in the fields. Note that the name is empty!
+ */
+ dv->vendorpec = vendor;
+ dv->type = 1;
+ dv->length = 1;
+
+ goto create_attrs;
+ }
+
+ /*
+ * WiMAX craziness
+ */
+ if (dv->flags) {
+ rcode = data2vp_wimax(ctx, packet, original, secret, vendor,
+ data, attrlen, packetlen, pvp);
+ return rcode;
+ }
+
+ /*
+ * VSAs should normally be in TLV format.
+ */
+ if (rad_tlv_ok(data + 4, attrlen - 4,
+ dv->type, dv->length) < 0) {
+ VP_TRACE("data2vp_vsas: tlvs not OK: %s\n", fr_strerror());
+ return -1;
+ }
+
+ /*
+ * There may be more than one VSA in the
+ * Vendor-Specific. If so, loop over them all.
+ */
+create_attrs:
+ data += 4;
+ attrlen -= 4;
+ packetlen -= 4;
+ total = 4;
+ head = NULL;
+ tail = &head;
+
+ while (attrlen > 0) {
+ ssize_t vsa_len;
+
+ vsa_len = data2vp_vsa(ctx, packet, original, secret, dv,
+ data, attrlen, tail);
+ if (vsa_len < 0) {
+ fr_pair_list_free(&head);
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+ /*
+ * Vendors can send zero-length VSAs.
+ */
+ if (*tail) tail = &((*tail)->next);
+
+ data += vsa_len;
+ attrlen -= vsa_len;
+ packetlen -= vsa_len;
+ total += vsa_len;
+ }
+
+ *pvp = head;
+ return total;
+}
+
+/** Create any kind of VP from the attribute contents
+ *
+ * "length" is AT LEAST the length of this attribute, as we
+ * expect the caller to have verified the data with
+ * rad_packet_ok(). "length" may be up to the length of the
+ * packet.
+ *
+ * @return -1 on error, or "length".
+ */
+ssize_t data2vp(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ DICT_ATTR const *da, uint8_t const *start,
+ size_t const attrlen, size_t const packetlen,
+ VALUE_PAIR **pvp)
+{
+ int8_t tag = TAG_NONE;
+ size_t datalen;
+ ssize_t rcode;
+ uint32_t vendor;
+ DICT_ATTR const *child;
+ VALUE_PAIR *vp;
+ uint8_t const *data = start;
+ char *p;
+ uint8_t buffer[256];
+
+ /*
+ * FIXME: Attrlen can be larger than 253 for extended attrs!
+ */
+ if (!da || (attrlen > packetlen) ||
+ ((attrlen > 253) && (attrlen != packetlen)) ||
+ (attrlen > 128*1024)) {
+ fr_strerror_printf("data2vp: invalid arguments");
+ return -1;
+ }
+
+ VP_HEXDUMP("data2vp", start, attrlen);
+
+ VP_TRACE("parent %s len %zu ... %zu\n", da->name, attrlen, packetlen);
+
+ datalen = attrlen;
+
+ /*
+ * Hacks for CUI. The WiMAX spec says that it can be
+ * zero length, even though this is forbidden by the
+ * RADIUS specs. So... we make a special case for it.
+ */
+ if (attrlen == 0) {
+ if (!((da->vendor == 0) &&
+ (da->attr == PW_CHARGEABLE_USER_IDENTITY))) {
+ *pvp = NULL;
+ return 0;
+ }
+
+ /*
+ * Create a zero-length attribute.
+ */
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return -1;
+ goto done;
+ }
+
+ /*
+ * Hacks for tags. If the attribute is capable of
+ * encoding a tag, and there's room for the tag, and
+ * there is a tag, or it's encrypted with Tunnel-Password,
+ * then decode the tag.
+ */
+ if (da->flags.has_tag && (datalen > 1) &&
+ ((data[0] < 0x20)
+#ifndef WITH_RADIUSV11_ONLY
+ || (da->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD)
+#endif
+ )) {
+
+ /*
+ * Only "short" attributes can be encrypted.
+ */
+ if (datalen >= sizeof(buffer)) return -1;
+
+ if (da->type == PW_TYPE_STRING) {
+ memcpy(buffer, data + 1, datalen - 1);
+ tag = data[0];
+ datalen -= 1;
+
+ } else if (da->type == PW_TYPE_INTEGER) {
+ memcpy(buffer, data, attrlen);
+ tag = buffer[0];
+ buffer[0] = 0;
+
+ } else {
+ return -1; /* only string and integer can have tags */
+ }
+
+ data = buffer;
+ }
+
+#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * Decrypt the attribute.
+ */
+ if (secret && packet &&
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encrypt any attributes.
+ */
+ !packet->radiusv11 &&
+#endif
+
+ (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
+ VP_TRACE("data2vp: decrypting type %u\n", da->flags.encrypt);
+ /*
+ * Encrypted attributes can only exist for the
+ * old-style format. Extended attributes CANNOT
+ * be encrypted.
+ */
+ if (attrlen > 253) {
+ return -1;
+ }
+
+ if (data == start) {
+ memcpy(buffer, data, attrlen);
+ }
+ data = buffer;
+
+ switch (da->flags.encrypt) { /* can't be tagged */
+ /*
+ * User-Password
+ */
+ case FLAG_ENCRYPT_USER_PASSWORD:
+ if (original) {
+ rad_pwdecode((char *) buffer,
+ attrlen, secret,
+ original->vector);
+ } else {
+ rad_pwdecode((char *) buffer,
+ attrlen, secret,
+ packet->vector);
+ }
+ buffer[253] = '\0';
+
+ /*
+ * MS-CHAP-MPPE-Keys are 24 octets, and
+ * encrypted. Since it's binary, we can't
+ * look for trailing zeros.
+ */
+ if (da->flags.length) {
+ if (datalen > da->flags.length) {
+ datalen = da->flags.length;
+ } /* else leave datalen alone */
+ } else {
+ /*
+ * Take off trailing zeros from the END.
+ * This allows passwords to have zeros in
+ * the middle of a field.
+ *
+ * However, if the password has a zero at
+ * the end, it will get mashed by this
+ * code. There's really no way around
+ * that.
+ */
+ while ((datalen > 0) && (buffer[datalen - 1] == '\0')) datalen--;
+ }
+ break;
+
+ /*
+ * Tunnel-Password's may go ONLY in response
+ * packets. They can have a tag, so datalen is
+ * not the same as attrlen.
+ */
+ case FLAG_ENCRYPT_TUNNEL_PASSWORD:
+ if (rad_tunnel_pwdecode(buffer, &datalen, secret,
+ original ? original->vector : nullvector) < 0) {
+ goto raw;
+ }
+ break;
+
+ /*
+ * Ascend-Send-Secret
+ * Ascend-Receive-Secret
+ */
+ case FLAG_ENCRYPT_ASCEND_SECRET:
+ if (!original) {
+ goto raw;
+ } else {
+ uint8_t my_digest[AUTH_VECTOR_LEN];
+ size_t secret_len;
+
+ secret_len = datalen;
+ if (secret_len > AUTH_VECTOR_LEN) secret_len = AUTH_VECTOR_LEN;
+
+ make_secret(my_digest,
+ original->vector,
+ secret, data, secret_len);
+ memcpy(buffer, my_digest,
+ AUTH_VECTOR_LEN );
+ buffer[AUTH_VECTOR_LEN] = '\0';
+ datalen = strlen((char *) buffer);
+ }
+ break;
+
+ default:
+ break;
+ } /* switch over encryption flags */
+ }
+#endif /* WITH_RADIUSV11_ONLY */
+
+ /*
+ * Double-check the length after decrypting the
+ * attribute.
+ */
+ VP_TRACE("data2vp: type %u\n", da->type);
+ switch (da->type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ break;
+
+ case PW_TYPE_ABINARY:
+ if (datalen > sizeof(vp->vp_filter)) goto raw;
+ break;
+
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_DATE:
+ case PW_TYPE_SIGNED:
+ if (datalen != 4) goto raw;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ case PW_TYPE_IFID:
+ if (datalen != 8) goto raw;
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ if (datalen != 16) goto raw;
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if ((datalen < 2) || (datalen > 18)) goto raw;
+ if (data[1] > 128) goto raw;
+ break;
+
+ case PW_TYPE_BYTE:
+ if (datalen != 1) goto raw;
+ break;
+
+ case PW_TYPE_SHORT:
+ if (datalen != 2) goto raw;
+ break;
+
+ case PW_TYPE_ETHERNET:
+ if (datalen != 6) goto raw;
+ break;
+
+ case PW_TYPE_COMBO_IP_ADDR:
+ if (datalen == 4) {
+ child = dict_attrbytype(da->attr, da->vendor,
+ PW_TYPE_IPV4_ADDR);
+ } else if (datalen == 16) {
+ child = dict_attrbytype(da->attr, da->vendor,
+ PW_TYPE_IPV6_ADDR);
+ } else {
+ goto raw;
+ }
+ if (!child) goto raw;
+ da = child; /* re-write it */
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ if (datalen != 6) goto raw;
+ if ((data[1] & 0x3f) > 32) goto raw;
+ break;
+
+ /*
+ * The rest of the data types can cause
+ * recursion! Ask yourself, "is recursion OK?"
+ */
+
+ case PW_TYPE_EXTENDED:
+ if (datalen < 2) goto raw; /* etype, value */
+
+ child = dict_attrbyparent(da, data[0], 0);
+ if (!child) goto raw;
+
+ /*
+ * Recurse to decode the contents, which could be
+ * a TLV, IPaddr, etc. Note that we decode only
+ * the current attribute, and we ignore any extra
+ * data after it.
+ */
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data + 1, attrlen - 1, attrlen - 1, pvp);
+ if (rcode < 0) goto raw;
+ return 1 + rcode;
+
+ case PW_TYPE_LONG_EXTENDED:
+ if (datalen < 3) goto raw; /* etype, flags, value */
+
+ child = dict_attrbyparent(da, data[0], 0);
+ if (!child) {
+ if ((data[0] != PW_VENDOR_SPECIFIC) ||
+ (datalen < (3 + 4 + 1))) {
+ /* da->attr < 255, da->vendor == 0 */
+ child = dict_unknown_afrom_fields(ctx, data[0], da->attr * FR_MAX_VENDOR);
+ } else {
+ /*
+ * Try to find the VSA.
+ */
+ memcpy(&vendor, data + 3, 4);
+ vendor = ntohl(vendor);
+
+ if (vendor == 0) goto raw;
+
+ child = dict_unknown_afrom_fields(ctx, data[7], vendor | (da->attr * FR_MAX_VENDOR));
+ }
+
+ if (!child) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+ }
+
+ /*
+ * This requires a whole lot more work.
+ */
+ return data2vp_extended(ctx, packet, original, secret, child,
+ start, attrlen, packetlen, pvp);
+
+ case PW_TYPE_EVS:
+ if (datalen < 6) goto raw; /* vid, vtype, value */
+
+ if (data[0] != 0) goto raw; /* we require 24-bit VIDs */
+
+ memcpy(&vendor, data, 4);
+ vendor = ntohl(vendor);
+ vendor |= da->vendor;
+
+ child = dict_attrbyvalue(data[4], vendor);
+ if (!child) {
+ /*
+ * Create a "raw" attribute from the
+ * contents of the EVS VSA.
+ */
+ da = dict_unknown_afrom_fields(ctx, data[4], vendor);
+ data += 5;
+ datalen -= 5;
+ break;
+ }
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data + 5, attrlen - 5, attrlen - 5, pvp);
+ if (rcode < 0) goto raw;
+ return 5 + rcode;
+
+ case PW_TYPE_TLV:
+ /*
+ * We presume that the TLVs all fit into one
+ * attribute, OR they've already been grouped
+ * into a contiguous memory buffer.
+ */
+ rcode = rad_data2vp_tlvs(ctx, packet, original, secret, da,
+ data, attrlen, pvp);
+ if (rcode < 0) goto raw;
+ return rcode;
+
+ case PW_TYPE_VSA:
+ /*
+ * VSAs can be WiMAX, in which case they don't
+ * fit into one attribute.
+ */
+ rcode = data2vp_vsas(ctx, packet, original, secret,
+ data, attrlen, packetlen, pvp);
+ if (rcode < 0) goto raw;
+ return rcode;
+
+ default:
+ raw:
+ /*
+ * If it's already unknown, don't create a new
+ * unknown one.
+ */
+ if (da->flags.is_unknown) break;
+
+ /*
+ * Re-write the attribute to be "raw". It is
+ * therefore of type "octets", and will be
+ * handled below.
+ *
+ * We allocate the VP *first*, and then the da
+ * from it, so that there are no memory leaks.
+ */
+ vp = fr_pair_alloc(ctx);
+ if (!vp) return -1;
+
+ da = dict_unknown_afrom_fields(vp, da->attr, da->vendor);
+ if (!da) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+ tag = TAG_NONE;
+ vp->da = da;
+ goto alloc_raw;
+ }
+
+ /*
+ * And now that we've verified the basic type
+ * information, decode the actual data.
+ */
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return -1;
+
+alloc_raw:
+ vp->vp_length = datalen;
+ vp->tag = tag;
+
+ switch (da->type) {
+ case PW_TYPE_STRING:
+ p = talloc_array(vp, char, vp->vp_length + 1);
+#ifdef __clang_analyzer__
+ if (!p) goto fail;
+#endif
+ memcpy(p, data, vp->vp_length);
+ p[vp->vp_length] = '\0';
+ vp->vp_strvalue = p;
+ break;
+
+ case PW_TYPE_OCTETS:
+ fr_pair_value_memcpy(vp, data, vp->vp_length);
+ break;
+
+ case PW_TYPE_ABINARY:
+ if (vp->vp_length > sizeof(vp->vp_filter)) {
+ vp->vp_length = sizeof(vp->vp_filter);
+ }
+ memcpy(vp->vp_filter, data, vp->vp_length);
+ break;
+
+ case PW_TYPE_BYTE:
+ vp->vp_byte = data[0];
+ break;
+
+ case PW_TYPE_SHORT:
+ vp->vp_short = (data[0] << 8) | data[1];
+ break;
+
+ case PW_TYPE_INTEGER:
+ memcpy(&vp->vp_integer, data, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ memcpy(&vp->vp_integer64, data, 8);
+ vp->vp_integer64 = ntohll(vp->vp_integer64);
+ break;
+
+ case PW_TYPE_DATE:
+ memcpy(&vp->vp_date, data, 4);
+ vp->vp_date = ntohl(vp->vp_date);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(vp->vp_ether, data, 6);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(&vp->vp_ipaddr, data, 4);
+ break;
+
+ case PW_TYPE_IFID:
+ memcpy(vp->vp_ifid, data, 8);
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ memcpy(&vp->vp_ipv6addr, data, 16);
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ /*
+ * FIXME: double-check that
+ * (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
+ */
+ memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
+ if (vp->vp_length < 18) {
+ memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
+ 18 - vp->vp_length);
+ }
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ /* FIXME: do the same double-check as for IPv6Prefix */
+ memcpy(vp->vp_ipv4prefix, data, vp->vp_length);
+
+ /*
+ * /32 means "keep all bits". Otherwise, mask
+ * them out.
+ */
+ if ((data[1] & 0x3f) > 32) {
+ uint32_t addr, mask;
+
+ memcpy(&addr, vp->vp_octets + 2, sizeof(addr));
+ mask = 1;
+ mask <<= (32 - (data[1] & 0x3f));
+ mask--;
+ mask = ~mask;
+ mask = htonl(mask);
+ addr &= mask;
+ memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
+ }
+ break;
+
+ case PW_TYPE_SIGNED: /* overloaded with vp_integer */
+ memcpy(&vp->vp_integer, data, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+#ifdef __clang_analyzer__
+ fail:
+#endif
+ default:
+ fr_pair_list_free(&vp);
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+done:
+ vp->type = VT_DATA;
+ *pvp = vp;
+
+ return attrlen;
+}
+
+
+/** Create a "normal" VALUE_PAIR from the given data
+ *
+ */
+ssize_t rad_attr2vp(TALLOC_CTX *ctx,
+ RADIUS_PACKET *packet, RADIUS_PACKET const *original,
+ char const *secret,
+ uint8_t const *data, size_t length,
+ VALUE_PAIR **pvp)
+{
+ ssize_t rcode;
+
+ DICT_ATTR const *da;
+
+ if ((length < 2) || (data[1] < 2) || (data[1] > length)) {
+ fr_strerror_printf("rad_attr2vp: Insufficient data");
+ return -1;
+ }
+
+ da = dict_attrbyvalue(data[0], 0);
+ if (!da) {
+ VP_TRACE("attr2vp: unknown attribute %u\n", data[0]);
+ da = dict_unknown_afrom_fields(ctx, data[0], 0);
+ }
+ if (!da) return -1;
+
+ /*
+ * Pass the entire thing to the decoding function
+ */
+ if (da->flags.concat) {
+ VP_TRACE("attr2vp: concat attribute\n");
+ return data2vp_concat(ctx, da, data, length, pvp);
+ }
+
+ if (!da->vendor && (da->attr == PW_NAS_FILTER_RULE)) {
+ VP_TRACE("attr2vp: NAS-Filter-Rule attribute\n");
+ return data2vp_nas_filter_rule(ctx, da, data, length, pvp);
+ }
+
+ /*
+ * Note that we pass the entire length, not just the
+ * length of this attribute. The Extended or WiMAX
+ * attributes may have the "continuation" bit set, and
+ * will thus be more than one attribute in length.
+ */
+ rcode = data2vp(ctx, packet, original, secret, da,
+ data + 2, data[1] - 2, length - 2, pvp);
+ if (rcode < 0) return rcode;
+
+ return 2 + rcode;
+}
+
+fr_thread_local_setup(uint8_t *, rad_vp2data_buff)
+
+/** Converts vp_data to network byte order
+ *
+ * Provide a pointer to a buffer which contains the value of the VALUE_PAIR
+ * in an architecture independent format.
+ *
+ * The pointer is only guaranteed to be valid between calls to rad_vp2data, and so long
+ * as the source VALUE_PAIR is not freed.
+ *
+ * @param out where to write the pointer to the value.
+ * @param vp to get the value from.
+ * @return -1 on error, or the length of the value
+ */
+ssize_t rad_vp2data(uint8_t const **out, VALUE_PAIR const *vp)
+{
+ uint8_t *buffer;
+ uint32_t lvalue;
+ uint64_t lvalue64;
+
+ *out = NULL;
+
+ buffer = fr_thread_local_init(rad_vp2data_buff, free);
+ if (!buffer) {
+ int ret;
+
+ buffer = malloc(sizeof(uint8_t) * sizeof(value_data_t));
+ if (!buffer) {
+ fr_strerror_printf("Failed allocating memory for rad_vp2data buffer");
+ return -1;
+ }
+
+ ret = fr_thread_local_set(rad_vp2data_buff, buffer);
+ if (ret != 0) {
+ fr_strerror_printf("Failed setting up TLS for rad_vp2data buffer: %s", strerror(errno));
+ free(buffer);
+ return -1;
+ }
+ }
+
+ VERIFY_VP(vp);
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ memcpy(out, &vp->data.ptr, sizeof(*out));
+ break;
+
+ /*
+ * All of these values are at the same location.
+ */
+ case PW_TYPE_IFID:
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_ABINARY:
+ case PW_TYPE_ETHERNET:
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_COMBO_IP_PREFIX:
+ {
+ void const *p = &vp->data;
+ memcpy(out, &p, sizeof(*out));
+ break;
+ }
+
+ case PW_TYPE_BOOLEAN:
+ buffer[0] = vp->vp_byte & 0x01;
+ *out = buffer;
+ break;
+
+ case PW_TYPE_BYTE:
+ buffer[0] = vp->vp_byte & 0xff;
+ *out = buffer;
+ break;
+
+ case PW_TYPE_SHORT:
+ buffer[0] = (vp->vp_short >> 8) & 0xff;
+ buffer[1] = vp->vp_short & 0xff;
+ *out = buffer;
+ break;
+
+ case PW_TYPE_INTEGER:
+ lvalue = htonl(vp->vp_integer);
+ memcpy(buffer, &lvalue, sizeof(lvalue));
+ *out = buffer;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ lvalue64 = htonll(vp->vp_integer64);
+ memcpy(buffer, &lvalue64, sizeof(lvalue64));
+ *out = buffer;
+ break;
+
+ case PW_TYPE_DATE:
+ lvalue = htonl(vp->vp_date);
+ memcpy(buffer, &lvalue, sizeof(lvalue));
+ *out = buffer;
+ break;
+
+ case PW_TYPE_SIGNED:
+ {
+ int32_t slvalue = htonl(vp->vp_signed);
+ memcpy(buffer, &slvalue, sizeof(slvalue));
+ *out = buffer;
+ break;
+ }
+
+ case PW_TYPE_INVALID:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TLV:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_MAX:
+ fr_strerror_printf("Cannot get data for VALUE_PAIR type %i", vp->da->type);
+ return -1;
+
+ /* Don't add default */
+ }
+
+ return vp->vp_length;
+}
+
+/** Calculate/check digest, and decode radius attributes
+ *
+ * @return -1 on decoding error, 0 on success
+ */
+int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
+ char const *secret)
+{
+ int packet_length;
+ uint32_t num_attributes;
+ uint8_t *ptr;
+ radius_packet_t *hdr;
+ VALUE_PAIR *head, **tail, *vp = NULL;
+
+ /*
+ * Extract attribute-value pairs
+ */
+ hdr = (radius_packet_t *)packet->data;
+ ptr = hdr->data;
+ packet_length = packet->data_len - RADIUS_HDR_LEN;
+
+ head = NULL;
+ tail = &head;
+ num_attributes = 0;
+
+ /*
+ * Loop over the attributes, decoding them into VPs.
+ */
+ while (packet_length > 0) {
+ ssize_t my_len;
+
+#ifdef WITH_RADIUSV11
+ /*
+ * Don't decode Message-Authenticator
+ */
+ if (ptr[0] == PW_MESSAGE_AUTHENTICATOR) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
+
+ /*
+ * Don't decode Original-Packet-Code
+ */
+ if ((ptr[0] == PW_EXTENDED_ATTRIBUTE_1) && (ptr[1] >= 3) && (ptr[2] == 4)) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
+#endif
+
+ /*
+ * This may return many VPs
+ */
+ my_len = rad_attr2vp(packet, packet, original, secret,
+ ptr, packet_length, &vp);
+ if (my_len < 0) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ *tail = vp;
+ while (vp) {
+ num_attributes++;
+ tail = &(vp->next);
+ vp = vp->next;
+ }
+
+ /*
+ * VSA's may not have been counted properly in
+ * rad_packet_ok() above, as it is hard to count
+ * then without using the dictionary. We
+ * therefore enforce the limits here, too.
+ */
+ if ((fr_max_attributes > 0) &&
+ (num_attributes > fr_max_attributes)) {
+ char host_ipaddr[128];
+
+ fr_pair_list_free(&head);
+ fr_strerror_printf("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ num_attributes, fr_max_attributes);
+ return -1;
+ }
+
+ ptr += my_len;
+ packet_length -= my_len;
+ }
+
+ /*
+ * Merge information from the outside world into our
+ * random pool.
+ */
+ fr_rand_seed(packet->data, RADIUS_HDR_LEN);
+
+ /*
+ * There may be VP's already in the packet. Don't
+ * destroy them. Instead, add the decoded attributes to
+ * the tail of the list.
+ */
+ for (tail = &packet->vps; *tail != NULL; tail = &((*tail)->next)) {
+ /* nothing */
+ }
+ *tail = head;
+
+ return 0;
+}
+
+#ifndef WITH_RADIUSV11_ONLY
+/** Encode password
+ *
+ * We assume that the passwd buffer passed is big enough.
+ * RFC2138 says the password is max 128 chars, so the size
+ * of the passwd buffer must be at least 129 characters.
+ * Preferably it's just MAX_STRING_LEN.
+ *
+ * int *pwlen is updated to the new length of the encrypted
+ * password - a multiple of 16 bytes.
+ */
+int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
+ uint8_t const *vector)
+{
+ FR_MD5_CTX context, old;
+ uint8_t digest[AUTH_VECTOR_LEN];
+ int i, n, secretlen;
+ int len;
+
+ /*
+ * RFC maximum is 128 bytes.
+ *
+ * If length is zero, pad it out with zeros.
+ *
+ * If the length isn't aligned to 16 bytes,
+ * zero out the extra data.
+ */
+ len = *pwlen;
+
+ if (len > 128) len = 128;
+
+ if (len == 0) {
+ memset(passwd, 0, AUTH_PASS_LEN);
+ len = AUTH_PASS_LEN;
+ } else if ((len % AUTH_PASS_LEN) != 0) {
+ memset(&passwd[len], 0, AUTH_PASS_LEN - (len % AUTH_PASS_LEN));
+ len += AUTH_PASS_LEN - (len % AUTH_PASS_LEN);
+ }
+ *pwlen = len;
+
+ /*
+ * Use the secret to setup the decryption digest
+ */
+ secretlen = strlen(secret);
+
+ fr_md5_init(&context);
+ fr_md5_init(&old);
+ fr_md5_update(&context, (uint8_t const *) secret, secretlen);
+ fr_md5_copy(old, context); /* save intermediate work */
+
+ /*
+ * Encrypt it in place. Don't bother checking
+ * len, as we've ensured above that it's OK.
+ */
+ for (n = 0; n < len; n += AUTH_PASS_LEN) {
+ if (n == 0) {
+ fr_md5_update(&context, vector, AUTH_PASS_LEN);
+ fr_md5_final(digest, &context);
+ } else {
+ fr_md5_copy(context, old);
+ fr_md5_update(&context,
+ (uint8_t *) passwd + n - AUTH_PASS_LEN,
+ AUTH_PASS_LEN);
+ fr_md5_final(digest, &context);
+ }
+
+ for (i = 0; i < AUTH_PASS_LEN; i++) {
+ passwd[i + n] ^= digest[i];
+ }
+ }
+
+ fr_md5_destroy(&old);
+ fr_md5_destroy(&context);
+
+ return 0;
+}
+
+/** Decode password
+ *
+ */
+int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
+ uint8_t const *vector)
+{
+ FR_MD5_CTX context, old;
+ uint8_t digest[AUTH_VECTOR_LEN];
+ int i;
+ size_t n, secretlen;
+
+ /*
+ * The RFC's say that the maximum is 128.
+ * The buffer we're putting it into above is 254, so
+ * we don't need to do any length checking.
+ */
+ if (pwlen > 128) pwlen = 128;
+
+ /*
+ * Catch idiots.
+ */
+ if (pwlen == 0) goto done;
+
+ /*
+ * Use the secret to setup the decryption digest
+ */
+ secretlen = strlen(secret);
+
+ fr_md5_init(&context);
+ fr_md5_init(&old);
+ fr_md5_update(&context, (uint8_t const *) secret, secretlen);
+ fr_md5_copy(old, context); /* save intermediate work */
+
+ /*
+ * The inverse of the code above.
+ */
+ for (n = 0; n < pwlen; n += AUTH_PASS_LEN) {
+ if (n == 0) {
+ fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+ fr_md5_final(digest, &context);
+
+ fr_md5_copy(context, old);
+ if (pwlen > AUTH_PASS_LEN) {
+ fr_md5_update(&context, (uint8_t *) passwd,
+ AUTH_PASS_LEN);
+ }
+ } else {
+ fr_md5_final(digest, &context);
+
+ fr_md5_copy(context, old);
+ if (pwlen > (n + AUTH_PASS_LEN)) {
+ fr_md5_update(&context, (uint8_t *) passwd + n,
+ AUTH_PASS_LEN);
+ }
+ }
+
+ for (i = 0; i < AUTH_PASS_LEN; i++) {
+ passwd[i + n] ^= digest[i];
+ }
+ }
+
+ done:
+ fr_md5_destroy(&old);
+ fr_md5_destroy(&context);
+
+ passwd[pwlen] = '\0';
+ return strlen(passwd);
+}
+
+
+/** Encode Tunnel-Password attributes when sending them out on the wire
+ *
+ * int *pwlen is updated to the new length of the encrypted
+ * password - a multiple of 16 bytes.
+ *
+ * This is per RFC-2868 which adds a two char SALT to the initial intermediate
+ * value MD5 hash.
+ */
+ssize_t rad_tunnel_pwencode(char *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
+{
+ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];
+ unsigned char digest[AUTH_VECTOR_LEN];
+ char* salt;
+ int i, n, secretlen;
+ unsigned len, n2;
+
+ len = *pwlen;
+
+ if (len > 127) len = 127;
+
+ /*
+ * Shift the password 3 positions right to place a salt and original
+ * length, tag will be added automatically on packet send.
+ */
+ for (n = len ; n >= 0 ; n--) passwd[n + 3] = passwd[n];
+ salt = passwd;
+ passwd += 2;
+
+ /*
+ * save original password length as first password character;
+ */
+ *passwd = len;
+ len += 1;
+
+
+ /*
+ * Generate salt. The RFC's say:
+ *
+ * The high bit of salt[0] must be set, each salt in a
+ * packet should be unique, and they should be random
+ *
+ * So, we set the high bit, add in a counter, and then
+ * add in some CSPRNG data. should be OK..
+ */
+ salt[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
+ (fr_rand() & 0x07));
+ salt[1] = fr_rand();
+
+ /*
+ * Padd password to multiple of AUTH_PASS_LEN bytes.
+ */
+ n = len % AUTH_PASS_LEN;
+ if (n) {
+ n = AUTH_PASS_LEN - n;
+ for (; n > 0; n--, len++)
+ passwd[len] = 0;
+ }
+ /* set new password length */
+ *pwlen = len + 2;
+
+ /*
+ * Use the secret to setup the decryption digest
+ */
+ secretlen = strlen(secret);
+ memcpy(buffer, secret, secretlen);
+
+ for (n2 = 0; n2 < len; n2+=AUTH_PASS_LEN) {
+ if (!n2) {
+ memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
+ memcpy(buffer + secretlen + AUTH_VECTOR_LEN, salt, 2);
+ fr_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2);
+ } else {
+ memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN);
+ fr_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN);
+ }
+
+ for (i = 0; i < AUTH_PASS_LEN; i++) {
+ passwd[i + n2] ^= digest[i];
+ }
+ }
+ passwd[n2] = 0;
+ return 0;
+}
+
+/** Decode Tunnel-Password encrypted attributes
+ *
+ * Defined in RFC-2868, this uses a two char SALT along with the
+ * initial intermediate value, to differentiate it from the
+ * above.
+ */
+ssize_t rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, char const *secret, uint8_t const *vector)
+{
+ FR_MD5_CTX context, old;
+ uint8_t digest[AUTH_VECTOR_LEN];
+ int secretlen;
+ size_t i, n, encrypted_len, reallen;
+
+ encrypted_len = *pwlen;
+
+ /*
+ * We need at least a salt.
+ */
+ if (encrypted_len < 2) {
+ fr_strerror_printf("tunnel password is too short");
+ return -1;
+ }
+
+ /*
+ * There's a salt, but no password. Or, there's a salt
+ * and a 'data_len' octet. It's wrong, but at least we
+ * can figure out what it means: the password is empty.
+ *
+ * Note that this means we ignore the 'data_len' field,
+ * if the attribute length tells us that there's no
+ * more data. So the 'data_len' field may be wrong,
+ * but that's ok...
+ */
+ if (encrypted_len <= 3) {
+ passwd[0] = 0;
+ *pwlen = 0;
+ return 0;
+ }
+
+ encrypted_len -= 2; /* discount the salt */
+
+ /*
+ * Use the secret to setup the decryption digest
+ */
+ secretlen = strlen(secret);
+
+ fr_md5_init(&context);
+ fr_md5_init(&old);
+ fr_md5_update(&context, (uint8_t const *) secret, secretlen);
+ fr_md5_copy(old, context); /* save intermediate work */
+
+ /*
+ * Set up the initial key:
+ *
+ * b(1) = MD5(secret + vector + salt)
+ */
+ fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
+ fr_md5_update(&context, passwd, 2);
+
+ reallen = 0;
+ for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+ size_t base;
+ size_t block_len = AUTH_PASS_LEN;
+
+ /*
+ * Ensure we don't overflow the input on MD5
+ */
+ if ((n + 2 + AUTH_PASS_LEN) > *pwlen) {
+ block_len = *pwlen - n - 2;
+ }
+
+ if (n == 0) {
+ base = 1;
+
+ fr_md5_final(digest, &context);
+
+ fr_md5_copy(context, old);
+
+ /*
+ * A quick check: decrypt the first octet
+ * of the password, which is the
+ * 'data_len' field. Ensure it's sane.
+ */
+ reallen = passwd[2] ^ digest[0];
+ if (reallen > encrypted_len) {
+ fr_strerror_printf("tunnel password is too long for the attribute");
+ return -1;
+ }
+
+ fr_md5_update(&context, passwd + 2, block_len);
+
+ } else {
+ base = 0;
+
+ fr_md5_final(digest, &context);
+
+ fr_md5_copy(context, old);
+ fr_md5_update(&context, passwd + n + 2, block_len);
+ }
+
+ for (i = base; i < block_len; i++) {
+ passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i];
+ }
+ }
+
+ *pwlen = reallen;
+ passwd[reallen] = 0;
+
+ fr_md5_destroy(&old);
+ fr_md5_destroy(&context);
+
+ return reallen;
+}
+
+/** Encode a CHAP password
+ *
+ * @bug FIXME: might not work with Ascend because
+ * we use vp->vp_length, and Ascend gear likes
+ * to send an extra '\0' in the string!
+ */
+int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
+ VALUE_PAIR *password)
+{
+ int i;
+ uint8_t *ptr;
+ uint8_t string[MAX_STRING_LEN * 2 + 1];
+ VALUE_PAIR *challenge;
+
+ /*
+ * Sanity check the input parameters
+ */
+ if ((packet == NULL) || (password == NULL)) {
+ return -1;
+ }
+
+ /*
+ * Note that the password VP can be EITHER
+ * a User-Password attribute (from a check-item list),
+ * or a CHAP-Password attribute (the client asking
+ * the library to encode it).
+ */
+
+ i = 0;
+ ptr = string;
+ *ptr++ = id;
+
+ i++;
+ memcpy(ptr, password->vp_strvalue, password->vp_length);
+ ptr += password->vp_length;
+ i += password->vp_length;
+
+ /*
+ * Use Chap-Challenge pair if present,
+ * Request Authenticator otherwise.
+ */
+ challenge = fr_pair_find_by_num(packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
+ if (challenge) {
+ memcpy(ptr, challenge->vp_strvalue, challenge->vp_length);
+ i += challenge->vp_length;
+ } else {
+ memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
+ i += AUTH_VECTOR_LEN;
+ }
+
+ *output = id;
+ fr_md5_calc((uint8_t *)output + 1, (uint8_t *)string, i);
+
+ return 0;
+}
+#endif /* WITH_RADIUSV11_ONLYx */
+
+
+/** Seed the random number generator
+ *
+ * May be called any number of times.
+ */
+void fr_rand_seed(void const *data, size_t size)
+{
+ uint32_t hash;
+
+ /*
+ * Ensure that the pool is initialized.
+ */
+ if (!fr_rand_initialized) {
+ int fd;
+
+ memset(&fr_rand_pool, 0, sizeof(fr_rand_pool));
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0) {
+ size_t total;
+ ssize_t this;
+
+ total = 0;
+ while (total < sizeof(fr_rand_pool.randrsl)) {
+ this = read(fd, fr_rand_pool.randrsl,
+ sizeof(fr_rand_pool.randrsl) - total);
+ if ((this < 0) && (errno != EINTR)) break;
+ if (this > 0) total += this;
+ }
+ close(fd);
+ } else {
+ fr_rand_pool.randrsl[0] = fd;
+ fr_rand_pool.randrsl[1] = time(NULL);
+ fr_rand_pool.randrsl[2] = errno;
+ }
+
+ fr_randinit(&fr_rand_pool, 1);
+ fr_rand_pool.randcnt = 0;
+ fr_rand_initialized = 1;
+ }
+
+ if (!data) return;
+
+ /*
+ * Hash the user data
+ */
+ hash = fr_rand();
+ if (!hash) hash = fr_rand();
+ hash = fr_hash_update(data, size, hash);
+
+ fr_rand_pool.randmem[fr_rand_pool.randcnt & 0xff] ^= hash;
+}
+
+
+/** Return a 32-bit random number
+ *
+ */
+uint32_t fr_rand(void)
+{
+ uint32_t num;
+
+ /*
+ * Ensure that the pool is initialized.
+ */
+ if (!fr_rand_initialized) {
+ fr_rand_seed(NULL, 0);
+ }
+
+ num = fr_rand_pool.randrsl[fr_rand_pool.randcnt++ & 0xff];
+ if (fr_rand_pool.randcnt >= 256) {
+ fr_rand_pool.randcnt = 0;
+ fr_isaac(&fr_rand_pool);
+ }
+
+ return num;
+}
+
+
+/** Allocate a new RADIUS_PACKET
+ *
+ * @param ctx the context in which the packet is allocated. May be NULL if
+ * the packet is not associated with a REQUEST.
+ * @param new_vector if true a new request authenticator will be generated.
+ * @return a new RADIUS_PACKET or NULL on error.
+ */
+RADIUS_PACKET *rad_alloc(TALLOC_CTX *ctx, bool new_vector)
+{
+ RADIUS_PACKET *rp;
+
+ rp = talloc_zero(ctx, RADIUS_PACKET);
+ if (!rp) {
+ fr_strerror_printf("out of memory");
+ return NULL;
+ }
+ rp->id = -1;
+ rp->offset = -1;
+
+ if (new_vector) {
+ int i;
+ uint32_t hash, base;
+
+ /*
+ * Don't expose the actual contents of the random
+ * pool.
+ */
+ base = fr_rand();
+ for (i = 0; i < AUTH_VECTOR_LEN; i += sizeof(uint32_t)) {
+ hash = fr_rand() ^ base;
+ memcpy(rp->vector + i, &hash, sizeof(hash));
+ }
+ }
+ fr_rand(); /* stir the pool again */
+
+ return rp;
+}
+
+/** Allocate a new RADIUS_PACKET response
+ *
+ * @param ctx the context in which the packet is allocated. May be NULL if
+ * the packet is not associated with a REQUEST.
+ * @param packet The request packet.
+ * @return a new RADIUS_PACKET or NULL on error.
+ */
+RADIUS_PACKET *rad_alloc_reply(TALLOC_CTX *ctx, RADIUS_PACKET *packet)
+{
+ RADIUS_PACKET *reply;
+
+ if (!packet) return NULL;
+
+ reply = rad_alloc(ctx, false);
+ if (!reply) return NULL;
+
+ /*
+ * Initialize the fields from the request.
+ */
+ reply->sockfd = packet->sockfd;
+ reply->dst_ipaddr = packet->src_ipaddr;
+ reply->src_ipaddr = packet->dst_ipaddr;
+ reply->dst_port = packet->src_port;
+ reply->src_port = packet->dst_port;
+ reply->id = packet->id;
+ reply->code = 0; /* UNKNOWN code */
+ memcpy(reply->vector, packet->vector,
+ sizeof(reply->vector));
+ reply->vps = NULL;
+ reply->data = NULL;
+ reply->data_len = 0;
+
+#ifdef WITH_TCP
+ reply->proto = packet->proto;
+#ifdef WITH_RADIUSV11
+ reply->radiusv11 = packet->radiusv11;
+#endif
+#endif
+ return reply;
+}
+
+
+/** Free a RADIUS_PACKET
+ *
+ */
+void rad_free(RADIUS_PACKET **radius_packet_ptr)
+{
+ RADIUS_PACKET *radius_packet;
+
+ if (!radius_packet_ptr || !*radius_packet_ptr) return;
+ radius_packet = *radius_packet_ptr;
+
+ VERIFY_PACKET(radius_packet);
+
+ fr_pair_list_free(&radius_packet->vps);
+
+ talloc_free(radius_packet);
+ *radius_packet_ptr = NULL;
+}
+
+/** Duplicate a RADIUS_PACKET
+ *
+ * @param ctx the context in which the packet is allocated. May be NULL if
+ * the packet is not associated with a REQUEST.
+ * @param in The packet to copy
+ * @return a new RADIUS_PACKET or NULL on error.
+ */
+RADIUS_PACKET *rad_copy_packet(TALLOC_CTX *ctx, RADIUS_PACKET const *in)
+{
+ RADIUS_PACKET *out;
+
+ out = rad_alloc(ctx, false);
+ if (!out) return NULL;
+
+ /*
+ * Bootstrap by copying everything.
+ */
+ memcpy(out, in, sizeof(*out));
+
+ /*
+ * Then reset necessary fields
+ */
+ out->sockfd = -1;
+
+ out->data = NULL;
+ out->data_len = 0;
+
+ out->vps = fr_pair_list_copy(out, in->vps);
+ out->offset = 0;
+
+ return out;
+}
+
+#ifdef WITH_RADIUSV11
+const FR_NAME_NUMBER radiusv11_types[] = {
+ { "forbid", FR_RADIUSV11_FORBID },
+ { "allow", FR_RADIUSV11_ALLOW },
+ { "require", FR_RADIUSV11_REQUIRE },
+ { NULL, 0 }
+
+};
+#endif
diff --git a/src/lib/rbtree.c b/src/lib/rbtree.c
new file mode 100644
index 0000000..d9892bd
--- /dev/null
+++ b/src/lib/rbtree.c
@@ -0,0 +1,744 @@
+/*
+ * rbtree.c RED-BLACK balanced binary trees.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2004,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+
+#define PTHREAD_MUTEX_LOCK(_x) if (_x->lock) pthread_mutex_lock(&((_x)->mutex))
+#define PTHREAD_MUTEX_UNLOCK(_x) if (_x->lock) pthread_mutex_unlock(&((_x)->mutex))
+#else
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+/* Red-Black tree description */
+typedef enum {
+ BLACK,
+ RED
+} node_colour_t;
+
+struct rbnode_t {
+ rbnode_t *left; //!< Left child
+ rbnode_t *right; //!< Right child
+ rbnode_t *parent; //!< Parent
+ node_colour_t colour; //!< Node colour (BLACK, RED)
+ void *data; //!< data stored in node
+};
+
+#define NIL &sentinel /* all leafs are sentinels */
+static rbnode_t sentinel = { NIL, NIL, NIL, BLACK, NULL};
+
+#define NOT_AT_ROOT(_node) ((_node) != NIL)
+
+struct rbtree_t {
+#ifndef NDEBUG
+ uint32_t magic;
+#endif
+ rbnode_t *root;
+ int num_elements;
+ rb_comparator_t compare;
+ rb_free_t free;
+ bool replace;
+#ifdef HAVE_PTHREAD_H
+ bool lock;
+ pthread_mutex_t mutex;
+#endif
+};
+#define RBTREE_MAGIC (0x5ad09c42)
+
+/** Walks the tree to delete all nodes Does NOT re-balance it!
+ *
+ */
+static void free_walker(rbtree_t *tree, rbnode_t *x)
+{
+ (void) talloc_get_type_abort(x, rbnode_t);
+
+ if (x->left != NIL) free_walker(tree, x->left);
+ if (x->right != NIL) free_walker(tree, x->right);
+
+ if (tree->free) tree->free(x->data);
+ talloc_free(x);
+}
+
+void rbtree_free(rbtree_t *tree)
+{
+ if (!tree) return;
+
+ PTHREAD_MUTEX_LOCK(tree);
+
+ /*
+ * walk the tree, deleting the nodes...
+ */
+ if (tree->root != NIL) free_walker(tree, tree->root);
+
+#ifndef NDEBUG
+ tree->magic = 0;
+#endif
+ tree->root = NULL;
+
+ PTHREAD_MUTEX_UNLOCK(tree);
+
+#ifdef HAVE_PTHREAD_H
+ if (tree->lock) pthread_mutex_destroy(&tree->mutex);
+#endif
+
+ talloc_free(tree);
+}
+
+/** Create a new RED-BLACK tree
+ *
+ */
+rbtree_t *rbtree_create(TALLOC_CTX *ctx, rb_comparator_t compare, rb_free_t node_free, int flags)
+{
+ rbtree_t *tree;
+
+ if (!compare) return NULL;
+
+ tree = talloc_zero(ctx, rbtree_t);
+ if (!tree) return NULL;
+
+#ifndef NDEBUG
+ tree->magic = RBTREE_MAGIC;
+#endif
+ tree->root = NIL;
+ tree->compare = compare;
+ tree->replace = (flags & RBTREE_FLAG_REPLACE) != 0 ? true : false;
+#ifdef HAVE_PTHREAD_H
+ tree->lock = (flags & RBTREE_FLAG_LOCK) != 0 ? true : false;
+ if (tree->lock) {
+ pthread_mutex_init(&tree->mutex, NULL);
+ }
+#endif
+ tree->free = node_free;
+
+ return tree;
+}
+
+/** Rotate Node x to left
+ *
+ */
+static void rotate_left(rbtree_t *tree, rbnode_t *x)
+{
+
+ rbnode_t *y = x->right;
+
+ /* establish x->right link */
+ x->right = y->left;
+ if (y->left != NIL) y->left->parent = x;
+
+ /* establish y->parent link */
+ if (y != NIL) y->parent = x->parent;
+ if (NOT_AT_ROOT(x->parent)) {
+ if (x == x->parent->left) {
+ x->parent->left = y;
+ } else {
+ x->parent->right = y;
+ }
+ } else {
+ tree->root = y;
+ }
+
+ /* link x and y */
+ y->left = x;
+ if (x != NIL) x->parent = y;
+}
+
+/** Rotate Node x to right
+ *
+ */
+static void rotate_right(rbtree_t *tree, rbnode_t *x)
+{
+ rbnode_t *y = x->left;
+
+ /* establish x->left link */
+ x->left = y->right;
+ if (y->right != NIL) y->right->parent = x;
+
+ /* establish y->parent link */
+ if (y != NIL) y->parent = x->parent;
+ if (NOT_AT_ROOT(x->parent)) {
+ if (x == x->parent->right) {
+ x->parent->right = y;
+ } else {
+ x->parent->left = y;
+ }
+ } else {
+ tree->root = y;
+ }
+
+ /* link x and y */
+ y->right = x;
+ if (x != NIL) x->parent = y;
+}
+
+/** Maintain red-black tree balance after inserting node x
+ *
+ */
+static void insert_fixup(rbtree_t *tree, rbnode_t *x)
+{
+ /* check RED-BLACK properties */
+ while ((x != tree->root) && (x->parent->colour == RED)) {
+ /* we have a violation */
+ if (x->parent == x->parent->parent->left) {
+ rbnode_t *y = x->parent->parent->right;
+ if (y->colour == RED) {
+
+ /* uncle is RED */
+ x->parent->colour = BLACK;
+ y->colour = BLACK;
+ x->parent->parent->colour = RED;
+ x = x->parent->parent;
+ } else {
+
+ /* uncle is BLACK */
+ if (x == x->parent->right) {
+ /* make x a left child */
+ x = x->parent;
+ rotate_left(tree, x);
+ }
+
+ /* recolour and rotate */
+ x->parent->colour = BLACK;
+ x->parent->parent->colour = RED;
+ rotate_right(tree, x->parent->parent);
+ }
+ } else {
+
+ /* mirror image of above code */
+ rbnode_t *y = x->parent->parent->left;
+ if (y->colour == RED) {
+
+ /* uncle is RED */
+ x->parent->colour = BLACK;
+ y->colour = BLACK;
+ x->parent->parent->colour = RED;
+ x = x->parent->parent;
+ } else {
+
+ /* uncle is BLACK */
+ if (x == x->parent->left) {
+ x = x->parent;
+ rotate_right(tree, x);
+ }
+ x->parent->colour = BLACK;
+ x->parent->parent->colour = RED;
+ rotate_left(tree, x->parent->parent);
+ }
+ }
+ }
+
+ if (tree->root != NIL) tree->root->colour = BLACK; /* Avoid cache-dirty on NIL */
+}
+
+
+/** Insert an element into the tree
+ *
+ */
+rbnode_t *rbtree_insert_node(rbtree_t *tree, void *data)
+{
+ rbnode_t *current, *parent, *x;
+
+ PTHREAD_MUTEX_LOCK(tree);
+
+ /* find where node belongs */
+ current = tree->root;
+ parent = NIL;
+ while (current != NIL) {
+ int result;
+
+ /*
+ * See if two entries are identical.
+ */
+ result = tree->compare(data, current->data);
+ if (result == 0) {
+ /*
+ * Don't replace the entry.
+ */
+ if (!tree->replace) {
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return NULL;
+ }
+
+ /*
+ * Do replace the entry.
+ */
+ if (tree->free) tree->free(current->data);
+ current->data = data;
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return current;
+ }
+
+ parent = current;
+ current = (result < 0) ? current->left : current->right;
+ }
+
+ /* setup new node */
+ x = talloc_zero(tree, rbnode_t);
+ if (!x) {
+ fr_strerror_printf("No memory for new rbtree node");
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return NULL;
+ }
+
+ x->data = data;
+ x->parent = parent;
+ x->left = NIL;
+ x->right = NIL;
+ x->colour = RED;
+
+ /* insert node in tree */
+ if (NOT_AT_ROOT(parent)) {
+ if (tree->compare(data, parent->data) <= 0) {
+ parent->left = x;
+ } else {
+ parent->right = x;
+ }
+ } else {
+ tree->root = x;
+ }
+
+ insert_fixup(tree, x);
+
+ tree->num_elements++;
+
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return x;
+}
+
+bool rbtree_insert(rbtree_t *tree, void *data)
+{
+ if (rbtree_insert_node(tree, data)) return true;
+ return false;
+}
+
+/** Maintain RED-BLACK tree balance after deleting node x
+ *
+ */
+static void delete_fixup(rbtree_t *tree, rbnode_t *x, rbnode_t *parent)
+{
+
+ while (x != tree->root && x->colour == BLACK) {
+ if (x == parent->left) {
+ rbnode_t *w = parent->right;
+ if (w->colour == RED) {
+ w->colour = BLACK;
+ parent->colour = RED; /* parent != NIL? */
+ rotate_left(tree, parent);
+ w = parent->right;
+ }
+ if ((w->left->colour == BLACK) && (w->right->colour == BLACK)) {
+ if (w != NIL) w->colour = RED;
+ x = parent;
+ parent = x->parent;
+ } else {
+ if (w->right->colour == BLACK) {
+ if (w->left != NIL) w->left->colour = BLACK;
+ w->colour = RED;
+ rotate_right(tree, w);
+ w = parent->right;
+ }
+ w->colour = parent->colour;
+ if (parent != NIL) parent->colour = BLACK;
+ if (w->right->colour != BLACK) {
+ w->right->colour = BLACK;
+ }
+ rotate_left(tree, parent);
+ x = tree->root;
+ }
+ } else {
+ rbnode_t *w = parent->left;
+ if (w->colour == RED) {
+ w->colour = BLACK;
+ parent->colour = RED; /* parent != NIL? */
+ rotate_right(tree, parent);
+ w = parent->left;
+ }
+ if ((w->right->colour == BLACK) && (w->left->colour == BLACK)) {
+ if (w != NIL) w->colour = RED;
+ x = parent;
+ parent = x->parent;
+ } else {
+ if (w->left->colour == BLACK) {
+ if (w->right != NIL) w->right->colour = BLACK;
+ w->colour = RED;
+ rotate_left(tree, w);
+ w = parent->left;
+ }
+ w->colour = parent->colour;
+ if (parent != NIL) parent->colour = BLACK;
+ if (w->left->colour != BLACK) {
+ w->left->colour = BLACK;
+ }
+ rotate_right(tree, parent);
+ x = tree->root;
+ }
+ }
+ }
+ if (x != NIL) x->colour = BLACK; /* Avoid cache-dirty on NIL */
+}
+
+/** Delete an element (z) from the tree
+ *
+ */
+static void rbtree_delete_internal(rbtree_t *tree, rbnode_t *z, bool skiplock)
+{
+ rbnode_t *x, *y;
+ rbnode_t *parent;
+
+ if (!z || z == NIL) return;
+
+ if (!skiplock) {
+ PTHREAD_MUTEX_LOCK(tree);
+ }
+
+ if (z->left == NIL || z->right == NIL) {
+ /* y has a NIL node as a child */
+ y = z;
+ } else {
+ /* find tree successor with a NIL node as a child */
+ y = z->right;
+ while (y->left != NIL) y = y->left;
+ }
+
+ /* x is y's only child */
+ if (y->left != NIL) {
+ x = y->left;
+ } else {
+ x = y->right; /* may be NIL! */
+ }
+
+ /* remove y from the parent chain */
+ parent = y->parent;
+ if (x != NIL) x->parent = parent;
+
+ if (NOT_AT_ROOT(parent)) {
+ if (y == parent->left) {
+ parent->left = x;
+ } else {
+ parent->right = x;
+ }
+ } else {
+ tree->root = x;
+ }
+
+ if (y != z) {
+ if (tree->free) tree->free(z->data);
+ z->data = y->data;
+ y->data = NULL;
+
+ if ((y->colour == BLACK) && NOT_AT_ROOT(parent)) {
+ delete_fixup(tree, x, parent);
+ }
+
+ /*
+ * The user structure in y->data MAy include a
+ * pointer to y. In that case, we CANNOT delete
+ * y. Instead, we copy z (which is now in the
+ * tree) to y, and fix up the parent/child
+ * pointers.
+ */
+ memcpy(y, z, sizeof(*y));
+
+ if (NOT_AT_ROOT(y->parent)) {
+ if (y->parent->left == z) y->parent->left = y;
+ if (y->parent->right == z) y->parent->right = y;
+ } else {
+ tree->root = y;
+ }
+ if (y->left->parent == z) y->left->parent = y;
+ if (y->right->parent == z) y->right->parent = y;
+
+ talloc_free(z);
+
+ } else {
+ if (tree->free) tree->free(y->data);
+
+ if (y->colour == BLACK)
+ delete_fixup(tree, x, parent);
+
+ talloc_free(y);
+ }
+
+ tree->num_elements--;
+ if (!skiplock) {
+ PTHREAD_MUTEX_UNLOCK(tree);
+ }
+}
+void rbtree_delete(rbtree_t *tree, rbnode_t *z) {
+ rbtree_delete_internal(tree, z, false);
+}
+
+/** Delete a node from the tree, based on given data, which MUST have come from rbtree_finddata().
+ *
+ *
+ */
+bool rbtree_deletebydata(rbtree_t *tree, void const *data)
+{
+ rbnode_t *node = rbtree_find(tree, data);
+
+ if (!node) return false;
+
+ rbtree_delete(tree, node);
+
+ return true;
+}
+
+
+/** Find an element in the tree, returning the data, not the node
+ *
+ */
+rbnode_t *rbtree_find(rbtree_t *tree, void const *data)
+{
+ rbnode_t *current;
+
+ PTHREAD_MUTEX_LOCK(tree);
+ current = tree->root;
+
+ while (current != NIL) {
+ int result = tree->compare(data, current->data);
+
+ if (result == 0) {
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return current;
+ } else {
+ current = (result < 0) ?
+ current->left : current->right;
+ }
+ }
+
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return NULL;
+}
+
+/** Find the user data.
+ *
+ */
+void *rbtree_finddata(rbtree_t *tree, void const *data)
+{
+ rbnode_t *x;
+
+ x = rbtree_find(tree, data);
+ if (!x) return NULL;
+
+ return x->data;
+}
+
+/** Walk the tree, Pre-order
+ *
+ * We call ourselves recursively for each function, but that's OK,
+ * as the stack is only log(N) deep, which is ~12 entries deep.
+ */
+static int walk_node_pre_order(rbnode_t *x, rb_walker_t compare, void *context)
+{
+ int rcode;
+ rbnode_t *left, *right;
+
+ left = x->left;
+ right = x->right;
+
+ rcode = compare(context, x->data);
+ if (rcode != 0) return rcode;
+
+ if (left != NIL) {
+ rcode = walk_node_pre_order(left, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ if (right != NIL) {
+ rcode = walk_node_pre_order(right, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ return 0; /* we know everything returned zero */
+}
+
+/** rbtree_in_order
+ *
+ */
+static int walk_node_in_order(rbnode_t *x, rb_walker_t compare, void *context)
+{
+ int rcode;
+ rbnode_t *right;
+
+ if (x->left != NIL) {
+ rcode = walk_node_in_order(x->left, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ right = x->right;
+
+ rcode = compare(context, x->data);
+ if (rcode != 0) return rcode;
+
+ if (right != NIL) {
+ rcode = walk_node_in_order(right, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ return 0; /* we know everything returned zero */
+}
+
+
+/** rbtree_post_order
+ *
+ */
+static int walk_node_post_order(rbnode_t *x, rb_walker_t compare, void *context)
+{
+ int rcode;
+
+ if (x->left != NIL) {
+ rcode = walk_node_post_order(x->left, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ if (x->right != NIL) {
+ rcode = walk_node_post_order(x->right, compare, context);
+ if (rcode != 0) return rcode;
+ }
+
+ rcode = compare(context, x->data);
+ if (rcode != 0) return rcode;
+
+ return 0; /* we know everything returned zero */
+}
+
+
+/** rbtree_delete_order
+ *
+ * This executes an rbtree_in_order-like walk that adapts to changes in the
+ * tree above it, which may occur because we allow the compare to
+ * tell us to delete the current node.
+ *
+ * The compare should return:
+ *
+ * < 0 - on error
+ * 0 - continue walking, don't delete the node
+ * 1 - delete the node and stop walking
+ * 2 - delete the node and continue walking
+ */
+static int walk_delete_order(rbtree_t *tree, rb_walker_t compare, void *context)
+{
+ rbnode_t *solid, *x;
+ int rcode = 0;
+
+ /* Keep track of last node that refused deletion. */
+ solid = NIL;
+ while (solid == NIL) {
+ x = tree->root;
+ if (x == NIL) break;
+ descend:
+ while (x->left != NIL) {
+ x = x->left;
+ }
+ visit:
+ rcode = compare(context, x->data);
+ if (rcode < 0) {
+ return rcode;
+ }
+ if (rcode) {
+ rbtree_delete_internal(tree, x, true);
+ if (rcode != 2) {
+ return rcode;
+ }
+ } else {
+ solid = x;
+ }
+ }
+ if (solid != NIL) {
+ x = solid;
+ if (x->right != NIL) {
+ x = x->right;
+ goto descend;
+ }
+ while (NOT_AT_ROOT(x->parent)) {
+ if (x->parent->left == x) {
+ x = x->parent;
+ goto visit;
+ }
+ x = x->parent;
+ }
+ }
+ return rcode;
+}
+
+
+/*
+ * walk the entire tree. The compare function CANNOT modify
+ * the tree.
+ *
+ * The compare function should return 0 to continue walking.
+ * Any other value stops the walk, and is returned.
+ */
+int rbtree_walk(rbtree_t *tree, rb_order_t order, rb_walker_t compare, void *context)
+{
+ int rcode;
+
+ if (tree->root == NIL) return 0;
+
+ PTHREAD_MUTEX_LOCK(tree);
+
+ switch (order) {
+ case RBTREE_PRE_ORDER:
+ rcode = walk_node_pre_order(tree->root, compare, context);
+ break;
+
+ case RBTREE_IN_ORDER:
+ rcode = walk_node_in_order(tree->root, compare, context);
+ break;
+
+ case RBTREE_POST_ORDER:
+ rcode = walk_node_post_order(tree->root, compare, context);
+ break;
+
+ case RBTREE_DELETE_ORDER:
+ rcode = walk_delete_order(tree, compare, context);
+ break;
+
+ default:
+ rcode = -1;
+ break;
+ }
+
+ PTHREAD_MUTEX_UNLOCK(tree);
+ return rcode;
+}
+
+uint32_t rbtree_num_elements(rbtree_t *tree)
+{
+ if (!tree) return 0;
+
+ return tree->num_elements;
+}
+
+/*
+ * Given a Node, return the data.
+ */
+void *rbtree_node2data(UNUSED rbtree_t *tree, rbnode_t *node)
+{
+ if (!node) return NULL;
+
+ return node->data;
+}
diff --git a/src/lib/regex.c b/src/lib/regex.c
new file mode 100644
index 0000000..64a6dbe
--- /dev/null
+++ b/src/lib/regex.c
@@ -0,0 +1,390 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file lib/regex.c
+ * @brief regex abstraction functions
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ * @copyright 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+
+#ifdef HAVE_REGEX
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/regex.h>
+
+/*
+ * Wrapper functions for libpcre. Much more powerful, and guaranteed
+ * to be binary safe but require libpcre.
+ */
+# ifdef HAVE_PCRE
+/** Free regex_t structure
+ *
+ * Calls libpcre specific free functions for the expression and study.
+ *
+ * @param preg to free.
+ */
+static int _regex_free(regex_t *preg)
+{
+ if (preg->compiled) {
+ pcre_free(preg->compiled);
+ preg->compiled = NULL;
+ }
+
+ if (preg->extra) {
+#ifdef PCRE_CONFIG_JIT
+ pcre_free_study(preg->extra);
+#else
+ pcre_free(preg->extra);
+#endif
+ preg->extra = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * Replace the libpcre malloc and free functions with
+ * talloc wrappers. This allows us to use the subcapture copy
+ * functions and just reparent the memory allocated.
+ */
+static void *_pcre_malloc(size_t to_alloc)
+{
+ return talloc_array(NULL, uint8_t, to_alloc);
+}
+
+static void _pcre_free(void *to_free)
+{
+ talloc_free(to_free);
+}
+
+/** Wrapper around pcre_compile
+ *
+ * Allows the rest of the code to do compilations using one function signature.
+ *
+ * @note Compiled expression must be freed with talloc_free.
+ *
+ * @param out Where to write out a pointer to the structure containing the compiled expression.
+ * @param pattern to compile.
+ * @param len of pattern.
+ * @param ignore_case whether to do case insensitive matching.
+ * @param multiline If true $ matches newlines.
+ * @param subcaptures Whether to compile the regular expression to store subcapture
+ * data.
+ * @param runtime If false run the pattern through the PCRE JIT to convert it to machine code.
+ * This trades startup time (longer) for runtime performance (better).
+ * @return >= 1 on success, <= 0 on error. Negative value is offset of parse error.
+ */
+ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
+ bool ignore_case, bool multiline, bool subcaptures, bool runtime)
+{
+ char const *error;
+ int offset;
+ int cflags = 0;
+ regex_t *preg;
+
+ static bool setup = false;
+
+ /*
+ * Lets us use subcapture copy
+ */
+ if (!setup) {
+ pcre_malloc = _pcre_malloc;
+ pcre_free = _pcre_free;
+ setup = true;
+ }
+
+ *out = NULL;
+
+ if (len == 0) {
+ fr_strerror_printf("Empty expression");
+ return 0;
+ }
+
+ if (ignore_case) cflags |= PCRE_CASELESS;
+ if (multiline) cflags |= PCRE_MULTILINE;
+ if (!subcaptures) cflags |= PCRE_NO_AUTO_CAPTURE;
+
+ preg = talloc_zero(ctx, regex_t);
+ talloc_set_destructor(preg, _regex_free);
+
+ preg->compiled = pcre_compile(pattern, cflags, &error, &offset, NULL);
+ if (!preg->compiled) {
+ talloc_free(preg);
+ fr_strerror_printf("Pattern compilation failed: %s", error);
+
+ return -(ssize_t)offset;
+ }
+ if (!runtime) {
+ preg->precompiled = true;
+ preg->extra = pcre_study(preg->compiled, PCRE_STUDY_JIT_COMPILE, &error);
+ if (error) {
+ talloc_free(preg);
+ fr_strerror_printf("Pattern study failed: %s", error);
+
+ return 0;
+ }
+ }
+
+ *out = preg;
+
+ return len;
+}
+
+static const FR_NAME_NUMBER regex_pcre_error_str[] = {
+ { "PCRE_ERROR_NOMATCH", PCRE_ERROR_NOMATCH },
+ { "PCRE_ERROR_NULL", PCRE_ERROR_NULL },
+ { "PCRE_ERROR_BADOPTION", PCRE_ERROR_BADOPTION },
+ { "PCRE_ERROR_BADMAGIC", PCRE_ERROR_BADMAGIC },
+ { "PCRE_ERROR_UNKNOWN_OPCODE", PCRE_ERROR_UNKNOWN_OPCODE },
+ { "PCRE_ERROR_NOMEMORY", PCRE_ERROR_NOMEMORY },
+ { "PCRE_ERROR_NOSUBSTRING", PCRE_ERROR_NOSUBSTRING },
+ { "PCRE_ERROR_MATCHLIMIT", PCRE_ERROR_MATCHLIMIT },
+ { "PCRE_ERROR_CALLOUT", PCRE_ERROR_CALLOUT },
+ { "PCRE_ERROR_BADUTF8", PCRE_ERROR_BADUTF8 },
+ { "PCRE_ERROR_BADUTF8_OFFSET", PCRE_ERROR_BADUTF8_OFFSET },
+ { "PCRE_ERROR_PARTIAL", PCRE_ERROR_PARTIAL },
+ { "PCRE_ERROR_BADPARTIAL", PCRE_ERROR_BADPARTIAL },
+ { "PCRE_ERROR_INTERNAL", PCRE_ERROR_INTERNAL },
+ { "PCRE_ERROR_BADCOUNT", PCRE_ERROR_BADCOUNT },
+ { "PCRE_ERROR_DFA_UITEM", PCRE_ERROR_DFA_UITEM },
+ { "PCRE_ERROR_DFA_UCOND", PCRE_ERROR_DFA_UCOND },
+ { "PCRE_ERROR_DFA_UMLIMIT", PCRE_ERROR_DFA_UMLIMIT },
+ { "PCRE_ERROR_DFA_WSSIZE", PCRE_ERROR_DFA_WSSIZE },
+ { "PCRE_ERROR_DFA_RECURSE", PCRE_ERROR_DFA_RECURSE },
+ { "PCRE_ERROR_RECURSIONLIMIT", PCRE_ERROR_RECURSIONLIMIT },
+ { "PCRE_ERROR_NULLWSLIMIT", PCRE_ERROR_NULLWSLIMIT },
+ { "PCRE_ERROR_BADNEWLINE", PCRE_ERROR_BADNEWLINE },
+ { NULL, 0 }
+};
+
+/** Wrapper around pcre_exec
+ *
+ * @param preg The compiled expression.
+ * @param subject to match.
+ * @param len Length of subject.
+ * @param pmatch Array of match pointers.
+ * @param nmatch How big the match array is. Updated to number of matches.
+ * @return -1 on error, 0 on no match, 1 on match.
+ */
+int regex_exec(regex_t *preg, char const *subject, size_t len, regmatch_t pmatch[], size_t *nmatch)
+{
+ int ret;
+ size_t matches;
+
+ /*
+ * PCRE_NO_AUTO_CAPTURE is a compile time only flag,
+ * and can't be passed here.
+ * We rely on the fact that matches has been set to
+ * 0 as a hint that no subcapture data should be
+ * generated.
+ */
+ if (!pmatch || !nmatch) {
+ pmatch = NULL;
+ if (nmatch) *nmatch = 0;
+ matches = 0;
+ } else {
+ matches = *nmatch;
+ }
+
+ ret = pcre_exec(preg->compiled, preg->extra, subject, len, 0, 0, (int *)pmatch, matches * 3);
+ if (ret < 0) {
+ if (ret == PCRE_ERROR_NOMATCH) return 0;
+
+ fr_strerror_printf("regex evaluation failed with code (%i): %s", ret,
+ fr_int2str(regex_pcre_error_str, ret, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * 0 signifies more offsets than we provided space for,
+ * so don't touch nmatches.
+ */
+ if (nmatch && (ret > 0)) *nmatch = ret;
+
+ return 1;
+}
+/*
+ * Wrapper functions for POSIX like, and extended regular
+ * expressions. These use the system regex library.
+ */
+# else
+/** Free heap allocated regex_t structure
+ *
+ * Heap allocation of regex_t is needed so regex_compile has the same signature with
+ * POSIX or libpcre.
+ *
+ * @param preg to free.
+ */
+static int _regex_free(regex_t *preg)
+{
+ regfree(preg);
+
+ return 0;
+}
+
+/** Binary safe wrapper around regcomp
+ *
+ * If we have the BSD extensions we don't need to do any special work
+ * if we don't have the BSD extensions we need to check to see if the
+ * regular expression contains any \0 bytes.
+ *
+ * If it does we fail and print the appropriate error message.
+ *
+ * @note Compiled expression must be freed with talloc_free.
+ *
+ * @param ctx To allocate memory in.
+ * @param out Where to write out a pointer to the structure containing the
+ * compiled expression.
+ * @param pattern to compile.
+ * @param len of pattern.
+ * @param ignore_case Whether the match should be case ignore_case.
+ * @param multiline If true $ matches newlines.
+ * @param subcaptures Whether to compile the regular expression to store subcapture
+ * data.
+ * @param runtime Whether the compilation is being done at runtime.
+ * @return >= 1 on success, <= 0 on error. Negative value is offset of parse error.
+ * With POSIX regex we only give the correct offset for embedded \0 errors.
+ */
+ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **out, char const *pattern, size_t len,
+ bool ignore_case, bool multiline, bool subcaptures, UNUSED bool runtime)
+{
+ int ret;
+ int cflags = REG_EXTENDED;
+ regex_t *preg;
+
+ if (len == 0) {
+ fr_strerror_printf("Empty expression");
+ return 0;
+ }
+
+ if (ignore_case) cflags |= REG_ICASE;
+ if (multiline) cflags |= REG_NEWLINE;
+ if (!subcaptures) cflags |= REG_NOSUB;
+
+#ifndef HAVE_REGNCOMP
+ {
+ char const *p;
+
+ p = pattern;
+ p += strlen(pattern);
+
+ if ((size_t)(p - pattern) != len) {
+ fr_strerror_printf("Found null in pattern at offset %zu. Pattern unsafe for compilation",
+ (p - pattern));
+ return -(p - pattern);
+ }
+
+ preg = talloc_zero(ctx, regex_t);
+ if (!preg) return 0;
+
+ ret = regcomp(preg, pattern, cflags);
+ }
+#else
+ preg = talloc_zero(ctx, regex_t);
+ if (!preg) return 0;
+ ret = regncomp(preg, pattern, len, cflags);
+#endif
+ if (ret != 0) {
+ char errbuf[128];
+
+ regerror(ret, preg, errbuf, sizeof(errbuf));
+ fr_strerror_printf("Pattern compilation failed: %s", errbuf);
+
+ talloc_free(preg);
+
+ return 0; /* POSIX expressions don't give us the failure offset */
+ }
+
+ talloc_set_destructor(preg, _regex_free);
+ *out = preg;
+
+ return len;
+}
+
+/** Binary safe wrapper around regexec
+ *
+ * If we have the BSD extensions we don't need to do any special work
+ * If we don't have the BSD extensions we need to check to see if the
+ * value to be compared contains any \0 bytes.
+ *
+ * If it does, we fail and print the appropriate error message.
+ *
+ * @param preg The compiled expression.
+ * @param subject to match.
+ * @param pmatch Array of match pointers.
+ * @param nmatch How big the match array is. Updated to number of matches.
+ * @return -1 on error, 0 on no match, 1 on match.
+ */
+int regex_exec(regex_t *preg, char const *subject, size_t len, regmatch_t pmatch[], size_t *nmatch)
+{
+ int ret;
+ size_t matches;
+
+ /*
+ * Disable capturing
+ */
+ if (!pmatch || !nmatch) {
+ pmatch = NULL;
+ if (nmatch) *nmatch = 0;
+ matches = 0;
+ } else {
+ /* regexec does not seem to initialise unused elements */
+ matches = *nmatch;
+ memset(pmatch, 0, sizeof(pmatch[0]) * matches);
+ }
+
+#ifndef HAVE_REGNEXEC
+ {
+ char const *p;
+
+ p = subject;
+ p += strlen(subject);
+
+ if ((size_t)(p - subject) != len) {
+ fr_strerror_printf("Found null in subject at offset %zu. String unsafe for evaluation",
+ (p - subject));
+ return -1;
+ }
+ ret = regexec(preg, subject, matches, pmatch, 0);
+ }
+#else
+ ret = regnexec(preg, subject, len, matches, pmatch, 0);
+#endif
+ if (ret != 0) {
+ if (ret != REG_NOMATCH) {
+ char errbuf[128];
+
+ regerror(ret, preg, errbuf, sizeof(errbuf));
+
+ fr_strerror_printf("regex evaluation failed: %s", errbuf);
+ if (nmatch) *nmatch = 0;
+ return -1;
+ }
+ return 0;
+ }
+
+ /*
+ * Update *nmatch to be the maximum number of
+ * groups that *could* have been populated,
+ * need to check them later.
+ */
+ if (nmatch && (*nmatch > preg->re_nsub)) *nmatch = preg->re_nsub + 1;
+
+ return 1;
+}
+# endif
+#endif
diff --git a/src/lib/sha1.c b/src/lib/sha1.c
new file mode 100644
index 0000000..59545bb
--- /dev/null
+++ b/src/lib/sha1.c
@@ -0,0 +1,185 @@
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Version: $Id$
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include "../include/sha1.h"
+
+#ifndef WITH_OPENSSL_SHA1
+# define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+
+# define blk0(i) (block->l[i] = htonl(block->l[i]))
+
+# define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+# define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+# define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+# define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+# define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+# define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void fr_sha1_transform(uint32_t state[5], uint8_t const buffer[64])
+{
+ uint32_t a, b, c, d, e;
+ typedef union {
+ uint8_t c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 *block;
+ uint8_t workspace[64];
+
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+# endif
+}
+
+
+/* fr_sha1_init - Initialize new context */
+
+void fr_sha1_init(fr_sha1_ctx* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+void fr_sha1_update(fr_sha1_ctx *context,uint8_t const *data, size_t len)
+{
+ unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) {
+ context->count[1]++;
+ }
+
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ fr_sha1_transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ fr_sha1_transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else {
+ i = 0;
+ }
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void fr_sha1_final(uint8_t digest[20], fr_sha1_ctx *context)
+{
+ uint32_t i, j;
+ uint8_t finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+
+ fr_sha1_update(context, (unsigned char const *) "\200", 1);
+
+ while ((context->count[0] & 504) != 448) {
+ fr_sha1_update(context, (unsigned char const *) "\0", 1);
+ }
+ fr_sha1_update(context, finalcount, 8); /* Should cause a fr_sha1_transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (uint8_t)((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+# endif
+
+# ifdef SHA1HANDSOFF /* make fr_sha1_transform overwrite it's own static vars */
+ fr_sha1_transform(context->state, context->buffer);
+# endif
+}
+
+void fr_sha1_final_no_len(uint8_t digest[20], fr_sha1_ctx *context)
+{
+ uint32_t i, j;
+
+ for (i = 0; i < 20; i++) {
+ digest[i] = (uint8_t)((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+
+# ifndef __clang_analyzer__
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+# endif
+
+# ifdef SHA1HANDSOFF /* make fr_sha1_transform overwrite it's own static vars */
+ fr_sha1_transform(context->state, context->buffer);
+# endif
+}
+#endif
diff --git a/src/lib/snprintf.c b/src/lib/snprintf.c
new file mode 100644
index 0000000..9002464
--- /dev/null
+++ b/src/lib/snprintf.c
@@ -0,0 +1,880 @@
+
+/*
+ Unix snprintf implementation.
+ Version 1.4
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 1.4:
+ * integrate in FreeRADIUS's libradius:
+ * Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.c?rev=1.4
+ * Fetched from: http://savannah.gnu.org/cgi-bin/viewcvs/mailutils/mailutils/lib/snprintf.h?rev=1.4
+ * Replace config.h with autoconf.h
+ * Protect with HAVE_SNPRINTF and HAVE_VSNPRINTF
+ 1.3:
+ * add #include <config.h> ifdef HAVE_CONFIG_H
+ * cosmetic change, when exponent is 0 print xxxE+00
+ instead of xxxE-00
+ 1.2:
+ * put the program under LGPL.
+ 1.1:
+ * added changes from Miles Bader
+ * corrected a bug with %f
+ * added support for %#g
+ * added more comments :-)
+ 1.0:
+ * supporting must ANSI syntaxic_sugars
+ 0.0:
+ * suppot %s %c %d
+
+ THANKS(for the patches and ideas):
+ Miles Bader
+ Cyrille Rustom
+ Jacek Slabocewiz
+ Mike Parker(mouse)
+
+*/
+
+RCSID("$Id$")
+
+#include "snprintf.h"
+
+#ifndef HAVE_VSNPRINTF
+
+/*
+ * Find the nth power of 10
+ */
+PRIVATE double
+#ifdef __STDC__
+pow_10(int n)
+#else
+pow_10(n)
+int n;
+#endif
+{
+ int i;
+ double P;
+
+ if (n < 0)
+ for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
+ else
+ for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
+ return P;
+}
+
+/*
+ * Find the integral part of the log in base 10
+ * Note: this not a real log10()
+ I just need and approximation(integerpart) of x in:
+ 10^x ~= r
+ * log_10(200) = 2;
+ * log_10(250) = 2;
+ */
+PRIVATE int
+#ifdef __STDC__
+log_10(double r)
+#else
+log_10(r)
+double r;
+#endif
+{
+ int i = 0;
+ double result = 1.;
+
+ if (r < 0.)
+ r = -r;
+
+ if (r < 1.) {
+ while (result >= r) {result *= .1; i++;}
+ return (-i);
+ } else {
+ while (result <= r) {result *= 10.; i++;}
+ return (i - 1);
+ }
+}
+
+/*
+ * This function return the fraction part of a double
+ * and set in ip the integral part.
+ * In many ways it resemble the modf() found on most Un*x
+ */
+PRIVATE double
+#ifdef __STDC__
+integral(double real, double * ip)
+#else
+integral(real, ip)
+double real;
+double * ip;
+#endif
+{
+ int j;
+ double i, s, p;
+ double real_integral = 0.;
+
+/* take care of the obvious */
+/* equal to zero ? */
+ if (real == 0.) {
+ *ip = 0.;
+ return (0.);
+ }
+
+/* negative number ? */
+ if (real < 0.)
+ real = -real;
+
+/* a fraction ? */
+ if ( real < 1.) {
+ *ip = 0.;
+ return real;
+ }
+/* the real work :-) */
+ for (j = log_10(real); j >= 0; j--) {
+ p = pow_10(j);
+ s = (real - real_integral)/p;
+ i = 0.;
+ while (i + 1. <= s) {i++;}
+ real_integral += i*p;
+ }
+ *ip = real_integral;
+ return (real - real_integral);
+}
+
+#define PRECISION 1.e-6
+/*
+ * return an ascii representation of the integral part of the number
+ * and set fract to be an ascii representation of the fraction part
+ * the container for the fraction and the integral part or staticly
+ * declare with fix size
+ */
+PRIVATE char *
+#ifdef __STDC__
+numtoa(double number, int base, int precision, char ** fract)
+#else
+numtoa(number, base, precision, fract)
+double number;
+int base;
+int precision;
+char ** fract;
+#endif
+{
+ register int i, j;
+ double ip, fp; /* integer and fraction part */
+ double fraction;
+ int digits = MAX_INT - 1;
+ static char integral_part[MAX_INT];
+ static char fraction_part[MAX_FRACT];
+ double sign;
+ int ch;
+
+/* taking care of the obvious case: 0.0 */
+ if (number == 0.) {
+ integral_part[0] = '0';
+ integral_part[1] = '\0';
+ fraction_part[0] = '0';
+ fraction_part[1] = '\0';
+ return integral_part;
+ }
+
+/* for negative numbers */
+ if ((sign = number) < 0.) {
+ number = -number;
+ digits--; /* sign consume one digit */
+ }
+
+ fraction = integral(number, &ip);
+ number = ip;
+/* do the integral part */
+ if ( ip == 0.) {
+ integral_part[0] = '0';
+ i = 1;
+ } else {
+ for ( i = 0; i < digits && number != 0.; ++i) {
+ number /= base;
+ fp = integral(number, &ip);
+ ch = (int)((fp + PRECISION)*base); /* force to round */
+ integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
+ if (! isxdigit(integral_part[i])) /* bail out overflow !! */
+ break;
+ number = ip;
+ }
+ }
+
+/* Oh No !! out of bound, ho well fill it up ! */
+ if (number != 0.)
+ for (i = 0; i < digits; ++i)
+ integral_part[i] = '9';
+
+/* put the sign ? */
+ if (sign < 0.)
+ integral_part[i++] = '-';
+
+ integral_part[i] = '\0';
+
+/* reverse every thing */
+ for ( i--, j = 0; j < i; j++, i--)
+ SWAP_INT(integral_part[i], integral_part[j]);
+
+/* the fractionnal part */
+ for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) {
+ fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
+ if (! isdigit(fraction_part[i])) /* underflow ? */
+ break;
+ fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
+ }
+ fraction_part[i] = '\0';
+
+ if (fract != (char **)0)
+ *fract = fraction_part;
+
+ return integral_part;
+
+}
+
+/* for %d and friends, it puts in holder
+ * the representation with the right padding
+ */
+PRIVATE void
+#ifdef __STDC__
+decimal(struct DATA *p, double d)
+#else
+decimal(p, d)
+struct DATA *p;
+double d;
+#endif
+{
+ char *tmp;
+
+ tmp = itoa(d);
+ p->width -= strlen(tmp);
+ PAD_RIGHT(p);
+ PUT_PLUS(d, p);
+ PUT_SPACE(d, p);
+ while (*tmp) { /* the integral */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ PAD_LEFT(p);
+}
+
+/* for %o octal representation */
+PRIVATE void
+#ifdef __STDC__
+octal(struct DATA *p, double d)
+#else
+octal(p, d)
+struct DATA *p;
+double d;
+#endif
+{
+ char *tmp;
+
+ tmp = otoa(d);
+ p->width -= strlen(tmp);
+ PAD_RIGHT(p);
+ if (p->square == FOUND) /* had prefix '0' for octal */
+ PUT_CHAR('0', p);
+ while (*tmp) { /* octal */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ PAD_LEFT(p);
+}
+
+/* for %x %X hexadecimal representation */
+PRIVATE void
+#ifdef __STDC__
+hexa(struct DATA *p, double d)
+#else
+hexa(p, d)
+struct DATA *p;
+double d;
+#endif
+{
+ char *tmp;
+
+ tmp = htoa(d);
+ p->width -= strlen(tmp);
+ PAD_RIGHT(p);
+ if (p->square == FOUND) { /* prefix '0x' for hexa */
+ PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
+ }
+ while (*tmp) { /* hexa */
+ PUT_CHAR((*p->pf == 'X' ? toupper((uint8_t) *tmp) : *tmp), p);
+ tmp++;
+ }
+ PAD_LEFT(p);
+}
+
+/* %s strings */
+PRIVATE void
+#ifdef __STDC__
+strings(struct DATA *p, char *tmp)
+#else
+strings(p, tmp)
+struct DATA *p;
+char *tmp;
+#endif
+{
+ int i;
+
+ i = strlen(tmp);
+ if (p->precision != NOT_FOUND) /* the smallest number */
+ i = (i < p->precision ? i : p->precision);
+ p->width -= i;
+ PAD_RIGHT(p);
+ while (i-- > 0) { /* put the sting */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ PAD_LEFT(p);
+}
+
+/* %f or %g floating point representation */
+PRIVATE void
+#ifdef __STDC__
+floating(struct DATA *p, double d)
+#else
+floating(p, d)
+struct DATA *p;
+double d;
+#endif
+{
+ char *tmp, *tmp2;
+ int i;
+
+ DEF_PREC(p);
+ d = ROUND(d, p);
+ tmp = dtoa(d, p->precision, &tmp2);
+ /* calculate the padding. 1 for the dot */
+ p->width = p->width -
+ ((d > 0. && p->justify == RIGHT) ? 1:0) -
+ ((p->space == FOUND) ? 1:0) -
+ strlen(tmp) - p->precision - 1;
+ PAD_RIGHT(p);
+ PUT_PLUS(d, p);
+ PUT_SPACE(d, p);
+ while (*tmp) { /* the integral */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ if (p->precision != 0 || p->square == FOUND)
+ PUT_CHAR('.', p); /* put the '.' */
+ if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
+ for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
+ tmp2[i] = '\0';
+ for (; *tmp2; tmp2++)
+ PUT_CHAR(*tmp2, p); /* the fraction */
+
+ PAD_LEFT(p);
+}
+
+/* %e %E %g exponent representation */
+PRIVATE void
+#ifdef __STDC__
+exponent(struct DATA *p, double d)
+#else
+exponent(p, d)
+struct DATA *p;
+double d;
+#endif
+{
+ char *tmp, *tmp2;
+ int j, i;
+
+ DEF_PREC(p);
+ j = log_10(d);
+ d = d / pow_10(j); /* get the Mantissa */
+ d = ROUND(d, p);
+ tmp = dtoa(d, p->precision, &tmp2);
+ /* 1 for unit, 1 for the '.', 1 for 'e|E',
+ * 1 for '+|-', 3 for 'exp' */
+ /* calculate how much padding need */
+ p->width = p->width -
+ ((d > 0. && p->justify == RIGHT) ? 1:0) -
+ ((p->space == FOUND) ? 1:0) - p->precision - 7;
+ PAD_RIGHT(p);
+ PUT_PLUS(d, p);
+ PUT_SPACE(d, p);
+ while (*tmp) {/* the integral */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ if (p->precision != 0 || p->square == FOUND)
+ PUT_CHAR('.', p); /* the '.' */
+ if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
+ for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
+ tmp2[i] = '\0';
+ for (; *tmp2; tmp2++)
+ PUT_CHAR(*tmp2, p); /* the fraction */
+
+ if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
+ PUT_CHAR('e', p);
+ } else
+ PUT_CHAR('E', p);
+ if (j >= 0) { /* the sign of the exp */
+ PUT_CHAR('+', p);
+ } else {
+ PUT_CHAR('-', p);
+ j = -j;
+ }
+ tmp = itoa((double)j);
+ if (j < 9) { /* need to pad the exponent with 0 '000' */
+ PUT_CHAR('0', p); PUT_CHAR('0', p);
+ } else if (j < 99)
+ PUT_CHAR('0', p);
+ while (*tmp) { /* the exponent */
+ PUT_CHAR(*tmp, p);
+ tmp++;
+ }
+ PAD_LEFT(p);
+}
+
+/* initialize the conversion specifiers */
+PRIVATE void
+#ifdef __STDC__
+conv_flag(char * s, struct DATA * p)
+#else
+conv_flag(s, p)
+char * s;
+struct DATA * p;
+#endif
+{
+ char number[MAX_FIELD/2];
+ int i;
+
+ /* reset the flags. */
+ p->precision = p->width = NOT_FOUND;
+ p->star_w = p->star_p = NOT_FOUND;
+ p->square = p->space = NOT_FOUND;
+ p->a_long = p->justify = NOT_FOUND;
+ p->a_longlong = NOT_FOUND;
+ p->pad = ' ';
+
+ for(;s && *s ;s++) {
+ switch (*s) {
+ case ' ': p->space = FOUND; break;
+ case '#': p->square = FOUND; break;
+ case '*': if (p->width == NOT_FOUND)
+ p->width = p->star_w = FOUND;
+ else
+ p->precision = p->star_p = FOUND;
+ break;
+ case '+': p->justify = RIGHT; break;
+ case '-': p->justify = LEFT; break;
+ case '.': if (p->width == NOT_FOUND)
+ p->width = 0;
+ break;
+ case '0': p->pad = '0'; break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9': /* gob all the digits */
+ for (i = 0; isdigit((uint8_t) *s); i++, s++)
+ if (i < MAX_FIELD/2 - 1)
+ number[i] = *s;
+ number[i] = '\0';
+ if (p->width == NOT_FOUND)
+ p->width = atoi(number);
+ else
+ p->precision = atoi(number);
+ s--; /* went to far go back */
+ break;
+ }
+ }
+}
+
+PUBLIC int
+#ifdef __STDC__
+vsnprintf(char *string, size_t length, char const * format, va_list args)
+#else
+vsnprintf(string, length, format, args)
+char *string;
+size_t length;
+char * format;
+va_list args;
+#endif
+{
+ struct DATA data;
+ char conv_field[MAX_FIELD];
+ double d; /* temporary holder */
+ int state;
+ int i;
+
+ data.length = length - 1; /* leave room for '\0' */
+ data.holder = string;
+ data.pf = format;
+ data.counter = 0;
+
+
+/* sanity check, the string must be > 1 */
+ if (length < 1)
+ return -1;
+
+
+ for (; *data.pf && (data.counter < data.length); data.pf++) {
+ if ( *data.pf == '%' ) { /* we got a magic % cookie */
+ conv_flag((char *)0, &data); /* initialise format flags */
+ for (state = 1; *data.pf && state;) {
+ switch (*(++data.pf)) {
+ case '\0': /* a NULL here ? ? bail out */
+ *data.holder = '\0';
+ return data.counter;
+ break;
+ case 'f': /* float, double */
+ STAR_ARGS(&data);
+ if (data.a_long == FOUND)
+ d = va_arg(args, LONG_DOUBLE);
+ else
+ d = va_arg(args, double);
+ floating(&data, d);
+ state = 0;
+ break;
+ case 'g':
+ case 'G':
+ STAR_ARGS(&data);
+ DEF_PREC(&data);
+ if (data.a_long == FOUND)
+ d = va_arg(args, LONG_DOUBLE);
+ else
+ d = va_arg(args, double);
+ i = log_10(d);
+ /*
+ * for '%g|%G' ANSI: use f if exponent
+ * is in the range or [-4,p] exclusively
+ * else use %e|%E
+ */
+ if (-4 < i && i < data.precision)
+ floating(&data, d);
+ else
+ exponent(&data, d);
+ state = 0;
+ break;
+ case 'e':
+ case 'E': /* Exponent double */
+ STAR_ARGS(&data);
+ if (data.a_long == FOUND)
+ d = va_arg(args, LONG_DOUBLE);
+ else
+ d = va_arg(args, double);
+ exponent(&data, d);
+ state = 0;
+ break;
+ case 'u': /* unsigned decimal */
+ STAR_ARGS(&data);
+ if (data.a_longlong == FOUND)
+ d = va_arg(args, unsigned LONG_LONG);
+ else if (data.a_long == FOUND)
+ d = va_arg(args, unsigned long);
+ else
+ d = va_arg(args, unsigned int);
+ decimal(&data, d);
+ state = 0;
+ break;
+ case 'd': /* decimal */
+ STAR_ARGS(&data);
+ if (data.a_longlong == FOUND)
+ d = va_arg(args, LONG_LONG);
+ else if (data.a_long == FOUND)
+ d = va_arg(args, long);
+ else
+ d = va_arg(args, int);
+ decimal(&data, d);
+ state = 0;
+ break;
+ case 'o': /* octal */
+ STAR_ARGS(&data);
+ if (data.a_longlong == FOUND)
+ d = va_arg(args, LONG_LONG);
+ else if (data.a_long == FOUND)
+ d = va_arg(args, long);
+ else
+ d = va_arg(args, int);
+ octal(&data, d);
+ state = 0;
+ break;
+ case 'x':
+ case 'X': /* hexadecimal */
+ STAR_ARGS(&data);
+ if (data.a_longlong == FOUND)
+ d = va_arg(args, LONG_LONG);
+ else if (data.a_long == FOUND)
+ d = va_arg(args, long);
+ else
+ d = va_arg(args, int);
+ hexa(&data, d);
+ state = 0;
+ break;
+ case 'c': /* character */
+ d = va_arg(args, int);
+ PUT_CHAR(d, &data);
+ state = 0;
+ break;
+ case 's': /* string */
+ STAR_ARGS(&data);
+ strings(&data, va_arg(args, char *));
+ state = 0;
+ break;
+ case 'n':
+ *(va_arg(args, int *)) = data.counter; /* what's the count ? */
+ state = 0;
+ break;
+ case 'q':
+ data.a_longlong = FOUND;
+ break;
+ case 'L':
+ case 'l':
+ if (data.a_long == FOUND)
+ data.a_longlong = FOUND;
+ else
+ data.a_long = FOUND;
+ break;
+ case 'h':
+ break;
+ case '%': /* nothing just % */
+ PUT_CHAR('%', &data);
+ state = 0;
+ break;
+ case '#': case ' ': case '+': case '*':
+ case '-': case '.': case '0': case '1':
+ case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ /* initialize width and precision */
+ for (i = 0; isflag(*data.pf); i++, data.pf++)
+ if (i < MAX_FIELD - 1)
+ conv_field[i] = *data.pf;
+ conv_field[i] = '\0';
+ conv_flag(conv_field, &data);
+ data.pf--; /* went to far go back */
+ break;
+ default:
+ /* is this an error ? maybe bail out */
+ state = 0;
+ break;
+ } /* end switch */
+ } /* end of for state */
+ } else { /* not % */
+ PUT_CHAR(*data.pf, &data); /* add the char the string */
+ }
+ }
+
+ *data.holder = '\0'; /* the end ye ! */
+
+ return data.counter;
+}
+
+#endif /* HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+
+PUBLIC int
+#if __STDC__
+snprintf(char *string, size_t length, char const * format, ...)
+#else
+snprintf(string, length, format, va_alist)
+char *string;
+size_t length;
+char * format;
+va_dcl
+#endif
+{
+ int rval;
+ va_list args;
+
+#if __STDC__
+ va_start(args, format);
+#else
+ va_start(args);
+#endif
+
+ rval = vsnprintf (string, length, format, args);
+
+ va_end(args);
+
+ return rval;
+}
+
+#endif /* HAVE_SNPRINTF */
+
+
+#ifdef DRIVER
+
+#include <stdio.h>
+
+/* set of small tests for snprintf() */
+int main()
+{
+ char holder[100];
+ int i;
+
+/*
+ printf("Suite of test for snprintf:\n");
+ printf("a_format\n");
+ printf("printf() format\n");
+ printf("snprintf() format\n\n");
+*/
+/* Checking the field widths */
+
+ printf("/%%d/, 336\n");
+ snprintf(holder, sizeof holder, "/%d/\n", 336);
+ printf("/%d/\n", 336);
+ printf("%s\n", holder);
+
+ printf("/%%2d/, 336\n");
+ snprintf(holder, sizeof holder, "/%2d/\n", 336);
+ printf("/%2d/\n", 336);
+ printf("%s\n", holder);
+
+ printf("/%%10d/, 336\n");
+ snprintf(holder, sizeof holder, "/%10d/\n", 336);
+ printf("/%10d/\n", 336);
+ printf("%s\n", holder);
+
+ printf("/%%-10d/, 336\n");
+ snprintf(holder, sizeof holder, "/%-10d/\n", 336);
+ printf("/%-10d/\n", 336);
+ printf("%s\n", holder);
+
+/* long long */
+
+ printf("/%%lld/, 336\n");
+ snprintf(holder, sizeof holder, "/%lld/\n", (LONG_LONG)336);
+ printf("/%lld/\n", (LONG_LONG)336);
+ printf("%s\n", holder);
+
+ printf("/%%2qd/, 336\n");
+ snprintf(holder, sizeof holder, "/%2qd/\n", (LONG_LONG)336);
+ printf("/%2qd/\n", (LONG_LONG)336);
+ printf("%s\n", holder);
+
+/* floating points */
+
+ printf("/%%f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
+ printf("/%f/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%e/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
+ printf("/%e/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%4.2f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
+ printf("/%4.2f/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%3.1f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
+ printf("/%3.1f/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%10.3f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
+ printf("/%10.3f/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%10.3e/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
+ printf("/%10.3e/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%+4.2f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
+ printf("/%+4.2f/\n", 1234.56);
+ printf("%s\n", holder);
+
+ printf("/%%010.2f/, 1234.56\n");
+ snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
+ printf("/%010.2f/\n", 1234.56);
+ printf("%s\n", holder);
+
+#define BLURB "Outstanding acting !"
+/* strings precisions */
+
+ printf("/%%2s/, \"%s\"\n", BLURB);
+ snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
+ printf("/%2s/\n", BLURB);
+ printf("%s\n", holder);
+
+ printf("/%%22s/ %s\n", BLURB);
+ snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
+ printf("/%22s/\n", BLURB);
+ printf("%s\n", holder);
+
+ printf("/%%22.5s/ %s\n", BLURB);
+ snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
+ printf("/%22.5s/\n", BLURB);
+ printf("%s\n", holder);
+
+ printf("/%%-22.5s/ %s\n", BLURB);
+ snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
+ printf("/%-22.5s/\n", BLURB);
+ printf("%s\n", holder);
+
+/* see some flags */
+
+ printf("%%x %%X %%#x, 31, 31, 31\n");
+ snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
+ printf("%x %X %#x\n", 31, 31, 31);
+ printf("%s\n", holder);
+
+ printf("**%%d**%% d**%% d**, 42, 42, -42\n");
+ snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
+ printf("**%d**% d**% d**\n", 42, 42, -42);
+ printf("%s\n", holder);
+
+/* other flags */
+
+ printf("/%%g/, 31.4\n");
+ snprintf(holder, sizeof holder, "/%g/\n", 31.4);
+ printf("/%g/\n", 31.4);
+ printf("%s\n", holder);
+
+ printf("/%%.6g/, 31.4\n");
+ snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
+ printf("/%.6g/\n", 31.4);
+ printf("%s\n", holder);
+
+ printf("/%%.1G/, 31.4\n");
+ snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
+ printf("/%.1G/\n", 31.4);
+ printf("%s\n", holder);
+
+ printf("abc%%n\n");
+ printf("abc%n", &i); printf("%d\n", i);
+ snprintf(holder, sizeof holder, "abc%n", &i);
+ printf("%s", holder); printf("%d\n\n", i);
+
+ printf("%%*.*s --> 10.10\n");
+ snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
+ printf("%*.*s\n", 10, 10, BLURB);
+ printf("%s\n", holder);
+
+ printf("%%%%%%%%\n");
+ snprintf(holder, sizeof holder, "%%%%\n");
+ printf("%%%%\n");
+ printf("%s\n", holder);
+
+#define BIG "Hello this is a too big string for the buffer"
+/* printf("A buffer to small of 10, trying to put this:\n");*/
+ printf("<%%>, %s\n", BIG);
+ i = snprintf(holder, 10, "%s\n", BIG);
+ printf("<%s>\n", BIG);
+ printf("<%s>\n", holder);
+
+ return 0;
+}
+#endif /* !DRIVER */
diff --git a/src/lib/snprintf.h b/src/lib/snprintf.h
new file mode 100644
index 0000000..c80de2d
--- /dev/null
+++ b/src/lib/snprintf.h
@@ -0,0 +1,220 @@
+/*
+ Unix snprintf implementation.
+ Version 1.4
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+ see header of snprintf.c.
+
+format:
+ int snprintf(holder, sizeof_holder, format, ...)
+
+Return values:
+ (sizeof_holder - 1)
+
+
+ THANKS(for the patches and ideas):
+ Miles Bader
+ Cyrille Rustom
+ Jacek Slabocewiz
+ Mike Parker(mouse)
+
+Alain Magloire: alainm@rcsm.ee.mcgill.ca
+*/
+
+#ifndef HAVE_VSNPRINTF
+
+RCSIDH(snprintf_h, "$Id$")
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <stdlib.h> /* for atoi() */
+#include <ctype.h>
+
+#define PRIVATE static
+#define PUBLIC
+
+/*
+ * For the FLOATING POINT FORMAT :
+ * the challenge was finding a way to
+ * manipulate the Real numbers without having
+ * to resort to mathematical function(it
+ * would require to link with -lm) and not
+ * going down to the bit pattern(not portable)
+ *
+ * so a number, a real is:
+
+ real = integral + fraction
+
+ integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
+ fraction = b(1)*10^-1 + b(2)*10^-2 + ...
+
+ where:
+ 0 <= a(i) => 9
+ 0 <= b(i) => 9
+
+ from then it was simple math
+ */
+
+/*
+ * size of the buffer for the integral part
+ * and the fraction part
+ */
+#define MAX_INT 99 + 1 /* 1 for the null */
+#define MAX_FRACT 29 + 1
+
+/*
+ * If the compiler supports (long long)
+ */
+#ifndef LONG_LONG
+# define LONG_LONG long long
+/*# define LONG_LONG int64_t*/
+#endif
+
+/*
+ * If the compiler supports (long double)
+ */
+#ifndef LONG_DOUBLE
+# define LONG_DOUBLE long double
+/*# define LONG_DOUBLE double*/
+#endif
+
+/*
+ * numtoa() uses PRIVATE buffers to store the results,
+ * So this function is not reentrant
+ */
+#define itoa(n) numtoa(n, 10, 0, (char **)0)
+#define otoa(n) numtoa(n, 8, 0, (char **)0)
+#define htoa(n) numtoa(n, 16, 0, (char **)0)
+#define dtoa(n, p, f) numtoa(n, 10, p, f)
+
+#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
+
+/* this struct holds everything we need */
+struct DATA {
+ int length;
+ char *holder;
+ int counter;
+#ifdef __STDC__
+ char const *pf;
+#else
+ char *pf;
+#endif
+/* FLAGS */
+ int width, precision;
+ int justify; char pad;
+ int square, space, star_w, star_p, a_long, a_longlong;
+};
+
+/* signature of the functions */
+#ifdef __STDC__
+/* the floating point stuff */
+ PRIVATE double pow_10(int);
+ PRIVATE int log_10(double);
+ PRIVATE double integral(double, double *);
+ PRIVATE char * numtoa(double, int, int, char **);
+
+/* for the format */
+ PRIVATE void conv_flag(char *, struct DATA *);
+ PRIVATE void floating(struct DATA *, double);
+ PRIVATE void exponent(struct DATA *, double);
+ PRIVATE void decimal(struct DATA *, double);
+ PRIVATE void octal(struct DATA *, double);
+ PRIVATE void hexa(struct DATA *, double);
+ PRIVATE void strings(struct DATA *, char *);
+
+#else
+/* the floating point stuff */
+ PRIVATE double pow_10();
+ PRIVATE int log_10();
+ PRIVATE double integral();
+ PRIVATE char * numtoa();
+
+/* for the format */
+ PRIVATE void conv_flag();
+ PRIVATE void floating();
+ PRIVATE void exponent();
+ PRIVATE void decimal();
+ PRIVATE void octal();
+ PRIVATE void hexa();
+ PRIVATE void strings();
+#endif
+
+/* those are defines specific to snprintf to hopefully
+ * make the code clearer :-)
+ */
+#define RIGHT 1
+#define LEFT 0
+#define NOT_FOUND -1
+#define FOUND 1
+#define MAX_FIELD 15
+
+/* the conversion flags */
+#define isflag(c) ((c) == '#' || (c) == ' ' || \
+ (c) == '*' || (c) == '+' || \
+ (c) == '-' || (c) == '.' || \
+ isdigit(c))
+
+/* round off to the precision */
+#define ROUND(d, p) \
+ (d < 0.) ? \
+ d - pow_10(-(p)->precision) * 0.5 : \
+ d + pow_10(-(p)->precision) * 0.5
+
+/* set default precision */
+#define DEF_PREC(p) \
+ if ((p)->precision == NOT_FOUND) \
+ (p)->precision = 6
+
+/* put a char */
+#define PUT_CHAR(c, p) \
+ if ((p)->counter < (p)->length) { \
+ *(p)->holder++ = (c); \
+ (p)->counter++; \
+ }
+
+#define PUT_PLUS(d, p) \
+ if ((d) > 0. && (p)->justify == RIGHT) \
+ PUT_CHAR('+', p)
+
+#define PUT_SPACE(d, p) \
+ if ((p)->space == FOUND && (d) > 0.) \
+ PUT_CHAR(' ', p)
+
+/* pad right */
+#define PAD_RIGHT(p) \
+ if ((p)->width > 0 && (p)->justify != LEFT) \
+ for (; (p)->width > 0; (p)->width--) \
+ PUT_CHAR((p)->pad, p)
+
+/* pad left */
+#define PAD_LEFT(p) \
+ if ((p)->width > 0 && (p)->justify == LEFT) \
+ for (; (p)->width > 0; (p)->width--) \
+ PUT_CHAR((p)->pad, p)
+
+/* if width and prec. in the args */
+#define STAR_ARGS(p) \
+ if ((p)->star_w == FOUND) \
+ (p)->width = va_arg(args, int); \
+ if ((p)->star_p == FOUND) \
+ (p)->precision = va_arg(args, int)
+
+#endif /* HAVE_VSNPRINTF */
diff --git a/src/lib/socket.c b/src/lib/socket.c
new file mode 100644
index 0000000..970f4f4
--- /dev/null
+++ b/src/lib/socket.c
@@ -0,0 +1,390 @@
+/*
+ * 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 socket.c
+ * @brief Functions for establishing and managing low level sockets.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @author Alan DeKok <aland@freeradius.org>
+ *
+ * @copyright 2015 The FreeRADIUS project
+ */
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/socket.h>
+
+#ifdef HAVE_SYS_UN_H
+/** Open a Unix socket
+ *
+ * @note If the file doesn't exist then errno will be set to ENOENT.
+ *
+ * The following code demonstrates using this function with a connection timeout:
+ @code {.c}
+ sockfd = fr_socket_client_unix(path, true);
+ if (sockfd < 0) {
+ fr_perror();
+ exit(1);
+}
+ if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
+ error:
+ fr_perror();
+ close(sockfd);
+ goto error;
+}
+//Optionally, if blocking operation is required
+ if (fr_blocking(sockfd) < 0) goto error;
+ @endcode
+ *
+ * @param path to the file bound to the unix socket.
+ * @param async Whether to set the socket to nonblocking, allowing use of
+ * #fr_socket_wait_for_connect.
+ * @return socket FD on success, -1 on error.
+ */
+int fr_socket_client_unix(char const *path, bool async)
+{
+ int sockfd = -1;
+ size_t len;
+ socklen_t socklen;
+ struct sockaddr_un saremote;
+
+ len = strlen(path);
+ if (len >= sizeof(saremote.sun_path)) {
+ fr_strerror_printf("Path too long, maximum length is %zu", sizeof(saremote.sun_path) - 1);
+ errno = EINVAL;
+ return -1;
+ }
+
+ sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ fr_strerror_printf("Failed creating UNIX socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ if (async && (fr_nonblock(sockfd) < 0)) {
+ close(sockfd);
+ return -1;
+ }
+
+ saremote.sun_family = AF_UNIX;
+ memcpy(saremote.sun_path, path, len + 1); /* SUN_LEN does strlen */
+
+ socklen = SUN_LEN(&saremote);
+
+ /*
+ * Although we ignore SIGPIPE, some operating systems
+ * like BSD and OSX ignore the ignoring.
+ *
+ * Fortunately, those operating systems usually support
+ * SO_NOSIGPIPE, to prevent them raising the signal in
+ * the first place.
+ */
+#ifdef SO_NOSIGPIPE
+ {
+ int set = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+ }
+#endif
+
+ if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
+ /*
+ * POSIX says the only time we will get this,
+ * is if the socket has been marked as
+ * nonblocking. This is not an error, the caller
+ * must check the state of errno, and wait for
+ * the connection to complete.
+ */
+ if (errno == EINPROGRESS) return sockfd;
+
+ close(sockfd);
+ fr_strerror_printf("Failed connecting to %s: %s", path, fr_syserror(errno));
+
+ return -1;
+ }
+ return sockfd;
+}
+#else
+int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
+{
+ fprintf(stderr, "Unix domain sockets not supported on this system");
+ return -1;
+}
+#endif /* WITH_SYS_UN_H */
+
+/** Establish a connected TCP socket
+ *
+ * The following code demonstrates using this function with a connection timeout:
+ @code {.c}
+ sockfd = fr_socket_client_tcp(NULL, ipaddr, port, true);
+ if (sockfd < 0) {
+ fr_perror();
+ exit(1);
+}
+ if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
+ error:
+ fr_perror();
+ close(sockfd);
+ goto error;
+}
+//Optionally, if blocking operation is required
+ if (fr_blocking(sockfd) < 0) goto error;
+ @endcode
+ *
+ * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific
+ * address.
+ * @param dst_ipaddr Where to connect to.
+ * @param dst_port Where to connect to.
+ * @param async Whether to set the socket to nonblocking, allowing use of
+ * #fr_socket_wait_for_connect.
+ * @return FD on success, -1 on failure.
+ */
+int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
+{
+ int sockfd;
+ struct sockaddr_storage salocal;
+ socklen_t salen;
+
+ if (!dst_ipaddr) return -1;
+
+ sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0);
+ if (sockfd < 0) {
+ fr_strerror_printf("Error creating TCP socket: %s", fr_syserror(errno));
+ return sockfd;
+ }
+
+ if (async && (fr_nonblock(sockfd) < 0)) {
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Allow the caller to bind us to a specific source IP.
+ */
+ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
+ if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) {
+ close(sockfd);
+ return -1;
+ }
+
+ if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
+ fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+ }
+
+ if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) {
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Although we ignore SIGPIPE, some operating systems
+ * like BSD and OSX ignore the ignoring.
+ *
+ * Fortunately, those operating systems usually support
+ * SO_NOSIGPIPE, to prevent them raising the signal in
+ * the first place.
+ */
+#ifdef SO_NOSIGPIPE
+ {
+ int set = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+ }
+#endif
+
+ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
+ /*
+ * POSIX says the only time we will get this,
+ * is if the socket has been marked as
+ * nonblocking. This is not an error, the caller
+ * must check the state of errno, and wait for
+ * the connection to complete.
+ */
+ if (errno == EINPROGRESS) return sockfd;
+
+ fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ return sockfd;
+}
+
+/** Establish a connected UDP socket
+ *
+ * Connected UDP sockets can be used with write(), unlike unconnected sockets
+ * which must be used with sendto and recvfrom.
+ *
+ * The following code demonstrates using this function with a connection timeout:
+ @code {.c}
+ sockfd = fr_socket_client_udp(NULL, ipaddr, port, true);
+ if (sockfd < 0) {
+ fr_perror();
+ exit(1);
+}
+ if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
+ error:
+ fr_perror();
+ close(sockfd);
+ goto error;
+}
+//Optionally, if blocking operation is required
+ if (fr_blocking(sockfd) < 0) goto error;
+ @endcode
+ *
+ * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific
+ * address.
+ * @param dst_ipaddr Where to send datagrams.
+ * @param dst_port Where to send datagrams.
+ * @param async Whether to set the socket to nonblocking, allowing use of
+ * #fr_socket_wait_for_connect.
+ * @return FD on success, -1 on failure.
+ */
+int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
+{
+ int sockfd;
+ struct sockaddr_storage salocal;
+ socklen_t salen;
+
+ if (!dst_ipaddr) return -1;
+
+ sockfd = socket(dst_ipaddr->af, SOCK_DGRAM, 0);
+ if (sockfd < 0) {
+ fr_strerror_printf("Error creating UDP socket: %s", fr_syserror(errno));
+ return sockfd;
+ }
+
+ if (async && (fr_nonblock(sockfd) < 0)) {
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Allow the caller to bind us to a specific source IP.
+ */
+ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
+ if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) {
+ close(sockfd);
+ return -1;
+ }
+
+ if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
+ fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+ }
+
+ if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) {
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Although we ignore SIGPIPE, some operating systems
+ * like BSD and OSX ignore the ignoring.
+ *
+ * Fortunately, those operating systems usually support
+ * SO_NOSIGPIPE, to prevent them raising the signal in
+ * the first place.
+ */
+#ifdef SO_NOSIGPIPE
+ {
+ int set = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+ }
+#endif
+
+ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
+ /*
+ * POSIX says the only time we will get this,
+ * is if the socket has been marked as
+ * nonblocking. This is not an error, the caller
+ * must check the state of errno, and wait for
+ * the connection to complete.
+ */
+ if (errno == EINPROGRESS) return sockfd;
+
+ fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ return sockfd;
+}
+
+/** Wait for a socket to be connected, with an optional timeout
+ *
+ * @note On error the caller is expected to ``close(sockfd)``.
+ *
+ * @param sockfd the socket to wait on.
+ * @param timeout How long to wait for socket to open.
+ * @return 0 on success, -1 on connection error, -2 on timeout, -3 on select error.
+ */
+int fr_socket_wait_for_connect(int sockfd, struct timeval *timeout)
+{
+ int ret;
+ fd_set error_set;
+ fd_set write_set; /* POSIX says sockets are open when they become writeable */
+
+ FD_ZERO(&error_set);
+ FD_ZERO(&write_set);
+
+ FD_SET(sockfd, &error_set);
+ FD_SET(sockfd, &write_set);
+
+ /* Don't let signals mess up the select */
+ do {
+ ret = select(sockfd + 1, NULL, &write_set, &error_set, timeout);
+ } while ((ret == -1) && (errno == EINTR));
+
+ switch (ret) {
+ case 1: /* ok (maybe) */
+ {
+ int error;
+ socklen_t socklen = sizeof(error);
+
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen)) {
+ fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ if (FD_ISSET(sockfd, &error_set)) {
+ fr_strerror_printf("Failed connecting socket: Unknown error");
+ return -1;
+ }
+ }
+ return 0;
+
+ case 0: /* timeout */
+ if (!fr_assert(timeout)) return -1;
+ fr_strerror_printf("Connection timed out after %" PRIu64"ms",
+ (timeout->tv_sec * (uint64_t)1000) + (timeout->tv_usec / 1000));
+ return -2;
+
+ case -1: /* select error */
+ fr_strerror_printf("Failed waiting for connection: %s", fr_syserror(errno));
+ return -3;
+
+ default:
+ fr_assert(0);
+ return -1;
+ }
+}
diff --git a/src/lib/strlcat.c b/src/lib/strlcat.c
new file mode 100644
index 0000000..b447206
--- /dev/null
+++ b/src/lib/strlcat.c
@@ -0,0 +1,67 @@
+/*
+ * strlcat.c Concatenate strings.
+ *
+ * Version: $Id$
+ *
+ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#ifndef HAVE_STRLCAT
+
+#include <freeradius-devel/missing.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, char const *src, size_t siz)
+{
+ char *d = dst;
+ char const *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+#endif
diff --git a/src/lib/strlcpy.c b/src/lib/strlcpy.c
new file mode 100644
index 0000000..689df5d
--- /dev/null
+++ b/src/lib/strlcpy.c
@@ -0,0 +1,63 @@
+/*
+ * strlcpy.c Copy strings.
+ *
+ * Version: $Id$
+ *
+ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#ifndef HAVE_STRLCPY
+
+#include <freeradius-devel/missing.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, char const *src, size_t siz)
+{
+ char *d = dst;
+ char const *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+
+#endif
diff --git a/src/lib/talloc.c b/src/lib/talloc.c
new file mode 100644
index 0000000..a2af16a
--- /dev/null
+++ b/src/lib/talloc.c
@@ -0,0 +1,74 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Functions which we wish were included in the standard talloc distribution
+ *
+ * @file src/lib/talloc.c
+ *
+ * @copyright 2017 The FreeRADIUS server project
+ * @copyright 2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/math.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/talloc.h>
+
+/** Return a page aligned talloc memory array
+ *
+ * Because we can't intercept talloc's malloc() calls, we need to do some tricks
+ * in order to get the first allocation in the array page aligned, and to limit
+ * the size of the array to a multiple of the page size.
+ *
+ * The reason for wanting a page aligned talloc array, is it allows us to
+ * mprotect() the pages that belong to the array.
+ *
+ * Talloc chunks appear to be allocated within the protected region, so this should
+ * catch frees too.
+ *
+ * @param[in] ctx to allocate array memory in.
+ * @param[out] start The first aligned address in the array.
+ * @param[in] alignment What alignment the memory chunk should have.
+ * @param[in] size How big to make the array. Will be corrected to a multiple
+ * of the page size. The actual array size will be size
+ * rounded to a multiple of the (page_size), + page_size
+ * @return
+ * - A talloc chunk on success.
+ * - NULL on failure.
+ */
+TALLOC_CTX *talloc_aligned_array(TALLOC_CTX *ctx, void **start, size_t alignment, size_t size)
+{
+ size_t rounded;
+ size_t array_size;
+ void *next;
+ TALLOC_CTX *array;
+
+ rounded = ROUND_UP(size, alignment); /* Round up to a multiple of the page size */
+ if (rounded == 0) rounded = alignment;
+
+ array_size = rounded + alignment;
+ array = talloc_array(ctx, uint8_t, array_size); /* Over allocate */
+ if (!array) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+
+ next = (void *)ROUND_UP((uintptr_t)array, alignment); /* Round up address to the next multiple */
+ *start = next;
+
+ return array;
+}
+
diff --git a/src/lib/tcp.c b/src/lib/tcp.c
new file mode 100644
index 0000000..355277c
--- /dev/null
+++ b/src/lib/tcp.c
@@ -0,0 +1,172 @@
+/*
+ * tcp.c TCP-specific functions.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright (C) 2009 Dante http://dante.net
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef WITH_TCP
+
+RADIUS_PACKET *fr_tcp_recv(int sockfd, int flags)
+{
+ RADIUS_PACKET *packet = rad_alloc(NULL, false);
+
+ if (!packet) return NULL;
+
+ packet->sockfd = sockfd;
+
+ if (fr_tcp_read_packet(packet, flags) != 1) {
+ rad_free(&packet);
+ return NULL;
+ }
+
+ return packet;
+}
+
+
+/*
+ * Receives a packet, assuming that the RADIUS_PACKET structure
+ * has been filled out already.
+ *
+ * This ASSUMES that the packet is allocated && fields
+ * initialized.
+ *
+ * This ASSUMES that the socket is marked as O_NONBLOCK, which
+ * the function above does set, if your system supports it.
+ *
+ * Calling this function MAY change sockfd,
+ * if src_ipaddr.af == AF_UNSPEC.
+ */
+int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags)
+{
+ ssize_t len;
+
+ /*
+ * No data allocated. Read the 4-byte header into
+ * a temporary buffer.
+ */
+ if (!packet->data) {
+ int packet_len;
+
+ len = recv(packet->sockfd, packet->vector + packet->data_len,
+ 4 - packet->data_len, 0);
+ if (len == 0) return -2; /* clean close */
+
+#ifdef ECONNRESET
+ if ((len < 0) && (errno == ECONNRESET)) { /* forced */
+ return -2;
+ }
+#endif
+
+ if (len < 0) {
+ fr_strerror_printf("Error receiving packet: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ packet->data_len += len;
+ if (packet->data_len < 4) { /* want more data */
+ return 0;
+ }
+
+ packet_len = (packet->vector[2] << 8) | packet->vector[3];
+
+ if (packet_len < RADIUS_HDR_LEN) {
+ fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes");
+ return -1;
+ }
+
+ /*
+ * If the packet is too big, then the socket is bad.
+ */
+ if (packet_len > MAX_PACKET_LEN) {
+ fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
+ return -1;
+ }
+
+ packet->data = talloc_array(packet, uint8_t, packet_len);
+ if (!packet->data) {
+ fr_strerror_printf("Out of memory");
+ return -1;
+ }
+
+ packet->data_len = packet_len;
+ packet->partial = 4;
+ memcpy(packet->data, packet->vector, 4);
+ }
+
+ /*
+ * Try to read more data.
+ */
+ len = recv(packet->sockfd, packet->data + packet->partial,
+ packet->data_len - packet->partial, 0);
+ if (len == 0) return -2; /* clean close */
+
+#ifdef ECONNRESET
+ if ((len < 0) && (errno == ECONNRESET)) { /* forced */
+ return -2;
+ }
+#endif
+
+ if (len < 0) {
+ fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ packet->partial += len;
+
+ if (packet->partial < packet->data_len) {
+ return 0;
+ }
+
+ /*
+ * See if it's a well-formed RADIUS packet.
+ */
+ if (!rad_packet_ok(packet, flags, NULL)) {
+ return -1;
+ }
+
+ /*
+ * Explicitly set the VP list to empty.
+ */
+ packet->vps = NULL;
+
+ if (fr_debug_lvl) {
+ char ip_buf[128], buffer[256];
+
+ if (packet->src_ipaddr.af != AF_UNSPEC) {
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ ip_buf, sizeof(ip_buf));
+ snprintf(buffer, sizeof(buffer), "host %s port %d",
+ ip_buf, packet->src_port);
+ } else {
+ snprintf(buffer, sizeof(buffer), "socket %d",
+ packet->sockfd);
+ }
+
+ }
+
+ return 1; /* done reading the packet */
+}
+
+#endif /* WITH_TCP */
diff --git a/src/lib/token.c b/src/lib/token.c
new file mode 100644
index 0000000..33b858b
--- /dev/null
+++ b/src/lib/token.c
@@ -0,0 +1,481 @@
+/*
+ * token.c Read the next token from a string.
+ * Yes it's pretty primitive but effective.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+
+const FR_NAME_NUMBER fr_tokens[] = {
+ { "=~", T_OP_REG_EQ, }, /* order is important! */
+ { "!~", T_OP_REG_NE, },
+ { "{", T_LCBRACE, },
+ { "}", T_RCBRACE, },
+ { "(", T_LBRACE, },
+ { ")", T_RBRACE, },
+ { ",", T_COMMA, },
+ { "++", T_OP_INCRM, },
+ { "+=", T_OP_ADD, },
+ { "-=", T_OP_SUB, },
+ { ":=", T_OP_SET, },
+ { "=*", T_OP_CMP_TRUE, },
+ { "!*", T_OP_CMP_FALSE, },
+ { "==", T_OP_CMP_EQ, },
+ { "^=", T_OP_PREPEND, },
+ { "=", T_OP_EQ, },
+ { "!=", T_OP_NE, },
+ { ">=", T_OP_GE, },
+ { ">", T_OP_GT, },
+ { "<=", T_OP_LE, },
+ { "<", T_OP_LT, },
+ { "#", T_HASH, },
+ { ";", T_SEMICOLON, },
+ { NULL, 0, },
+};
+
+const bool fr_assignment_op[] = {
+ false, /* invalid token */
+ false, /* end of line */
+ false, /* { */
+ false, /* } */
+ false, /* ( */
+ false, /* ) 5 */
+ false, /* , */
+ false, /* ; */
+
+ true, /* ++ */
+ true, /* += */
+ true, /* -= 10 */
+ true, /* := */
+ true, /* = */
+ false, /* != */
+ false, /* >= */
+ false, /* > 15 */
+ false, /* <= */
+ false, /* < */
+ false, /* =~ */
+ false, /* !~ */
+ false, /* =* 20 */
+ false, /* !* */
+ false, /* == */
+ true, /* ^= */
+ false, /* # */
+ false, /* bare word 25 */
+ false, /* "foo" */
+ false, /* 'foo' */
+ false, /* `foo` */
+ false
+};
+
+const bool fr_equality_op[] = {
+ false, /* invalid token */
+ false, /* end of line */
+ false, /* { */
+ false, /* } */
+ false, /* ( */
+ false, /* ) 5 */
+ false, /* , */
+ false, /* ; */
+
+ false, /* ++ */
+ false, /* += */
+ false, /* -= 10 */
+ false, /* := */
+ false, /* = */
+ true, /* != */
+ true, /* >= */
+ true, /* > 15 */
+ true, /* <= */
+ true, /* < */
+ true, /* =~ */
+ true, /* !~ */
+ true, /* =* 20 */
+ true, /* !* */
+ true, /* == */
+ false, /* ^= */
+ false, /* # */
+ false, /* bare word 25 */
+ false, /* "foo" */
+ false, /* 'foo' */
+ false, /* `foo` */
+ false
+};
+
+const bool fr_str_tok[] = {
+ false, /* invalid token */
+ false, /* end of line */
+ false, /* { */
+ false, /* } */
+ false, /* ( */
+ false, /* ) 5 */
+ false, /* , */
+ false, /* ; */
+
+ false, /* ++ */
+ false, /* += */
+ false, /* -= 10 */
+ false, /* := */
+ false, /* = */
+ false, /* != */
+ false, /* >= */
+ false, /* > 15 */
+ false, /* <= */
+ false, /* < */
+ false, /* =~ */
+ false, /* !~ */
+ false, /* =* 20 */
+ false, /* !* */
+ false, /* == */
+ false, /* ^= */
+ false, /* # */
+ true, /* bare word 25 */
+ true, /* "foo" */
+ true, /* 'foo' */
+ true, /* `foo` */
+ false
+};
+
+/*
+ * This works only as long as special tokens
+ * are max. 2 characters, but it's fast.
+ */
+#define TOKEN_MATCH(bptr, tptr) \
+ ( (tptr)[0] == (bptr)[0] && \
+ ((tptr)[1] == (bptr)[1] || (tptr)[1] == 0))
+
+/*
+ * Read a word from a buffer and advance pointer.
+ * This function knows about escapes and quotes.
+ *
+ * At end-of-line, buf[0] is set to '\0'.
+ * Returns 0 or special token value.
+ */
+static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
+ FR_NAME_NUMBER const *tokenlist, bool unescape)
+{
+ char *s;
+ char const *p;
+ char quote;
+ bool end = false;
+ unsigned int x;
+ FR_NAME_NUMBER const *t;
+ FR_TOKEN rcode;
+
+ buf[0] = '\0';
+
+ /* Skip whitespace */
+ p = *ptr;
+
+ while (*p && isspace((uint8_t) *p)) p++;
+
+ if (!*p) {
+ *ptr = p;
+ return T_EOL;
+ }
+
+ /*
+ * Might be a 1 or 2 character token.
+ */
+ if (tok) for (t = tokenlist; t->name; t++) {
+ if (TOKEN_MATCH(p, t->name)) {
+ strcpy(buf, t->name);
+ p += strlen(t->name);
+
+ rcode = t->number;
+ goto done;
+ }
+ }
+
+ /* Read word. */
+ quote = '\0';
+ switch (*p) {
+ default:
+ rcode = T_BARE_WORD;
+ break;
+
+ case '\'':
+ rcode = T_SINGLE_QUOTED_STRING;
+ break;
+
+ case '"':
+ rcode = T_DOUBLE_QUOTED_STRING;
+ break;
+
+ case '`':
+ rcode = T_BACK_QUOTED_STRING;
+ break;
+ }
+
+ if (rcode != T_BARE_WORD) {
+ quote = *p;
+ end = false;
+ p++;
+ }
+ s = buf;
+
+ while (*p && buflen-- > 1) {
+ /*
+ * We're looking for strings. Stop on spaces, or
+ * (if given a token list), on a token, or on a
+ * comma.
+ */
+ if (!quote) {
+ if (isspace((uint8_t) *p)) {
+ break;
+ }
+
+ if (tok) {
+ for (t = tokenlist; t->name; t++) {
+ if (TOKEN_MATCH(p, t->name)) {
+ *s++ = 0;
+ goto done;
+ }
+ }
+ }
+ if (*p == ',') break;
+
+ /*
+ * Copy the character over.
+ */
+ *s++ = *p++;
+ continue;
+ } /* else there was a quotation character */
+
+ /*
+ * Un-escaped quote character. We're done.
+ */
+ if (*p == quote) {
+ end = true;
+ p++;
+ break;
+ }
+
+ /*
+ * Everything but backslash gets copied over.
+ */
+ if (*p != '\\') {
+ *s++ = *p++;
+ continue;
+ }
+
+ /*
+ * There's nothing after the backslash, it's an error.
+ */
+ if (!p[1]) {
+ fr_strerror_printf("Unterminated string");
+ return T_INVALID;
+ }
+
+ if (unescape) {
+ p++;
+
+ switch (*p) {
+ case 'r':
+ *s++ = '\r';
+ break;
+ case 'n':
+ *s++ = '\n';
+ break;
+ case 't':
+ *s++ = '\t';
+ break;
+
+ default:
+ if (*p >= '0' && *p <= '9' &&
+ sscanf(p, "%3o", &x) == 1) {
+ *s++ = x;
+ p += 2;
+ } else
+ *s++ = *p;
+ break;
+ }
+ p++;
+
+ } else {
+ /*
+ * Convert backslash-quote to quote, but
+ * leave everything else alone.
+ */
+ if (p[1] == quote) { /* convert '\'' --> ' */
+ p++;
+ } else {
+ if (buflen < 2) {
+ fr_strerror_printf("Truncated input");
+ return T_INVALID;
+ }
+
+ *(s++) = *(p++);
+ }
+ *(s++) = *(p++);
+ }
+ }
+
+ *s++ = 0;
+
+ if (quote && !end) {
+ fr_strerror_printf("Unterminated string");
+ return T_INVALID;
+ }
+
+done:
+ /* Skip whitespace again. */
+ while (*p && isspace((uint8_t) *p)) p++;
+
+ *ptr = p;
+
+ return rcode;
+}
+
+/*
+ * Read a "word" - this means we don't honor
+ * tokens as delimiters.
+ */
+int getword(char const **ptr, char *buf, int buflen, bool unescape)
+{
+ return getthing(ptr, buf, buflen, false, fr_tokens, unescape) == T_EOL ? 0 : 1;
+}
+
+
+/*
+ * Read the next word, use tokens as delimiters.
+ */
+FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape)
+{
+ return getthing(ptr, buf, buflen, true, fr_tokens, unescape);
+}
+
+/*
+ * Expect an operator.
+ */
+FR_TOKEN getop(char const **ptr)
+{
+ char op[3];
+ FR_TOKEN rcode;
+
+ rcode = getthing(ptr, op, sizeof(op), true, fr_tokens, false);
+ if (!fr_assignment_op[rcode] && !fr_equality_op[rcode]) {
+ fr_strerror_printf("Expected operator");
+ return T_INVALID;
+ }
+ return rcode;
+}
+
+/*
+ * Expect a string.
+ */
+FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
+{
+ char const *p;
+
+ if (!ptr || !*ptr || !buf) return T_INVALID;
+
+ p = *ptr;
+
+ while (*p && (isspace((uint8_t)*p))) p++;
+
+ *ptr = p;
+
+ if ((*p == '"') || (*p == '\'') || (*p == '`')) {
+ return gettoken(ptr, buf, buflen, unescape);
+ }
+
+ return getthing(ptr, buf, buflen, false, fr_tokens, unescape);
+}
+
+/*
+ * Convert a string to an integer
+ */
+int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
+{
+ FR_NAME_NUMBER const *this;
+
+ if (!name) {
+ return def;
+ }
+
+ for (this = table; this->name != NULL; this++) {
+ if (strcasecmp(this->name, name) == 0) {
+ return this->number;
+ }
+ }
+
+ return def;
+}
+
+/*
+ * Convert a string matching part of name to an integer.
+ */
+int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
+{
+ FR_NAME_NUMBER const *this;
+ size_t max;
+
+ if (!name) {
+ return def;
+ }
+
+ for (this = table; this->name != NULL; this++) {
+ size_t tlen;
+
+ tlen = strlen(this->name);
+
+ /*
+ * Don't match "request" to user input "req".
+ */
+ if ((len > 0) && (len < (int) tlen)) continue;
+
+ /*
+ * Match up to the length of the table entry if len is < 0.
+ */
+ max = (len < 0) ? tlen : (unsigned)len;
+
+ if (strncasecmp(this->name, name, max) == 0) {
+ return this->number;
+ }
+ }
+
+ return def;
+}
+
+/*
+ * Convert an integer to a string.
+ */
+char const *fr_int2str(FR_NAME_NUMBER const *table, int number,
+ char const *def)
+{
+ FR_NAME_NUMBER const *this;
+
+ for (this = table; this->name != NULL; this++) {
+ if (this->number == number) {
+ return this->name;
+ }
+ }
+
+ return def;
+}
+
+char const *fr_token_name(int token)
+{
+ return fr_int2str(fr_tokens, token, "???");
+}
diff --git a/src/lib/udpfromto.c b/src/lib/udpfromto.c
new file mode 100644
index 0000000..d54d8a6
--- /dev/null
+++ b/src/lib/udpfromto.c
@@ -0,0 +1,579 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file udpfromto.c
+ * @brief Like recvfrom, but also stores the destination IP address. Useful on multihomed hosts.
+ *
+ * @copyright 2007 Alan DeKok <aland@deployingradius.com>
+ * @copyright 2002 Miquel van Smoorenburg
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/udpfromto.h>
+
+#ifdef WITH_UDPFROMTO
+
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+
+#include <fcntl.h>
+
+/*
+ * More portability idiocy
+ * Mac OSX Lion doesn't define SOL_IP. But IPPROTO_IP works.
+ */
+#ifndef SOL_IP
+# define SOL_IP IPPROTO_IP
+#endif
+
+/*
+ * glibc 2.4 and uClibc 0.9.29 introduce IPV6_RECVPKTINFO etc. and
+ * change IPV6_PKTINFO This is only supported in Linux kernel >=
+ * 2.6.14
+ *
+ * This is only an approximation because the kernel version that libc
+ * was compiled against could be older or newer than the one being
+ * run. But this should not be a problem -- we just keep using the
+ * old kernel interface.
+ */
+#ifdef __linux__
+# ifdef IPV6_RECVPKTINFO
+# include <linux/version.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+# ifdef IPV6_2292PKTINFO
+# undef IPV6_RECVPKTINFO
+# undef IPV6_PKTINFO
+# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
+# define IPV6_PKTINFO IPV6_2292PKTINFO
+# endif
+# endif
+/* Fall back to the legacy socket option if IPV6_RECVPKTINFO isn't defined */
+# elif defined(IPV6_2292PKTINFO)
+# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
+# endif
+#else
+
+/*
+ * For everything that's not Linux we assume RFC 3542 compliance
+ * - setsockopt() takes IPV6_RECVPKTINFO
+ * - cmsg_type is IPV6_PKTINFO (in sendmsg, recvmsg)
+ *
+ * If we don't have IPV6_RECVPKTINFO defined but do have IPV6_PKTINFO
+ * defined, chances are the API is RFC2292 compliant and we need to use
+ * IPV6_PKTINFO for both.
+ */
+# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
+# define IPV6_RECVPKTINFO IPV6_PKTINFO
+
+/*
+ * Ensure IPV6_RECVPKTINFO is not defined somehow if we have we
+ * don't have IPV6_PKTINFO.
+ */
+# elif !defined(IPV6_PKTINFO)
+# undef IPV6_RECVPKTINFO
+# endif
+#endif
+
+int udpfromto_init(int s)
+{
+ int proto, flag = 0, opt = 1;
+ struct sockaddr_storage si;
+ socklen_t si_len = sizeof(si);
+
+ errno = ENOSYS;
+
+ /*
+ * Clang analyzer doesn't see that getsockname initialises
+ * the memory passed to it.
+ */
+#ifdef __clang_analyzer__
+ memset(&si, 0, sizeof(si));
+#endif
+
+ if (getsockname(s, (struct sockaddr *) &si, &si_len) < 0) {
+ return -1;
+ }
+
+ if (si.ss_family == AF_INET) {
+#ifdef HAVE_IP_PKTINFO
+ /*
+ * Linux
+ */
+ proto = SOL_IP;
+ flag = IP_PKTINFO;
+#else
+# ifdef IP_RECVDSTADDR
+
+ /*
+ * Set the IP_RECVDSTADDR option (BSD). Note:
+ * IP_RECVDSTADDR == IP_SENDSRCADDR
+ */
+ proto = IPPROTO_IP;
+ flag = IP_RECVDSTADDR;
+# else
+ return -1;
+# endif
+#endif
+
+#if defined(AF_INET6) && defined(IPV6_PKTINFO)
+ } else if (si.ss_family == AF_INET6) {
+ /*
+ * This should actually be standard IPv6
+ */
+ proto = IPPROTO_IPV6;
+
+ /*
+ * Work around Linux-specific hackery.
+ */
+ flag = IPV6_RECVPKTINFO;
+ } else {
+#endif
+
+ /*
+ * Unknown AF. Return an error if possible.
+ */
+# ifdef EPROTONOSUPPORT
+ errno = EPROTONOSUPPORT;
+# endif
+ return -1;
+ }
+
+ return setsockopt(s, proto, flag, &opt, sizeof(opt));
+}
+
+int recvfromto(int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t *fromlen,
+ struct sockaddr *to, socklen_t *tolen)
+{
+ struct msghdr msgh;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char cbuf[256];
+ int err;
+ struct sockaddr_storage si;
+ socklen_t si_len = sizeof(si);
+
+#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) && !defined(IPV6_PKTINFO)
+ /*
+ * If the recvmsg() flags aren't defined, fall back to
+ * using recvfrom().
+ */
+ to = NULL:
+#endif
+
+ /*
+ * Catch the case where the caller passes invalid arguments.
+ */
+ if (!to || !tolen) return recvfrom(s, buf, len, flags, from, fromlen);
+
+ /*
+ * Clang analyzer doesn't see that getsockname initialises
+ * the memory passed to it.
+ */
+#ifdef __clang_analyzer__
+ memset(&si, 0, sizeof(si));
+#endif
+
+ /*
+ * recvmsg doesn't provide sin_port so we have to
+ * retrieve it using getsockname().
+ */
+ if (getsockname(s, (struct sockaddr *)&si, &si_len) < 0) {
+ return -1;
+ }
+
+ /*
+ * Initialize the 'to' address. It may be INADDR_ANY here,
+ * with a more specific address given by recvmsg(), below.
+ */
+ if (si.ss_family == AF_INET) {
+#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR)
+ return recvfrom(s, buf, len, flags, from, fromlen);
+#else
+ struct sockaddr_in *dst = (struct sockaddr_in *) to;
+ struct sockaddr_in *src = (struct sockaddr_in *) &si;
+
+ if (*tolen < sizeof(*dst)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *tolen = sizeof(*dst);
+ *dst = *src;
+#endif
+ }
+
+#ifdef AF_INET6
+ else if (si.ss_family == AF_INET6) {
+#if !defined(IPV6_PKTINFO)
+ return recvfrom(s, buf, len, flags, from, fromlen);
+#else
+ struct sockaddr_in6 *dst = (struct sockaddr_in6 *) to;
+ struct sockaddr_in6 *src = (struct sockaddr_in6 *) &si;
+
+ if (*tolen < sizeof(*dst)) {
+ errno = EINVAL;
+ return -1;
+ }
+ *tolen = sizeof(*dst);
+ *dst = *src;
+#endif
+ }
+#endif
+ /*
+ * Unknown address family.
+ */
+ else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Set up iov and msgh structures. */
+ memset(&cbuf, 0, sizeof(cbuf));
+ memset(&msgh, 0, sizeof(struct msghdr));
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ msgh.msg_control = cbuf;
+ msgh.msg_controllen = sizeof(cbuf);
+ msgh.msg_name = from;
+ msgh.msg_namelen = fromlen ? *fromlen : 0;
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_flags = 0;
+
+ /* Receive one packet. */
+ if ((err = recvmsg(s, &msgh, flags)) < 0) {
+ return err;
+ }
+
+ if (fromlen) *fromlen = msgh.msg_namelen;
+
+ /* Process auxiliary received data in msgh */
+ for (cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
+
+#ifdef IP_PKTINFO
+ if ((cmsg->cmsg_level == SOL_IP) &&
+ (cmsg->cmsg_type == IP_PKTINFO)) {
+ struct in_pktinfo *i =
+ (struct in_pktinfo *) CMSG_DATA(cmsg);
+ ((struct sockaddr_in *)to)->sin_addr = i->ipi_addr;
+ *tolen = sizeof(struct sockaddr_in);
+ break;
+ }
+#endif
+
+#ifdef IP_RECVDSTADDR
+ if ((cmsg->cmsg_level == IPPROTO_IP) &&
+ (cmsg->cmsg_type == IP_RECVDSTADDR)) {
+ struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
+ ((struct sockaddr_in *)to)->sin_addr = *i;
+ *tolen = sizeof(struct sockaddr_in);
+ break;
+ }
+#endif
+
+#ifdef IPV6_PKTINFO
+ if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
+ (cmsg->cmsg_type == IPV6_PKTINFO)) {
+ struct in6_pktinfo *i =
+ (struct in6_pktinfo *) CMSG_DATA(cmsg);
+ ((struct sockaddr_in6 *)to)->sin6_addr = i->ipi6_addr;
+ *tolen = sizeof(struct sockaddr_in6);
+ break;
+ }
+#endif
+ }
+
+ return err;
+}
+
+int sendfromto(int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, socklen_t fromlen,
+ struct sockaddr *to, socklen_t tolen)
+{
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+
+ /*
+ * Unknown address family, die.
+ */
+ if (from && (from->sa_family != AF_INET) && (from->sa_family != AF_INET6)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+#ifdef __FreeBSD__
+ /*
+ * FreeBSD is extra pedantic about the use of IP_SENDSRCADDR,
+ * and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used
+ * with a socket which is bound to something other than
+ * INADDR_ANY
+ */
+ struct sockaddr bound;
+ socklen_t bound_len = sizeof(bound);
+
+ if (getsockname(s, &bound, &bound_len) < 0) {
+ return -1;
+ }
+
+ switch (bound.sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
+ from = NULL;
+ }
+ break;
+
+ case AF_INET6:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr)) {
+ from = NULL;
+ }
+ break;
+ }
+#endif /* !__FreeBSD__ */
+
+ /*
+ * If the sendmsg() flags aren't defined, fall back to
+ * using sendto(). These flags are defined on FreeBSD,
+ * but laying it out this way simplifies the look of the
+ * code.
+ */
+# if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
+ if (from && from->sa_family == AF_INET) {
+ from = NULL;
+ }
+# endif
+
+# if !defined(IPV6_PKTINFO)
+ if (from && from->sa_family == AF_INET6) {
+ from = NULL;
+ }
+# endif
+
+ /*
+ * No "from", just use regular sendto.
+ */
+ if (!from || (fromlen == 0)) {
+ return sendto(s, buf, len, flags, to, tolen);
+ }
+
+ /* Set up control buffer iov and msgh structures. */
+ memset(&cbuf, 0, sizeof(cbuf));
+ memset(&msgh, 0, sizeof(msgh));
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_name = to;
+ msgh.msg_namelen = tolen;
+
+# if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
+ if (from->sa_family == AF_INET) {
+ struct sockaddr_in *s4 = (struct sockaddr_in *) from;
+
+# ifdef IP_PKTINFO
+ struct cmsghdr *cmsg;
+ struct in_pktinfo *pkt;
+
+ msgh.msg_control = cbuf;
+ msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
+
+ pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->ipi_spec_dst = s4->sin_addr;
+
+# elif defined(IP_SENDSRCADDR)
+ struct cmsghdr *cmsg;
+ struct in_addr *in;
+
+ msgh.msg_control = cbuf;
+ msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
+
+ in = (struct in_addr *) CMSG_DATA(cmsg);
+ *in = s4->sin_addr;
+# endif
+ }
+#endif
+
+# if defined(IPV6_PKTINFO)
+ if (from->sa_family == AF_INET6) {
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from;
+
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *pkt;
+
+ msgh.msg_control = cbuf;
+ msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
+
+ pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->ipi6_addr = s6->sin6_addr;
+ }
+# endif /* IPV6_PKTINFO */
+
+ return sendmsg(s, &msgh, flags);
+}
+
+
+#ifdef TESTING
+/*
+ * Small test program to test recvfromto/sendfromto
+ *
+ * use a virtual IP address as first argument to test
+ *
+ * reply packet should originate from virtual IP and not
+ * from the default interface the alias is bound to
+ */
+# include <sys/wait.h>
+
+# define DEF_PORT 20000 /* default port to listen on */
+# define DESTIP "127.0.0.1" /* send packet to localhost per default */
+# define TESTSTRING "foo" /* what to send */
+# define TESTLEN 4 /* 4 bytes */
+
+int main(int argc, char **argv)
+{
+ struct sockaddr_in from, to, in;
+ char buf[TESTLEN];
+ char *destip = DESTIP;
+ uint16_t port = DEF_PORT;
+ int n, server_socket, client_socket, fl, tl, pid;
+
+ if (argc > 1) destip = argv[1];
+ if (argc > 2) port = atoi(argv[2]);
+
+ in.sin_family = AF_INET;
+ in.sin_addr.s_addr = INADDR_ANY;
+ in.sin_port = htons(port);
+ fl = tl = sizeof(struct sockaddr_in);
+ memset(&from, 0, sizeof(from));
+ memset(&to, 0, sizeof(to));
+
+ switch (pid = fork()) {
+ case -1:
+ perror("fork");
+ return 0;
+ case 0:
+ /* child */
+ usleep(100000);
+ goto client;
+ }
+
+ /* parent: server */
+ server_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (udpfromto_init(server_socket) != 0) {
+ perror("udpfromto_init\n");
+ waitpid(pid, NULL, WNOHANG);
+ return 0;
+ }
+
+ if (bind(server_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
+ perror("server: bind");
+ waitpid(pid, NULL, WNOHANG);
+ return 0;
+ }
+
+ printf("server: waiting for packets on INADDR_ANY:%d\n", port);
+ if ((n = recvfromto(server_socket, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from, &fl,
+ (struct sockaddr *)&to, &tl)) < 0) {
+ perror("server: recvfromto");
+ waitpid(pid, NULL, WNOHANG);
+ return 0;
+ }
+
+ printf("server: received a packet of %d bytes [%s] ", n, buf);
+ printf("(src ip:port %s:%d ",
+ inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+ printf(" dst ip:port %s:%d)\n",
+ inet_ntoa(to.sin_addr), ntohs(to.sin_port));
+
+ printf("server: replying from address packet was received on to source address\n");
+
+ if ((n = sendfromto(server_socket, buf, n, 0,
+ (struct sockaddr *)&to, tl,
+ (struct sockaddr *)&from, fl)) < 0) {
+ perror("server: sendfromto");
+ }
+
+ waitpid(pid, NULL, 0);
+ return 0;
+
+client:
+ close(server_socket);
+ client_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (udpfromto_init(client_socket) != 0) {
+ perror("udpfromto_init");
+ fr_exit_now(0);
+ }
+ /* bind client on different port */
+ in.sin_port = htons(port+1);
+ if (bind(client_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
+ perror("client: bind");
+ fr_exit_now(0);
+ }
+
+ in.sin_port = htons(port);
+ in.sin_addr.s_addr = inet_addr(destip);
+
+ printf("client: sending packet to %s:%d\n", destip, port);
+ if (sendto(client_socket, TESTSTRING, TESTLEN, 0,
+ (struct sockaddr *)&in, sizeof(in)) < 0) {
+ perror("client: sendto");
+ fr_exit_now(0);
+ }
+
+ printf("client: waiting for reply from server on INADDR_ANY:%d\n", port+1);
+
+ if ((n = recvfromto(client_socket, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from, &fl,
+ (struct sockaddr *)&to, &tl)) < 0) {
+ perror("client: recvfromto");
+ fr_exit_now(0);
+ }
+
+ printf("client: received a packet of %d bytes [%s] ", n, buf);
+ printf("(src ip:port %s:%d",
+ inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+ printf(" dst ip:port %s:%d)\n",
+ inet_ntoa(to.sin_addr), ntohs(to.sin_port));
+
+ fr_exit_now(0);
+}
+
+#endif /* TESTING */
+#endif /* WITH_UDPFROMTO */
diff --git a/src/lib/value.c b/src/lib/value.c
new file mode 100644
index 0000000..aa49897
--- /dev/null
+++ b/src/lib/value.c
@@ -0,0 +1,2013 @@
+/*
+ * value.c Functions to handle value_data_t
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2014 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <ctype.h>
+
+/** Compare two values
+ *
+ * @param[in] a_type of data to compare.
+ * @param[in] a_len of data to compare.
+ * @param[in] a Value to compare.
+ * @param[in] b_type of data to compare.
+ * @param[in] b_len of data to compare.
+ * @param[in] b Value to compare.
+ * @return -1 if a is less than b, 0 if both are equal, 1 if a is more than b, < -1 on error.
+ */
+int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
+ PW_TYPE b_type, value_data_t const *b, size_t b_len)
+{
+ int compare = 0;
+
+ if (a_type != b_type) {
+ fr_strerror_printf("Can't compare values of different types");
+ return -2;
+ }
+
+ /*
+ * After doing the previous check for special comparisons,
+ * do the per-type comparison here.
+ */
+ switch (a_type) {
+ case PW_TYPE_ABINARY:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_STRING: /* We use memcmp to be \0 safe */
+ {
+ size_t length;
+
+ if (a_len < b_len) {
+ length = a_len;
+ } else {
+ length = b_len;
+ }
+
+ if (length) {
+ compare = memcmp(a->octets, b->octets, length);
+ if (compare != 0) break;
+ }
+
+ /*
+ * Contents are the same. The return code
+ * is therefore the difference in lengths.
+ *
+ * i.e. "0x00" is smaller than "0x0000"
+ */
+ compare = a_len - b_len;
+ }
+ break;
+
+ /*
+ * Short-hand for simplicity.
+ */
+#define CHECK(_type) if (a->_type < b->_type) { compare = -1; \
+ } else if (a->_type > b->_type) { compare = +1; }
+
+ case PW_TYPE_BOOLEAN: /* this isn't a RADIUS type, and shouldn't really ever be used */
+ case PW_TYPE_BYTE:
+ CHECK(byte);
+ break;
+
+
+ case PW_TYPE_SHORT:
+ CHECK(ushort);
+ break;
+
+ case PW_TYPE_DATE:
+ CHECK(date);
+ break;
+
+ case PW_TYPE_INTEGER:
+ CHECK(integer);
+ break;
+
+ case PW_TYPE_SIGNED:
+ CHECK(sinteger);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ CHECK(integer64);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ compare = memcmp(a->ether, b->ether, sizeof(a->ether));
+ break;
+
+ case PW_TYPE_IPV4_ADDR: {
+ uint32_t a_int, b_int;
+
+ a_int = ntohl(a->ipaddr.s_addr);
+ b_int = ntohl(b->ipaddr.s_addr);
+ if (a_int < b_int) {
+ compare = -1;
+ } else if (a_int > b_int) {
+ compare = +1;
+ }
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ compare = memcmp(a->ipv6prefix, b->ipv6prefix, sizeof(a->ipv6prefix));
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ compare = memcmp(a->ipv4prefix, b->ipv4prefix, sizeof(a->ipv4prefix));
+ break;
+
+ case PW_TYPE_IFID:
+ compare = memcmp(a->ifid, b->ifid, sizeof(a->ifid));
+ break;
+
+ /*
+ * Na of the types below should be in the REQUEST
+ */
+ case PW_TYPE_INVALID: /* We should never see these */
+ case PW_TYPE_COMBO_IP_ADDR: /* This should have been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_COMBO_IP_PREFIX: /* This should have been converted into IPADDR/IPV6ADDR */
+ case PW_TYPE_TLV:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_MAX:
+ fr_assert(0); /* unknown type */
+ return -2;
+
+ /*
+ * Do NOT add a default here, as new types are added
+ * static analysis will warn us they're not handled
+ */
+ }
+
+ if (compare > 0) {
+ return 1;
+ } else if (compare < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * We leverage the fact that IPv4 and IPv6 prefixes both
+ * have the same format:
+ *
+ * reserved, prefix-len, data...
+ */
+static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes,
+ uint8_t a_net, uint8_t const *a,
+ uint8_t b_net, uint8_t const *b)
+{
+ int i, common;
+ uint32_t mask;
+
+ /*
+ * Handle the case of netmasks being identical.
+ */
+ if (a_net == b_net) {
+ int compare;
+
+ compare = memcmp(a, b, bytes);
+
+ /*
+ * If they're identical return true for
+ * identical.
+ */
+ if ((compare == 0) &&
+ ((op == T_OP_CMP_EQ) ||
+ (op == T_OP_LE) ||
+ (op == T_OP_GE))) {
+ return true;
+ }
+
+ /*
+ * Everything else returns false.
+ *
+ * 10/8 == 24/8 --> false
+ * 10/8 <= 24/8 --> false
+ * 10/8 >= 24/8 --> false
+ */
+ return false;
+ }
+
+ /*
+ * Netmasks are different. That limits the
+ * possible results, based on the operator.
+ */
+ switch (op) {
+ case T_OP_CMP_EQ:
+ return false;
+
+ case T_OP_NE:
+ return true;
+
+ case T_OP_LE:
+ case T_OP_LT: /* 192/8 < 192.168/16 --> false */
+ if (a_net < b_net) {
+ return false;
+ }
+ break;
+
+ case T_OP_GE:
+ case T_OP_GT: /* 192/16 > 192.168/8 --> false */
+ if (a_net > b_net) {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ if (a_net < b_net) {
+ common = a_net;
+ } else {
+ common = b_net;
+ }
+
+ /*
+ * Do the check byte by byte. If the bytes are
+ * identical, it MAY be a match. If they're different,
+ * it is NOT a match.
+ */
+ i = 0;
+ while (i < bytes) {
+ /*
+ * All leading bytes are identical.
+ */
+ if (common == 0) return true;
+
+ /*
+ * Doing bitmasks takes more work.
+ */
+ if (common < 8) break;
+
+ if (a[i] != b[i]) return false;
+
+ common -= 8;
+ i++;
+ continue;
+ }
+
+ mask = 1;
+ mask <<= (8 - common);
+ mask--;
+ mask = ~mask;
+
+ if ((a[i] & mask) == ((b[i] & mask))) {
+ return true;
+ }
+
+ return false;
+}
+
+/** Compare two attributes using an operator
+ *
+ * @param[in] op to use in comparison.
+ * @param[in] a_type of data to compare.
+ * @param[in] a_len of data to compare.
+ * @param[in] a Value to compare.
+ * @param[in] b_type of data to compare.
+ * @param[in] b_len of data to compare.
+ * @param[in] b Value to compare.
+ * @return 1 if true, 0 if false, -1 on error.
+ */
+int value_data_cmp_op(FR_TOKEN op,
+ PW_TYPE a_type, value_data_t const *a, size_t a_len,
+ PW_TYPE b_type, value_data_t const *b, size_t b_len)
+{
+ int compare = 0;
+
+ if (!a || !b) return -1;
+
+ switch (a_type) {
+ case PW_TYPE_IPV4_ADDR:
+ switch (b_type) {
+ case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
+ goto cmp;
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
+ return value_data_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->ipaddr,
+ b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
+ return -1;
+ }
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
+ switch (b_type) {
+ case PW_TYPE_IPV4_ADDR:
+ return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
+ (uint8_t const *) &a->ipv4prefix[2],
+ 32, (uint8_t const *) &b->ipaddr);
+
+ case PW_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
+ return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
+ (uint8_t const *) &a->ipv4prefix[2],
+ b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
+ return -1;
+ }
+
+ case PW_TYPE_IPV6_ADDR:
+ switch (b_type) {
+ case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
+ goto cmp;
+
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
+ return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
+ b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
+ return -1;
+ }
+
+ case PW_TYPE_IPV6_PREFIX:
+ switch (b_type) {
+ case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
+ return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
+ (uint8_t const *) &a->ipv6prefix[2],
+ 128, (uint8_t const *) &b->ipv6addr);
+
+ case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
+ return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
+ (uint8_t const *) &a->ipv6prefix[2],
+ b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
+
+ default:
+ fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
+ return -1;
+ }
+
+ default:
+ cmp:
+ compare = value_data_cmp(a_type, a, a_len,
+ b_type, b, b_len);
+ if (compare < -1) { /* comparison error */
+ return -1;
+ }
+ }
+
+ /*
+ * Now do the operator comparison.
+ */
+ switch (op) {
+ case T_OP_CMP_EQ:
+ return (compare == 0);
+
+ case T_OP_NE:
+ return (compare != 0);
+
+ case T_OP_LT:
+ return (compare < 0);
+
+ case T_OP_GT:
+ return (compare > 0);
+
+ case T_OP_LE:
+ return (compare <= 0);
+
+ case T_OP_GE:
+ return (compare >= 0);
+
+ default:
+ return 0;
+ }
+}
+
+static char const hextab[] = "0123456789abcdef";
+
+/** Convert string value to a value_data_t type
+ *
+ * @param[in] ctx to alloc strings in.
+ * @param[out] dst where to write parsed value.
+ * @param[in,out] src_type of value data to create/type of value created.
+ * @param[in] src_enumv DICT_ATTR with string aliases for integer values.
+ * @param[in] src String to convert. Binary safe for variable length values if len is provided.
+ * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
+ * should be the length of the string or sub string to parse.
+ * @param[in] quote quotation character used to drive de-escaping
+ * @return length of data written to out or -1 on parse error.
+ */
+ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
+ PW_TYPE *src_type, DICT_ATTR const *src_enumv,
+ char const *src, ssize_t src_len, char quote)
+{
+ DICT_VALUE *dval;
+ size_t len;
+ ssize_t ret;
+ char buffer[256];
+
+ if (!src) return -1;
+
+ len = (src_len < 0) ? strlen(src) : (size_t)src_len;
+
+ /*
+ * Set size for all fixed length attributes.
+ */
+ ret = dict_attr_sizes[*src_type][1]; /* Max length */
+
+ /*
+ * It's a variable ret src_type so we just alloc a new buffer
+ * of size len and copy.
+ */
+ switch (*src_type) {
+ case PW_TYPE_STRING:
+ {
+ char *p, *buff;
+ char const *q;
+ int x;
+
+ buff = p = talloc_bstrndup(ctx, src, len);
+
+ /*
+ * No de-quoting. Just copy the string.
+ */
+ if (!quote) {
+ ret = len;
+ dst->strvalue = buff;
+ goto finish;
+ }
+
+ /*
+ * Do escaping for single quoted strings. Only
+ * single quotes get escaped. Everything else is
+ * left as-is.
+ */
+ if (quote == '\'') {
+ q = p;
+
+ while (q < (buff + len)) {
+ /*
+ * The quotation character is escaped.
+ */
+ if ((q[0] == '\\') &&
+ (q[1] == quote)) {
+ *(p++) = quote;
+ q += 2;
+ continue;
+ }
+
+ /*
+ * Two backslashes get mangled to one.
+ */
+ if ((q[0] == '\\') &&
+ (q[1] == '\\')) {
+ *(p++) = '\\';
+ q += 2;
+ continue;
+ }
+
+ /*
+ * Not escaped, just copy it over.
+ */
+ *(p++) = *(q++);
+ }
+
+ *p = '\0';
+ ret = p - buff;
+
+ /* Shrink the buffer to the correct size */
+ dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
+ goto finish;
+ }
+
+ /*
+ * It's "string" or `string`, do all standard
+ * escaping.
+ */
+ q = p;
+ while (q < (buff + len)) {
+ char c = *q++;
+
+ if ((c == '\\') && (q >= (buff + len))) {
+ fr_strerror_printf("Invalid escape at end of string");
+ talloc_free(buff);
+ return -1;
+ }
+
+ /*
+ * Fix up \X -> ... the binary form of it.
+ */
+ if (c == '\\') {
+ switch (*q) {
+ case 'r':
+ c = '\r';
+ q++;
+ break;
+
+ case 'n':
+ c = '\n';
+ q++;
+ break;
+
+ case 't':
+ c = '\t';
+ q++;
+ break;
+
+ case '\\':
+ c = '\\';
+ q++;
+ break;
+
+ default:
+ /*
+ * \" --> ", but only inside of double quoted strings, etc.
+ */
+ if (*q == quote) {
+ c = quote;
+ q++;
+ break;
+ }
+
+ /*
+ * \000 --> binary zero character
+ */
+ if ((q[0] >= '0') &&
+ (q[0] <= '9') &&
+ (q[1] >= '0') &&
+ (q[1] <= '9') &&
+ (q[2] >= '0') &&
+ (q[2] <= '9') &&
+ (sscanf(q, "%3o", &x) == 1)) {
+ c = x;
+ q += 3;
+ }
+
+ /*
+ * Else It's not a recognised escape sequence DON'T
+ * consume the backslash. This is identical
+ * behaviour to bash and most other things that
+ * use backslash escaping.
+ */
+ }
+ }
+
+ *p++ = c;
+ }
+
+ *p = '\0';
+ ret = p - buff;
+ dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
+ }
+ goto finish;
+
+ case PW_TYPE_VSA:
+ fr_strerror_printf("Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'");
+ return -1;
+
+ /* raw octets: 0x01020304... */
+#ifndef WITH_ASCEND_BINARY
+ do_octets:
+#endif
+ case PW_TYPE_OCTETS:
+ {
+ uint8_t *p;
+
+ /*
+ * No 0x prefix, just copy verbatim.
+ */
+ if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
+ dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
+ talloc_set_type(dst->octets, uint8_t);
+ ret = len;
+ goto finish;
+ }
+
+ len -= 2;
+
+ /*
+ * Invalid.
+ */
+ if ((len & 0x01) != 0) {
+ fr_strerror_printf("Length of Hex String is not even, got %zu bytes", len);
+ return -1;
+ }
+
+ ret = len >> 1;
+ p = talloc_array(ctx, uint8_t, ret);
+ if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
+ talloc_free(p);
+ fr_strerror_printf("Invalid hex data");
+ return -1;
+ }
+
+ dst->octets = p;
+ }
+ goto finish;
+
+ case PW_TYPE_ABINARY:
+#ifdef WITH_ASCEND_BINARY
+ if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) {
+ ssize_t bin;
+
+ if (len > ((sizeof(dst->filter) + 1) * 2)) {
+ fr_strerror_printf("Hex data is too large for ascend filter");
+ return -1;
+ }
+
+ bin = fr_hex2bin((uint8_t *) &dst->filter, ret, src + 2, len - 2);
+ if (bin < ret) {
+ memset(((uint8_t *) &dst->filter) + bin, 0, ret - bin);
+ }
+ } else {
+ if (ascend_parse_filter(dst, src, len) < 0 ) {
+ /* Allow ascend_parse_filter's strerror to bubble up */
+ return -1;
+ }
+ }
+
+ ret = sizeof(dst->filter);
+ goto finish;
+#else
+ /*
+ * If Ascend binary is NOT defined,
+ * then fall through to raw octets, so that
+ * the user can at least make them by hand...
+ */
+ goto do_octets;
+#endif
+
+ /* don't use this! */
+ case PW_TYPE_TLV:
+ fr_strerror_printf("Cannot parse TLV");
+ return -1;
+
+ case PW_TYPE_IPV4_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
+
+ /*
+ * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 32) {
+ fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
+ }
+ goto finish;
+
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
+
+ dst->ipv4prefix[1] = addr.prefix;
+ memcpy(&dst->ipv4prefix[2], &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_ADDR:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
+
+ /*
+ * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
+ * print them this way.
+ */
+ if (addr.prefix != 128) {
+ fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
+ "for non-prefix types", addr.prefix);
+ return -1;
+ }
+
+ memcpy(&dst->ipv6addr, addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
+ }
+ goto finish;
+
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ fr_ipaddr_t addr;
+
+ if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
+
+ dst->ipv6prefix[1] = addr.prefix;
+ memcpy(&dst->ipv6prefix[2], addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
+ }
+ goto finish;
+
+ default:
+ break;
+ }
+
+ /*
+ * It's a fixed size src_type, copy to a temporary buffer and
+ * \0 terminate if insize >= 0.
+ */
+ if (src_len > 0) {
+ if (len >= sizeof(buffer)) {
+ fr_strerror_printf("Temporary buffer too small");
+ return -1;
+ }
+
+ memcpy(buffer, src, src_len);
+ buffer[src_len] = '\0';
+ src = buffer;
+ }
+
+ switch (*src_type) {
+ case PW_TYPE_BYTE:
+ {
+ char *p;
+ unsigned int i;
+
+ /*
+ * Note that ALL integers are unsigned!
+ */
+ i = fr_strtoul(src, &p);
+
+ /*
+ * Look for the named src for the given
+ * attribute.
+ */
+ if (src_enumv && *p && !is_whitespace(p)) {
+ if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
+ fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
+ src, src_enumv->name);
+ return -1;
+ }
+
+ dst->byte = dval->value;
+ } else {
+ if (i > 255) {
+ fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
+ return -1;
+ }
+
+ dst->byte = i;
+ }
+ break;
+ }
+
+ case PW_TYPE_SHORT:
+ {
+ char *p;
+ unsigned int i;
+
+ /*
+ * Note that ALL integers are unsigned!
+ */
+ i = fr_strtoul(src, &p);
+
+ /*
+ * Look for the named src for the given
+ * attribute.
+ */
+ if (src_enumv && *p && !is_whitespace(p)) {
+ if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
+ fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
+ src, src_enumv->name);
+ return -1;
+ }
+
+ dst->ushort = dval->value;
+ } else {
+ if (i > 65535) {
+ fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
+ return -1;
+ }
+
+ dst->ushort = i;
+ }
+ break;
+ }
+
+ case PW_TYPE_INTEGER:
+ {
+ char *p;
+ unsigned int i;
+
+ /*
+ * Note that ALL integers are unsigned!
+ */
+ i = fr_strtoul(src, &p);
+
+ /*
+ * Look for the named src for the given
+ * attribute.
+ */
+ if (src_enumv && *p && !is_whitespace(p)) {
+ if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
+ fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
+ src, src_enumv->name);
+ return -1;
+ }
+
+ dst->integer = dval->value;
+ } else {
+ /*
+ * Value is always within the limits
+ */
+ dst->integer = i;
+ }
+ }
+ break;
+
+ case PW_TYPE_INTEGER64:
+ {
+ uint64_t i;
+
+ /*
+ * Note that ALL integers are unsigned!
+ */
+ if (sscanf(src, "%" PRIu64, &i) != 1) {
+ fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
+ return -1;
+ }
+ dst->integer64 = i;
+ }
+ break;
+
+ case PW_TYPE_DATE:
+ {
+ /*
+ * time_t may be 64 bits, whule vp_date MUST be 32-bits. We need an
+ * intermediary variable to handle the conversions.
+ */
+ time_t date;
+ struct tm tm = { 0 };
+ char *end;
+
+ /*
+ * Try to parse dates via locale-specific names,
+ * using the same format string as strftime(),
+ * below.
+ *
+ * If that fails (e.g. unix dates as integer),
+ * then we fall back to our parsing routine,
+ * which is much more forgiving.
+ */
+ end = strptime(src, "%b %e %Y %H:%M:%S %Z", &tm);
+ if (end && (*end == '\0')) {
+ date = mktime(&tm);
+
+ } else if (fr_get_time(src, &date) < 0) {
+ fr_strerror_printf("failed to parse time string \"%s\"", src);
+ return -1;
+ }
+
+ dst->date = date;
+ }
+
+ break;
+
+ case PW_TYPE_IFID:
+ if (ifid_aton(src, (void *) dst->ifid) == NULL) {
+ fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
+ return -1;
+ }
+ break;
+
+ case PW_TYPE_ETHERNET:
+ {
+ char const *c1, *c2, *cp;
+ size_t p_len = 0;
+
+ /*
+ * Convert things which are obviously integers to Ethernet addresses
+ *
+ * We assume the number is the bigendian representation of the
+ * ethernet address.
+ */
+ if (is_integer(src)) {
+ uint64_t integer = htonll(atoll(src));
+
+ memcpy(dst->ether, &integer, sizeof(dst->ether));
+ break;
+ }
+
+ cp = src;
+ while (*cp) {
+ if (cp[1] == ':') {
+ c1 = hextab;
+ c2 = memchr(hextab, tolower((uint8_t) cp[0]), 16);
+ cp += 2;
+ } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
+ c1 = memchr(hextab, tolower((uint8_t) cp[0]), 16);
+ c2 = memchr(hextab, tolower((uint8_t) cp[1]), 16);
+ cp += 2;
+ if (*cp == ':') cp++;
+ } else {
+ c1 = c2 = NULL;
+ }
+ if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
+ fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
+ return -1;
+ }
+ dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
+ p_len++;
+ }
+ }
+ break;
+
+ /*
+ * Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
+ *
+ * We try and make is saner by replacing the original
+ * da, with either an IPv4 or IPv6 da src_type.
+ *
+ * These are not dynamic da, and will have the same vendor
+ * and attribute as the original.
+ */
+ case PW_TYPE_COMBO_IP_ADDR:
+ {
+ if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
+ *src_type = PW_TYPE_IPV6_ADDR;
+ ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
+ } else {
+ fr_ipaddr_t ipaddr;
+
+ if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
+ fr_strerror_printf("Failed to find IPv4 address for %s", src);
+ return -1;
+ }
+
+ *src_type = PW_TYPE_IPV4_ADDR;
+ dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
+ ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
+ }
+ }
+ break;
+
+ case PW_TYPE_SIGNED:
+ /* Damned code for 1 WiMAX attribute */
+ dst->sinteger = (int32_t)strtol(src, NULL, 10);
+ break;
+
+ /*
+ * Anything else.
+ */
+ default:
+ fr_strerror_printf("Unknown attribute type %d", *src_type);
+ return -1;
+ }
+
+finish:
+ return ret;
+}
+
+/** Performs byte order reversal for types that need it
+ *
+ */
+static ssize_t value_data_hton(value_data_t *dst, PW_TYPE dst_type, void const *src, size_t src_len)
+{
+ size_t dst_len;
+ uint8_t *dst_ptr;
+
+ /* 8 byte integers */
+ switch (dst_type) {
+ case PW_TYPE_INTEGER64:
+ dst_len = sizeof(dst->integer64);
+
+ if (src_len < dst_len) {
+ too_small:
+ fr_strerror_printf("Source is too small to cast to destination type");
+ return -1;
+ }
+
+ dst->integer64 = htonll(*(uint64_t const *)src);
+ break;
+
+ /* 4 byte integers */
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ case PW_TYPE_SIGNED:
+ dst_len = sizeof(dst->integer);
+
+ if (src_len < dst_len) goto too_small;
+
+ dst->integer = htonl(*(uint32_t const *)src);
+ break;
+
+ /* 2 byte integers */
+ case PW_TYPE_SHORT:
+ dst_len = sizeof(dst->ushort);
+
+ if (src_len < dst_len) goto too_small;
+
+ dst->ushort = htons(*(uint16_t const *)src);
+ break;
+
+ /* 1 byte integer */
+ case PW_TYPE_BYTE:
+ dst_len = sizeof(dst->byte);
+
+ if (src_len < dst_len) goto too_small;
+
+ dst->byte = *(uint8_t const *)src;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ dst_len = 4;
+ dst_ptr = (uint8_t *) &dst->ipaddr.s_addr;
+
+ copy:
+ /*
+ * Not enough information, die.
+ */
+ if (src_len < dst_len) goto too_small;
+
+ /*
+ * Copy only as much as we need from the source.
+ */
+ memcpy(dst_ptr, src, dst_len);
+ break;
+
+ case PW_TYPE_ABINARY:
+ dst_len = sizeof(dst->filter);
+ dst_ptr = (uint8_t *) dst->filter;
+
+ /*
+ * Too little data is OK here.
+ */
+ if (src_len < dst_len) {
+ memcpy(dst_ptr, src, src_len);
+ memset(dst_ptr + src_len, 0, dst_len - src_len);
+ break;
+ }
+ goto copy;
+
+ case PW_TYPE_IFID:
+ dst_len = sizeof(dst->ifid);
+ dst_ptr = (uint8_t *) dst->ifid;
+ goto copy;
+
+ case PW_TYPE_IPV6_ADDR:
+ dst_len = sizeof(dst->ipv6addr);
+ dst_ptr = (uint8_t *) dst->ipv6addr.s6_addr;
+ goto copy;
+
+ case PW_TYPE_IPV4_PREFIX:
+ dst_len = sizeof(dst->ipv4prefix);
+ dst_ptr = (uint8_t *) dst->ipv4prefix;
+
+ if (src_len < dst_len) goto too_small;
+ if ((((uint8_t const *)src)[1] & 0x3f) > 32) return -1;
+ goto copy;
+
+ case PW_TYPE_IPV6_PREFIX:
+ dst_len = sizeof(dst->ipv6prefix);
+ dst_ptr = (uint8_t *) dst->ipv6prefix;
+
+ /*
+ * Smaller IPv6 prefixes are OK, too, so long as
+ * they're not too short.
+ */
+ if (src_len < 2) goto too_small;
+
+ /*
+ * Prefix is too long.
+ */
+ if (((uint8_t const *)src)[1] > 128) return -1;
+
+ if (src_len < dst_len) {
+ memcpy(dst_ptr, src, src_len);
+ memset(dst_ptr + src_len, 0, dst_len - src_len);
+ break;
+ }
+
+ goto copy;
+
+ case PW_TYPE_ETHERNET:
+ dst_len = sizeof(dst->ether);
+ dst_ptr = (uint8_t *) dst->ether;
+ goto copy;
+
+ default:
+ fr_strerror_printf("Invalid cast to %s",
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+ return -1; /* can't do it */
+ }
+
+ return dst_len;
+}
+
+/** Convert one type of value_data_t to another
+ *
+ * @note This should be the canonical function used to convert between data types.
+ *
+ * @param ctx to allocate buffers in (usually the same as dst)
+ * @param dst Where to write result of casting.
+ * @param dst_type to cast to.
+ * @param dst_enumv Enumerated values used to converts strings to integers.
+ * @param src_type to cast from.
+ * @param src_enumv Enumerated values used to convert integers to strings.
+ * @param src Input data.
+ * @param src_len Input data len.
+ * @return the length of data in the dst or -1 on error.
+ */
+ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
+ PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
+ PW_TYPE src_type, DICT_ATTR const *src_enumv,
+ value_data_t const *src, size_t src_len)
+{
+ ssize_t dst_len;
+
+ if (!fr_assert(dst_type != src_type)) {
+ fr_strerror_printf("Types do not match");
+ return -1;
+ }
+
+ /*
+ * Deserialise a value_data_t
+ */
+ if (src_type == PW_TYPE_STRING) {
+ return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
+ }
+
+ /*
+ * Converts the src data to octets with no processing.
+ */
+ if (dst_type == PW_TYPE_OCTETS) {
+ dst_len = value_data_hton(dst, src_type, src, src_len);
+ if (dst_len < 0) return -1;
+
+ dst->octets = talloc_memdup(ctx, dst, dst_len);
+ talloc_set_type(dst->octets, uint8_t);
+ return dst_len;
+ }
+
+ /*
+ * Serialise a value_data_t
+ */
+ if (dst_type == PW_TYPE_STRING) {
+ dst->strvalue = value_data_aprints(ctx, src_type, src_enumv, src, src_len, '\0');
+ return talloc_array_length(dst->strvalue) - 1;
+ }
+
+ if ((src_type == PW_TYPE_IFID) &&
+ (dst_type == PW_TYPE_INTEGER64)) {
+ memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
+ dst->integer64 = htonll(dst->integer64);
+ fixed_length:
+ return dict_attr_sizes[dst_type][0];
+ }
+
+ if ((src_type == PW_TYPE_INTEGER64) &&
+ (dst_type == PW_TYPE_ETHERNET)) {
+ uint8_t array[8];
+ uint64_t i;
+
+ i = htonll(src->integer64);
+ memcpy(array, &i, 8);
+
+ /*
+ * For OUIs in the DB.
+ */
+ if ((array[0] != 0) || (array[1] != 0)) return -1;
+
+ memcpy(dst->ether, &array[2], 6);
+ goto fixed_length;
+ }
+
+ /*
+ * For integers, we allow the casting of a SMALL type to
+ * a larger type, but not vice-versa.
+ */
+ if (dst_type == PW_TYPE_INTEGER64) {
+ switch (src_type) {
+ case PW_TYPE_BYTE:
+ dst->integer64 = src->byte;
+ break;
+
+ case PW_TYPE_SHORT:
+ dst->integer64 = src->ushort;
+ break;
+
+ case PW_TYPE_INTEGER:
+ dst->integer64 = src->integer;
+ break;
+
+ case PW_TYPE_DATE:
+ dst->integer64 = src->date;
+ break;
+
+ case PW_TYPE_OCTETS:
+ goto do_octets;
+
+ default:
+ invalid_cast:
+ fr_strerror_printf("Invalid cast from %s to %s",
+ fr_int2str(dict_attr_types, src_type, "<INVALID>"),
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+ return -1;
+
+ }
+ goto fixed_length;
+ }
+
+ /*
+ * We can cast LONG integers to SHORTER ones, so long
+ * as the long one is on the LHS.
+ */
+ if (dst_type == PW_TYPE_INTEGER) {
+ switch (src_type) {
+ case PW_TYPE_BYTE:
+ dst->integer = src->byte;
+ break;
+
+ case PW_TYPE_SHORT:
+ dst->integer = src->ushort;
+ break;
+
+ case PW_TYPE_DATE:
+ dst->integer = src->date;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ dst->integer = ntohl(src->ipaddr.s_addr);
+ break;
+
+ case PW_TYPE_OCTETS:
+ goto do_octets;
+
+ default:
+ goto invalid_cast;
+ }
+ goto fixed_length;
+ }
+
+ if (dst_type == PW_TYPE_SHORT) {
+ switch (src_type) {
+ case PW_TYPE_BYTE:
+ dst->ushort = src->byte;
+ break;
+
+ case PW_TYPE_OCTETS:
+ goto do_octets;
+
+ default:
+ goto invalid_cast;
+ }
+ goto fixed_length;
+ }
+
+ /*
+ * We can cast integers less that < INT_MAX to signed
+ */
+ if (dst_type == PW_TYPE_SIGNED) {
+ switch (src_type) {
+ case PW_TYPE_BYTE:
+ dst->sinteger = src->byte;
+ break;
+
+ case PW_TYPE_SHORT:
+ dst->sinteger = src->ushort;
+ break;
+
+ case PW_TYPE_INTEGER:
+ if (src->integer > INT_MAX) {
+ fr_strerror_printf("Invalid cast: From integer to signed. integer value %u is larger "
+ "than max signed int and would overflow", src->integer);
+ return -1;
+ }
+ dst->sinteger = (int)src->integer;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ if (src->integer > INT_MAX) {
+ fr_strerror_printf("Invalid cast: From integer64 to signed. integer64 value %" PRIu64
+ " is larger than max signed int and would overflow", src->integer64);
+ return -1;
+ }
+ dst->sinteger = (int)src->integer64;
+ break;
+
+ case PW_TYPE_OCTETS:
+ goto do_octets;
+
+ default:
+ goto invalid_cast;
+ }
+ goto fixed_length;
+ }
+ /*
+ * Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
+ *
+ * For prefix to ipaddress conversions, we assume that the host portion has already
+ * been zeroed out.
+ *
+ * We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
+ *
+ * We only allow casts from prefixes to addresses if the prefix is the the length of
+ * the address, e.g. 32 for ipv4 128 for ipv6.
+ */
+ {
+ /*
+ * 10 bytes of 0x00 2 bytes of 0xff
+ */
+ static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
+
+ switch (dst_type) {
+ case PW_TYPE_IPV4_ADDR:
+ switch (src_type) {
+ case PW_TYPE_IPV6_ADDR:
+ if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
+ bad_v6_prefix_map:
+ fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
+ fr_int2str(dict_attr_types, src_type, "<INVALID>"),
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+ return -1;
+ }
+
+ memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
+ sizeof(dst->ipaddr));
+ goto fixed_length;
+
+ case PW_TYPE_IPV4_PREFIX:
+ if (src->ipv4prefix[1] != 32) {
+ bad_v4_prefix_len:
+ fr_strerror_printf("Invalid cast from %s to %s. Only /32 prefixes may be "
+ "cast to IP address types",
+ fr_int2str(dict_attr_types, src_type, "<INVALID>"),
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+ return -1;
+ }
+
+ memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
+ goto fixed_length;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (src->ipv6prefix[1] != 128) {
+ bad_v6_prefix_len:
+ fr_strerror_printf("Invalid cast from %s to %s. Only /128 prefixes may be "
+ "cast to IP address types",
+ fr_int2str(dict_attr_types, src_type, "<INVALID>"),
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
+ return -1;
+ }
+ if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
+ goto bad_v6_prefix_map;
+ }
+ memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
+ sizeof(dst->ipaddr));
+ goto fixed_length;
+
+ default:
+ break;
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ switch (src_type) {
+ case PW_TYPE_IPV4_ADDR:
+ /* Add the v4/v6 mapping prefix */
+ memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
+ memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
+ sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
+
+ goto fixed_length;
+
+ case PW_TYPE_IPV4_PREFIX:
+ if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
+
+ /* Add the v4/v6 mapping prefix */
+ memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
+ memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
+ sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
+ goto fixed_length;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
+
+ memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
+ goto fixed_length;
+
+ default:
+ break;
+ }
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ switch (src_type) {
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
+ dst->ipv4prefix[0] = 0;
+ dst->ipv4prefix[1] = 32;
+ goto fixed_length;
+
+ case PW_TYPE_IPV6_ADDR:
+ if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
+ goto bad_v6_prefix_map;
+ }
+ memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
+ sizeof(dst->ipv4prefix) - 2);
+ dst->ipv4prefix[0] = 0;
+ dst->ipv4prefix[1] = 32;
+ goto fixed_length;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
+ goto bad_v6_prefix_map;
+ }
+
+ /*
+ * Prefix must be >= 96 bits. If it's < 96 bytes and the
+ * above check passed, the v6 address wasn't masked
+ * correctly when it was packet into a value_data_t.
+ */
+ if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
+
+ memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
+ sizeof(dst->ipv4prefix) - 2);
+ dst->ipv4prefix[0] = 0;
+ dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
+ goto fixed_length;
+
+ default:
+ break;
+ }
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ switch (src_type) {
+ case PW_TYPE_IPV4_ADDR:
+ /* Add the v4/v6 mapping prefix */
+ memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
+ memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
+ (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
+ dst->ipv6prefix[0] = 0;
+ dst->ipv6prefix[1] = 128;
+ goto fixed_length;
+
+ case PW_TYPE_IPV4_PREFIX:
+ /* Add the v4/v6 mapping prefix */
+ memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
+ memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
+ (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
+ dst->ipv6prefix[0] = 0;
+ dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
+ goto fixed_length;
+
+ case PW_TYPE_IPV6_ADDR:
+ memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
+ dst->ipv6prefix[0] = 0;
+ dst->ipv6prefix[1] = 128;
+ goto fixed_length;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * The attribute we've found has to have a size which is
+ * compatible with the type of the destination cast.
+ */
+ if ((src_len < dict_attr_sizes[dst_type][0]) ||
+ (src_len > dict_attr_sizes[dst_type][1])) {
+ char const *src_type_name;
+
+ src_type_name = fr_int2str(dict_attr_types, src_type, "<INVALID>");
+ fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
+ src_type_name,
+ fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
+ dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
+ src_len);
+ return -1;
+ }
+
+ if (src_type == PW_TYPE_OCTETS) {
+ do_octets:
+ return value_data_hton(dst, dst_type, src->octets, src_len);
+ }
+
+ /*
+ * Convert host order to network byte order.
+ */
+ if ((dst_type == PW_TYPE_IPV4_ADDR) &&
+ ((src_type == PW_TYPE_INTEGER) ||
+ (src_type == PW_TYPE_DATE) ||
+ (src_type == PW_TYPE_SIGNED))) {
+ dst->ipaddr.s_addr = htonl(src->integer);
+
+ } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
+ ((dst_type == PW_TYPE_INTEGER) ||
+ (dst_type == PW_TYPE_DATE) ||
+ (dst_type == PW_TYPE_SIGNED))) {
+ dst->integer = htonl(src->ipaddr.s_addr);
+
+ } else { /* they're of the same byte order */
+ memcpy(&dst, &src, src_len);
+ }
+
+ return src_len;
+}
+
+/** Copy value data verbatim duplicating any buffers
+ *
+ * @param ctx To allocate buffers in.
+ * @param dst Where to copy value_data to.
+ * @param src_type Type of src.
+ * @param src Where to copy value_data from.
+ * @param src_len Where
+ */
+ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
+ const value_data_t *src, size_t src_len)
+{
+ switch (src_type) {
+ default:
+ memcpy(dst, src, sizeof(*src));
+ break;
+
+ case PW_TYPE_STRING:
+ dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src_len);
+ if (!dst->strvalue) return -1;
+ break;
+
+ case PW_TYPE_OCTETS:
+ dst->octets = talloc_memdup(ctx, src->octets, src_len);
+ talloc_set_type(dst->strvalue, uint8_t);
+ if (!dst->octets) return -1;
+ break;
+ }
+
+ return src_len;
+}
+
+
+
+/** Print one attribute value to a string
+ *
+ */
+char *value_data_aprints(TALLOC_CTX *ctx,
+ PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
+ size_t inlen, char quote)
+{
+ char *p = NULL;
+ unsigned int i;
+
+ switch (type) {
+ case PW_TYPE_STRING:
+ {
+ size_t len, ret;
+
+ if (!quote) {
+ p = talloc_bstrndup(ctx, data->strvalue, inlen);
+ if (!p) return NULL;
+ talloc_set_type(p, char);
+ return p;
+ }
+
+ /* Gets us the size of the buffer we need to alloc */
+ len = fr_prints_len(data->strvalue, inlen, quote);
+ p = talloc_array(ctx, char, len);
+ if (!p) return NULL;
+
+ ret = fr_prints(p, len, data->strvalue, inlen, quote);
+ if (!fr_assert(ret == (len - 1))) {
+ talloc_free(p);
+ return NULL;
+ }
+ break;
+ }
+
+ case PW_TYPE_INTEGER:
+ i = data->integer;
+ goto print_int;
+
+ case PW_TYPE_SHORT:
+ i = data->ushort;
+ goto print_int;
+
+ case PW_TYPE_BYTE:
+ i = data->byte;
+
+ print_int:
+ {
+ DICT_VALUE const *dv;
+
+ if (enumv && (dv = dict_valbyattr(enumv->attr, enumv->vendor, i))) {
+ p = talloc_typed_strdup(ctx, dv->name);
+ } else {
+ p = talloc_typed_asprintf(ctx, "%u", i);
+ }
+ }
+ break;
+
+ case PW_TYPE_SIGNED:
+ p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
+ data->ether[0], data->ether[1],
+ data->ether[2], data->ether[3],
+ data->ether[4], data->ether[5]);
+ break;
+
+ case PW_TYPE_ABINARY:
+#ifdef WITH_ASCEND_BINARY
+ p = talloc_array(ctx, char, 128);
+ if (!p) return NULL;
+ print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
+ break;
+#else
+ /* FALL THROUGH */
+#endif
+
+ case PW_TYPE_OCTETS:
+ p = talloc_array(ctx, char, 2 + 1 + inlen * 2);
+ if (!p) return NULL;
+ p[0] = '0';
+ p[1] = 'x';
+
+ fr_bin2hex(p + 2, data->octets, inlen);
+ p[2 + (inlen * 2)] = '\0';
+ break;
+
+ case PW_TYPE_DATE:
+ {
+ time_t t;
+ struct tm s_tm;
+
+ t = data->date;
+
+ p = talloc_zero_array(ctx, char, 64);
+ strftime(p, 63, "%b %e %Y %H:%M:%S %Z",
+ localtime_r(&t, &s_tm));
+ break;
+ }
+
+ /*
+ * We need to use the proper inet_ntop functions for IP
+ * addresses, else the output might not match output of
+ * other functions, which makes testing difficult.
+ *
+ * An example is tunnelled ipv4 in ipv6 addresses.
+ */
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ char buff[INET_ADDRSTRLEN + 4]; // + /prefix
+
+ buff[0] = '\0';
+ value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
+
+ p = talloc_typed_strdup(ctx, buff);
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
+
+ buff[0] = '\0';
+ value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
+
+ p = talloc_typed_strdup(ctx, buff);
+ }
+ break;
+
+ case PW_TYPE_IFID:
+ p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
+ (data->ifid[0] << 8) | data->ifid[1],
+ (data->ifid[2] << 8) | data->ifid[3],
+ (data->ifid[4] << 8) | data->ifid[5],
+ (data->ifid[6] << 8) | data->ifid[7]);
+ break;
+
+ case PW_TYPE_BOOLEAN:
+ p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
+ break;
+
+ /*
+ * Don't add default here
+ */
+ case PW_TYPE_INVALID:
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_COMBO_IP_PREFIX:
+ case PW_TYPE_TLV:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_MAX:
+ fr_assert(0);
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/** Print the value of an attribute to a string
+ *
+ * @note return value should be checked with is_truncated.
+ * @note Will always \0 terminate unless outlen == 0.
+ *
+ * @param out Where to write the printed version of the attribute value.
+ * @param outlen Length of the output buffer.
+ * @param type of data being printed.
+ * @param enumv Enumerated string values for integer types.
+ * @param data to print.
+ * @param inlen Length of data.
+ * @param quote char to escape in string output.
+ * @return the number of bytes written to the out buffer, or a number >= outlen if truncation has occurred.
+ */
+size_t value_data_prints(char *out, size_t outlen,
+ PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
+ ssize_t inlen, char quote)
+{
+ DICT_VALUE *v;
+ char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
+ char const *a = NULL;
+ char *p = out;
+ time_t t;
+ struct tm s_tm;
+ unsigned int i;
+
+ size_t len = 0, freespace = outlen;
+
+ if (!data) return 0;
+ if (outlen == 0) return inlen;
+
+ *out = '\0';
+
+ p = out;
+
+ switch (type) {
+ case PW_TYPE_STRING:
+
+ /*
+ * Ensure that WE add the quotation marks around the string.
+ */
+ if (quote) {
+ if (freespace < 3) return inlen + 2;
+
+ *p++ = quote;
+ freespace--;
+
+ len = fr_prints(p, freespace, data->strvalue, inlen, quote);
+ /* always terminate the quoted string with another quote */
+ if (len >= (freespace - 1)) {
+ /* Use out not p as we're operating on the entire buffer */
+ out[outlen - 2] = (char) quote;
+ out[outlen - 1] = '\0';
+ return len + 2;
+ }
+ p += len;
+ freespace -= len;
+
+ *p++ = (char) quote;
+ freespace--;
+ *p = '\0';
+
+ return len + 2;
+ }
+
+ return fr_prints(out, outlen, data->strvalue, inlen, quote);
+
+ case PW_TYPE_INTEGER:
+ i = data->integer;
+ goto print_int;
+
+ case PW_TYPE_SHORT:
+ i = data->ushort;
+ goto print_int;
+
+ case PW_TYPE_BYTE:
+ i = data->byte;
+
+print_int:
+ /* Normal, non-tagged attribute */
+ if (enumv && (v = dict_valbyattr(enumv->attr, enumv->vendor, i)) != NULL) {
+ a = v->name;
+ len = strlen(a);
+ } else {
+ /* should never be truncated */
+ len = snprintf(buf, sizeof(buf), "%u", i);
+ a = buf;
+ }
+ break;
+
+ case PW_TYPE_INTEGER64:
+ return snprintf(out, outlen, "%" PRIu64, data->integer64);
+
+ case PW_TYPE_DATE:
+ t = data->date;
+ if (quote > 0) {
+ len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
+ buf[0] = (char) quote;
+ buf[len - 1] = (char) quote;
+ buf[len] = '\0';
+ } else {
+ len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
+ }
+ a = buf;
+ break;
+
+ case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
+ len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
+ a = buf;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
+ len = strlen(buf);
+ break;
+
+ case PW_TYPE_ABINARY:
+#ifdef WITH_ASCEND_BINARY
+ print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, inlen, quote);
+ a = buf;
+ len = strlen(buf);
+ break;
+#else
+ /* FALL THROUGH */
+#endif
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_TLV:
+ {
+ size_t binlen;
+ size_t hexlen;
+
+ binlen = inlen;
+ hexlen = (binlen * 2) + 2; /* NOT accounting for trailing NUL */
+
+ /*
+ * If the buffer is too small, put something into
+ * it, and return how much we should have written
+ *
+ * 0 + x + H + H + NUL = 5
+ */
+ if (freespace < 5) {
+ switch (freespace) {
+ case '4':
+ case '3':
+ out[0] = '0';
+ out[1] = 'x';
+ out[2] = '\0';
+ return hexlen;
+
+ case 2:
+ *out = '0';
+ out++;
+ /* FALL-THROUGH */
+
+ case 1:
+ *out = '\0';
+ break;
+
+ case 0:
+ break;
+ }
+
+ return hexlen;
+ }
+
+ /*
+ * The output buffer is at least 5 bytes, we haev
+ * room for '0xHH' plus a trailing NUL byte.
+ */
+ out[0] = '0';
+ out[1] = 'x';
+
+ /*
+ * Get maximum number of bytes we can encode
+ * given freespace, ensuring we account for '0',
+ * 'x', and the trailing NUL in the buffer.
+ *
+ * Note that we can't have "freespace = 0" after
+ * this, as 'freespace' has to be at least 5.
+ */
+ freespace -= 3;
+ freespace /= 2;
+ if (binlen > freespace) {
+ binlen = freespace;
+ }
+
+ fr_bin2hex(out + 2, data->octets, binlen);
+ return hexlen;
+ }
+
+ case PW_TYPE_IFID:
+ a = ifid_ntoa(buf, sizeof(buf), data->ifid);
+ len = strlen(buf);
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
+ len = strlen(buf);
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ {
+ struct in6_addr addr;
+
+ /*
+ * Alignment issues.
+ */
+ memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
+
+ a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
+ if (a) {
+ p = buf;
+
+ len = strlen(buf);
+ p += len;
+ len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
+ }
+ }
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ {
+ struct in_addr addr;
+
+ /*
+ * Alignment issues.
+ */
+ memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
+
+ a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
+ if (a) {
+ p = buf;
+
+ len = strlen(buf);
+ p += len;
+ len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
+ }
+ }
+ break;
+
+ case PW_TYPE_ETHERNET:
+ return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
+ data->ether[0], data->ether[1],
+ data->ether[2], data->ether[3],
+ data->ether[4], data->ether[5]);
+
+ /*
+ * Don't add default here
+ */
+ case PW_TYPE_INVALID:
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_COMBO_IP_PREFIX:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ case PW_TYPE_TIMEVAL:
+ case PW_TYPE_BOOLEAN:
+ case PW_TYPE_MAX:
+ fr_assert(0);
+ *out = '\0';
+ return 0;
+ }
+
+ if (a) strlcpy(out, a, outlen);
+
+ return len; /* Return the number of bytes we would of written (for truncation detection) */
+}
+
diff --git a/src/lib/version.c b/src/lib/version.c
new file mode 100644
index 0000000..c4dc025
--- /dev/null
+++ b/src/lib/version.c
@@ -0,0 +1,58 @@
+/*
+ * version.c Validate application and library magic numbers.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 1999-2014 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
+
+/** Check if the application linking to the library has the correct magic number
+ *
+ * @param magic number as defined by RADIUSD_MAGIC_NUMBER
+ * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch.
+ */
+int fr_check_lib_magic(uint64_t magic)
+{
+ if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (prefix) mismatch."
+ " application: %x library: %x",
+ MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (version) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
+ fr_strerror_printf("Application and libfreeradius-radius magic number (commit) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
+ return -3;
+ }
+
+ return 0;
+}
diff --git a/src/main/.gitignore b/src/main/.gitignore
new file mode 100644
index 0000000..cc538fe
--- /dev/null
+++ b/src/main/.gitignore
@@ -0,0 +1,13 @@
+Makefile
+radsniff.mk
+checkrad
+radclient
+radiusd
+radlast
+radtest
+radsniff
+radwho
+radmin
+radconf2xml
+dhclient
+*_ext
diff --git a/src/main/acct.c b/src/main/acct.c
new file mode 100644
index 0000000..90a0dd8
--- /dev/null
+++ b/src/main/acct.c
@@ -0,0 +1,186 @@
+/*
+ * acct.c Accounting routines.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ * Copyright 2000 Alan Curry <pacman@world.std.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#ifdef WITH_ACCOUNTING
+/*
+ * rad_accounting: call modules.
+ *
+ * The return value of this function isn't actually used right now, so
+ * it's not entirely clear if it is returning the right things. --Pac.
+ */
+int rad_accounting(REQUEST *request)
+{
+ int result = RLM_MODULE_OK;
+
+
+#ifdef WITH_PROXY
+#define WAS_PROXIED (request->proxy)
+#else
+#define WAS_PROXIED (0)
+#endif
+
+ /*
+ * Run the modules only once, before proxying.
+ */
+ if (!WAS_PROXIED) {
+ VALUE_PAIR *vp;
+ int acct_type = 0;
+
+ result = module_preacct(request);
+ switch (result) {
+ /*
+ * The module has a number of OK return codes.
+ */
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ break;
+ /*
+ * The module handled the request, stop here.
+ */
+ case RLM_MODULE_HANDLED:
+ return result;
+ /*
+ * The module failed, or said the request is
+ * invalid, therefore we stop here.
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ return result;
+ }
+
+ /*
+ * Do the data storage before proxying. This is to ensure
+ * that we log the packet, even if the proxy never does.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_ACCT_TYPE, 0, TAG_ANY);
+ if (vp) {
+ acct_type = vp->vp_integer;
+ DEBUG2(" Found Acct-Type %s",
+ dict_valnamebyattr(PW_ACCT_TYPE, 0, acct_type));
+ }
+ result = process_accounting(acct_type, request);
+ switch (result) {
+ /*
+ * In case the accounting module returns FAIL,
+ * it's still useful to send the data to the
+ * proxy.
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ break;
+ /*
+ * The module handled the request, don't reply.
+ */
+ case RLM_MODULE_HANDLED:
+ return result;
+ /*
+ * Neither proxy, nor reply to invalid requests.
+ */
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ return result;
+ }
+
+ /*
+ * Maybe one of the preacct modules has decided
+ * that a proxy should be used.
+ */
+ if ((vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY))) {
+ REALM *realm;
+
+ /*
+ * Check whether Proxy-To-Realm is
+ * a LOCAL realm.
+ */
+ realm = realm_find2(vp->vp_strvalue);
+ if (realm && !realm->acct_pool) {
+ DEBUG("rad_accounting: Cancelling proxy to realm %s, as it is a LOCAL realm.", realm->name);
+ fr_pair_delete_by_num(&request->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+ } else {
+ /*
+ * Don't reply to the NAS now because
+ * we have to send the proxied packet
+ * before that.
+ */
+ return result;
+ }
+ }
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * We didn't see a reply to the proxied request. Fail.
+ */
+ if (request->proxy && !request->proxy_reply) return RLM_MODULE_FAIL;
+#endif
+
+ /*
+ * We get here IF we're not proxying, OR if we've
+ * received the accounting reply from the end server,
+ * THEN we can reply to the NAS.
+ * If the accounting module returns NOOP, the data
+ * storage did not succeed, so radiusd should not send
+ * Accounting-Response.
+ */
+ switch (result) {
+ /*
+ * Send back an ACK to the NAS.
+ */
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ /*
+ * Failed to log or to proxy the accounting data,
+ * therefore don't reply to the NAS.
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ break;
+ }
+ return result;
+}
+#endif
diff --git a/src/main/all.mk b/src/main/all.mk
new file mode 100644
index 0000000..2517cd2
--- /dev/null
+++ b/src/main/all.mk
@@ -0,0 +1,3 @@
+SUBMAKEFILES := radclient.mk radiusd.mk radsniff.mk radmin.mk radattr.mk \
+ radwho.mk radlast.mk radtest.mk radzap.mk checkrad.mk \
+ libfreeradius-server.mk unittest.mk
diff --git a/src/main/auth.c b/src/main/auth.c
new file mode 100644
index 0000000..84889b8
--- /dev/null
+++ b/src/main/auth.c
@@ -0,0 +1,894 @@
+/*
+ * auth.c User authentication.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Jeff Carneal <jeff@apex.net>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/state.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+/*
+ * Return a short string showing the terminal server, port
+ * and calling station ID.
+ */
+char *auth_name(char *buf, size_t buflen, REQUEST *request, bool do_cli)
+{
+ VALUE_PAIR *cli;
+ VALUE_PAIR *pair;
+ uint32_t port = 0; /* RFC 2865 NAS-Port is 4 bytes */
+ char const *tls = "";
+
+ if ((cli = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) == NULL) {
+ do_cli = false;
+ }
+
+ if ((pair = fr_pair_find_by_num(request->packet->vps, PW_NAS_PORT, 0, TAG_ANY)) != NULL) {
+ port = pair->vp_integer;
+ }
+
+ if (request->packet->dst_port == 0) {
+ if (fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_PROXIED_TO, 0, TAG_ANY)) {
+ tls = " via TLS tunnel";
+ } else {
+ tls = " via proxy to virtual server";
+ }
+ }
+
+ snprintf(buf, buflen, "from client %.128s port %u%s%.128s%s",
+ request->client->shortname, port,
+ (do_cli ? " cli " : ""), (do_cli ? cli->vp_strvalue : ""),
+ tls);
+
+ return buf;
+}
+
+
+
+/*
+ * Make sure user/pass are clean
+ * and then log them
+ */
+static int rad_authlog(char const *msg, REQUEST *request, int goodpass)
+{
+ int logit;
+ char const *extra_msg = NULL;
+ char clean_password[1024];
+ char clean_username[1024];
+ char buf[1024];
+ char extra[1024];
+ char *p;
+ VALUE_PAIR *username = NULL;
+
+ if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) && !request->root->log_accept) {
+ return 0;
+ }
+
+ if ((request->reply->code == PW_CODE_ACCESS_REJECT) && !request->root->log_reject) {
+ return 0;
+ }
+
+ /*
+ * Get the correct username based on the configured value
+ */
+ if (!log_stripped_names) {
+ username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ } else {
+ username = request->username;
+ }
+
+ /*
+ * Clean up the username
+ */
+ if (username == NULL) {
+ strcpy(clean_username, "<no User-Name attribute>");
+ } else {
+ fr_prints(clean_username, sizeof(clean_username), username->vp_strvalue, username->vp_length, '\0');
+ }
+
+ /*
+ * Clean up the password
+ */
+ if (request->root->log_auth_badpass || request->root->log_auth_goodpass) {
+ if (!request->password) {
+ VALUE_PAIR *auth_type;
+
+ auth_type = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY);
+ if (auth_type) {
+ snprintf(clean_password, sizeof(clean_password),
+ "<via Auth-Type = %s>",
+ dict_valnamebyattr(PW_AUTH_TYPE, 0,
+ auth_type->vp_integer));
+ } else {
+ strcpy(clean_password, "<no User-Password attribute>");
+ }
+ } else if (fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
+ strcpy(clean_password, "<CHAP-Password>");
+ } else {
+ fr_prints(clean_password, sizeof(clean_password),
+ request->password->vp_strvalue, request->password->vp_length, '\0');
+ }
+ }
+
+ if (goodpass) {
+ logit = request->root->log_auth_goodpass;
+ extra_msg = request->root->auth_goodpass_msg;
+ } else {
+ logit = request->root->log_auth_badpass;
+ extra_msg = request->root->auth_badpass_msg;
+ }
+
+ if (extra_msg) {
+ extra[0] = ' ';
+ p = extra + 1;
+ if (radius_xlat(p, sizeof(extra) - 1, request, extra_msg, NULL, NULL) < 0) {
+ return -1;
+ }
+ } else {
+ *extra = '\0';
+ }
+
+ RAUTH("%s: [%s%s%s] (%s)%s",
+ msg,
+ clean_username,
+ logit ? "/" : "",
+ logit ? clean_password : "",
+ auth_name(buf, sizeof(buf), request, 1),
+ extra);
+
+ return 0;
+}
+
+/*
+ * Check password.
+ *
+ * Returns: 0 OK
+ * -1 Password fail
+ * -2 Rejected (Auth-Type = Reject, send Port-Message back)
+ * 1 End check & return, don't reply
+ *
+ * NOTE: NOT the same as the RLM_ values !
+ */
+static int CC_HINT(nonnull) rad_check_password(REQUEST *request)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *auth_type_pair;
+ int auth_type = -1;
+ int result;
+ int auth_type_count = 0;
+
+ /*
+ * Look for matching check items. We skip the whole lot
+ * if the authentication type is PW_AUTH_TYPE_ACCEPT or
+ * PW_AUTH_TYPE_REJECT.
+ */
+ fr_cursor_init(&cursor, &request->config);
+ while ((auth_type_pair = fr_cursor_next_by_num(&cursor, PW_AUTH_TYPE, 0, TAG_ANY))) {
+ auth_type = auth_type_pair->vp_integer;
+ auth_type_count++;
+
+ RDEBUG2("Found Auth-Type = %s", dict_valnamebyattr(PW_AUTH_TYPE, 0, auth_type));
+ if (auth_type == PW_AUTH_TYPE_REJECT) {
+ RDEBUG2("Auth-Type = Reject, rejecting user");
+
+ return -2;
+ }
+ }
+
+ /*
+ * Warn if more than one Auth-Type was found, because only the last
+ * one found will actually be used.
+ */
+ if ((auth_type_count > 1) && (rad_debug_lvl) && request->username) {
+ RERROR("Warning: Found %d auth-types on request for user '%s'",
+ auth_type_count, request->username->vp_strvalue);
+ }
+
+ /*
+ * This means we have a proxy reply or an accept and it wasn't
+ * rejected in the above loop. So that means it is accepted and we
+ * do no further authentication.
+ */
+ if ((auth_type == PW_AUTH_TYPE_ACCEPT)
+#ifdef WITH_PROXY
+ || (request->proxy)
+#endif
+ ) {
+ RDEBUG2("Auth-Type = Accept, accepting the user");
+ return 0;
+ }
+
+ /*
+ * Check that Auth-Type has been set, and reject if not.
+ *
+ * Do quick checks to see if Cleartext-Password or Crypt-Password have
+ * been set, and complain if so.
+ */
+ if (auth_type < 0) {
+ if (fr_pair_find_by_num(request->config, PW_CRYPT_PASSWORD, 0, TAG_ANY) != NULL) {
+ RWDEBUG2("No module configured to handle comparisons with &control:Crypt-Password");
+ RWDEBUG2("Add pap to the authorize { ... } and authenticate { ... } sections of this "
+ "virtual server to handle this \"known good\" password type");
+ }
+ else if (fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) != NULL) {
+ RWDEBUG2("No module configured to handle comparisons with &control:Cleartext-Password");
+ RWDEBUG2("Add pap or chap to the authorize { ... } and authenticate { ... } sections "
+ "of this virtual server to handle this \"known good\" password type");
+ }
+
+ /*
+ * The admin hasn't told us how to
+ * authenticate the user, so we reject them!
+ *
+ * This is fail-safe.
+ */
+
+ REDEBUG2("No Auth-Type found: rejecting the user via Post-Auth-Type = Reject");
+ return -2;
+ }
+
+ /*
+ * See if there is a module that handles
+ * this Auth-Type, and turn the RLM_ return
+ * status into the values as defined at
+ * the top of this function.
+ */
+ result = process_authenticate(auth_type, request);
+ switch (result) {
+ /*
+ * An authentication module FAIL
+ * return code, or any return code that
+ * is not expected from authentication,
+ * is the same as an explicit REJECT!
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_UPDATED:
+ case RLM_MODULE_USERLOCK:
+ default:
+ result = -1;
+ break;
+
+ case RLM_MODULE_OK:
+ result = 0;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ result = 1;
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Post-authentication step processes the response before it is
+ * sent to the NAS. It can receive both Access-Accept and Access-Reject
+ * replies.
+ */
+int rad_postauth(REQUEST *request)
+{
+ int result;
+ int postauth_type = 0;
+ VALUE_PAIR *vp;
+
+ if (request->reply->code == PW_CODE_ACCESS_CHALLENGE) {
+ fr_pair_delete_by_num(&request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+ vp = pair_make_config("Post-Auth-Type", "Challenge", T_OP_SET);
+ if (!vp) return RLM_MODULE_OK;
+
+ } else if (request->reply->code == PW_CODE_ACCESS_REJECT) {
+ fr_pair_delete_by_num(&request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+ vp = pair_make_config("Post-Auth-Type", "Reject", T_OP_SET);
+ if (!vp) return RLM_MODULE_OK;
+
+ } else {
+ vp = fr_pair_find_by_num(request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+ }
+
+ /*
+ * If a method was chosen, use that.
+ */
+ if (vp) {
+ postauth_type = vp->vp_integer;
+ RDEBUG2("Using Post-Auth-Type %s",
+ dict_valnamebyattr(PW_POST_AUTH_TYPE, 0, postauth_type));
+
+ if (postauth_type == PW_POST_AUTH_TYPE_CHALLENGE) request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+
+ if (postauth_type == PW_POST_AUTH_TYPE_REJECT) request->reply->code = PW_CODE_ACCESS_REJECT;
+ }
+
+ result = process_post_auth(postauth_type, request);
+ switch (result) {
+ /*
+ * The module failed, or said to reject the user: Do so.
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ /*
+ * We WERE going to have a nice reply, but
+ * something went wrong. So we've got to run
+ * Post-Auth-Type Reject.
+ */
+ if (request->reply->code != PW_CODE_ACCESS_REJECT) {
+ RDEBUG("Using Post-Auth-Type Reject");
+
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ process_post_auth(PW_POST_AUTH_TYPE_REJECT, request);
+ }
+
+ /*
+ * Only discard session state when we're sending
+ * packets to the network. The State attribute
+ * is use both for the outer session and copied
+ * to the inner-tunnel session for (e.g.) PEAP.
+ * So we don't want to delete the information in
+ * the inner tunnel, and then have it no longer
+ * accessible from the outer session.
+ */
+ if (!request->parent) fr_state_discard(request, request->packet);
+ result = RLM_MODULE_REJECT;
+ break;
+ /*
+ * The module handled the request, cancel the reply.
+ */
+ case RLM_MODULE_HANDLED:
+ /* FIXME */
+ break;
+ /*
+ * The module had a number of OK return codes.
+ */
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ result = RLM_MODULE_OK;
+
+ if (request->reply->code == PW_CODE_ACCESS_CHALLENGE) {
+ fr_state_put_vps(request, request->packet, request->reply);
+
+ } else {
+ fr_state_discard(request, request->packet);
+ }
+ break;
+ }
+
+ /*
+ * Rejects during authorize, etc. are handled by the
+ * earlier code, which logs a reason for the rejection.
+ * If the packet is rejected in post-auth, we need to log
+ * that as a separate reason.
+ */
+ if (result == RLM_MODULE_REJECT) {
+ if (request->reply->code != RLM_MODULE_REJECT) {
+ rad_authlog("Rejected in post-auth", request, 0);
+ }
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ }
+
+ if (request->reply->code == PW_CODE_ACCESS_REJECT) {
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL) {
+ char msg[MAX_STRING_LEN+19];
+
+ snprintf(msg, sizeof(msg), "Login incorrect (%s)",
+ vp->vp_strvalue);
+ rad_authlog(msg, request, 0);
+ } else {
+ rad_authlog("Login incorrect", request, 0);
+ }
+ }
+
+ /*
+ * If we're still accepting the user, say so.
+ */
+ if (request->reply->code == PW_CODE_ACCESS_ACCEPT) {
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_MODULE_SUCCESS_MESSAGE, 0, TAG_ANY)) != NULL) {
+ char msg[MAX_STRING_LEN+12];
+
+ snprintf(msg, sizeof(msg), "Login OK (%s)",
+ vp->vp_strvalue);
+ rad_authlog(msg, request, 1);
+ } else {
+ rad_authlog("Login OK", request, 1);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Process and reply to an authentication request
+ *
+ * The return value of this function isn't actually used right now, so
+ * it's not entirely clear if it is returning the right things. --Pac.
+ */
+int rad_authenticate(REQUEST *request)
+{
+#ifdef WITH_SESSION_MGMT
+ VALUE_PAIR *check_item;
+#endif
+ VALUE_PAIR *module_msg;
+ VALUE_PAIR *tmp = NULL;
+ int result;
+ char autz_retry = 0;
+ int autz_type = 0;
+
+#ifdef WITH_PROXY
+ /*
+ * If this request got proxied to another server, we need
+ * to check whether it authenticated the request or not.
+ *
+ * request->proxy gets set only AFTER authorization, so
+ * it's safe to check it here. If it exists, it means
+ * we're doing a second pass through rad_authenticate().
+ */
+ if (request->proxy) {
+ int code = 0;
+
+ if (request->proxy_reply) code = request->proxy_reply->code;
+
+ switch (code) {
+ /*
+ * Reply of ACCEPT means accept, thus set Auth-Type
+ * accordingly.
+ */
+ case PW_CODE_ACCESS_ACCEPT:
+ tmp = radius_pair_create(request,
+ &request->config,
+ PW_AUTH_TYPE, 0);
+ if (tmp) tmp->vp_integer = PW_AUTH_TYPE_ACCEPT;
+ goto authenticate;
+
+ /*
+ * Challenges are punted back to the NAS without any
+ * further processing.
+ */
+ case PW_CODE_ACCESS_CHALLENGE:
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ fr_state_put_vps(request, request->packet, request->reply);
+ return RLM_MODULE_OK;
+
+ /*
+ * ALL other replies mean reject. (this is fail-safe)
+ *
+ * Do NOT do any authorization or authentication. They
+ * are being rejected, so we minimize the amount of work
+ * done by the server, by rejecting them here.
+ */
+ case PW_CODE_ACCESS_REJECT:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ rad_authlog("Login incorrect (Home Server says so)",
+ request, 0);
+ return RLM_MODULE_REJECT;
+
+ default:
+ rad_authlog("Login incorrect (Home Server failed to respond)",
+ request, 0);
+ return RLM_MODULE_REJECT;
+ }
+ }
+#endif
+ /*
+ * Look for, and cache, passwords.
+ */
+ if (!request->password) {
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ }
+ if (!request->password) {
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ }
+
+ /*
+ * Grab the VPS associated with the State attribute.
+ */
+ fr_state_get_vps(request, request->packet);
+
+ /*
+ * Get the user's authorization information from the database
+ */
+autz_redo:
+ result = process_authorize(autz_type, request);
+ switch (result) {
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ break;
+ case RLM_MODULE_HANDLED:
+ return result;
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ if ((module_msg = fr_pair_find_by_num(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL) {
+ char msg[MAX_STRING_LEN + 16];
+ snprintf(msg, sizeof(msg), "Invalid user (%s)",
+ module_msg->vp_strvalue);
+ rad_authlog(msg,request,0);
+ } else {
+ rad_authlog("Invalid user", request, 0);
+ }
+ return result;
+ }
+ if (!autz_retry) {
+ tmp = fr_pair_find_by_num(request->config, PW_AUTZ_TYPE, 0, TAG_ANY);
+ if (tmp) {
+ autz_type = tmp->vp_integer;
+ RDEBUG2("Using Autz-Type %s",
+ dict_valnamebyattr(PW_AUTZ_TYPE, 0, autz_type));
+ autz_retry = 1;
+ goto autz_redo;
+ }
+ }
+
+ /*
+ * If we haven't already proxied the packet, then check
+ * to see if we should. Maybe one of the authorize
+ * modules has decided that a proxy should be used. If
+ * so, get out of here and send the packet.
+ */
+#ifdef WITH_PROXY
+ if (request->proxy == NULL)
+#endif
+ {
+ if ((tmp = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY)) != NULL) {
+ REALM *realm;
+
+ realm = realm_find2(tmp->vp_strvalue);
+
+ /*
+ * Don't authenticate, as the request is going to
+ * be proxied.
+ */
+ if (realm && realm->auth_pool) {
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Catch users who set Proxy-To-Realm to a LOCAL
+ * realm (sigh). But don't complain if it is
+ * *the* LOCAL realm.
+ */
+ if (realm && (strcmp(realm->name, "LOCAL") != 0)) {
+ RWDEBUG2("You set Proxy-To-Realm = %s, but it is a LOCAL realm! Cancelling proxy request.", realm->name);
+ }
+
+ if (!realm) {
+ RWDEBUG2("You set Proxy-To-Realm = %s, but the realm does not exist! Cancelling invalid proxy request.", tmp->vp_strvalue);
+ }
+ } else if (((tmp = fr_pair_find_by_num(request->config, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) ||
+ ((tmp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY)) != NULL) ||
+ ((tmp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL) ||
+ ((tmp = fr_pair_find_by_num(request->config, PW_HOME_SERVER_NAME, 0, TAG_ANY)) != NULL)) {
+ RDEBUG("Proxying due to %s", tmp->da->name);
+ return RLM_MODULE_OK;
+ }
+ }
+
+#ifdef WITH_PROXY
+authenticate:
+#endif
+
+ /*
+ * Validate the user
+ */
+ do {
+ result = rad_check_password(request);
+ if (result > 0) {
+ return RLM_MODULE_HANDLED;
+ }
+
+ } while(0);
+
+ /*
+ * Failed to validate the user.
+ *
+ * We PRESUME that the code which failed will clean up
+ * request->reply->vps, to be ONLY the reply items it
+ * wants to send back.
+ */
+ if (result < 0) {
+ RDEBUG2("Failed to authenticate the user");
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+
+ if (request->password) {
+ VERIFY_VP(request->password);
+ /* double check: maybe the secret is wrong? */
+ if ((rad_debug_lvl > 1) && (request->password->da->attr == PW_USER_PASSWORD)) {
+ uint8_t const *p;
+
+ p = (uint8_t const *) request->password->vp_strvalue;
+ while (*p) {
+ int size;
+
+ size = fr_utf8_char(p, -1);
+ if (!size) {
+ RWDEBUG("Unprintable characters in the password. Double-check the "
+ "shared secret on the server and the NAS!");
+ break;
+ }
+ p += size;
+ }
+ }
+ }
+ }
+
+#ifdef WITH_SESSION_MGMT
+ if (result >= 0 &&
+ (check_item = fr_pair_find_by_num(request->config, PW_SIMULTANEOUS_USE, 0, TAG_ANY)) != NULL) {
+ int r, session_type = 0;
+ char logstr[1024];
+ char umsg[MAX_STRING_LEN + 1];
+
+ tmp = fr_pair_find_by_num(request->config, PW_SESSION_TYPE, 0, TAG_ANY);
+ if (tmp) {
+ session_type = tmp->vp_integer;
+ RDEBUG2("Using Session-Type %s",
+ dict_valnamebyattr(PW_SESSION_TYPE, 0, session_type));
+ }
+
+ /*
+ * User authenticated O.K. Now we have to check
+ * for the Simultaneous-Use parameter.
+ */
+ if (request->username &&
+ (r = process_checksimul(session_type, request, check_item->vp_integer)) != 0) {
+ char mpp_ok = 0;
+
+ if (r == 2){
+ /* Multilink attempt. Check if port-limit > simultaneous-use */
+ VALUE_PAIR *port_limit;
+
+ if ((port_limit = fr_pair_find_by_num(request->reply->vps, PW_PORT_LIMIT, 0, TAG_ANY)) != NULL &&
+ port_limit->vp_integer > check_item->vp_integer){
+ RDEBUG2("MPP is OK");
+ mpp_ok = 1;
+ }
+ }
+ if (!mpp_ok){
+ if (check_item->vp_integer > 1) {
+ snprintf(umsg, sizeof(umsg), "%s (%u)", main_config.denied_msg,
+ check_item->vp_integer);
+ } else {
+ strlcpy(umsg, main_config.denied_msg, sizeof(umsg));
+ }
+
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+
+ /*
+ * They're trying to log in too many times.
+ * Remove ALL reply attributes.
+ */
+ fr_pair_list_free(&request->reply->vps);
+ pair_make_reply("Reply-Message", umsg, T_OP_SET);
+
+ snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
+ check_item->vp_integer,
+ r == 2 ? "[MPP attempt]" : "");
+ rad_authlog(logstr, request, 1);
+
+ result = -1;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Result should be >= 0 here - if not, it means the user
+ * is rejected, so we just process post-auth and return.
+ */
+ if (result < 0) {
+ return RLM_MODULE_REJECT;
+ }
+
+ /*
+ * Set the reply to Access-Accept, if it hasn't already
+ * been set to something. (i.e. Access-Challenge)
+ */
+ if (request->reply->code == 0) {
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+ }
+
+ return result;
+}
+
+/*
+ * Run a virtual server auth and postauth
+ *
+ */
+int rad_virtual_server(REQUEST *request)
+{
+ VALUE_PAIR *vp;
+ int result;
+
+ RDEBUG("Virtual server %s received request", request->server);
+ rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
+
+ if (!request->username) {
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+
+ /*
+ * Complain about possible issues related to tunnels.
+ */
+ if (request->parent && request->parent->username && request->username) {
+ /*
+ * Look at the full User-Name with realm.
+ */
+ if (request->parent->username->da->attr == PW_STRIPPED_USER_NAME) {
+ vp = fr_pair_find_by_num(request->parent->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ rad_assert(vp != NULL);
+ } else {
+ vp = request->parent->username;
+ }
+
+ /*
+ * If the names aren't identical, we do some detailed checks.
+ */
+ if (strcmp(vp->vp_strvalue, request->username->vp_strvalue) != 0) {
+ char const *outer, *inner;
+
+ outer = strchr(vp->vp_strvalue, '@');
+
+ /*
+ * If there's no realm, or there's a user identifier before
+ * the realm name, check the user identifier.
+ *
+ * It SHOULD be "anonymous", or "anonymous@realm"
+ */
+ if (outer) {
+ if ((outer != vp->vp_strvalue) &&
+ ((vp->vp_length < 10) || (memcmp(vp->vp_strvalue, "anonymous@", 10) != 0))) {
+ RWDEBUG("Outer User-Name is not anonymized. User privacy is compromised.");
+ } /* else it is anonymized */
+
+ /*
+ * Check when there's no realm, and without the trailing '@'
+ */
+ } else if ((vp->vp_length < 9) || (memcmp(vp->vp_strvalue, "anonymous", 9) != 0)) {
+ RWDEBUG("Outer User-Name is not anonymized. User privacy is compromised.");
+
+ } /* else the user identifier is anonymized */
+
+ /*
+ * Look for an inner realm, which may or may not exist.
+ */
+ inner = strchr(request->username->vp_strvalue, '@');
+ if (outer && inner) {
+ outer++;
+ inner++;
+
+ /*
+ * The realms are different, do
+ * more detailed checks.
+ */
+ if (strcmp(outer, inner) != 0) {
+ size_t outer_len, inner_len;
+
+ outer_len = vp->vp_length;
+ outer_len -= (outer - vp->vp_strvalue);
+
+ inner_len = request->username->vp_length;
+ inner_len -= (inner - request->username->vp_strvalue);
+
+ /*
+ * Inner: secure.example.org
+ * Outer: example.org
+ */
+ if (inner_len > outer_len) {
+ char const *suffix;
+
+ suffix = inner + (inner_len - outer_len) - 1;
+
+ if ((*suffix != '.') ||
+ (strcmp(suffix + 1, outer) != 0)) {
+ RWDEBUG("Possible spoofing: Inner realm '%s' is not a subdomain of the outer realm '%s'", inner, outer);
+ }
+
+ } else {
+ RWDEBUG("Possible spoofing: Inner realm and outer realms are different");
+ }
+ }
+ }
+
+ } else {
+ RWDEBUG("Outer and inner identities are the same. User privacy is compromised.");
+ }
+ }
+
+ RDEBUG("server %s {", request->server);
+ RINDENT();
+
+ /*
+ * We currently only handle AUTH packets here.
+ * This could be expanded to handle other packets as well if required.
+ */
+ rad_assert(request->packet->code == PW_CODE_ACCESS_REQUEST);
+
+ result = rad_authenticate(request);
+
+ /*
+ * Allow bare "accept" and "reject" policies in the inner
+ * tunnel.
+ */
+ if (!request->reply->code &&
+ (vp = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY)) != NULL) {
+ switch (vp->vp_integer) {
+ case PW_AUTH_TYPE_ACCEPT:
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ case PW_AUTH_TYPE_REJECT:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (request->reply->code == PW_CODE_ACCESS_REJECT) {
+ fr_pair_delete_by_num(&request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+ vp = pair_make_config("Post-Auth-Type", "Reject", T_OP_SET);
+ if (vp) rad_postauth(request);
+ }
+
+ if (request->reply->code == PW_CODE_ACCESS_ACCEPT) {
+ /*
+ * Check that there is a name which can be used
+ * to identify the user. The configuration
+ * depends on User-Name or Stripped-User-Name
+ * existing, and being (mostly) unique to that
+ * user.
+ */
+ if (!request->parent && request->username &&
+ (request->username->da->attr == PW_USER_NAME) &&
+ (request->username->vp_strvalue[0] == '@') &&
+ !fr_pair_find_by_num(request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY)) {
+ RWDEBUG("User-Name is anonymized, and no Stripped-User-Name exists.");
+ RWDEBUG("It may be difficult or impossible to identify the user");
+ RWDEBUG("Please update Stripped-User-Name with information which identifies the user");
+ }
+
+ rad_postauth(request);
+ }
+
+ REXDENT();
+ RDEBUG("} # server %s", request->server);
+
+ RDEBUG("Virtual server sending reply");
+ rdebug_pair_list(L_DBG_LVL_1, request, request->reply->vps, NULL);
+
+ return result;
+}
diff --git a/src/main/cb.c b/src/main/cb.c
new file mode 100644
index 0000000..db764aa
--- /dev/null
+++ b/src/main/cb.c
@@ -0,0 +1,247 @@
+/*
+ * cb.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <freeradius-devel/radiusd.h>
+
+#ifdef WITH_TLS
+void cbtls_info(SSL const *s, int where, int ret)
+{
+ char const *role, *state;
+ REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
+
+ if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) {
+ role = "Client ";
+ } else if (((where & ~SSL_ST_MASK)) & SSL_ST_ACCEPT) {
+ role = "Server ";
+ } else {
+ role = "";
+ }
+
+ state = SSL_state_string_long(s);
+ state = state ? state : "<none>";
+
+ if ((where & SSL_CB_LOOP) || (where & SSL_CB_HANDSHAKE_START) || (where & SSL_CB_HANDSHAKE_DONE)) {
+ if (RDEBUG_ENABLED3) {
+ char const *abbrv = SSL_state_string(s);
+ size_t len;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ STACK_OF(SSL_CIPHER) *client_ciphers;
+ STACK_OF(SSL_CIPHER) *server_ciphers;
+#endif
+
+ /*
+ * Trim crappy OpenSSL state strings...
+ */
+ len = strlen(abbrv);
+ if ((len > 1) && (abbrv[len - 1] == ' ')) len--;
+
+ RDEBUG3("(TLS) Handshake state [%.*s] - %s%s (%d)",
+ (int)len, abbrv, role, state, SSL_get_state(s));
+
+ /*
+ * After a ClientHello, list all the proposed ciphers from the client
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (SSL_get_state(s) == TLS_ST_SR_CLNT_HELLO) {
+ int i;
+ int num_ciphers;
+ const SSL_CIPHER *this_cipher;
+
+ server_ciphers = SSL_get_ciphers(s);
+ if (server_ciphers) {
+ RDEBUG3("Server preferred ciphers (by priority)");
+ num_ciphers = sk_SSL_CIPHER_num(server_ciphers);
+ for (i = 0; i < num_ciphers; i++) {
+ this_cipher = sk_SSL_CIPHER_value(server_ciphers, i);
+ RDEBUG3("(TLS) [%i] %s", i, SSL_CIPHER_get_name(this_cipher));
+ }
+ }
+
+ client_ciphers = SSL_get_client_ciphers(s);
+ if (client_ciphers) {
+ RDEBUG3("Client preferred ciphers (by priority)");
+ num_ciphers = sk_SSL_CIPHER_num(client_ciphers);
+ for (i = 0; i < num_ciphers; i++) {
+ this_cipher = sk_SSL_CIPHER_value(client_ciphers, i);
+ RDEBUG3("(TLS) [%i] %s", i, SSL_CIPHER_get_name(this_cipher));
+ }
+ }
+ }
+#endif
+ } else {
+ RDEBUG2("(TLS) Handshake state - %s%s", role, state);
+ }
+ return;
+ }
+
+ if (where & SSL_CB_ALERT) {
+ if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) return;
+
+ RERROR("(TLS) Alert %s:%s:%s", (where & SSL_CB_READ) ? "read": "write",
+ SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
+ return;
+ }
+
+ if (where & SSL_CB_EXIT) {
+ if (ret == 0) {
+ RERROR("(TLS) %s: Failed in %s", role, state);
+ return;
+ }
+
+ if (ret < 0) {
+ if (SSL_want_read(s)) {
+ RDEBUG2("(TLS) %s: Need to read more data: %s", role, state);
+ return;
+ }
+ RERROR("(TLS) %s: Error in %s", role, state);
+ }
+ }
+}
+
+/*
+ * Fill in our 'info' with TLS data.
+ */
+void cbtls_msg(int write_p, int msg_version, int content_type,
+ void const *inbuf, size_t len,
+ SSL *ssl UNUSED, void *arg)
+{
+ uint8_t const *buf = inbuf;
+ tls_session_t *state = (tls_session_t *)arg;
+
+ /*
+ * OpenSSL 1.0.2 calls this function with 'pseudo'
+ * content types. Which breaks our tracking of
+ * the SSL Session state.
+ */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ if ((msg_version == 0) && (content_type > UINT8_MAX)) {
+#else
+ /*
+ * "...we do not see the need to resolve application breakage
+ * just because the documentation now is incorrect."
+ *
+ * https://github.com/openssl/openssl/issues/17262
+ */
+ if ((content_type > UINT8_MAX) && (content_type != SSL3_RT_INNER_CONTENT_TYPE)) {
+#endif
+ DEBUG4("(TLS) Ignoring cbtls_msg call with pseudo content type %i, version %08x",
+ content_type, msg_version);
+ return;
+ }
+
+ if ((write_p != 0) && (write_p != 1)) {
+ DEBUG4("(TLS) Ignoring cbtls_msg call with invalid write_p %d", write_p);
+ return;
+ }
+
+ /*
+ * Work around bug #298, where we may be called with a NULL
+ * argument. We should really log a serious error
+ */
+ if (!state) return;
+
+ if (rad_debug_lvl > 3) {
+ size_t i, j, data_len = len;
+ char buffer[3*16 + 1];
+ uint8_t const *in = inbuf;
+
+ DEBUG("(TLS) Received %zu bytes of TLS data", len);
+ if (data_len > 256) data_len = 256;
+
+ for (i = 0; i < data_len; i += 16) {
+ for (j = 0; j < 16; j++) {
+ if ((i + j) >= data_len) break;
+
+ sprintf(buffer + 3 * j, "%02x ", in[i + j]);
+ }
+
+ DEBUG("(TLS) %s", buffer);
+ }
+ }
+
+ /*
+ * 0 - received (from peer)
+ * 1 - sending (to peer)
+ */
+ state->info.origin = write_p;
+ state->info.content_type = content_type;
+ state->info.record_len = len;
+ state->info.initialized = true;
+
+ if (content_type == SSL3_RT_ALERT) {
+ state->info.alert_level = buf[0];
+ state->info.alert_description = buf[1];
+ state->info.handshake_type = 0x00;
+
+ } else if (content_type == SSL3_RT_HANDSHAKE) {
+ state->info.handshake_type = buf[0];
+ state->info.alert_level = 0x00;
+ state->info.alert_description = 0x00;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ } else if (content_type == SSL3_RT_INNER_CONTENT_TYPE && buf[0] == SSL3_RT_APPLICATION_DATA) {
+ /* let tls_ack_handler set application_data */
+ state->info.content_type = SSL3_RT_HANDSHAKE;
+#endif
+
+#ifdef SSL3_RT_HEARTBEAT
+ } else if (content_type == TLS1_RT_HEARTBEAT) {
+ uint8_t *p = buf;
+
+ if ((len >= 3) && (p[0] == 1)) {
+ size_t payload_len;
+
+ payload_len = (p[1] << 8) | p[2];
+
+ if ((payload_len + 3) > len) {
+ state->invalid_hb_used = true;
+ ERROR("OpenSSL Heartbeat attack detected. Closing connection");
+ return;
+ }
+ }
+#endif
+ }
+
+ tls_session_information(state);
+}
+
+int cbtls_password(char *buf,
+ int num,
+ int rwflag UNUSED,
+ void *userdata)
+{
+ size_t len;
+
+ len = strlcpy(buf, (char *)userdata, num);
+ if (len >= (size_t) num) {
+ ERROR("Password too long. Maximum length is %i bytes", num - 1);
+ return 0;
+ }
+
+ return len;
+}
+
+#endif
diff --git a/src/main/channel.c b/src/main/channel.c
new file mode 100644
index 0000000..757ccd2
--- /dev/null
+++ b/src/main/channel.c
@@ -0,0 +1,231 @@
+/*
+ * radmin.c RADIUS Administration tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2015 The FreeRADIUS server project
+ * Copyright 2015 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/channel.h>
+
+typedef struct rchannel_t {
+ uint32_t channel;
+ uint32_t length;
+} rchannel_t;
+
+
+static ssize_t lo_read(int fd, void *inbuf, size_t buflen)
+{
+ size_t total;
+ ssize_t r;
+ uint8_t *p = inbuf;
+
+ for (total = 0; total < buflen; total += r) {
+ r = read(fd, p + total, buflen - total);
+
+ if (r == 0) return 0;
+
+ if (r < 0) {
+ if (errno == EINTR) continue;
+
+ return -1;
+
+ }
+ }
+
+ return total;
+}
+
+
+/*
+ * A non-blocking copy of fr_channel_read().
+ */
+ssize_t fr_channel_drain(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen, uint8_t **outbuf, size_t have_read)
+{
+ ssize_t r;
+ size_t data_len;
+ uint8_t *buffer = inbuf;
+ rchannel_t hdr;
+
+ /*
+ * If we can't even read a header, die.
+ */
+ if (buflen <= sizeof(hdr)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Ensure that we read the header first.
+ */
+ if (have_read < sizeof(hdr)) {
+ *pchannel = FR_CHANNEL_WANT_MORE;
+
+ r = lo_read(fd, buffer + have_read, sizeof(hdr) - have_read);
+ if (r <= 0) return r;
+
+ have_read += r;
+
+ if (have_read < sizeof(hdr)) return have_read;
+ }
+
+ /*
+ * We've read the header. Figure out how much more data
+ * we need to read.
+ */
+ memcpy(&hdr, buffer, sizeof(hdr));
+ data_len = ntohl(hdr.length);
+
+ /*
+ * The data will overflow the buffer. Die.
+ */
+ if ((sizeof(hdr) + data_len) > buflen) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * This is how much we really want.
+ */
+ buflen = sizeof(hdr) + data_len;
+
+ r = lo_read(fd, buffer + have_read, buflen - have_read);
+ if (r <= 0) return r;
+
+ have_read += r;
+
+ if (have_read == buflen) {
+ *pchannel = ntohl(hdr.channel);
+ *outbuf = buffer + sizeof(hdr);
+ return data_len;
+ }
+
+ *pchannel = FR_CHANNEL_WANT_MORE;
+ return have_read;
+}
+
+ssize_t fr_channel_read(int fd, fr_channel_type_t *pchannel, void *inbuf, size_t buflen)
+{
+ ssize_t r;
+ size_t data_len;
+ uint8_t *buffer = inbuf;
+ rchannel_t hdr;
+
+ /*
+ * Read the header
+ */
+ r = lo_read(fd, &hdr, sizeof(hdr));
+ if (r <= 0) return r;
+
+ /*
+ * Read the data into the buffer.
+ */
+ *pchannel = ntohl(hdr.channel);
+ data_len = ntohl(hdr.length);
+
+#if 0
+ fprintf(stderr, "CHANNEL R %zu length %zu\n", *pchannel, data_len);
+#endif
+
+ /*
+ * Shrink the output buffer to the size of the data we
+ * have.
+ */
+ if (buflen > data_len) buflen = data_len;
+
+ r = lo_read(fd, buffer, buflen);
+ if (r <= 0) return r;
+
+ /*
+ * Read and discard any extra data sent to us. Sorry,
+ * caller, you should have used a larger buffer!
+ */
+ while (data_len > buflen) {
+ size_t discard;
+ uint8_t junk[64];
+
+ discard = data_len - buflen;
+ if (discard > sizeof(junk)) discard = sizeof(junk);
+
+ r = lo_read(fd, junk, discard);
+ if (r <= 0) break;
+
+ data_len -= r;
+ }
+
+ return buflen;
+}
+
+static ssize_t lo_write(int fd, void const *inbuf, size_t buflen)
+{
+ size_t total;
+ ssize_t r;
+ uint8_t const *buffer = inbuf;
+
+ total = buflen;
+
+ while (total > 0) {
+ r = write(fd, buffer, total);
+ if (r == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (r < 0) {
+ if (errno == EINTR) continue;
+
+ return -1;
+ }
+
+ buffer += r;
+ total -= r;
+ }
+
+ return buflen;
+}
+
+ssize_t fr_channel_write(int fd, fr_channel_type_t channel, void const *inbuf, size_t buflen)
+{
+ ssize_t r;
+ rchannel_t hdr;
+ uint8_t const *buffer = inbuf;
+
+ hdr.channel = htonl(channel);
+ hdr.length = htonl(buflen);
+
+#if 0
+ fprintf(stderr, "CHANNEL W %zu length %zu\n", channel, buflen);
+#endif
+
+ /*
+ * write the header
+ */
+ r = lo_write(fd, &hdr, sizeof(hdr));
+ if (r <= 0) return r;
+
+ /*
+ * write the data directly from the buffer
+ */
+ r = lo_write(fd, buffer, buflen);
+ if (r <= 0) return r;
+
+ return buflen;
+}
diff --git a/src/main/checkrad.in b/src/main/checkrad.in
new file mode 100644
index 0000000..c0cf440
--- /dev/null
+++ b/src/main/checkrad.in
@@ -0,0 +1,1515 @@
+#!@PERL@
+#
+# checkrad See if a user is (still) logged in on a certain port.
+#
+# This is used by the FreeRADIUS server to check
+# if its idea of a user logged in on a certain port/nas
+# is correct if a double login is detected.
+#
+# Called as: nas_type nas_ip nas_port login session_id
+#
+# Returns: 0 = no duplicate, 1 = duplicate, >1 = error.
+#
+# Version: $Id$
+#
+# livingston_snmp 1.2 Author: miquels@cistron.nl
+# cvx_snmp 1.0 Author: miquels@cistron.nl
+# portslave_finger 1.0 Author: miquels@cistron.nl
+# max40xx_finger 1.0 Author: costa@mdi.ca
+# ascend_snmp 1.1 Author: blaz@amis.net
+# computone_finger 1.2 Author: pacman@world.std.com
+# sub tc_tccheck 1.1 Author: alexisv@compass.com.ph
+# cyclades_telnet 1.2 Author: accdias@sst.com.br
+# patton_snmp 1.0 Author: accdias@sst.com.br
+# digitro_rusers 1.1 Author: accdias@sst.com.br
+# cyclades_snmp 1.0 Author: accdias@sst.com.br
+# usrhiper_snmp 1.0 Author: igor@ipass.net
+# juniper_e_snmp 1.1 Author: guilhermefranco@gmail.com
+# multitech_snmp 1.0 Author: ehonzay@willmar.com
+# netserver_telnet 1.0 Author: mts@interplanet.es
+# versanet_snmp 1.0 Author: support@versanetcomm.com
+# bay_finger 1.0 Author: chris@shenton.org
+# cisco_l2tp 1.14 Author: paul@distributel.net
+# mikrotik_telnet 1.1 Author: Evren Yurtesen <yurtesen@ispro.net.tr>
+# mikrotik_snmp 1.0 Author: Evren Yurtesen <yurtesen@ispro.net.tr>
+# redback_telnet Author: Eduardo Roldan
+#
+# Config: $debug is the file you want to put debug messages in
+# $snmpget is the location of your ``snmpget'' program
+# $snmpwalk is the location of your ``snmpwalk'' program
+# $snmp_timeout is the timeout for snmp queries
+# $snmp_retries is the number of retries for timed out snmp queries
+# $snmp_version is the version of to use for snmp queries [1,2c,3]
+# $rusers is the location of your ``rusers'' program
+# $naspass is the location of your NAS admin password file
+#
+
+$prefix = "@prefix@";
+$localstatedir = "@localstatedir@";
+$logdir = "@logdir@";
+$sysconfdir = "@sysconfdir@";
+$raddbdir = "@raddbdir@";
+
+$debug = "";
+#$debug = "$logdir/checkrad.log";
+
+$snmpget = "@SNMPGET@";
+$snmpwalk = "@SNMPWALK@";
+$snmp_timeout = 5;
+$snmp_retries = 1;
+$snmp_version = "2c";
+$rusers = "@RUSERS@";
+$naspass = "$raddbdir/naspasswd";
+
+# Community string. Change this if yours isn't "public".
+$cmmty_string = "public";
+# path to finger command
+$finger = "/usr/bin/finger";
+
+# Extremely slow way of converting port descriptions to actual indexes
+$portisdescr = 0;
+
+# Realm used by Cisco sub
+$realm = '';
+
+#
+# USR-Hiper: $hiper_density is the reported port density (default 256
+# but 24 makes more sense)
+#
+$hiper_density = 256;
+
+#
+# Try to load Net::Telnet, SNMP_Session etc.
+# Do not complain if we cannot find it.
+# Prefer a locally installed copy.
+#
+BEGIN {
+ unshift @INC, "/usr/local/lib/site_perl";
+
+ eval "use Net::Telnet 3.00;";
+ $::HAVE_NET_TELNET = ($@ eq "");
+
+ eval "use SNMP_Session;";
+ if ($@ eq "") {
+ eval "use BER;";
+ $::HAVE_SNMP_SESSION = ($@ eq "");
+ eval "use Socket;";
+ }
+};
+
+#
+# Get password from /etc/raddb/naspasswd file.
+# Returns (login, password).
+#
+sub naspasswd {
+ my ($terminalserver, $emptyok) = @_;
+ my ($login, $password);
+ my ($ts, $log, $pass);
+
+ unless (open(NFD, $naspass)) {
+ if (!$emptyok) {
+ print LOG "checkrad: naspasswd file not found; " .
+ "possible match for $ARGV[3]\n" if ($debug);
+ print STDERR "checkrad: naspasswd file not found; " .
+ "possible match for $ARGV[3]\n";
+ }
+ return ();
+ }
+ while (<NFD>) {
+ chop;
+ next if (m/^(#|$|[\t ]+$)/);
+ ($ts, $log, $pass) = split(/\s+/, $_, 3);
+ if ($ts eq $terminalserver) {
+ $login = $log;
+ $password = $pass;
+ last;
+ }
+ }
+ close NFD;
+ if ($password eq "" && !$emptyok) {
+ print LOG "checkrad: password for $ARGV[1] is null; " .
+ "possible match for $ARGV[3] on " .
+ "port $ARGV[2]\n" if ($debug);
+ print STDERR "checkrad: password for $ARGV[1] is null; " .
+ "possible match for $ARGV[3] on port $ARGV[2]\n";
+ }
+ ($login, $password);
+}
+
+#
+# See if Net::Telnet is there.
+#
+sub check_net_telnet {
+ if (!$::HAVE_NET_TELNET) {
+ print LOG
+ " checkrad: Net::Telnet 3.00+ CPAN module not installed\n"
+ if ($debug);
+ print STDERR
+ "checkrad: Net::Telnet 3.00+ CPAN module not installed\n";
+ return 0;
+ }
+ 1;
+}
+
+#
+# Do snmpwalk by calling snmpwalk.
+#
+sub snmpwalk_prog {
+ my ($host, $community, $oid) = @_;
+ local $_;
+
+ print LOG "snpwalk: $snmpwalk -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid\n";
+ $_ = `$snmpwalk -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid`;
+
+ return $_;
+}
+
+#
+# Do snmpwalk.
+#
+sub snmpwalk {
+ my $ret;
+
+ if (-x $snmpwalk) {
+ $ret = snmpwalk_prog(@_);
+ } else {
+ $e = "$snmpwalk not found!";
+ print LOG "$e\n" if ($debug);
+ print STDERR "checkrad: $e\n";
+ $ret = "";
+ }
+ $ret;
+}
+
+
+#
+# Do snmpget by calling snmpget.
+#
+sub snmpget_prog {
+ my ($host, $community, $oid) = @_;
+ my ($ret);
+ local $_;
+
+ print LOG "snmpget: $snmpget -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid\n";
+ $_ = `$snmpget -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid`;
+ if (/^.*(\s|\")([0-9A-Za-z]{8})(\s|\"|$).*$/) {
+ # Session ID format.
+ $ret = $2;
+ } elsif (/^.*=.*"(.*)"/) {
+ # oid = "...." junk format.
+ $ret = $1;
+ } elsif (/^.*=\s*(?:.*:\s*)?(\S+)/) {
+ # oid = string format
+ $ret = $1;
+ }
+
+ # Strip trailing junk if any.
+ $ret =~ s/\s*Hex:.*$//;
+ $ret;
+}
+
+#
+# Do snmpget by using SNMP_Session.
+# Coded by Jerry Workman <jerry@newwave.net>
+#
+sub snmpget_session {
+ my ($host, $community, $OID) = @_;
+ my ($ret);
+ local $_;
+ my (@enoid, $var,$response, $bindings, $binding, $value);
+ my ($inoid, $outoid, $upoid, $oid, @retvals);
+
+ $OID =~ s/^.iso.org.dod.internet.private.enterprises/.1.3.6.1.4.1/;
+
+ push @enoid, encode_oid((split /\./, $OID));
+ srand();
+
+ my $session = SNMP_Session->open($host, $community, 161);
+ if (!$session->get_request_response(@enoid)) {
+ $e = "No SNMP answer from $ARGV[0].";
+ print LOG "$e\n" if ($debug);
+ print STDERR "checkrad: $e\n";
+ return "";
+ }
+ $response = $session->pdu_buffer;
+ ($bindings) = $session->decode_get_response ($response);
+ $session->close ();
+ while ($bindings) {
+ ($binding,$bindings) = decode_sequence ($bindings);
+ ($oid,$value) = decode_by_template ($binding, "%O%@");
+ my $tempo = pretty_print($value);
+ $tempo=~s/\t/ /g;
+ $tempo=~s/\n/ /g;
+ $tempo=~s/^\s+//;
+ $tempo=~s/\s+$//;
+
+ push @retvals, $tempo;
+ }
+ $retvals[0];
+}
+
+#
+# Do snmpget
+#
+sub snmpget {
+ my $ret;
+
+ if ($::HAVE_SNMP_SESSION) {
+ $ret = snmpget_session(@_);
+ } elsif (-x $snmpget) {
+ $ret = snmpget_prog(@_);
+ } else {
+ $e = "Neither SNMP_Session module or $snmpget found!";
+ print LOG "$e\n" if ($debug);
+ print STDERR "checkrad: $e\n";
+ $ret = "";
+ }
+ $ret;
+}
+
+#
+# Get ifindex from description
+#
+sub ifindex {
+ my $port = shift;
+
+ # If its not an integer, portisdescr lies!
+ return $port unless $portisdescr || $port !~ /^[0-9]*$/;
+
+ $_ = snmpwalk($ARGV[1], "$cmmty_string", ".1.3.6.1.2.1.2.2.1.2");
+
+ foreach (split /\n/){
+ if(/\.([0-9]+)\s*=.*$port"?$/){
+ print LOG " port descr $port is at SNMP ifIndex $1\n" if ($debug);
+ return $1;
+ }
+ }
+
+
+ return $port;
+}
+
+#
+# Strip domains, prefixes and suffixes from username
+#
+# Known prefixes: (P)PP, (S)LIP e (C)SLIP
+# Known suffixes: .ppp, .slip e .cslip
+#
+# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
+#
+sub strip_username {
+ my ($user) = @_;
+ #
+ # Trim white spaces.
+ #
+ $user =~ s/^\s*(.*?)\s*$/$1/;
+ #
+ # Strip out domains, prefix and suffixes
+ #
+ $user =~ s/\@(.)*$//;
+ $user =~ s/^[PSC]//;
+ $user =~ s/\.(ppp|slip|cslip)$//;
+ $user;
+}
+
+#
+# Check whether a session is current on any device which implements the standard IEEE 802.1X MIB
+#
+# Note: Vendors use different formats for the session ID, and it often doesn't map
+# between Acct-Session-ID so can't be used to identify and 802.1X session (we ignore it).
+#
+# If a session matching the username is found on the port specified, and the
+# session is still active then thats good enough...
+#
+# Author: Arran Cudbard-Bell <arran.cudbard-bell@freeradius.org>
+#
+$ieeedot1m = '.iso.0.8802.1.1';
+sub dot1x_snmp {
+ $ifIndex = ifindex($ARGV[2]);
+
+ # User matches and not terminated yet?
+ if(
+ snmpget($ARGV[1], "$cmmty_string", "$ieeedot1m.1.1.2.4.1.9.$ifIndex") eq $ARGV[3] &&
+ snmpget($ARGV[1], "$cmmty_string", "$ieeedot1m.1.1.2.4.1.8.$ifIndex") eq '999'
+ ){
+ print LOG " found user $ARGV[3] at port $ARGV[2] ($ifIndex)" if $debug;
+ return 1;
+ }
+
+ 0;
+}
+
+#
+# See if the user is logged in using the Livingston MIB.
+# We don't check the username but the session ID.
+#
+$lvm = '.iso.org.dod.internet.private.enterprises.307';
+sub livingston_snmp {
+
+ #
+ # We don't know at which ifIndex S0 is, and
+ # there might be a hole at S23, or at S30+S31.
+ # So we figure out dynamically which offset to use.
+ #
+ # If the port < S23, probe ifIndex 5.
+ # If the port < S30, probe IfIndex 23.
+ # Otherwise probe ifIndex 32.
+ #
+ my $ifIndex;
+ my $test_index;
+ if ($ARGV[2] < 23) {
+ $test_index = 5;
+ } elsif ($ARGV[2] < 30) {
+ $test_index = 23;
+ } else {
+ $test_index = 32;
+ }
+ $_ = snmpget($ARGV[1], "$cmmty_string", "$lvm.3.2.1.1.1.2.$test_index");
+ /S([0-9]+)/;
+ $xport = $1 + 0;
+ $ifIndex = $ARGV[2] + ($test_index - $xport);
+
+ print LOG " port S$ARGV[2] at SNMP ifIndex $ifIndex\n"
+ if ($debug);
+
+ #
+ # Now get the session id from the terminal server.
+ #
+ $sessid = snmpget($ARGV[1], "$cmmty_string", "$lvm.3.2.1.1.1.5.$ifIndex");
+
+ print LOG " session id at port S$ARGV[2]: $sessid\n" if ($debug);
+
+ ($sessid eq $ARGV[4]) ? 1 : 0;
+}
+
+#
+# See if the user is logged in using the Aptis MIB.
+# We don't check the username but the session ID.
+#
+# sessionStatusActiveName
+$apm1 = '.iso.org.dod.internet.private.enterprises.2637.2.2.102.1.12';
+# sessionStatusActiveStopTime
+$apm2 = '.iso.org.dod.internet.private.enterprises.2637.2.2.102.1.20';
+sub cvx_snmp {
+
+ # Remove unique identifier, then take remainder of the
+ # session-id as a hex number, convert that to decimal.
+ my $sessid = $ARGV[4];
+ $sessid =~ s/^.*://;
+ $sessid =~ s/^0*//;
+ $sessid = "0" if ($sessid eq '');
+
+ #
+ # Now get the login from the terminal server.
+ # Blech - the SNMP table is called 'sessionStatusActiveTable,
+ # but it sometimes lists inactive sessions too.
+ # However an active session doesn't have a Stop time,
+ # so we can differentiate that way.
+ #
+ my $login = snmpget($ARGV[1], "$cmmty_string", "$apm1." . hex($sessid));
+ my $stopt = snmpget($ARGV[1], "$cmmty_string", "$apm2." . hex($sessid));
+ $login = "--" if ($stopt > 0);
+
+ print LOG " login with session-id $ARGV[4]: $login\n" if ($debug);
+
+ (strip_username($login) eq strip_username($ARGV[3])) ? 1 : 0;
+}
+
+#
+# See if the user is logged in using the Cisco MIB
+#
+$csm = '.iso.org.dod.internet.private.enterprises.9';
+sub cisco_snmp {
+
+ # Look up community string in naspasswd file.
+ my ($login, $pass) = naspasswd($ARGV[1], 1);
+ if ($login eq '') {
+ $pass = $cmmty_string;
+ } elsif ($login ne 'SNMP') {
+ if ($debug) {
+ print LOG
+ " Error: Need SNMP community string for $ARGV[1]\n";
+ }
+ return 2;
+ }
+
+ my $port = $ARGV[2];
+ my $sess_id = hex($ARGV[4]);
+
+ if ($port < 20000) {
+ #
+ # The AS5350 doesn't support polling the session ID,
+ # so we do it based on nas-port-id. This only works
+ # for analog sessions where port < 20000.
+ # Yes, this means that simultaneous-use on the as5350
+ # doesn't work for ISDN users.
+ #
+ $login = snmpget($ARGV[1], $pass, "$csm.2.9.2.1.18.$port");
+ print LOG " user at port S$port: $login\n" if ($debug);
+ } else {
+ $login = snmpget($ARGV[1], $pass,
+ "$csm.9.150.1.1.3.1.2.$sess_id");
+ print LOG " user with session id $ARGV[4] ($sess_id): " .
+ "$login\n" if ($debug);
+ }
+
+ # ($login eq $ARGV[3]) ? 1 : 0;
+ if($login eq $ARGV[3]) {
+ return 1;
+ }else{
+ $out=snmpwalk($ARGV[1],$pass,".iso.org.dod.internet.private.enterprises.9.10.19.1.3.1.1.3");
+ if($out=~/\"$ARGV[3]\"/){
+ return 1;
+ }else{
+ return 0;
+ }
+ }
+}
+
+#
+# Check the subscriber name on a Juniper JunosE E-Series BRAS (ERX, E120, E320). Requires "radius acct-session-id-format decimal" configuration in the BRAS.
+#
+# Author: Guilherme Franco <guilhermefranco@gmail.com>
+#
+sub juniper_e_snmp {
+ #receives acct_session
+ my $temp = $ARGV[4];
+ #removes the leading 0s
+ my $clean_temp = int $temp;
+
+ $out=snmpget($ARGV[1], $cmmty_string, ".1.3.6.1.4.1.4874.2.2.20.1.8.4.1.2.$clean_temp");
+ if($out=~/\"$ARGV[3]\"/){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+#
+# Check a MultiTech CommPlete Server ( CC9600 & CC2400 )
+#
+# Author: Eric Honzay of Bennett Office Products <ehonzay@willmar.com>
+#
+$msm = '.iso.org.dod.internet.private.enterprises.995';
+sub multitech_snmp {
+ my $temp = $ARGV[2] + 1;
+
+ $login = snmpget($ARGV[1], "$cmmty_string", "$msm.2.31.1.1.1.$temp");
+ print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
+
+ ($login eq $ARGV[3]) ? 1 : 0;
+}
+
+#
+# Check a Computone Powerrack via finger
+#
+# Old Author: Shiloh Costa of MDI Internet Inc. <costa@mdi.ca>
+# New Author: Alan Curry <pacman@world.std.com>
+#
+# The finger response format is version-dependent. To do this *right*, you
+# need to know exactly where the port number and username are. I know that
+# for 1.7.2, and 3.0.4 but for others I just guess.
+# Oh yeah and on top of it all, the thing truncates usernames. --Pac.
+#
+# 1.7.2 and 3.0.4 both look like this:
+#
+# 0 0 000 00:56 luser pppfsm Incoming PPP, ppp00, 10.0.0.1
+#
+# and the truncated ones look like this:
+#
+# 25 0 000 00:15 longnameluse..pppfsm Incoming PPP, ppp25, 10.0.0.26
+#
+# Yes, the fields run together. Long Usernames Considered Harmful.
+#
+sub computone_finger {
+ my $trunc, $ver;
+
+ open(FD, "$finger \@$ARGV[1]|") or return 2;
+ <FD>; # the [hostname] line is definitely uninteresting
+ $trunc = substr($ARGV[3], 0, 12);
+ $ver = "";
+ while(<FD>) {
+ if(/cnx kernel release ([^ ,]+)[, ]/) {
+ $ver = $1;
+ next;
+ }
+ # Check for known versions
+ if ($ver eq '1.7.2' || $ver eq '3.0.4') {
+ if (/^\Q$ARGV[2]\E\s+\S+\s+\S+\s+\S+\s+\Q$trunc\E(\s+|\.\.)/) {
+ close FD;
+ return 1;
+ }
+ next;
+ }
+ # All others.
+ if (/^\s*\Q$ARGV[2]\E\s+.*\s+\Q$trunc\E\s+/) {
+ close FD;
+ return 1;
+ }
+ }
+
+ close FD;
+ return 0;
+}
+
+#
+# Check an Ascend Max4000 or similar model via finger
+#
+# Note: Not all software revisions support finger
+# You may also need to enable the finger option.
+#
+# Author: Shiloh Costa of MDI Internet Inc. <costa@mdi.ca>
+#
+sub max40xx_finger {
+ open(FD, "$finger $ARGV[3]\@$ARGV[1]|");
+ while(<FD>) {
+ $line = $_;
+ if( $line =~ /Session/ ){
+ next;
+ }
+
+ if( $line =~ /$ARGV[4]/ ){
+ return 1; # user is online
+ }
+ }
+ close FD;
+ return 0; # user is offline
+}
+
+
+#
+# Check an Ascend Max4000 or similar model via SNMP
+#
+# Author: Blaz Zupan of Medinet <blaz@amis.net>
+#
+$asm = '.iso.org.dod.internet.private.enterprises.529';
+sub ascend_snmp {
+ my $sess_id;
+ my $l1, $l2;
+
+ $l1 = '';
+ $l2 = '';
+
+ #
+ # If it looks like hex, only try it as hex,
+ # otherwise try it as both decimal and hex.
+ #
+ $sess_id = $ARGV[4];
+ if ($sess_id !~ /^0/ && $sess_id !~ /[a-f]/i) {
+ $l1 = snmpget($ARGV[1], "$cmmty_string", "$asm.12.3.1.4.$sess_id");
+ }
+ if (!$l1){
+ $sess_id = hex $ARGV[4];
+ $l2 = snmpget($ARGV[1], "$cmmty_string", "$asm.12.3.1.4.$sess_id");
+ }
+
+ print LOG " user at port S$ARGV[2]: $l1 (dec)\n" if ($debug && $l1);
+ print LOG " user at port S$ARGV[2]: $l2 (hex)\n" if ($debug && $l2);
+
+ (($l1 && $l1 eq $ARGV[3]) || ($l2 && $l2 eq $ARGV[3])) ? 1 : 0;
+}
+
+
+#
+# See if the user is logged in using the portslave finger.
+#
+sub portslave_finger {
+ my ($Port_seen);
+
+ $Port_seen = 0;
+
+ open(FD, "$finger \@$ARGV[1]|");
+ while(<FD>) {
+ #
+ # Check for ^Port. If we don't see it we
+ # wont get confused by non-portslave-finger
+ # output too.
+ #
+ if (/^Port/) {
+ $Port_seen++;
+ next;
+ }
+ next if (!$Port_seen);
+ next if (/^---/);
+
+ ($port, $user) = /^.(...) (...............)/;
+
+ $port =~ s/ .*//;
+ $user =~ s/ .*//;
+ $ulen = length($user);
+ #
+ # HACK: strip [PSC] from the front of the username,
+ # and things like .ppp from the end.
+ #
+ $user =~ s/^[PSC]//;
+ $user =~ s/\.(ppp|slip|cslip)$//;
+
+ #
+ # HACK: because ut_user usually has max. 8 characters
+ # we only compare up the the length of $user if the
+ # unstripped name had 8 chars.
+ #
+ $argv_user = $ARGV[3];
+ if ($ulen == 8) {
+ $ulen = length($user);
+ $argv_user = substr($ARGV[3], 0, $ulen);
+ }
+
+ if ($port == $ARGV[2]) {
+ if ($user eq $argv_user) {
+ print LOG " $user matches $argv_user " .
+ "on port $port" if ($debug);
+ close FD;
+ return 1;
+ } else {
+ print LOG " $user doesn't match $argv_user " .
+ "on port $port" if ($debug);
+ close FD;
+ return 0;
+ }
+ }
+ }
+ close FD;
+ 0;
+}
+
+#
+# See if the user is already logged-in at the 3Com/USR Total Control.
+# (this routine by Alexis C. Villalon <alexisv@compass.com.ph>).
+# You must have the Net::Telnet module from CPAN for this to work.
+# You must also have your /etc/raddb/naspasswd made up.
+#
+sub tc_tccheck {
+ #
+ # Localize all variables first.
+ #
+ my ($Port_seen, $ts, $terminalserver, $log, $login, $pass, $password);
+ my ($telnet, $curprompt, $curline, $ok, $totlines, $ccntr);
+ my (@curlines, @cltok, $user, $port, $ulen);
+
+ return 2 unless (check_net_telnet());
+
+ $terminalserver = $ARGV[1];
+ $Port_seen = 0;
+ #
+ # Get login name and password for a certain NAS from $naspass.
+ #
+ ($login, $password) = naspasswd($terminalserver, 1);
+ return 2 if ($password eq "");
+
+ #
+ # Communicate with NAS using Net::Telnet, then issue
+ # the command "show sessions" to see who are logged in.
+ # Thanks to Chris Jackson <chrisj@tidewater.net> for the
+ # for the "-- Press Return for More --" workaround.
+ #
+ $telnet = new Net::Telnet (Timeout => 5,
+ Prompt => '/\>/');
+ $telnet->open($terminalserver);
+ $telnet->login($login, $password);
+ $telnet->print("show sessions");
+ while ($curprompt ne "\>") {
+ ($curline, $curprompt) = $telnet->waitfor
+ (String => "-- Press Return for More --",
+ String => "\>",
+ Timeout => 5);
+ $ok = $telnet->print("");
+ push @curlines, split(/^/m, $curline);
+ }
+ $telnet->close;
+ #
+ # Telnet closed. We got the info. Let's examine it.
+ #
+ $totlines = @curlines;
+ $ccntr = 0;
+ while($ccntr < $totlines) {
+ #
+ # Check for ^Port.
+ #
+ if ($curlines[$ccntr] =~ /^Port/) {
+ $Port_seen++;
+ $ccntr++;
+ next;
+ }
+ #
+ # Ignore all unnecessary lines.
+ #
+ if (!$Port_seen || $curlines[$ccntr] =~ /^---/ ||
+ $curlines[$ccntr] =~ /^ .*$/) {
+ $ccntr++;
+ next;
+ }
+ #
+ # Parse the current line for the port# and username.
+ #
+ @cltok = split(/\s+/, $curlines[$ccntr]);
+ $ccntr++;
+ $port = $cltok[0];
+ $user = $cltok[1];
+ $ulen = length($user);
+ #
+ # HACK: strip [PSC] from the front of the username,
+ # and things like .ppp from the end. Strip S from
+ # the front of the port number.
+ #
+ $user =~ s/^[PSC]//;
+ $user =~ s/\.(ppp|slip|cslip)$//;
+ $port =~ s/^S//;
+ #
+ # HACK: because "show sessions" shows max. 15 characters
+ # we only compare up to the length of $user if the
+ # unstripped name had 15 chars.
+ #
+ $argv_user = $ARGV[3];
+ if ($ulen == 15) {
+ $ulen = length($user);
+ $argv_user = substr($ARGV[3], 0, $ulen);
+ }
+ if ($port == $ARGV[2]) {
+ if ($user eq $argv_user) {
+ print LOG " $user matches $argv_user " .
+ "on port $port" if ($debug);
+ return 1;
+ } else {
+ print LOG " $user doesn't match $argv_user " .
+ "on port $port" if ($debug);
+ return 0;
+ }
+ }
+ }
+ 0;
+}
+
+#
+# Check a Cyclades PathRAS via telnet
+#
+# Version: 1.2
+#
+# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
+#
+sub cyclades_telnet {
+ #
+ # Localize all variables first.
+ #
+ my ($pr, $pr_login, $pr_passwd, $pr_prompt, $endlist, @list, $port, $user);
+ #
+ # This variable must match PathRAS' command prompt
+ # string as entered in menu option 6.2.
+ # The value below matches the default command prompt.
+ #
+ $pr_prompt = '/Select option ==\>$/i';
+
+ #
+ # This variable match the end of userslist.
+ #
+ $endlist = '/Type \<enter\>/i';
+
+ #
+ # Do we have Net::Telnet installed?
+ #
+ return 2 unless (check_net_telnet());
+
+ #
+ # Get login name and password for NAS
+ # from $naspass file.
+ #
+ ($pr_login, $pr_passwd) = naspasswd($ARGV[1], 1);
+
+ #
+ # Communicate with PathRAS using Net::Telnet, then access
+ # menu option 6.8 to see who are logged in.
+ # Based on PathRAS firmware version 1.2.3
+ #
+ $pr = new Net::Telnet (
+ Timeout => 5,
+ Host => $ARGV[1],
+ ErrMode => 'return'
+ ) || return 2;
+
+ #
+ # Force PathRAS shows its banner.
+ #
+ $pr->break();
+
+ #
+ # Log on PathRAS
+ #
+ if ($pr->waitfor(Match => '/login : $/i') == 1) {
+ $pr->print($pr_login);
+ } else {
+ print LOG " Error: sending login name to PathRAS\n" if ($debug);
+ $pr->close;
+ return 2;
+ }
+
+ if ($pr->waitfor(Match => '/password : $/i') == 1) {
+ $pr->print($pr_passwd);
+ } else {
+ print LOG " Error: sending password to PathRAS.\n" if ($debug);
+ $pr->close;
+ return 2;
+ }
+
+ $pr->print();
+
+ #
+ # Access menu option 6 "PathRAS Management"
+ #
+ if ($pr->waitfor(Match => $pr_prompt) == 1) {
+ $pr->print('6');
+ } else {
+ print LOG " Error: accessing menu option '6'.\n" if ($debug);
+ $pr->close;
+ return 2;
+ }
+ #
+ # Access menu option 8 "Show Active Ports"
+ #
+ if ($pr->waitfor(Match => $pr_prompt) == 1) {
+ @list = $pr->cmd(String => '8', Prompt => $endlist);
+ } else {
+ print LOG " Error: accessing menu option '8'.\n" if ($debug);
+ $pr->close;
+ return 2;
+ }
+ #
+ # Since we got the info we want, let's close
+ # the telnet session
+ #
+ $pr->close;
+
+ #
+ # Lets examine the userlist stored in @list
+ #
+ foreach(@list) {
+ #
+ # We are interested in active sessions only
+ #
+ if (/Active/i) {
+ ($port, $user) = split;
+ #
+ # Strip out any prefix, suffix and
+ # realm from $user check to see if
+ # $ARGV[3] matches.
+ #
+ if(strip_username($ARGV[3]) eq strip_username($user)) {
+ print LOG " User '$ARGV[3]' found on '$ARGV[1]:$port'.\n" if ($debug);
+ return 1;
+ }
+ }
+ }
+ print LOG " User '$ARGV[3]' not found on '$ARGV[1]'.\n" if ($debug);
+ 0;
+}
+
+#
+# Check a Patton 2800 via SNMP
+#
+# Version: 1.0
+#
+# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
+#
+sub patton_snmp {
+ my($oid);
+
+ #$oid = '.1.3.6.1.4.1.1768.5.100.1.40.' . hex $ARGV[4];
+ # Reported by "Andria Legon" <andria@patton.com>
+ # The OID below should be the correct one instead of the one above.
+ $oid = '.1.3.6.1.4.1.1768.5.100.1.56.' . hex $ARGV[4];
+ #
+ # Check if the session still active
+ #
+ if (snmpget($ARGV[1], "monitor", "$oid") == 0) {
+ print LOG " Session $ARGV[4] still active on NAS " .
+ "$ARGV[1], port $ARGV[2], for user $ARGV[3].\n" if ($debug);
+ return 1;
+ }
+ 0;
+}
+
+#
+# Check a Digitro BXS via rusers
+#
+# Version: 1.1
+#
+# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
+#
+sub digitro_rusers {
+ my ($ret);
+ local $_;
+
+ if (-e $rusers && -x $rusers) {
+ #
+ # Get a list of users logged in via rusers
+ #
+ $_ = `$rusers $ARGV[1]`;
+ $ret = ((/$ARGV[3]/) ? 1 : 0);
+ } else {
+ print LOG " Error: can't execute $rusers\n" if $debug;
+ $ret = 2;
+ }
+ $ret;
+}
+
+#
+# Check Cyclades PR3000 and PR4000 via SNMP
+#
+# Version: 1.0
+#
+# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
+#
+sub cyclades_snmp {
+ my ($oid, $ret);
+ local $_;
+
+ $oid = ".1.3.6.1.4.1.2925.3.3.6.1.1.2";
+
+ $_ = snmpwalk($ARGV[1],"$cmmty_string",$oid);
+ $ret = ((/$ARGV[3]/) ? 1 : 0);
+ $ret;
+}
+
+#
+# 3Com/USR HiPer Arc Total Control.
+# This works with HiPer Arc 4.0.30
+# (this routine by Igor Brezac <igor@ipass.net>)
+#
+
+# This routine modified by Dan Halverson <danh@tbc.net>
+# to support additional versions of Hiper Arc
+#
+
+$usrm = '.iso.org.dod.internet.private.enterprises.429';
+sub usrhiper_snmp {
+ my ($login,$password,$oidext);
+
+ # Look up community string in naspasswd file.
+ ($login, $password) = naspasswd($ARGV[1], 1);
+ if ($login && $login ne 'SNMP') {
+ if($debug) {
+ print LOG
+ " Error: Need SNMP community string for $ARGV[1]\n";
+ }
+ return 2;
+ } else {
+# If password is defined in naspasswd file, use it as community, otherwise use $cmmty_string
+ if ($password eq '') {
+ $password = "$cmmty_string";
+ }
+ }
+ my ($ver) = get_hiper_ver(usrm=>$usrm, target=>$ARGV[1], community=>$password);
+ $oidext = get_oidext(ver=>$ver, tty=>$ARGV[2]);
+ my ($login);
+
+ $login = snmpget($ARGV[1], $password, "$usrm.4.10.1.1.18.$oidext");
+ if ($login =~ /\"/) {
+ $login =~ /^.*\"([^"]+)\"/;
+ $login = $1;
+ }
+
+ print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
+
+ ($login eq $ARGV[3]) ? 1 : 0;
+}
+
+#
+# get_hiper_ver and get_oidext by Dan Halverson <danh@tbc.net>
+#
+sub get_hiper_ver {
+ my (%args) = @_;
+ my ($ver
+ );
+ $ver = snmpget ($args{'target'}, $args{'community'}, $args{'usrm'}.".4.1.14.0");
+ return($ver);
+}
+
+#
+# Add additional OID checks below before the else.
+# Else is for 4.0.30
+#
+sub get_oidext {
+ my (%args) = @_;
+ my ($oid
+ );
+ if ($args{'ver'} =~ /V5.1.99/) {
+ $oid = $args{'tty'}+1257-1;
+ }
+ else {
+ $oid = 1257 + 256*int(($args{'tty'}-1) / $hiper_density) +
+ (($args{'tty'}-1) % $hiper_density);
+ }
+ return($oid);
+}
+
+#
+# Check USR Netserver with Telnet - based on tc_tccheck.
+# By "Marti" <mts@interplanet.es>
+#
+sub usrnet_telnet {
+ #
+ # Localize all variables first.
+ #
+ my ($ts, $terminalserver, $login, $password);
+ my ($telnet, $curprompt, $curline, $ok);
+ my (@curlines, $user, $port);
+
+ return 2 unless (check_net_telnet());
+
+ $terminalserver = $ARGV[1];
+ $Port_seen = 0;
+ #
+ # Get login name and password for a certain NAS from $naspass.
+ #
+ ($login, $password) = naspasswd($terminalserver, 1);
+ return 2 if ($password eq "");
+
+ #
+ # Communicate with Netserver using Net::Telnet, then access
+ # list connectionsto see who are logged in.
+ #
+ $telnet = new Net::Telnet (Timeout => 5,
+ Prompt => '/\>/');
+ $telnet->open($terminalserver);
+
+ #
+ # Log on Netserver
+ #
+ $telnet->login($login, $password);
+
+ #
+ # Launch list connections command
+
+ $telnet->print("list connections");
+
+ while ($curprompt ne "\>") {
+ ($curline, $curprompt) = $telnet->waitfor
+ ( String => "\>",
+ Timeout => 5);
+ $ok = $telnet->print("");
+ push @curlines, split(/^/m, $curline);
+ }
+
+ $telnet->close;
+ #
+ # Telnet closed. We got the info. Let's examine it.
+ #
+ foreach(@curlines) {
+ if ( /mod\:/ ) {
+ ($port, $user, $dummy) = split;
+ #
+ # Strip out any prefixes and suffixes
+ # from the username
+ #
+ # uncomment this if you use the standard
+ # prefixes
+ #$user =~ s/^[PSC]//;
+ #$user =~ s/\.(ppp|slip|cslip)$//;
+ #
+ # Check to see if $user is already connected
+ #
+ if ($user eq $ARGV[3]) {
+ print LOG " $user matches $ARGV[3] " .
+ "on port $port" if ($debug);
+ return 1;
+ };
+ };
+ };
+ print LOG
+ " $ARGV[3] not found on Netserver logged users list " if ($debug);
+ 0;
+}
+
+#
+# Versanet's Perl Script Support:
+#
+# ___ versanet_snmp 1.0 by support@versanetcomm.com ___ July 1999
+# Versanet Enterprise MIB Base: 1.3.6.1.4.1.2180
+#
+# VN2001/2002 use slot/port number to locate modems. To use snmp get we
+# have to translate the original port number into a slot/port pair.
+#
+$vsm = '.iso.org.dod.internet.private.enterprises.2180';
+sub versanet_snmp {
+
+ print LOG "argv[2] = $ARGV[2] " if ($debug);
+ $port = $ARGV[2]%8;
+ $port = 8 if ($port eq 0);
+ print LOG "port = $port " if ($debug);
+ $slot = (($ARGV[2]-$port)/8)+1;
+ print LOG "slot = $slot" if ($debug);
+ $loginname = snmpget($ARGV[1], "$cmmty_string", "$vsm.27.1.1.3.$slot.$port");
+#
+# Note: the "$cmmty_string" string above could be replaced by the public
+# community string defined in Versanet VN2001/VN2002.
+#
+ print LOG " user at slot $slot port $port: $loginname\n" if ($debug); ($loginname eq $ARGV[3]) ? 1 : 0;
+}
+
+
+# 1999/08/24 Chris Shenton <chris@shenton.org>
+# Check Bay8000 NAS (aka: Annex) using finger.
+# Returns from "finger @bay" like:
+# Port What User Location When Idle Address
+# asy2 PPP bill --- 9:33am :08 192.0.2.194
+# asy4 PPP hillary --- 9:36am :04 192.0.2.195
+# [...]
+# But also returns partial-match users if you say like "finger g@bay":
+# Port What User Location When Idle Address
+# asy2 PPP gore --- 9:33am :09 192.0.2.194
+# asy22 PPP gwbush --- Mon 9:19am :07 192.0.2.80
+# So check exact match of username!
+
+sub bay_finger { # ARGV: 1=nas_ip, 2=nas_port, 3=login, 4=sessid
+ open(FINGER, "$finger $ARGV[3]\@$ARGV[1]|") || return 2; # error
+ while(<FINGER>) {
+ my ($Asy, $PPP, $User) = split;
+ if( $User =~ /^$ARGV[3]$/ ){
+ close FINGER;
+ print LOG "checkrad:bay_finger: ONLINE $ARGV[3]\@$ARGV[1]"
+ if ($debug);
+ return 1; # online
+ }
+ }
+ close FINGER;
+ print LOG "checkrad:bay_finger: offline $ARGV[3]\@$ARGV[1]" if ($debug);
+ return 0; # offline
+}
+
+#
+# Cisco L2TP support
+# This is for PPP sessions coming from an L2TP tunnel from a Dial
+# or DSL wholesale provider
+# Paul Khavkine <paul@distributel.net>
+# July 19 2001
+#
+# find_l2tp_login() walks a part of cisco vpdn tree to find out what session
+# and tunnel ID's are for a given Virtual-Access interface to construct
+# the following OID: .1.3.6.1.4.1.9.10.24.1.3.2.1.2.2.$tunID.$sessID
+# Then gets the username from that OID.
+# Make sure you set the $realm variable at the begining of the file if
+# needed. The new type for naslist is cisco_l2tp
+
+sub find_l2tp_login
+{
+ my($host, $community, $port_num) = @_;
+ my $l2tp_oid = '.1.3.6.1.4.1.9.10.24.1.3.2.1.2.2';
+ my $port_oid = '.iso.org.dod.internet.private.enterprises.9.10.51.1.2.1.1.2.2';
+ my $port = 'Vi' . $port_num;
+
+ my $sess = new SNMP::Session(DestHost => $host, Community => $community);
+ my $snmp_var = new SNMP::Varbind(["$port_oid"]);
+ my $val = $sess->getnext($snmp_var);
+
+ do
+ {
+ $sess->getnext($snmp_var);
+ } until ($snmp_var->[$SNMP::Varbind::val_f] =~ /$port/) ||
+ (!($snmp_var->[$SNMP::Varbind::ref_f] =~ /^$port_oid\.(\d+)\.(\d+)$/)) ||
+ ($sess->{ErrorNum});
+
+ my $val1 = $snmp_var->[$SNMP::Varbind::ref_f];
+
+ if ($val1 =~ /^$port_oid/) {
+ $result = substr($val1, length($port_oid));
+ $result =~ /^\.(\d+)\.(\d+)$/;
+ $tunID = $1;
+ $sessID = $2;
+ }
+
+ my $snmp_var1 = new SNMP::Varbind(["$l2tp_oid\.$tunID\.$sessID"]);
+ $val = $sess->get($snmp_var1);
+ my $login = $snmp_var1->[$SNMP::Varbind::val_f];
+
+ return $login;
+}
+
+sub cisco_l2tp_snmp
+{
+ my $login = find_l2tp_login("$ARGV[1]", $cmmty_string, "$ARGV[2]");
+ print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
+ ($login eq "$ARGV[3]\@$realm") ? 1 : 0;
+}
+
+sub mikrotik_snmp {
+
+ # Set SNMP version
+ # MikroTik only supports version 1
+ $snmp_version = "1";
+
+ # Look up community string in naspasswd file.
+ ($login, $password) = naspasswd($ARGV[1], 1);
+ if ($login && $login ne 'SNMP') {
+ if($debug) {
+ print LOG "Error: Need SNMP community string for $ARGV[1]\n";
+ }
+ return 2;
+ } else {
+ # If password is defined in naspasswd file, use it as community,
+ # otherwise use $cmmty_string
+ if ($password eq '') {
+ $password = "$cmmty_string";
+ }
+ }
+
+ # We want mtxrInterfaceStatsName from MIKROTIK-MIB
+ $oid = "1.3.6.1.4.1.14988.1.1.14.1.1.2";
+
+ # Mikrotik doesnt give port IDs correctly to RADIUS :(
+ # practically this would limit us to a simple only-one user limit for
+ # this script to work properly.
+ @output = snmpwalk_prog($ARGV[1], $password, "$oid");
+
+ foreach $line ( @output ) {
+ #remove newline
+ chomp $line;
+ #remove trailing whitespace
+ ($line = $line) =~ s/\s+$//;
+ if( $line =~ /<.*-$ARGV[3]>/ ) {
+ $username_seen++;
+ }
+ }
+
+ #lets return something
+ if ($username_seen > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub mikrotik_telnet {
+ # Localize all variables first.
+ my ($t, $login, $password);
+ my (@fields, @output, $output, $username_seen, $user);
+
+ return 2 unless (check_net_telnet());
+
+ $terminalserver = $ARGV[1];
+ $user = $ARGV[3];
+
+ # Get login name and password for a certain NAS from $naspass.
+ ($login, $password) = naspasswd($terminalserver, 1);
+ return 2 if ($password eq "");
+
+ # MikroTik routeros doesnt tell us to which port the user is connected
+ # practically this would limit us to a simple only-one user limit for
+ # this script to work properly.
+ $t = new Net::Telnet (Timeout => 5,
+ Prompt => '//\[.*@.*\] > /');
+
+ # Dont just exit when there is error
+ $t->errmode('return');
+
+ # Telnet to terminal server
+ $t->open($terminalserver) or return 2;
+
+ #Send login and password etc.
+ $t->login(Name => $login,
+ Password => $password,
+ # We must detect if we are logged in from the login banner.
+ # Because if routeros is with a free license the command
+ # prompt dont come. Instead it waits us to press "Enter".
+ Prompt => '/MikroTik/');
+
+ # Just be sure that routeros isn't waiting for us to press "Enter"
+ $t->print("");
+
+ # Wait for the real prompt
+ $t->waitfor('/\[.*@.*\] > /');
+
+ # It is not possible to get the line numbers etc.
+ # Thus we cant support if simultaneous-use is over 1
+ # At least I was using pppoe so it wasnt possible.
+ $t->print('ppp active print column name detail');
+
+ # Somehow routeros echo'es our commands 2 times. We dont want to mix
+ # this with the real command prompt.
+ $t->waitfor('/\[.*@.*\] > ppp active print column name detail/');
+
+ # Now lets get the list of online ppp users.
+ ( $output ) = $t->waitfor('/\[.*@.*\] > /');
+
+ # For debugging we can print the list to stdout
+# print $output;
+
+ #Lets logout to make everybody happy.
+ #If we close the connection without logging out then routeros
+ #starts to complain after a while. Saying;
+ #telnetd: All network ports in use.
+ $t->print("quit");
+ $t->close;
+
+ #check for # of $user in output
+ #the output includes only one = between name and username so we can
+ #safely use it as a seperator.
+
+#disabled until mikrotik starts to send newline after each line...
+# @output = $output;
+# foreach $line ( @output ) {
+# #remove newline
+# chomp $line;
+# #remove trailing whitespace
+# ($line = $line) =~ s/\s+$//;
+# if( $line =~ /name=/ ) {
+# print($line);
+# @fields = split( /=/, $line );
+# if( $fields[1] == "\"$user\"") {
+# $username_seen++;
+# }
+# }
+# }
+
+ if( $output =~ /name="$user"/ ) {
+ $username_seen++;
+ }
+
+ #lets return something
+ if ($username_seen > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+sub redback_telnet {
+ #Localize all variables first.
+ my ($terminalserver, $login, $password);
+ my ($user, $context, $operprompt, $adminprompt, $t);
+ return 2 unless (check_net_telnet());
+ $terminalserver = $ARGV[1];
+ ($user, $context) = split /@/, $ARGV[3];
+ if (not $user) {
+ print LOG " Error: No user defined\n" if ($debug);
+ return 2;
+ }
+ if (not $context) {
+ print LOG " Error: No context defined\n" if ($debug);
+ return 2;
+ }
+
+ # Get loggin information
+ ($root, $password) = naspasswd($terminalserver, 1);
+ return 2 if ($password eq "");
+
+ $operprompt = '/\[.*\].*>$/';
+ $adminprompt = '/\[.*\].*#$/';
+
+ # Logging to the RedBack NAS
+ $t = new Net::Telnet (Timeout => 5, Prompt => $operprompt);
+ $t->input_log("./debug");
+ $t->open($terminalserver);
+ $t->login($root, $password);
+
+ #Enable us
+ $t->print('ena');
+ $t->waitfor('/Password/');
+ $t->print($password);
+ $t->waitfor($adminprompt);
+ $t->prompt($adminprompt);
+
+ #Switch context
+ $t->cmd(String => "context $context");
+
+ #Ask the question
+ @lines = $t->cmd(String => "show subscribers active $user\@$context");
+ if ($lines[0] =~ /subscriber $user\@$context/ ) {
+ return 1;
+ }
+ return 0;
+}
+
+###############################################################################
+
+# Poor man's getopt (for -d)
+if ($ARGV[0] eq '-d') {
+ shift @ARGV;
+ $debug = "stdout";
+}
+
+if ($debug) {
+ if ($debug eq 'stdout') {
+ open(LOG, ">&STDOUT");
+ } elsif ($debug eq 'stderr') {
+ open(LOG, ">&STDERR");
+ } else {
+ open(LOG, ">>$debug");
+ $now = localtime;
+ print LOG "$now checkrad @ARGV\n";
+ }
+}
+
+if ($#ARGV != 4) {
+ print LOG "Usage: checkrad nas_type nas_ip " .
+ "nas_port login session_id\n" if ($debug);
+ print STDERR "Usage: checkrad nas_type nas_ip " .
+ "nas_port login session_id\n"
+ unless ($debug =~ m/^(stdout|stderr)$/);
+ close LOG if ($debug);
+ exit(2);
+}
+
+if ($ARGV[0] eq 'livingston') {
+ $ret = &livingston_snmp;
+} elsif ($ARGV[0] eq 'cisco') {
+ $ret = &cisco_snmp;
+} elsif ($ARGV[0] eq 'cvx') {
+ $ret = &cvx_snmp;
+} elsif ($ARGV[0] eq 'juniper') {
+ $ret = &juniper_e_snmp;
+} elsif ($ARGV[0] eq 'multitech') {
+ $ret = &multitech_snmp;
+} elsif ($ARGV[0] eq 'computone') {
+ $ret = &computone_finger;
+} elsif ($ARGV[0] eq 'max40xx') {
+ $ret = &max40xx_finger;
+} elsif ($ARGV[0] eq 'ascend' || $ARGV[0] eq 'max40xx_snmp') {
+ $ret = &ascend_snmp;
+} elsif ($ARGV[0] eq 'portslave') {
+ $ret = &portslave_finger;
+} elsif ($ARGV[0] eq 'tc') {
+ $ret = &tc_tccheck;
+} elsif ($ARGV[0] eq 'pathras') {
+ $ret = &cyclades_telnet;
+} elsif ($ARGV[0] eq 'pr3000') {
+ $ret = &cyclades_snmp;
+} elsif ($ARGV[0] eq 'pr4000') {
+ $ret = &cyclades_snmp;
+} elsif ($ARGV[0] eq 'patton') {
+ $ret = &patton_snmp;
+} elsif ($ARGV[0] eq 'digitro') {
+ $ret = &digitro_rusers;
+} elsif ($ARGV[0] eq 'usrhiper') {
+ $ret = &usrhiper_snmp;
+} elsif ($ARGV[0] eq 'netserver') {
+ $ret = &usrnet_telnet;
+} elsif ($ARGV[0] eq 'versanet') {
+ $ret = &versanet_snmp;
+} elsif ($ARGV[0] eq 'bay') {
+ $ret = &bay_finger;
+} elsif ($ARGV[0] eq 'cisco_l2tp'){
+ $ret = &cisco_l2tp_snmp;
+} elsif ($ARGV[0] eq 'mikrotik'){
+ $ret = &mikrotik_telnet;
+} elsif ($ARGV[0] eq 'mikrotik_snmp'){
+ $ret = &mikrotik_snmp;
+} elsif ($ARGV[0] eq 'redback'){
+ $ret = &redback_telnet;
+} elsif ($ARGV[0] eq 'dot1x'){
+ $ret = &dot1x_snmp;
+} elsif ($ARGV[0] eq 'other') {
+ $ret = 1;
+} else {
+ print LOG " checkrad: unknown NAS type $ARGV[0]\n" if ($debug);
+ print STDERR "checkrad: unknown NAS type $ARGV[0]\n";
+ $ret = 2;
+}
+
+if ($debug) {
+ $mn = "login ok";
+ $mn = "double detected" if ($ret == 1);
+ $mn = "error detected" if ($ret == 2);
+ print LOG " Returning $ret ($mn)\n";
+ close LOG;
+}
+
+exit($ret);
diff --git a/src/main/checkrad.mk b/src/main/checkrad.mk
new file mode 100644
index 0000000..e991bf7
--- /dev/null
+++ b/src/main/checkrad.mk
@@ -0,0 +1,5 @@
+install: $(R)$(sbindir)/checkrad
+
+$(R)$(sbindir)/checkrad: src/main/checkrad | $(R)$(sbindir)
+ @echo INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(sbindir)
diff --git a/src/main/client.c b/src/main/client.c
new file mode 100644
index 0000000..12f7824
--- /dev/null
+++ b/src/main/client.c
@@ -0,0 +1,1581 @@
+/*
+ * 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 main/client.c
+ * @brief Manage clients allowed to communicate with the server.
+ *
+ * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+
+#ifdef WITH_DYNAMIC_CLIENTS
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#endif
+
+struct radclient_list {
+ char const *name; /* name of this list */
+ char const *server; /* virtual server associated with this client list */
+
+ /*
+ * FIXME: One set of trees for IPv4, and another for IPv6?
+ */
+ rbtree_t *trees[129]; /* for 0..128, inclusive. */
+ uint32_t min_prefix;
+
+ bool parsed;
+};
+
+
+#ifdef WITH_STATS
+static rbtree_t *tree_num = NULL; /* client numbers 0..N */
+static int tree_num_max = 0;
+#endif
+static RADCLIENT_LIST *root_clients = NULL;
+
+/*
+ * Callback for freeing a client.
+ */
+void client_free(RADCLIENT *client)
+{
+ if (!client) return;
+
+ talloc_free(client);
+}
+
+/*
+ * Callback for comparing two clients.
+ */
+static int client_ipaddr_cmp(void const *one, void const *two)
+{
+ RADCLIENT const *a = one;
+ RADCLIENT const *b = two;
+#ifndef WITH_TCP
+
+ return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
+#else
+ int rcode;
+
+ rcode = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
+ if (rcode != 0) return rcode;
+
+ /*
+ * Wildcard match
+ */
+ if ((a->proto == IPPROTO_IP) ||
+ (b->proto == IPPROTO_IP)) return 0;
+
+ return (a->proto - b->proto);
+#endif
+}
+
+#ifdef WITH_STATS
+static int client_num_cmp(void const *one, void const *two)
+{
+ RADCLIENT const *a = one;
+ RADCLIENT const *b = two;
+
+ return (a->number - b->number);
+}
+#endif
+
+/*
+ * Free a RADCLIENT list.
+ */
+void client_list_free(RADCLIENT_LIST *clients)
+{
+ int i;
+
+ if (!clients) clients = root_clients;
+ if (!clients) return; /* Clients may not have been initialised yet */
+
+ for (i = 0; i <= 128; i++) {
+ if (clients->trees[i]) rbtree_free(clients->trees[i]);
+ clients->trees[i] = NULL;
+ }
+
+ if (clients == root_clients) {
+#ifdef WITH_STATS
+ if (tree_num) rbtree_free(tree_num);
+ tree_num = NULL;
+ tree_num_max = 0;
+#endif
+ root_clients = NULL;
+ }
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ /*
+ * FIXME: No fr_fifo_delete()
+ */
+#endif
+
+ talloc_free(clients);
+}
+
+/*
+ * Return a new, initialized, set of clients.
+ */
+RADCLIENT_LIST *client_list_init(CONF_SECTION *cs)
+{
+ RADCLIENT_LIST *clients = talloc_zero(cs, RADCLIENT_LIST);
+
+ if (!clients) return NULL;
+
+ clients->min_prefix = 128;
+
+ /*
+ * Associate the "clients" list with the virtual server.
+ */
+ if (cs && (cf_data_add(cs, "clients", clients, NULL) < 0)) {
+ ERROR("Failed to associate client list with section %s\n", cf_section_name1(cs));
+ client_list_free(clients);
+ return false;
+ }
+
+ return clients;
+}
+
+/** Add a client to a RADCLIENT_LIST
+ *
+ * @param clients list to add client to, may be NULL if global client list is being used.
+ * @param client to add.
+ * @return true on success, false on failure.
+ */
+bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
+{
+ RADCLIENT *old;
+ char buffer[INET6_ADDRSTRLEN + 3];
+
+ if (!client) return false;
+
+ /*
+ * Initialize the global list, if not done already.
+ */
+ if (!root_clients) {
+ root_clients = cf_data_find(main_config.config, "clients");
+ if (!root_clients) root_clients = client_list_init(main_config.config);
+ if (!root_clients) {
+ ERROR("Cannot add client - failed creating client list");
+ return false;
+ }
+ }
+
+ /*
+ * Hack to fixup wildcard clients
+ *
+ * If the IP is all zeros, with a 32 or 128 bit netmask
+ * assume the user meant to configure 0.0.0.0/0 instead
+ * of 0.0.0.0/32 - which would require the src IP of
+ * the client to be all zeros.
+ */
+ if (fr_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
+ case AF_INET:
+ if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
+ break;
+
+ case AF_INET6:
+ if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
+ DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
+
+ /*
+ * If the client also defines a server, do that now.
+ */
+ if (client->defines_coa_server) if (!realm_home_server_add(client->coa_home_server)) return false;
+
+ /*
+ * If there's no client list, BUT there's a virtual
+ * server, try to add the client to the appropriate
+ * "clients" section for that virtual server.
+ */
+ if (!clients && client->server) {
+ CONF_SECTION *cs;
+ CONF_SECTION *subcs;
+ CONF_PAIR *cp;
+ char const *section_name;
+
+ cs = cf_section_sub_find_name2(main_config.config, "server", client->server);
+ if (!cs) {
+ ERROR("Cannot add client - virtual server %s does not exist", client->server);
+ return false;
+ }
+
+ /*
+ * If this server has no "listen" section, add the clients
+ * to the global client list.
+ */
+ subcs = cf_section_sub_find(cs, "listen");
+ if (!subcs) {
+ DEBUG("No 'listen' section in virtual server %s. Adding client to global client list",
+ client->server);
+ goto check_list;
+ }
+
+ cp = cf_pair_find(subcs, "clients");
+ if (!cp) {
+ DEBUG("No 'clients' configuration item in first listener of virtual server %s. Adding client to global client list",
+ client->server);
+ goto check_list;
+ }
+
+ /*
+ * Duplicate the lookup logic in common_socket_parse()
+ *
+ * Explicit list given: use it.
+ */
+ section_name = cf_pair_value(cp);
+ if (!section_name) goto check_list;
+
+ subcs = cf_section_sub_find_name2(main_config.config, "clients", section_name);
+ if (!subcs) {
+ subcs = cf_section_find(section_name);
+ }
+ if (!subcs) {
+ cf_log_err_cs(cs,
+ "Failed to find clients %s {...}",
+ section_name);
+ return false;
+ }
+
+ DEBUG("Adding client to client list %s", section_name);
+
+ /*
+ * If the client list already exists, use that.
+ * Otherwise, create a new client list.
+ *
+ * @todo - add the client to _all_ listeners?
+ */
+ clients = cf_data_find(subcs, "clients");
+ if (clients) goto check_list;
+
+ clients = client_list_init(subcs);
+ if (!clients) {
+ ERROR("Cannot add client - failed creating client list %s for server %s", section_name,
+ client->server);
+ return false;
+ }
+ }
+
+check_list:
+ if (!clients) clients = root_clients;
+ client->list = clients;
+
+ /*
+ * Create a tree for it.
+ */
+ if (!clients->trees[client->ipaddr.prefix]) {
+ clients->trees[client->ipaddr.prefix] = rbtree_create(clients, client_ipaddr_cmp, NULL, 0);
+ if (!clients->trees[client->ipaddr.prefix]) {
+ return false;
+ }
+ }
+
+#define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
+
+ /*
+ * Cannot insert the same client twice.
+ */
+ old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client);
+ if (old) {
+ /*
+ * If it's a complete duplicate, then free the new
+ * one, and return "OK".
+ */
+ if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) &&
+ (old->ipaddr.prefix == client->ipaddr.prefix) &&
+ namecmp(longname) && namecmp(secret) &&
+ namecmp(shortname) && namecmp(nas_type) &&
+ namecmp(login) && namecmp(password) && namecmp(server) &&
+#ifdef WITH_DYNAMIC_CLIENTS
+ (old->lifetime == client->lifetime) &&
+ namecmp(client_server) &&
+#endif
+#ifdef WITH_COA
+ namecmp(coa_name) &&
+ (old->coa_home_server == client->coa_home_server) &&
+ (old->coa_home_pool == client->coa_home_pool) &&
+#endif
+ (old->message_authenticator == client->message_authenticator)) {
+ WARN("Ignoring duplicate client %s", client->longname);
+ client_free(client);
+ return true;
+ }
+
+ ERROR("Failed to add duplicate client %s", client->shortname);
+ return false;
+ }
+#undef namecmp
+
+ /*
+ * Other error adding client: likely is fatal.
+ */
+ if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) {
+ return false;
+ }
+
+#ifdef WITH_STATS
+ if (!tree_num) {
+ tree_num = rbtree_create(clients, client_num_cmp, NULL, 0);
+ }
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ /*
+ * More catching of clients added by rlm_sql.
+ *
+ * The sql modules sets the dynamic flag BEFORE calling
+ * us. The client_afrom_request() function sets it AFTER
+ * calling us.
+ */
+ if (client->dynamic && (client->lifetime == 0)) {
+ RADCLIENT *network;
+
+ /*
+ * If there IS an enclosing network,
+ * inherit the lifetime from it.
+ */
+ network = client_find(clients, &client->ipaddr, client->proto);
+ if (network) {
+ client->lifetime = network->lifetime;
+ }
+ }
+#endif
+
+ client->number = tree_num_max;
+ tree_num_max++;
+ if (tree_num) rbtree_insert(tree_num, client);
+#endif
+
+ if (client->ipaddr.prefix < clients->min_prefix) {
+ clients->min_prefix = client->ipaddr.prefix;
+ }
+
+ (void) talloc_steal(clients, client); /* reparent it */
+
+ return true;
+}
+
+
+#ifdef WITH_DYNAMIC_CLIENTS
+void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
+{
+ if (!client) return;
+
+ if (!clients) clients = root_clients;
+
+ if (!client->dynamic) return;
+
+ rad_assert(client->ipaddr.prefix <= 128);
+
+#ifdef WITH_STATS
+ rbtree_deletebydata(tree_num, client);
+#endif
+ rbtree_deletebydata(clients->trees[client->ipaddr.prefix], client);
+}
+#endif
+
+#ifdef WITH_STATS
+/*
+ * Find a client in the RADCLIENTS list by number.
+ * This is a support function for the statistics code.
+ */
+RADCLIENT *client_findbynumber(RADCLIENT_LIST const *clients, int number)
+{
+ if (!clients) clients = root_clients;
+
+ if (!clients) return NULL;
+
+ if (number >= tree_num_max) return NULL;
+
+ if (tree_num) {
+ RADCLIENT myclient;
+
+ myclient.number = number;
+
+ return rbtree_finddata(tree_num, &myclient);
+ }
+
+ return NULL;
+}
+#else
+RADCLIENT *client_findbynumber(UNUSED const RADCLIENT_LIST *clients, UNUSED int number)
+{
+ return NULL;
+}
+#endif
+
+
+/*
+ * Find a client in the RADCLIENTS list.
+ */
+RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
+{
+ int32_t i, max_prefix;
+ RADCLIENT myclient;
+
+ if (!clients) clients = root_clients;
+
+ if (!clients || !ipaddr) return NULL;
+
+ switch (ipaddr->af) {
+ case AF_INET:
+ max_prefix = 32;
+ break;
+
+ case AF_INET6:
+ max_prefix = 128;
+ break;
+
+ default :
+ return NULL;
+ }
+
+ for (i = max_prefix; i >= (int32_t) clients->min_prefix; i--) {
+ void *data;
+
+ myclient.ipaddr = *ipaddr;
+ myclient.proto = proto;
+ fr_ipaddr_mask(&myclient.ipaddr, i);
+
+ if (!clients->trees[i]) continue;
+
+ data = rbtree_finddata(clients->trees[i], &myclient);
+ if (data) return data;
+ }
+
+ return NULL;
+}
+
+/*
+ * Old wrapper for client_find
+ */
+RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr)
+{
+ return client_find(root_clients, ipaddr, IPPROTO_UDP);
+}
+
+static fr_ipaddr_t cl_ipaddr;
+static uint32_t cl_netmask;
+static char const *cl_srcipaddr = NULL;
+static char const *hs_proto = NULL;
+
+#ifdef WITH_TCP
+static CONF_PARSER limit_config[] = {
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.max_connections), "16" },
+
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.lifetime), "0" },
+
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.idle_timeout), "30" },
+
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+static const CONF_PARSER client_config[] = {
+ { "ipaddr", FR_CONF_POINTER(PW_TYPE_COMBO_IP_PREFIX, &cl_ipaddr), NULL },
+ { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_PREFIX, &cl_ipaddr), NULL },
+ { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_PREFIX, &cl_ipaddr), NULL },
+
+ { "netmask", FR_CONF_POINTER(PW_TYPE_INTEGER, &cl_netmask), NULL },
+
+ { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
+
+ { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" },
+
+ { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
+ { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL },
+
+ { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
+
+ { "login", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, login), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, password), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
+ { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, RADCLIENT, response_window), NULL },
+
+#ifdef WITH_TCP
+ { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
+ { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
+#endif
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ { "dynamic_clients", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, client_server), NULL },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, lifetime), NULL },
+ { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
+#endif
+
+#ifdef WITH_RADIUSV11
+ { "radiusv1_1", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, radiusv11_name), NULL },
+#endif
+
+ CONF_PARSER_TERMINATOR
+};
+
+/** Create the linked list of clients from the new configuration type
+ *
+ */
+#ifdef WITH_TLS
+RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, bool tls_required)
+#else
+RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
+#endif
+{
+ bool global = false, in_server = false;
+ CONF_SECTION *cs;
+ RADCLIENT *c = NULL;
+ RADCLIENT_LIST *clients = NULL;
+
+ /*
+ * Be forgiving. If there's already a clients, return
+ * it. Otherwise create a new one.
+ */
+ clients = cf_data_find(section, "clients");
+ if (clients) {
+ /*
+ * Modules are initialized before the listeners.
+ * Which means that we MIGHT have read clients
+ * from SQL before parsing this "clients"
+ * section. So there may already be a clients
+ * list.
+ *
+ * But the list isn't _our_ list that we parsed,
+ * so we still need to parse the clients here.
+ */
+ if (clients->parsed) return clients;
+ } else {
+ clients = client_list_init(section);
+ if (!clients) return NULL;
+ }
+
+ if (cf_top_section(section) == section) {
+ global = true;
+ clients->name = "global";
+ clients->server = NULL;
+ }
+
+ if (strcmp("server", cf_section_name1(section)) == 0) {
+ clients->name = NULL;
+ clients->server = cf_section_name2(section);
+ in_server = true;
+ }
+
+ for (cs = cf_subsection_find_next(section, NULL, "client");
+ cs;
+ cs = cf_subsection_find_next(section, cs, "client")) {
+ c = client_afrom_cs(cs, cs, in_server, false);
+ if (!c) {
+ error:
+ client_free(c);
+ client_list_free(clients);
+ return NULL;
+ }
+
+#ifdef WITH_TLS
+ /*
+ * TLS clients CANNOT use non-TLS listeners.
+ * non-TLS clients CANNOT use TLS listeners.
+ */
+ if (tls_required != c->tls_required) {
+ cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
+ goto error;
+ }
+#endif
+
+ /*
+ * FIXME: Add the client as data via cf_data_add,
+ * for migration issues.
+ */
+
+#ifdef WITH_DYNAMIC_CLIENTS
+#ifdef HAVE_DIRENT_H
+ if (c->client_server) {
+ char const *value;
+ CONF_PAIR *cp;
+ DIR *dir;
+ struct dirent *dp;
+ struct stat stat_buf;
+ char buf2[2048];
+
+ /*
+ * Find the directory where individual
+ * client definitions are stored.
+ */
+ cp = cf_pair_find(cs, "directory");
+ if (!cp) goto add_client;
+
+ value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cs(cs, "The \"directory\" entry must not be empty");
+ goto error;
+ }
+
+ DEBUG("including dynamic clients in %s", value);
+
+ dir = opendir(value);
+ if (!dir) {
+ cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
+ goto error;
+ }
+
+ /*
+ * Read the directory, ignoring "." files.
+ */
+ while ((dp = readdir(dir)) != NULL) {
+ char const *p;
+ RADCLIENT *dc;
+
+ if (dp->d_name[0] == '.') continue;
+
+ /*
+ * Check for valid characters
+ */
+ for (p = dp->d_name; *p != '\0'; p++) {
+ if (isalpha((uint8_t)*p) ||
+ isdigit((uint8_t)*p) ||
+ (*p == ':') ||
+ (*p == '.')) continue;
+ break;
+ }
+ if (*p != '\0') continue;
+
+ snprintf(buf2, sizeof(buf2), "%s/%s", value, dp->d_name);
+
+ if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue;
+
+ dc = client_read(buf2, in_server, true);
+ if (!dc) {
+ cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2);
+ closedir(dir);
+ goto error;
+ }
+
+ /*
+ * Validate, and add to the list.
+ */
+ if (!client_add_dynamic(clients, c, dc)) {
+ closedir(dir);
+ goto error;
+ }
+ } /* loop over the directory */
+ closedir(dir);
+ }
+#endif /* HAVE_DIRENT_H */
+
+ add_client:
+#endif /* WITH_DYNAMIC_CLIENTS */
+ if (!client_add(clients, c)) {
+ cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs));
+ goto error;
+ }
+
+ }
+
+ /*
+ * Replace the global list of clients with the new one.
+ * The old one is still referenced from the original
+ * configuration, and will be freed when that is freed.
+ */
+ if (global) root_clients = clients;
+
+ clients->parsed = true;
+ return clients;
+}
+
+#ifdef WITH_DYNAMIC_CLIENTS
+/*
+ * We overload this structure a lot.
+ */
+static const CONF_PARSER dynamic_config[] = {
+ { "FreeRADIUS-Client-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IP-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV4_PREFIX, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-IPv6-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV6_PREFIX, RADCLIENT, ipaddr), NULL },
+ { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
+ { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
+
+ { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL },
+
+ { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
+ { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
+ { "FreeRADIUS-Client-NAS-Type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
+ { "FreeRADIUS-Client-Virtual-Server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+/** Add a dynamic client
+ *
+ */
+bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c)
+{
+ char buffer[128];
+
+ /*
+ * No virtual server defined. Inherit the parent's
+ * definition.
+ */
+ if (master->server && !c->server) {
+ c->server = talloc_typed_strdup(c, master->server);
+ }
+
+ /*
+ * If the client network isn't global (not tied to a
+ * virtual server), then ensure that this clients server
+ * is the same as the enclosing networks virtual server.
+ */
+ if (master->server && (strcmp(master->server, c->server) != 0)) {
+ ERROR("Cannot add client %s/%i: Virtual server %s is not the same as the virtual server for the network",
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->server);
+
+ goto error;
+ }
+
+ if (!client_add(clients, c)) {
+ ERROR("Cannot add client %s/%i: Internal error",
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
+
+ goto error;
+ }
+
+ /*
+ * Initialize the remaining fields.
+ */
+ c->dynamic = true;
+ c->lifetime = master->lifetime;
+ c->created = time(NULL);
+ c->longname = talloc_typed_strdup(c, c->shortname);
+
+ if (rad_debug_lvl <= 2) {
+ INFO("Adding client %s/%i",
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
+ } else {
+ INFO("Adding client %s/%i with shared secret \"%s\"",
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->secret);
+ }
+ return true;
+
+error:
+ client_free(c);
+ return false;
+}
+
+/** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
+ *
+ * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
+ *
+ * @note Caller should free CONF_SECTION passed in as out, on error.
+ * Contents of that section will be in an undefined state.
+ *
+ * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
+ * (when this function is called recursively).
+ * Should be alloced with cf_section_alloc, or if there's a separate template section, the
+ * result of calling cf_section_dup on that section.
+ * @param[in] map section.
+ * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
+ * @param[in] data to pass to func, usually a result pointer.
+ * @return 0 on success else -1 on error.
+ */
+int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
+{
+ CONF_ITEM const *ci;
+
+ for (ci = cf_item_find_next(map, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(map, ci)) {
+ CONF_PAIR const *cp;
+ CONF_PAIR *old;
+ char *value;
+ char const *attr;
+
+ /*
+ * Recursively process map subsection
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *cs, *cc;
+
+ cs = cf_item_to_section(ci);
+ /*
+ * Use pre-existing section or alloc a new one
+ */
+ cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
+ if (!cc) {
+ cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
+ cf_section_add(out, cc);
+ if (!cc) return -1;
+ }
+
+ if (client_map_section(cc, cs, func, data) < 0) return -1;
+ continue;
+ }
+
+ cp = cf_item_to_pair(ci);
+ attr = cf_pair_attr(cp);
+
+ /*
+ * The callback can return 0 (success) and not provide a value
+ * in which case we skip the mapping pair.
+ *
+ * Or return -1 in which case we error out.
+ */
+ if (func(&value, cp, data) < 0) {
+ cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
+ return -1;
+ }
+ if (!value) continue;
+
+ /*
+ * Replace an existing CONF_PAIR
+ */
+ old = cf_pair_find(out, attr);
+ if (old) {
+ cf_pair_replace(out, old, value);
+ talloc_free(value);
+ continue;
+ }
+
+ /*
+ * ...or add a new CONF_PAIR
+ */
+ cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (!cp) {
+ cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
+ talloc_free(value);
+ return -1;
+ }
+ talloc_free(value);
+ cf_item_add(out, cf_pair_to_item(cp));
+ }
+
+ return 0;
+}
+
+/** Allocate a new client from a config section
+ *
+ * @param ctx to allocate new clients in.
+ * @param cs to process as a client.
+ * @param in_server Whether the client should belong to a specific virtual server.
+ * @param with_coa If true and coa_home_server or coa_home_pool aren't specified automatically,
+ * create a coa home_server section and add it to the client CONF_SECTION.
+ * @return new RADCLIENT struct.
+ */
+RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
+{
+ RADCLIENT *c;
+ char const *name2;
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err_cs(cs, "Missing client name");
+ return NULL;
+ }
+
+ /*
+ * The size is fine.. Let's create the buffer
+ */
+ c = talloc_zero(ctx, RADCLIENT);
+ c->cs = cs;
+
+ memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
+ cl_netmask = 255;
+
+ if (cf_section_parse(cs, c, client_config) < 0) {
+ cf_log_err_cs(cs, "Error parsing client section");
+ error:
+ client_free(c);
+#ifdef WITH_TCP
+ hs_proto = NULL;
+ cl_srcipaddr = NULL;
+#endif
+
+ return NULL;
+ }
+
+ /*
+ * Global clients can set servers to use, per-server clients cannot.
+ */
+ if (in_server && c->server) {
+ cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
+ goto error;
+ }
+
+ /*
+ * Allow the old method to specify "netmask". Just using "1.2.3.4" means it's a /32.
+ */
+ if (cl_netmask != 255) {
+ if ((cl_ipaddr.prefix != cl_netmask) &&
+ (((cl_ipaddr.af == AF_INET) && cl_ipaddr.prefix != 32) ||
+ ((cl_ipaddr.af == AF_INET6) && cl_ipaddr.prefix != 128))) {
+ cf_log_err_cs(cs, "Clients cannot use 'ipaddr/mask' and 'netmask' at the same time.");
+ goto error;
+ }
+
+ cl_ipaddr.prefix = cl_netmask;
+ }
+
+ /*
+ * Newer style client definitions with either ipaddr or ipaddr6
+ * config items.
+ */
+ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
+ char buffer[128];
+
+ /*
+ * Sets ipv4/ipv6 address and prefix.
+ */
+ c->ipaddr = cl_ipaddr;
+
+ /*
+ * Set the long name to be the result of a reverse lookup on the IP address.
+ */
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
+ c->longname = talloc_typed_strdup(c, buffer);
+
+ /*
+ * Set the short name to the name2.
+ */
+ if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
+ /*
+ * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
+ */
+ } else {
+ WARN("No 'ipaddr' or 'ipv4addr' or 'ipv6addr' field found in client %s. "
+ "Please fix your configuration", name2);
+ WARN("Support for old-style clients will be removed in a future release");
+
+#ifdef WITH_TCP
+ if (cf_pair_find(cs, "proto") != NULL) {
+ cf_log_err_cs(cs, "Cannot use 'proto' inside of old-style client definition");
+ goto error;
+ }
+#endif
+ if (fr_pton(&c->ipaddr, name2, -1, AF_UNSPEC, true) < 0) {
+ cf_log_err_cs(cs, "Failed parsing client name \"%s\" as ip address or hostname: %s", name2,
+ fr_strerror());
+ goto error;
+ }
+
+ c->longname = talloc_typed_strdup(c, name2);
+ if (!c->shortname) c->shortname = talloc_typed_strdup(c, c->longname);
+ }
+
+ c->proto = IPPROTO_UDP;
+ if (hs_proto) {
+ if (strcmp(hs_proto, "udp") == 0) {
+ hs_proto = NULL;
+
+#ifdef WITH_TCP
+ } else if (strcmp(hs_proto, "tcp") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+# ifdef WITH_TLS
+ } else if (strcmp(hs_proto, "tls") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+ c->tls_required = true;
+
+ } else if (strcmp(hs_proto, "radsec") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_TCP;
+ c->tls_required = true;
+# endif
+ } else if (strcmp(hs_proto, "*") == 0) {
+ hs_proto = NULL;
+ c->proto = IPPROTO_IP; /* fake for dual */
+#endif
+ } else {
+ cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
+ goto error;
+ }
+ }
+
+ /*
+ * If a src_ipaddr is specified, when we send the return packet
+ * we will use this address instead of the src from the
+ * request.
+ */
+ if (cl_srcipaddr) {
+#ifdef WITH_UDPFROMTO
+ switch (c->ipaddr.af) {
+ case AF_INET:
+ if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
+ cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ goto error;
+ }
+ break;
+
+ case AF_INET6:
+ if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
+ cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
+ goto error;
+ }
+ break;
+ default:
+ rad_assert(0);
+ }
+#else
+ WARN("Server not built with udpfromto, ignoring client src_ipaddr");
+#endif
+ cl_srcipaddr = NULL;
+ }
+
+#ifdef WITH_RADIUSV11
+ if (c->tls_required && c->radiusv11_name) {
+ int rcode;
+
+ rcode = fr_str2int(radiusv11_types, c->radiusv11_name, -1);
+ if (rcode < 0) {
+ cf_log_err_cs(cs, "Invalid value for 'radiusv11'");
+ goto error;
+ }
+
+ c->radiusv11 = rcode;
+ }
+#endif
+
+ /*
+ * A response_window of zero is OK, and means that it's
+ * ignored by the rest of the server timers.
+ */
+ if (timerisset(&c->response_window)) {
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
+ }
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ if (c->client_server) {
+ c->secret = talloc_typed_strdup(c, "testing123");
+
+ if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
+ ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
+ cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
+ goto error;
+ }
+
+ return c;
+ }
+#endif
+
+ if (!c->secret || (c->secret[0] == '\0')) {
+#ifdef WITH_DHCP
+ char const *value = NULL;
+ CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
+
+ if (cp) value = cf_pair_value(cp);
+
+ /*
+ * Secrets aren't needed for DHCP.
+ */
+ if (value && (strcmp(value, "yes") == 0)) return c;
+#endif
+
+#ifdef WITH_TLS
+ /*
+ * If the client is TLS only, the secret can be
+ * omitted. When omitted, it's hard-coded to
+ * "radsec". See RFC 6614.
+ */
+ if (c->tls_required) {
+ c->secret = talloc_typed_strdup(cs, "radsec");
+ } else
+#endif
+
+ {
+ cf_log_err_cs(cs, "secret must be at least 1 character long");
+ goto error;
+ }
+ }
+
+#ifdef WITH_COA
+ {
+ CONF_PAIR *cp;
+
+ /*
+ * Point the client to the home server pool, OR to the
+ * home server. This gets around the problem of figuring
+ * out which port to use.
+ */
+ cp = cf_pair_find(cs, "coa_server");
+ if (cp) {
+ c->coa_name = cf_pair_value(cp);
+ c->coa_home_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
+ if (!c->coa_home_pool) {
+ c->coa_home_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
+ }
+ if (!c->coa_home_pool && !c->coa_home_server) {
+ cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
+ goto error;
+ }
+ /*
+ * If we're implicitly adding a CoA home server for
+ * every client, or there's a server subsection,
+ * create a home server CONF_SECTION and then parse
+ * it into a home_server_t.
+ */
+ } else if (with_coa || cf_section_sub_find(cs, "coa_server")) {
+ CONF_SECTION *server;
+ home_server_t *home;
+
+ if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix != 32)) ||
+ ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix != 128))) {
+ WARN("Subnets not supported for home servers. "
+ "Not adding client %s as home_server", name2);
+ goto done_coa;
+ }
+
+ server = home_server_cs_afrom_client(cs);
+ if (!server) goto error;
+
+ /*
+ * Must be allocated in the context of the client,
+ * as allocating using the context of the
+ * realm_config_t without a mutex, by one of the
+ * workers, would be bad.
+ */
+ home = home_server_afrom_cs(NULL, NULL, server);
+ if (!home) {
+ talloc_free(server);
+ goto error;
+ }
+
+ rad_assert(home->type == HOME_TYPE_COA);
+
+ c->coa_home_server = home;
+ c->defines_coa_server = true;
+ }
+ }
+done_coa:
+#endif
+
+#ifdef WITH_TCP
+ if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
+ if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5))
+ c->limit.idle_timeout = 5;
+ if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5))
+ c->limit.lifetime = 5;
+ if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime))
+ c->limit.idle_timeout = 0;
+ }
+#endif
+
+ return c;
+}
+
+/** Add a client from a result set (SQL)
+ *
+ * @todo This function should die. SQL should use client_afrom_cs.
+ *
+ * @param ctx Talloc context.
+ * @param identifier Client IP Address / IPv4 subnet / IPv6 subnet / FQDN.
+ * @param secret Client secret.
+ * @param shortname Client friendly name.
+ * @param type NAS-Type.
+ * @param server Virtual-Server to associate clients with.
+ * @param require_ma If true all packets from client must include a message-authenticator.
+ * @return The new client, or NULL on error.
+ */
+RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char const *secret,
+ char const *shortname, char const *type, char const *server, bool require_ma)
+{
+ RADCLIENT *c;
+ char buffer[128];
+
+ c = talloc_zero(ctx, RADCLIENT);
+
+ if (fr_pton(&c->ipaddr, identifier, -1, AF_UNSPEC, true) < 0) {
+ ERROR("%s", fr_strerror());
+ talloc_free(c);
+
+ return NULL;
+ }
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ c->dynamic = true;
+#endif
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
+ c->longname = talloc_typed_strdup(c, buffer);
+
+ /*
+ * Other values (secret, shortname, nas_type, virtual_server)
+ */
+ c->secret = talloc_typed_strdup(c, secret);
+ if (shortname) c->shortname = talloc_typed_strdup(c, shortname);
+ if (type) c->nas_type = talloc_typed_strdup(c, type);
+ if (server) c->server = talloc_typed_strdup(c, server);
+ c->message_authenticator = require_ma;
+
+ return c;
+}
+
+/** Create a new client, consuming all attributes in the control list of the request
+ *
+ * @param clients list to add new client to.
+ * @param request Fake request.
+ * @return a new client on success, else NULL on error.
+ */
+RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
+{
+ static int cnt;
+ int i, *pi;
+ char **p;
+ RADCLIENT *c;
+ char buffer[128];
+
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp = NULL;
+
+ if (!clients || !request) return NULL;
+
+ /*
+ * Hack for the "dynamic_clients" module.
+ */
+ if (request->client->dynamic) {
+ c = request->client;
+ goto validate;
+ }
+
+ snprintf(buffer, sizeof(buffer), "dynamic%i", cnt++);
+
+ c = talloc_zero(clients, RADCLIENT);
+ c->cs = cf_section_alloc(NULL, "client", buffer);
+ talloc_steal(c, c->cs);
+ c->ipaddr.af = AF_UNSPEC;
+ c->src_ipaddr.af = AF_UNSPEC;
+
+ fr_cursor_init(&cursor, &request->config);
+
+ RDEBUG2("Converting control list to client fields");
+ RINDENT();
+ for (i = 0; dynamic_config[i].name != NULL; i++) {
+ DICT_ATTR const *da;
+ char *strvalue = NULL;
+ CONF_PAIR *cp = NULL;
+
+ da = dict_attrbyname(dynamic_config[i].name);
+ if (!da) {
+ RERROR("Cannot add client %s: attribute \"%s\" is not in the dictionary",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
+ dynamic_config[i].name);
+ error:
+ REXDENT();
+ talloc_free(vp);
+ client_free(c);
+ return NULL;
+ }
+
+ fr_cursor_first(&cursor);
+ if (!fr_cursor_next_by_da(&cursor, da, TAG_ANY)) {
+ /*
+ * Not required. Skip it.
+ */
+ if (!dynamic_config[i].dflt) continue;
+
+ RERROR("Cannot add client %s: Required attribute \"%s\" is missing",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
+ dynamic_config[i].name);
+ goto error;
+ }
+ vp = fr_cursor_remove(&cursor);
+
+ /*
+ * Freed at the same time as the vp.
+ */
+ strvalue = vp_aprints_value(vp, vp, '\'');
+
+ switch (dynamic_config[i].type) {
+ case PW_TYPE_IPV4_ADDR:
+ if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
+ c->ipaddr.af = AF_INET;
+ c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ c->ipaddr.prefix = 32;
+ cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
+#ifdef WITH_UDPFROMTO
+ RDEBUG2("src_ipaddr = %s", strvalue);
+ c->src_ipaddr.af = AF_INET;
+ c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ c->src_ipaddr.prefix = 32;
+ cp = cf_pair_alloc(c->cs, "src_ipaddr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+#else
+ RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
+#endif
+ }
+
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
+ c->ipaddr.af = AF_INET6;
+ c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ c->ipaddr.prefix = 128;
+ cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
+#ifdef WITH_UDPFROMTO
+ c->src_ipaddr.af = AF_INET6;
+ c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ c->src_ipaddr.prefix = 128;
+ cp = cf_pair_alloc(c->cs, "src_addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+#else
+ RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
+#endif
+ }
+
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
+ c->ipaddr.af = AF_INET;
+ memcpy(&c->ipaddr.ipaddr.ip4addr, &vp->vp_ipv4prefix[2],
+ sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
+ fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
+ cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ }
+
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
+ c->ipaddr.af = AF_INET6;
+ memcpy(&c->ipaddr.ipaddr.ip6addr, &vp->vp_ipv6prefix[2],
+ sizeof(c->ipaddr.ipaddr.ip6addr));
+ fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
+ cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ }
+
+ break;
+
+ case PW_TYPE_STRING:
+ {
+ CONF_PARSER const *parse;
+
+ /*
+ * Cache pointer to CONF_PAIR buffer in RADCLIENT struct
+ */
+ p = (char **) ((char *) c + dynamic_config[i].offset);
+ if (*p) TALLOC_FREE(*p);
+ if (!vp->vp_strvalue[0]) break;
+
+ /*
+ * We could reuse the CONF_PAIR buff, this just keeps things
+ * consistent between client_afrom_cs, and client_afrom_query.
+ */
+ *p = talloc_strdup(c, vp->vp_strvalue);
+
+ /*
+ * This is fairly nasty... In order to figure out the CONF_PAIR
+ * name associated with a field, find offsets that match between
+ * the dynamic_config CONF_PARSER table, and the client_config
+ * CONF_PARSER table.
+ *
+ * This is so that things that expect to find CONF_PAIRs in the
+ * client CONF_SECTION for fields like 'nas_type' can.
+ */
+ for (parse = client_config; parse->name; parse++) {
+ if (parse->offset == dynamic_config[i].offset) break;
+ }
+
+ if (!parse) break;
+
+ cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ }
+ break;
+
+ case PW_TYPE_BOOLEAN:
+ {
+ CONF_PARSER const *parse;
+
+ pi = (int *) ((bool *) ((char *) c + dynamic_config[i].offset));
+ *pi = vp->vp_integer;
+
+ /*
+ * Same nastiness as above.
+ */
+ for (parse = client_config; parse->name; parse++) {
+ if (parse->offset == dynamic_config[i].offset) break;
+ }
+ if (!parse) break;
+
+ cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ }
+ break;
+
+ default:
+ goto error;
+ }
+
+ if (!cp) {
+ RERROR("Error creating equivalent conf pair for %s", vp->da->name);
+ goto error;
+ }
+
+ if (cf_pair_attr_type(cp) == T_SINGLE_QUOTED_STRING) {
+ RDEBUG2("%s = '%s'", cf_pair_attr(cp), cf_pair_value(cp));
+ } else {
+ RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
+ }
+ cf_pair_add(c->cs, cp);
+
+ talloc_free(vp);
+ }
+
+ fr_cursor_first(&cursor);
+ vp = fr_cursor_remove(&cursor);
+ if (vp) {
+ CONF_PAIR *cp;
+
+ do {
+ char *value;
+
+ value = vp_aprints_value(vp, vp, '\'');
+ if (!value) {
+ ERROR("Failed stringifying value of &control:%s", vp->da->name);
+ goto error;
+ }
+
+ if (vp->da->type == PW_TYPE_STRING) {
+ RDEBUG2("%s = '%s'", vp->da->name, value);
+ cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
+ T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ } else {
+ RDEBUG2("%s = %s", vp->da->name, value);
+ cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
+ T_BARE_WORD, T_BARE_WORD);
+ }
+ cf_pair_add(c->cs, cp);
+
+ talloc_free(vp);
+ } while ((vp = fr_cursor_remove(&cursor)));
+ }
+ REXDENT();
+
+validate:
+ if (c->ipaddr.af == AF_UNSPEC) {
+ RERROR("Cannot add client %s: No IP address was specified.",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
+
+ goto error;
+ }
+
+ {
+ fr_ipaddr_t addr;
+
+ /*
+ * Need to apply the same mask as we set for the client
+ * else clients created with FreeRADIUS-Client-IPv6-Prefix
+ * or FreeRADIUS-Client-IPv4-Prefix will fail this check.
+ */
+ addr = request->packet->src_ipaddr;
+ fr_ipaddr_mask(&addr, c->ipaddr.prefix);
+ if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
+ char buf2[128];
+
+ RERROR("Cannot add client %s: Not in specified subnet %s/%i",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
+ ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)), c->ipaddr.prefix);
+ goto error;
+ }
+ }
+
+ if (!c->secret || !*c->secret) {
+ RERROR("Cannot add client %s: No secret was specified",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
+ goto error;
+ }
+
+ if (!client_add_dynamic(clients, request->client, c)) {
+ return NULL;
+ }
+
+ if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
+ RERROR("Cannot add client %s: Client IP and src address are different IP version",
+ ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
+
+ goto error;
+ }
+
+ return c;
+}
+
+/*
+ * Read a client definition from the given filename.
+ */
+RADCLIENT *client_read(char const *filename, int in_server, int flag)
+{
+ char const *p;
+ RADCLIENT *c;
+ CONF_SECTION *cs;
+ char buffer[256];
+
+ if (!filename) return NULL;
+
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) return NULL;
+
+ if (cf_file_read(cs, filename) < 0) {
+ talloc_free(cs);
+ return NULL;
+ }
+
+ cs = cf_section_sub_find(cs, "client");
+ if (!cs) {
+ ERROR("No \"client\" section found in client file");
+ return NULL;
+ }
+
+ c = client_afrom_cs(cs, cs, in_server, false);
+ if (!c) return NULL;
+
+ p = strrchr(filename, FR_DIR_SEP);
+ if (p) {
+ p++;
+ } else {
+ p = filename;
+ }
+
+ if (!flag) return c;
+
+ /*
+ * Additional validations
+ */
+ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
+ if (strcmp(p, buffer) != 0) {
+ ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);
+ client_free(c);
+ return NULL;
+ }
+
+ return c;
+}
+#endif
+
diff --git a/src/main/collectd.c b/src/main/collectd.c
new file mode 100644
index 0000000..b720471
--- /dev/null
+++ b/src/main/collectd.c
@@ -0,0 +1,382 @@
+/*
+ * 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 collectd.c
+ * @brief Helper functions to enabled radsniff to talk to collectd
+ *
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+#include <assert.h>
+#include <ctype.h>
+
+#ifdef HAVE_COLLECTDC_H
+#include <collectd/client.h>
+#include <freeradius-devel/radsniff.h>
+
+/** Copy a 64bit unsigned integer into a double
+ *
+ */
+/*
+static void _copy_uint64_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+/*
+static void _copy_uint64_to_uint64(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((uint64_t *) tmpl->dst) = *((uint64_t *) tmpl->src);
+}
+*/
+
+static void _copy_double_to_double(UNUSED rs_t *conf, rs_stats_value_tmpl_t *tmpl)
+{
+ assert(tmpl->src);
+ assert(tmpl->dst);
+
+ *((double *) tmpl->dst) = *((double*) tmpl->src);
+}
+
+
+/** Allocates a stats template which describes a single guage/counter
+ *
+ * This is just intended to simplify allocating a fairly complex memory structure
+ * src and dst pointers must be set
+ *
+ * @param ctx Context to allocate collectd struct in.
+ * @param conf Radsniff configuration.
+ * @param plugin_instance usually the type of packet (in our case).
+ * @param type string, the name of a collection of stats e.g. exchange
+ * @param type_instance the name of the counter/guage within the collection e.g. latency.
+ * @param stats structure to derive statistics from.
+ * @param values Value templates used to populate lcc_value_list.
+ * @return a new rs_stats_tmpl_t on success or NULL on failure.
+ */
+static rs_stats_tmpl_t *rs_stats_collectd_init(TALLOC_CTX *ctx, rs_t *conf,
+ char const *plugin_instance,
+ char const *type, char const *type_instance,
+ void *stats,
+ rs_stats_value_tmpl_t const *values)
+{
+ static char hostname[255];
+ static char fqdn[LCC_NAME_LEN];
+
+ size_t len;
+ int i;
+ char *p;
+
+ rs_stats_tmpl_t *tmpl;
+ lcc_value_list_t *value;
+
+ assert(conf);
+ assert(type);
+ assert(type_instance);
+
+ for (len = 0; values[len].src; len++) {} ;
+ assert(len > 0);
+
+ /*
+ * Initialise hostname once so we don't call gethostname every time
+ */
+ if (*fqdn == '\0') {
+ int ret;
+ struct addrinfo hints, *info = NULL;
+
+ if (gethostname(hostname, sizeof(hostname)) < 0) {
+ ERROR("Error getting hostname: %s", fr_syserror(errno));
+
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ if ((ret = getaddrinfo(hostname, "radius", &hints, &info)) != 0) {
+ ERROR("Error getting hostname: %s", gai_strerror(ret));
+ return NULL;
+ }
+
+ strlcpy(fqdn, info->ai_canonname, sizeof(fqdn));
+
+ freeaddrinfo(info);
+ }
+
+ tmpl = talloc_zero(ctx, rs_stats_tmpl_t);
+ if (!tmpl) {
+ return NULL;
+ }
+
+ tmpl->value_tmpl = talloc_zero_array(tmpl, rs_stats_value_tmpl_t, len);
+ if (!tmpl->value_tmpl) {
+ goto error;
+ }
+
+ tmpl->stats = stats;
+
+ value = talloc_zero(tmpl, lcc_value_list_t);
+ if (!value) {
+ goto error;
+ }
+ tmpl->value = value;
+
+ value->interval = conf->stats.interval;
+ value->values_len = len;
+
+ value->values_types = talloc_zero_array(value, int, len);
+ if (!value->values_types) {
+ goto error;
+ }
+
+ value->values = talloc_zero_array(value, value_t, len);
+ if (!value->values) {
+ goto error;
+ }
+
+ for (i = 0; i < (int) len; i++) {
+ assert(values[i].src);
+ assert(values[i].cb);
+
+ tmpl->value_tmpl[i] = values[i];
+ switch (tmpl->value_tmpl[i].type) {
+ case LCC_TYPE_COUNTER:
+ tmpl->value_tmpl[i].dst = &value->values[i].counter;
+ break;
+
+ case LCC_TYPE_GAUGE:
+ tmpl->value_tmpl[i].dst = &value->values[i].gauge;
+ break;
+
+ case LCC_TYPE_DERIVE:
+ tmpl->value_tmpl[i].dst = &value->values[i].derive;
+ break;
+
+ case LCC_TYPE_ABSOLUTE:
+ tmpl->value_tmpl[i].dst = &value->values[i].absolute;
+ break;
+
+ default:
+ assert(0);
+ }
+ value->values_types[i] = tmpl->value_tmpl[i].type;
+ }
+
+ /*
+ * These should be OK as is
+ */
+ strlcpy(value->identifier.host, fqdn, sizeof(value->identifier.host));
+
+ /*
+ * Plugin is ASCII only and no '/'
+ */
+ fr_prints(value->identifier.plugin, sizeof(value->identifier.plugin),
+ conf->stats.prefix, strlen(conf->stats.prefix), '\0');
+ for (p = value->identifier.plugin; *p; ++p) {
+ if ((*p == '-') || (*p == '/'))*p = '_';
+ }
+
+ /*
+ * Plugin instance is ASCII only (assuming printable only) and no '/'
+ */
+ fr_prints(value->identifier.plugin_instance, sizeof(value->identifier.plugin_instance),
+ plugin_instance, strlen(plugin_instance), '\0');
+ for (p = value->identifier.plugin_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ /*
+ * Type is ASCII only (assuming printable only) and no '/' or '-'
+ */
+ fr_prints(value->identifier.type, sizeof(value->identifier.type),
+ type, strlen(type), '\0');
+ for (p = value->identifier.type; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+ fr_prints(value->identifier.type_instance, sizeof(value->identifier.type_instance),
+ type_instance, strlen(type_instance), '\0');
+ for (p = value->identifier.type_instance; *p; ++p) {
+ if ((*p == '-') || (*p == '/')) *p = '_';
+ }
+
+
+ return tmpl;
+
+error:
+ talloc_free(tmpl);
+ return NULL;
+}
+
+
+/** Setup stats templates for latency
+ *
+ */
+rs_stats_tmpl_t *rs_stats_collectd_init_latency(TALLOC_CTX *ctx, rs_stats_tmpl_t **out, rs_t *conf,
+ char const *type, rs_latency_t *stats, PW_CODE code)
+{
+ rs_stats_tmpl_t **tmpl, *last;
+ char *p;
+ char buffer[LCC_NAME_LEN];
+ tmpl = out;
+
+ rs_stats_value_tmpl_t rtx[(RS_RETRANSMIT_MAX + 1) + 1 + 1]; // RTX bins + 0 bin + lost + NULL
+ int i;
+
+ /* not static so were thread safe */
+ rs_stats_value_tmpl_t const _packet_count[] = {
+ { &stats->interval.received, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.linked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.unlinked, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.reused, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+ rs_stats_value_tmpl_t const _latency[] = {
+ { &stats->latency_smoothed, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_average, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_high, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { &stats->interval.latency_low, LCC_TYPE_GAUGE, _copy_double_to_double, NULL },
+ { NULL, 0, NULL, NULL }
+ };
+
+#define INIT_STATS(_ti, _v) do {\
+ strlcpy(buffer, fr_packet_codes[code], sizeof(buffer)); \
+ for (p = buffer; *p; ++p) *p = tolower((uint8_t) *p);\
+ last = *tmpl = rs_stats_collectd_init(ctx, conf, type, _ti, buffer, stats, _v);\
+ if (!*tmpl) {\
+ TALLOC_FREE(*out);\
+ return NULL;\
+ }\
+ tmpl = &(*tmpl)->next;\
+ ctx = *tmpl;\
+ } while (0)
+
+
+ INIT_STATS("radius_count", _packet_count);
+ INIT_STATS("radius_latency", _latency);
+
+ for (i = 0; i < (RS_RETRANSMIT_MAX + 1); i++) {
+ rtx[i].src = &stats->interval.rt[i];
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+ }
+
+ rtx[i].src = &stats->interval.lost;
+ rtx[i].type = LCC_TYPE_GAUGE;
+ rtx[i].cb = _copy_double_to_double;
+ rtx[i].dst = NULL;
+
+ memset(&rtx[++i], 0, sizeof(rs_stats_value_tmpl_t));
+
+ INIT_STATS("radius_rtx", rtx);
+
+ return last;
+}
+
+/** Refresh and send the stats to the collectd server
+ *
+ */
+void rs_stats_collectd_do_stats(rs_t *conf, rs_stats_tmpl_t *tmpls, struct timeval *now)
+{
+ rs_stats_tmpl_t *tmpl = tmpls;
+ char identifier[6 * LCC_NAME_LEN];
+ int i;
+
+ while (tmpl) {
+ /*
+ * Refresh the value of whatever were sending
+ */
+ for (i = 0; i < (int) tmpl->value->values_len; i++) {
+ tmpl->value_tmpl[i].cb(conf, &tmpl->value_tmpl[i]);
+ }
+
+ tmpl->value->time = now->tv_sec;
+
+ lcc_identifier_to_string(conf->stats.handle, identifier, sizeof(identifier), &tmpl->value->identifier);
+
+ if (lcc_putval(conf->stats.handle, tmpl->value) < 0) {
+ char const *error;
+
+ error = lcc_strerror(conf->stats.handle);
+ ERROR("Failed PUTVAL \"%s\" interval=%i %" PRIu64 " : %s",
+ identifier,
+ (int) tmpl->value->interval,
+ (uint64_t) tmpl->value->time,
+ error ? error : "unknown error");
+ }
+
+ tmpl = tmpl->next;
+ }
+}
+
+/** Connect to a collectd server for stats output
+ *
+ * @param[in,out] conf radsniff configuration, we write the generated handle here.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_open(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ /*
+ * Tear down stale connections gracefully.
+ */
+ rs_stats_collectd_close(conf);
+
+ /*
+ * There's no way to get the error from the connection handle
+ * because it's freed on failure, before lcc returns.
+ */
+ if (lcc_connect(conf->stats.collectd, &conf->stats.handle) < 0) {
+ ERROR("Failed opening connection to collectd: %s", fr_syserror(errno));
+ return -1;
+ }
+ DEBUG2("Connected to \"%s\"", conf->stats.collectd);
+
+ assert(conf->stats.handle);
+ return 0;
+}
+
+/** Close connection
+ *
+ * @param[in,out] conf radsniff configuration.
+ * @return 0 on success -1 on failure.
+ */
+int rs_stats_collectd_close(rs_t *conf)
+{
+ assert(conf->stats.collectd);
+
+ int ret = 0;
+
+ if (conf->stats.handle) {
+ ret = lcc_disconnect(conf->stats.handle);
+ conf->stats.handle = NULL;
+ }
+
+ return ret;
+}
+#endif
diff --git a/src/main/command.c b/src/main/command.c
new file mode 100644
index 0000000..988f43b
--- /dev/null
+++ b/src/main/command.c
@@ -0,0 +1,3632 @@
+/*
+ * command.c Command socket processing.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+
+#ifdef WITH_COMMAND_SOCKET
+
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/channel.h>
+#include <freeradius-devel/connection.h>
+#include <freeradius-devel/socket.h>
+
+#include <libgen.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+
+typedef struct fr_command_table_t fr_command_table_t;
+
+typedef int (*fr_command_func_t)(rad_listen_t *, int, char *argv[]);
+
+#define FR_READ (1)
+#define FR_WRITE (2)
+
+#define CMD_FAIL FR_CHANNEL_FAIL
+#define CMD_OK FR_CHANNEL_SUCCESS
+
+struct fr_command_table_t {
+ char const *command;
+ int mode; /* read/write */
+ char const *help;
+ fr_command_func_t func;
+ fr_command_table_t *table;
+};
+
+#define COMMAND_BUFFER_SIZE (1024)
+
+typedef struct fr_cs_buffer_t {
+ int auth;
+ int mode;
+ ssize_t offset;
+ ssize_t next;
+ char buffer[COMMAND_BUFFER_SIZE];
+} fr_cs_buffer_t;
+
+#define COMMAND_SOCKET_MAGIC (0xffdeadee)
+typedef struct fr_command_socket_t {
+ uint32_t magic;
+ char const *path;
+ char *copy; /* <sigh> */
+ uid_t uid;
+ gid_t gid;
+ char const *uid_name;
+ char const *gid_name;
+ char const *mode_name;
+ bool peercred;
+ char user[256];
+
+ /*
+ * The next few entries handle fake packets injected by
+ * the control socket.
+ */
+ fr_ipaddr_t src_ipaddr; /* src_port is always 0 */
+ fr_ipaddr_t dst_ipaddr;
+ uint16_t dst_port;
+ rad_listen_t *inject_listener;
+ RADCLIENT *inject_client;
+
+ fr_cs_buffer_t co;
+} fr_command_socket_t;
+
+static const CONF_PARSER command_config[] = {
+ { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, path), "${run_dir}/radiusd.sock" },
+ { "uid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, uid_name), NULL },
+ { "gid", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, gid_name), NULL },
+ { "mode", FR_CONF_OFFSET(PW_TYPE_STRING, fr_command_socket_t, mode_name), NULL },
+ { "peercred", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_command_socket_t, peercred), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+static FR_NAME_NUMBER mode_names[] = {
+ { "ro", FR_READ },
+ { "read-only", FR_READ },
+ { "read-write", FR_READ | FR_WRITE },
+ { "rw", FR_READ | FR_WRITE },
+ { NULL, 0 }
+};
+
+#if !defined(HAVE_GETPEEREID) && defined(SO_PEERCRED)
+static int getpeereid(int s, uid_t *euid, gid_t *egid)
+{
+ struct ucred cr;
+ socklen_t cl = sizeof(cr);
+
+ if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cl) < 0) {
+ return -1;
+ }
+
+ *euid = cr.uid;
+ *egid = cr.gid;
+ return 0;
+}
+
+/* we now have getpeereid() in this file */
+#define HAVE_GETPEEREID (1)
+
+#endif /* HAVE_GETPEEREID */
+
+/** Initialise a socket for use with peercred authentication
+ *
+ * This function initialises a socket and path in a way suitable for use with
+ * peercred.
+ *
+ * @param path to socket.
+ * @param uid that should own the socket (linux only).
+ * @param gid that should own the socket (linux only).
+ * @return 0 on success -1 on failure.
+ */
+#ifdef __linux__
+static int fr_server_domain_socket_peercred(char const *path, uid_t uid, gid_t gid)
+#else
+static int fr_server_domain_socket_peercred(char const *path, uid_t UNUSED uid, UNUSED gid_t gid)
+#endif
+{
+ int sockfd;
+ size_t len;
+ socklen_t socklen;
+ struct sockaddr_un salocal;
+ struct stat buf;
+
+ if (!path) {
+ fr_strerror_printf("No path provided, was NULL");
+ return -1;
+ }
+
+ len = strlen(path);
+ if (len >= sizeof(salocal.sun_path)) {
+ fr_strerror_printf("Path too long in socket filename");
+ return -1;
+ }
+
+ if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fr_strerror_printf("Failed creating socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ memset(&salocal, 0, sizeof(salocal));
+ salocal.sun_family = AF_UNIX;
+ memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
+
+ socklen = SUN_LEN(&salocal);
+
+ /*
+ * Check the path.
+ */
+ if (stat(path, &buf) < 0) {
+ if (errno != ENOENT) {
+ fr_strerror_printf("Failed to stat %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * FIXME: Check the enclosing directory?
+ */
+ } else { /* it exists */
+ int client_fd;
+
+ if (!S_ISREG(buf.st_mode)
+#ifdef S_ISSOCK
+ && !S_ISSOCK(buf.st_mode)
+#endif
+ ) {
+ fr_strerror_printf("Cannot turn %s into socket", path);
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Refuse to open sockets not owned by us.
+ */
+ if (buf.st_uid != geteuid()) {
+ fr_strerror_printf("We do not own %s", path);
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * Check if a server is already listening on the
+ * socket?
+ */
+ client_fd = fr_socket_client_unix(path, false);
+ if (client_fd >= 0) {
+ fr_strerror_printf("Control socket '%s' is already in use", path);
+ close(client_fd);
+ close(sockfd);
+ return -1;
+ }
+
+ if (unlink(path) < 0) {
+ fr_strerror_printf("Failed to delete %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+ }
+
+ if (bind(sockfd, (struct sockaddr *)&salocal, socklen) < 0) {
+ fr_strerror_printf("Failed binding to %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ /*
+ * FIXME: There's a race condition here. But Linux
+ * doesn't seem to permit fchmod on domain sockets.
+ */
+ if (chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
+ fr_strerror_printf("Failed setting permissions on %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ if (listen(sockfd, 8) < 0) {
+ fr_strerror_printf("Failed listening to %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+#ifdef O_NONBLOCK
+ {
+ int flags;
+
+ if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) {
+ fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ if( fcntl(sockfd, F_SETFL, flags) < 0) {
+ fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+ }
+#endif
+
+ /*
+ * Changing socket permissions only works on linux.
+ * BSDs ignore socket permissions.
+ */
+#ifdef __linux__
+ /*
+ * Don't chown it from (possibly) non-root to root.
+ * Do chown it from (possibly) root to non-root.
+ */
+ if ((uid != (uid_t) -1) || (gid != (gid_t) -1)) {
+ /*
+ * Don't do chown if it's already owned by us.
+ */
+ if (fstat(sockfd, &buf) < 0) {
+ fr_strerror_printf("Failed reading %s: %s", path, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ if ((buf.st_uid != uid) || (buf.st_gid != gid)) {
+ rad_suid_up();
+ if (fchown(sockfd, uid, gid) < 0) {
+ fr_strerror_printf("Failed setting ownership of %s to (%d, %d): %s",
+ path, uid, gid, fr_syserror(errno));
+ rad_suid_down();
+ close(sockfd);
+ return -1;
+ }
+ rad_suid_down();
+ }
+ }
+#endif
+
+ return sockfd;
+}
+
+#if !defined(HAVE_OPENAT) || !defined(HAVE_MKDIRAT) || !defined(HAVE_UNLINKAT)
+static int fr_server_domain_socket_perm(UNUSED char const *path, UNUSED uid_t uid, UNUSED gid_t gid)
+{
+ fr_strerror_printf("Unable to initialise control socket. Set peercred = yes or update to "
+ "POSIX-2008 compliant libc");
+ return -1;
+}
+#else
+/** Alternative function for creating Unix domain sockets and enforcing permissions
+ *
+ * Unlike fr_server_unix_socket which is intended to be used with peercred auth
+ * this function relies on the file system to enforce access.
+ *
+ * The way it does this depends on the operating system. On Linux systems permissions
+ * can be set on the socket directly and the system will enforce them.
+ *
+ * On most other systems fchown and fchmod fail when called with socket descriptors,
+ * and although permissions can be changed in other ways, they're not enforced.
+ *
+ * For these systems we use the permissions on the parent directory to enforce
+ * permissions on the socket. It's not safe to modify these permissions ourselves
+ * due to TOCTOU attacks, so if they don't match what we require, we error out and
+ * get the user to change them (which arguably isn't any safer, but releases us of
+ * the responsibility).
+ *
+ * @note must be called without effective root permissions (fr_suid_down).
+ *
+ * @param path where domain socket should be created.
+ * @return a file descriptor for the bound socket on success, -1 on failure.
+ */
+static int fr_server_domain_socket_perm(char const *path, uid_t uid, gid_t gid)
+{
+ int dir_fd = -1, sock_fd = -1, parent_fd = -1;
+ char const *name;
+ char *buff = NULL, *dir = NULL, *p;
+
+ uid_t euid;
+ gid_t egid;
+
+ mode_t perm = 0;
+ struct stat st;
+
+ size_t len;
+
+ socklen_t socklen;
+ struct sockaddr_un salocal;
+
+ rad_assert(path);
+
+ euid = geteuid();
+ egid = getegid();
+
+ /*
+ * Determine the correct permissions for the socket, or its
+ * containing directory.
+ */
+ perm |= S_IREAD | S_IWRITE | S_IEXEC;
+ if (gid != (gid_t) -1) perm |= S_IRGRP | S_IWGRP | S_IXGRP;
+
+ buff = talloc_strdup(NULL, path);
+ if (!buff) return -1;
+
+ /*
+ * Some implementations modify it in place others use internal
+ * storage *sigh*. dirname also formats the path else we wouldn't
+ * be using it.
+ */
+ dir = dirname(buff);
+ if (dir != buff) {
+ dir = talloc_strdup(NULL, dir);
+ if (!dir) return -1;
+ talloc_free(buff);
+ }
+
+ p = strrchr(dir, FR_DIR_SEP);
+ if (!p) {
+ fr_strerror_printf("Failed determining parent directory");
+ error:
+ talloc_free(dir);
+ if (sock_fd >= 0) close(sock_fd);
+ if (dir_fd >= 0) close(dir_fd);
+ if (parent_fd >= 0) close(parent_fd);
+ return -1;
+ }
+
+ *p = '\0';
+
+ /*
+ * Ensure the parent of the control socket directory exists,
+ * and the euid we're running under has access to it.
+ */
+ parent_fd = open(dir, O_DIRECTORY);
+ if (parent_fd < 0) {
+ struct passwd *user;
+ struct group *group;
+
+ if (rad_getpwuid(NULL, &user, euid) < 0) goto error;
+ if (rad_getgrgid(NULL, &group, egid) < 0) {
+ talloc_free(user);
+ goto error;
+ }
+ fr_strerror_printf("Can't open directory \"%s\": %s. Must be created manually, or modified, "
+ "with permissions that allow writing by user %s or group %s", dir,
+ user->pw_name, group->gr_name, fr_syserror(errno));
+ talloc_free(user);
+ talloc_free(group);
+ goto error;
+ }
+
+ *p = FR_DIR_SEP;
+
+ dir_fd = openat(parent_fd, p + 1, O_NOFOLLOW | O_DIRECTORY);
+ if (dir_fd < 0) {
+ int ret = 0;
+
+ if (errno != ENOENT) {
+ fr_strerror_printf("Failed opening control socket directory: %s", fr_syserror(errno));
+ goto error;
+ }
+
+ /*
+ * This fails if the radius user can't write
+ * to the parent directory.
+ */
+ if (mkdirat(parent_fd, p + 1, 0700) < 0) {
+ fr_strerror_printf("Failed creating control socket directory: %s", fr_syserror(errno));
+ goto error;
+ }
+
+ dir_fd = openat(parent_fd, p + 1, O_NOFOLLOW | O_DIRECTORY);
+ if (dir_fd < 0) {
+ fr_strerror_printf("Failed opening the control socket directory we created: %s",
+ fr_syserror(errno));
+ goto error;
+ }
+ if (fchmod(dir_fd, perm) < 0) {
+ fr_strerror_printf("Failed setting permissions on control socket directory: %s",
+ fr_syserror(errno));
+ goto error;
+ }
+
+ rad_suid_up();
+ if ((uid != (uid_t)-1) || (gid != (gid_t)-1)) ret = fchown(dir_fd, uid, gid);
+ rad_suid_down();
+ if (ret < 0) {
+ fr_strerror_printf("Failed changing ownership of control socket directory: %s",
+ fr_syserror(errno));
+ goto error;
+ }
+ /*
+ * Control socket dir already exists, but we still need to
+ * check the permissions are what we expect.
+ */
+ } else {
+ int ret;
+ int client_fd;
+
+ ret = fstat(dir_fd, &st);
+ if (ret < 0) {
+ fr_strerror_printf("Failed checking permissions of control socket directory: %s",
+ fr_syserror(errno));
+ goto error;
+ }
+
+ if ((uid != (uid_t)-1) && (st.st_uid != uid)) {
+ struct passwd *need_user, *have_user;
+
+ if (rad_getpwuid(NULL, &need_user, uid) < 0) goto error;
+ if (rad_getpwuid(NULL, &have_user, st.st_uid) < 0) {
+ talloc_free(need_user);
+ goto error;
+ }
+ fr_strerror_printf("Control socket directory must be owned by user %s, "
+ "currently owned by %s", need_user->pw_name, have_user->pw_name);
+ talloc_free(need_user);
+ talloc_free(have_user);
+ goto error;
+ }
+
+ if ((gid != (gid_t)-1) && (st.st_gid != gid)) {
+ struct group *need_group, *have_group;
+
+ if (rad_getgrgid(NULL, &need_group, gid) < 0) goto error;
+ if (rad_getgrgid(NULL, &have_group, st.st_gid) < 0) {
+ talloc_free(need_group);
+ goto error;
+ }
+ fr_strerror_printf("Control socket directory \"%s\" must be owned by group %s, "
+ "currently owned by %s", dir, need_group->gr_name, have_group->gr_name);
+ talloc_free(need_group);
+ talloc_free(have_group);
+ goto error;
+ }
+
+ if ((perm & 0x0c) != (st.st_mode & 0x0c)) {
+ char str_need[10], oct_need[5];
+ char str_have[10], oct_have[5];
+
+ rad_mode_to_str(str_need, perm);
+ rad_mode_to_oct(oct_need, perm);
+ rad_mode_to_str(str_have, st.st_mode);
+ rad_mode_to_oct(oct_have, st.st_mode);
+ fr_strerror_printf("Control socket directory must have permissions %s (%s), current "
+ "permissions are %s (%s)", str_need, oct_need, str_have, oct_have);
+ goto error;
+ }
+
+ /*
+ * Check if a server is already listening on the
+ * socket?
+ */
+ client_fd = fr_socket_client_unix(path, false);
+ if (client_fd >= 0) {
+ fr_strerror_printf("Control socket '%s' is already in use", path);
+ close(client_fd);
+ goto error;
+ }
+ }
+
+ name = strrchr(path, FR_DIR_SEP);
+ if (!name) {
+ fr_strerror_printf("Can't determine socket name");
+ goto error;
+ }
+ name++;
+
+ /*
+ * We've checked the containing directory has the permissions
+ * we expect, and as we have the FD, and aren't following
+ * symlinks no one can trick us into changing or creating a
+ * file elsewhere.
+ *
+ * It's possible an attacker may still be able to create hard
+ * links, for the socket file. But they would need write
+ * access to the directory we just created or verified, so
+ * this attack vector is unlikely.
+ */
+ if ((uid != (uid_t)-1) && (rad_seuid(uid) < 0)) goto error;
+ if ((gid != (gid_t)-1) && (rad_segid(gid) < 0)) {
+ rad_seuid(euid);
+ goto error;
+ }
+
+ /*
+ * The original code, did openat, used fstat to figure out
+ * what type the file was and then used unlinkat to unlink
+ * it. Except on OSX (at least) openat refuses to open
+ * socket files. So we now rely on the fact that unlinkat
+ * has sane and consistent behaviour, and will not unlink
+ * directories. unlinkat should also fail if the socket user
+ * hasn't got permission to modify the socket.
+ */
+ if ((unlinkat(dir_fd, name, 0) < 0) && (errno != ENOENT)) {
+ fr_strerror_printf("Failed removing stale socket: %s", fr_syserror(errno));
+ sock_error:
+ if (uid != (uid_t)-1) rad_seuid(euid);
+ if (gid != (gid_t)-1) rad_segid(egid);
+ close(sock_fd);
+
+ goto error;
+ }
+
+ /*
+ * At this point we should have established a secure directory
+ * to house our socket, and cleared out any stale sockets.
+ */
+ sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock_fd < 0) {
+ fr_strerror_printf("Failed creating socket: %s", fr_syserror(errno));
+ goto sock_error;
+ }
+
+#ifdef HAVE_BINDAT
+ len = strlen(name);
+#else
+ len = strlen(path);
+#endif
+ if (len >= sizeof(salocal.sun_path)) {
+ fr_strerror_printf("Path too long in socket filename");
+ goto error;
+ }
+
+ memset(&salocal, 0, sizeof(salocal));
+ salocal.sun_family = AF_UNIX;
+
+#ifdef HAVE_BINDAT
+ memcpy(salocal.sun_path, name, len + 1); /* SUN_LEN does strlen */
+#else
+ memcpy(salocal.sun_path, path, len + 1); /* SUN_LEN does strlen */
+#endif
+ socklen = SUN_LEN(&salocal);
+
+ /*
+ * Direct socket permissions are only useful on Linux which
+ * actually enforces them. BSDs don't. They also need to be
+ * set before binding the socket to a file.
+ */
+#ifdef __linux__
+ if (fchmod(sock_fd, perm) < 0) {
+ char str_need[10], oct_need[5];
+
+ rad_mode_to_str(str_need, perm);
+ rad_mode_to_oct(oct_need, perm);
+ fr_strerror_printf("Failed changing socket permissions to %s (%s)", str_need, oct_need);
+
+ goto sock_error;
+ }
+
+ if (fchown(sock_fd, uid, gid) < 0) {
+ struct passwd *user;
+ struct group *group;
+
+ if (rad_getpwuid(NULL, &user, uid) < 0) goto sock_error;
+ if (rad_getgrgid(NULL, &group, gid) < 0) {
+ talloc_free(user);
+ goto sock_error;
+ }
+
+ fr_strerror_printf("Failed changing ownership of socket to %s:%s", user->pw_name, group->gr_name);
+ talloc_free(user);
+ talloc_free(group);
+ goto sock_error;
+ }
+#endif
+ /*
+ * The correct function to use here is bindat(), but only
+ * quite recent versions of FreeBSD actually have it, and
+ * it's definitely not POSIX.
+ */
+#ifdef HAVE_BINDAT
+ if (bindat(dir_fd, sock_fd, (struct sockaddr *)&salocal, socklen) < 0) {
+#else
+ if (bind(sock_fd, (struct sockaddr *)&salocal, socklen) < 0) {
+#endif
+ fr_strerror_printf("Failed binding socket: %s", fr_syserror(errno));
+ goto sock_error;
+ }
+
+ if (listen(sock_fd, 8) < 0) {
+ fr_strerror_printf("Failed listening on socket: %s", fr_syserror(errno));
+ goto sock_error;
+ }
+
+#ifdef O_NONBLOCK
+ {
+ int flags;
+
+ flags = fcntl(sock_fd, F_GETFL, NULL);
+ if (flags < 0) {
+ fr_strerror_printf("Failed getting socket flags: %s", fr_syserror(errno));
+ goto sock_error;
+ }
+
+ flags |= O_NONBLOCK;
+ if (fcntl(sock_fd, F_SETFL, flags) < 0) {
+ fr_strerror_printf("Failed setting nonblocking socket flag: %s", fr_syserror(errno));
+ goto sock_error;
+ }
+ }
+#endif
+
+ if (uid != (uid_t)-1) rad_seuid(euid);
+ if (gid != (gid_t)-1) rad_segid(egid);
+
+ if (dir_fd >= 0) close(dir_fd);
+ if (parent_fd >= 0) close(parent_fd);
+
+ return sock_fd;
+}
+#endif
+
+static void command_close_socket(rad_listen_t *this)
+{
+ this->status = RAD_LISTEN_STATUS_EOL;
+
+ /*
+ * This removes the socket from the event fd, so no one
+ * will be calling us any more.
+ */
+ radius_update_listener(this);
+}
+
+static ssize_t CC_HINT(format (printf, 2, 3)) cprintf(rad_listen_t *listener, char const *fmt, ...)
+{
+ ssize_t r, len;
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ if (listener->status == RAD_LISTEN_STATUS_EOL) return 0;
+
+ r = fr_channel_write(listener->fd, FR_CHANNEL_STDOUT, buffer, len);
+ if (r <= 0) command_close_socket(listener);
+
+ /*
+ * FIXME: Keep writing until done?
+ */
+ return r;
+}
+
+static ssize_t CC_HINT(format (printf, 2, 3)) cprintf_error(rad_listen_t *listener, char const *fmt, ...)
+{
+ ssize_t r, len;
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ if (listener->status == RAD_LISTEN_STATUS_EOL) return 0;
+
+ r = fr_channel_write(listener->fd, FR_CHANNEL_STDERR, buffer, len);
+ if (r <= 0) command_close_socket(listener);
+
+ /*
+ * FIXME: Keep writing until done?
+ */
+ return r;
+}
+
+static int command_hup(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+ char buffer[256];
+
+ if (argc == 0) {
+ radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
+ return CMD_OK;
+ }
+
+ /*
+ * Hack a "main" HUP thingy
+ */
+ if (strcmp(argv[0], "main.log") == 0) {
+ hup_logfile();
+ return CMD_OK;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
+ cprintf_error(listener, "Module %s cannot be hup'd\n",
+ argv[0]);
+ return CMD_FAIL;
+ }
+
+ if (!module_hup_module(mi->cs, mi, time(NULL))) {
+ cprintf_error(listener, "Failed to reload module\n");
+ return CMD_FAIL;
+ }
+
+ snprintf(buffer, sizeof(buffer), "modules.%s.hup",
+ cf_section_name1(mi->cs));
+ exec_trigger(NULL, mi->cs, buffer, true);
+
+ return CMD_OK;
+}
+
+static int command_terminate(UNUSED rad_listen_t *listener,
+ UNUSED int argc, UNUSED char *argv[])
+{
+ radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
+
+ return CMD_OK;
+}
+
+static int command_uptime(rad_listen_t *listener,
+ UNUSED int argc, UNUSED char *argv[])
+{
+ char buffer[128];
+
+ CTIME_R(&fr_start_time, buffer, sizeof(buffer));
+ cprintf(listener, "Up since %s", buffer); /* no \r\n */
+
+ return CMD_OK;
+}
+
+static int command_show_config(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+ char const *value;
+
+ if (argc != 1) {
+ cprintf_error(listener, "No path was given\n");
+ return CMD_FAIL;
+ }
+
+ ci = cf_reference_item(main_config.config, main_config.config, argv[0]);
+ if (!ci) return CMD_FAIL;
+
+ if (!cf_item_is_pair(ci)) return CMD_FAIL;
+
+ cp = cf_item_to_pair(ci);
+ value = cf_pair_value(cp);
+ if (!value) return CMD_FAIL;
+
+ cprintf(listener, "%s\n", value);
+
+ return CMD_OK;
+}
+
+static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+/*
+ * FIXME: Recurse && indent?
+ */
+static void cprint_conf_parser(rad_listen_t *listener, int indent, CONF_SECTION *cs,
+ void const *base)
+
+{
+ int i;
+ char const *name1 = cf_section_name1(cs);
+ char const *name2 = cf_section_name2(cs);
+ CONF_PARSER const *variables = cf_section_parse_table(cs);
+
+ if (name2) {
+ cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
+ } else {
+ cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
+ }
+
+ indent++;
+
+ /*
+ * Print
+ */
+ if (variables) for (i = 0; variables[i].name != NULL; i++) {
+ void const *data;
+ char buffer[256];
+
+ /*
+ * No base struct offset, data must be the pointer.
+ * If data doesn't exist, ignore the entry, there
+ * must be something wrong.
+ */
+ if (!base) {
+ if (!variables[i].data) {
+ continue;
+ }
+
+ data = variables[i].data;
+
+ } else if (variables[i].data) {
+ data = variables[i].data;
+
+ } else {
+ data = (((char const *)base) + variables[i].offset);
+ }
+
+ /*
+ * Ignore the various flags
+ */
+ switch (variables[i].type & 0xff) {
+ default:
+ cprintf(listener, "%.*s%s = ?\n", indent, tabs,
+ variables[i].name);
+ break;
+
+ case PW_TYPE_INTEGER:
+ cprintf(listener, "%.*s%s = %u\n", indent, tabs,
+ variables[i].name, *(int const *) data);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ inet_ntop(AF_INET, data, buffer, sizeof(buffer));
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ inet_ntop(AF_INET6, data, buffer, sizeof(buffer));
+ break;
+
+ case PW_TYPE_BOOLEAN:
+ cprintf(listener, "%.*s%s = %s\n", indent, tabs,
+ variables[i].name,
+ ((*(bool const *) data) == false) ? "no" : "yes");
+ break;
+
+ case PW_TYPE_STRING:
+ case PW_TYPE_FILE_INPUT:
+ case PW_TYPE_FILE_OUTPUT:
+ /*
+ * FIXME: Escape things in the string!
+ */
+ if (*(char const * const *) data) {
+ cprintf(listener, "%.*s%s = \"%s\"\n", indent, tabs,
+ variables[i].name, *(char const * const *) data);
+ } else {
+ cprintf(listener, "%.*s%s = \n", indent, tabs,
+ variables[i].name);
+ }
+
+ break;
+ }
+ }
+
+ indent--;
+
+ cprintf(listener, "%.*s}\n", indent, tabs);
+}
+
+static void cprint_conf_section(rad_listen_t *listener, int indent, CONF_SECTION *cs)
+{
+ char const *name1 = cf_section_name1(cs);
+ char const *name2 = cf_section_name2(cs);
+ CONF_ITEM *ci;
+
+ if (name2) {
+ cprintf(listener, "%.*s%s %s {\n", indent, tabs, name1, name2);
+ } else {
+ cprintf(listener, "%.*s%s {\n", indent, tabs, name1);
+ }
+
+ indent++;
+
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ CONF_PAIR const *cp;
+ char const *value;
+
+ if (cf_item_is_section(ci)) {
+ cprint_conf_section(listener, indent, cf_item_to_section(ci));
+ continue;
+ }
+
+ if (!cf_item_is_pair(ci)) continue;
+
+ cp = cf_item_to_pair(ci);
+ value = cf_pair_value(cp);
+
+ if (value) {
+ /*
+ * @todo - quote the value if necessary.
+ */
+ cprintf(listener, "%.*s%s = %s\n",
+ indent, tabs,
+ cf_pair_attr(cp), value);
+ } else {
+ cprintf(listener, "%.*s%s\n",
+ indent, tabs,
+ cf_pair_attr(cp));
+ }
+ }
+
+ indent--;
+
+ cprintf(listener, "%.*s}\n", indent, tabs);
+}
+
+static int command_show_module_config(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+
+ if (argc != 1) {
+ cprintf_error(listener, "No module name was given\n");
+ return CMD_FAIL;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ cprint_conf_parser(listener, 0, mi->cs, mi->insthandle);
+
+ return CMD_OK;
+}
+
+static char const *method_names[MOD_COUNT] = {
+ "authenticate",
+ "authorize",
+ "preacct",
+ "accounting",
+ "session",
+ "pre-proxy",
+ "post-proxy",
+ "post-auth"
+#ifdef WITH_COA
+ ,
+ "recv-coa",
+ "send-coa"
+#endif
+};
+
+
+static int command_show_module_methods(rad_listen_t *listener, int argc, char *argv[])
+{
+ int i;
+ CONF_SECTION *cs;
+ module_instance_t const *mi;
+ module_t const *mod;
+
+ if (argc != 1) {
+ cprintf_error(listener, "No module name was given\n");
+ return CMD_FAIL;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ mod = mi->entry->module;
+
+ for (i = 0; i < MOD_COUNT; i++) {
+ if (mod->methods[i]) cprintf(listener, "%s\n", method_names[i]);
+ }
+
+ return CMD_OK;
+}
+
+
+static int command_show_module_flags(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t const *mi;
+ module_t const *mod;
+
+ if (argc != 1) {
+ cprintf_error(listener, "No module name was given\n");
+ return CMD_FAIL;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ mod = mi->entry->module;
+
+ if ((mod->type & RLM_TYPE_THREAD_UNSAFE) != 0)
+ cprintf(listener, "thread-unsafe\n");
+
+ if ((mod->type & RLM_TYPE_HUP_SAFE) != 0)
+ cprintf(listener, "reload-on-hup\n");
+
+ return CMD_OK;
+}
+
+static int command_show_module_status(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ const module_instance_t *mi;
+
+ if (argc != 1) {
+ cprintf_error(listener, "No module name was given\n");
+ return CMD_FAIL;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ if (!mi->force) {
+ cprintf(listener, "alive\n");
+ } else {
+ cprintf(listener, "%s\n", fr_int2str(mod_rcode_table, mi->code, "<invalid>"));
+ }
+
+
+ return CMD_OK;
+}
+
+
+/*
+ * Show all loaded modules
+ */
+static int command_show_modules(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
+{
+ CONF_SECTION *cs, *subcs;
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ subcs = NULL;
+ while ((subcs = cf_subsection_find_next(cs, subcs, NULL)) != NULL) {
+ char const *name1 = cf_section_name1(subcs);
+ char const *name2 = cf_section_name2(subcs);
+
+ module_instance_t *mi;
+
+ if (name2) {
+ mi = module_find(cs, name2);
+ if (!mi) continue;
+
+ cprintf(listener, "%s (%s)\n", name2, name1);
+ } else {
+ mi = module_find(cs, name1);
+ if (!mi) continue;
+
+ cprintf(listener, "%s\n", name1);
+ }
+ }
+
+ return CMD_OK;
+}
+
+#ifdef WITH_PROXY
+static int command_show_home_servers(rad_listen_t *listener, int argc, char *argv[])
+{
+ int i;
+ home_server_t *home;
+ char const *type, *state, *proto;
+
+ char buffer[256];
+
+ for (i = 0; i < home_server_max_number; i++) {
+
+ if ((home = home_server_bynumber(i)) == NULL)
+ continue;
+
+ /*
+ * Internal "virtual" home server.
+ */
+ if (home->ipaddr.af == AF_UNSPEC) continue;
+
+ if (home->type == HOME_TYPE_AUTH) {
+ type = "auth";
+
+ } else if (home->type == HOME_TYPE_ACCT) {
+ type = "acct";
+
+ } else if (home->type == HOME_TYPE_AUTH_ACCT) {
+ type = "auth+acct";
+
+#ifdef WITH_COA
+ } else if (home->type == HOME_TYPE_COA) {
+ type = "coa";
+#endif
+
+ } else continue;
+
+ if (home->proto == IPPROTO_UDP) {
+ proto = "udp";
+ }
+#ifdef WITH_TCP
+ else if (home->proto == IPPROTO_TCP) {
+ proto = "tcp";
+ }
+#endif
+ else proto = "??";
+
+ if (home->state == HOME_STATE_ALIVE) {
+ state = "alive";
+
+ } else if (home->state == HOME_STATE_ZOMBIE) {
+ state = "zombie";
+
+ } else if (home->state == HOME_STATE_IS_DEAD) {
+ state = "dead";
+
+ } else if (home->state == HOME_STATE_ADMIN_DOWN) {
+ state = "down";
+
+ } else if (home->state == HOME_STATE_UNKNOWN) {
+ time_t now = time(NULL);
+
+ /*
+ * We've recently received a packet, so
+ * the home server seems to be alive.
+ *
+ * The *reported* state changes because
+ * the internal state machine NEEDS THE
+ * RIGHT STATE. However, reporting that
+ * to the admin will confuse them.
+ * So... we lie. No, that dress doesn't
+ * make you look fat...
+ */
+ if ((home->last_packet_recv + (int)home->ping_interval) >= now) {
+ state = "alive";
+ } else {
+ state = "unknown";
+ }
+
+ } else continue;
+
+ if (argc > 0 && !strcmp(argv[0], "all")) {
+ char const *dynamic = home->dynamic ? "yes" : "no";
+
+ cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\t(name=%s, dynamic=%s)\n",
+ ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
+ home->port, proto, type, state,
+ home->currently_outstanding, home->name, dynamic);
+ } else {
+ cprintf(listener, "%s\t%d\t%s\t%s\t%s\t%d\n",
+ ip_ntoh(&home->ipaddr, buffer, sizeof(buffer)),
+ home->port, proto, type, state,
+ home->currently_outstanding);
+ }
+ }
+
+ return CMD_OK;
+}
+#endif
+
+static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[]);
+
+static int command_show_client_config(rad_listen_t *listener, int argc, char *argv[])
+{
+ RADCLIENT *client;
+
+ client = get_client(listener, argc, argv);
+ if (!client) {
+ return 0;
+ }
+
+ if (!client->cs) return 1;
+
+ cprint_conf_section(listener, 0, client->cs);
+ return 1;
+}
+
+/*
+ * @todo - copied from clients.c. Better to re-use, but whatever.
+ */
+struct radclient_list {
+ char const *name; /* name of this list */
+ char const *server; /* virtual server associated with this client list */
+
+ /*
+ * FIXME: One set of trees for IPv4, and another for IPv6?
+ */
+ rbtree_t *trees[129]; /* for 0..128, inclusive. */
+ uint32_t min_prefix;
+};
+
+
+static int command_show_clients(rad_listen_t *listener, int argc, char *argv[])
+{
+ int i;
+ RADCLIENT *client;
+ char buffer[256];
+
+ if (argc == 0) {
+ for (i = 0; (client = client_findbynumber(NULL, i)) != NULL; i++) {
+ ip_ntoh(&client->ipaddr, buffer, sizeof(buffer));
+
+ if (((client->ipaddr.af == AF_INET) &&
+ (client->ipaddr.prefix != 32)) ||
+ ((client->ipaddr.af == AF_INET6) &&
+ (client->ipaddr.prefix != 128))) {
+ cprintf(listener, "%s/%d\n", buffer, client->ipaddr.prefix);
+ } else {
+ cprintf(listener, "%s\n", buffer);
+ }
+ }
+
+ return CMD_OK;
+ }
+
+ if (argc != 1) {
+ cprintf_error(listener, "Unknown command %s %s ...\n", argv[0], argv[1]);
+ return -1;
+ }
+
+ if (strcmp(argv[0], "verbose") != 0) {
+ cprintf_error(listener, "Unknown command %s\n", argv[0]);
+ return -1;
+ }
+
+ for (i = 0; (client = client_findbynumber(NULL, i)) != NULL; i++) {
+ if (client->cs) {
+ cprintf(listener, "client %s {\n", cf_section_name2(client->cs));
+ } else {
+ cprintf(listener, "client {\n");
+ }
+
+ fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
+ cprintf(listener, "\tipaddr = %s\n", buffer);
+
+ if (client->src_ipaddr.af != AF_UNSPEC) {
+ fr_ntop(buffer, sizeof(buffer), &client->src_ipaddr);
+ cprintf(listener, "\tsrc_ipaddr = %s\n", buffer);
+ }
+
+ if (client->proto == IPPROTO_UDP) {
+ cprintf(listener, "\tproto = udp\n");
+ } else if (client->proto == IPPROTO_TCP) {
+ cprintf(listener, "\tproto = tcp\n");
+ } else {
+ cprintf(listener, "\tproto = *\n");
+ }
+
+ cprintf(listener, "\tsecret = %s\n", client->secret);
+ cprintf(listener, "\tlongname = %s\n", client->longname);
+ cprintf(listener, "\tshortname = %s\n", client->shortname);
+ if (client->nas_type) cprintf(listener, "\tnas_type = %s\n", client->nas_type);
+ cprintf(listener, "\tnumber = %d\n", client->number);
+
+ if (client->server) {
+ cprintf(listener, "\tvirtual_server = %s\n", client->server);
+ }
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ if (client->dynamic) {
+ cprintf(listener, "\tdynamic = yes\n");
+ cprintf(listener, "\tlifetime = %u\n", client->lifetime);
+ }
+#endif
+
+#ifdef WITH_TLS
+ if (client->tls_required) {
+ cprintf(listener, "\ttls = yes\n");
+ }
+#endif
+
+ if (client->list && client->list->server) {
+ cprintf(listener, "\tparent_virtual_server = %s\n", client->list->server);
+ } else {
+ cprintf(listener, "\tglobal = yes\n");
+ }
+
+ cprintf(listener, "}\n");
+ }
+
+ return CMD_OK;
+}
+
+
+static int command_show_version(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
+{
+ cprintf(listener, "%s\n", radiusd_version);
+ return CMD_OK;
+}
+
+static int command_debug_level(rad_listen_t *listener, int argc, char *argv[])
+{
+ int number;
+
+ if (argc == 0) {
+ cprintf_error(listener, "Must specify <number>\n");
+ return -1;
+ }
+
+ number = atoi(argv[0]);
+ if ((number < 0) || (number > 4)) {
+ cprintf_error(listener, "<number> must be between 0 and 4\n");
+ return -1;
+ }
+
+ fr_debug_lvl = rad_debug_lvl = number;
+
+ return CMD_OK;
+}
+
+static char debug_log_file_buffer[1024];
+
+static int command_debug_file(rad_listen_t *listener, int argc, char *argv[])
+{
+ if (rad_debug_lvl && default_log.dst == L_DST_STDOUT) {
+ cprintf_error(listener, "Cannot redirect debug logs to a file when already in debugging mode.\n");
+ return -1;
+ }
+
+ if ((argc > 0) && (strchr(argv[0], FR_DIR_SEP) == argv[0])) {
+ cprintf_error(listener, "Cannot direct debug logs to absolute path.\n");
+ }
+
+ default_log.debug_file = NULL;
+
+ if (argc == 0) return CMD_OK;
+
+ /*
+ * This looks weird, but it's here to avoid locking
+ * a mutex for every log message.
+ */
+ memset(debug_log_file_buffer, 0, sizeof(debug_log_file_buffer));
+
+ /*
+ * Debug files always go to the logging directory.
+ */
+ snprintf(debug_log_file_buffer, sizeof(debug_log_file_buffer),
+ "%s/%s", radlog_dir, argv[0]);
+
+ default_log.debug_file = &debug_log_file_buffer[0];
+
+ return CMD_OK;
+}
+
+extern fr_cond_t *debug_condition;
+static int command_debug_condition(rad_listen_t *listener, int argc, char *argv[])
+{
+ int i;
+ char const *error;
+ ssize_t slen = 0;
+ fr_cond_t *new_condition = NULL;
+ char *p, buffer[1024];
+
+ /*
+ * Disable it.
+ */
+ if (argc == 0) {
+ TALLOC_FREE(debug_condition);
+ debug_condition = NULL;
+ return CMD_OK;
+ }
+
+ if (!((argc == 1) &&
+ ((argv[0][0] == '"') || (argv[0][0] == '\'')))) {
+ p = buffer;
+ *p = '\0';
+ for (i = 0; i < argc; i++) {
+ size_t len;
+
+ len = strlcpy(p, argv[i], buffer + sizeof(buffer) - p);
+ p += len;
+ *(p++) = ' ';
+ *p = '\0';
+ }
+
+ } else {
+ /*
+ * Backwards compatibility. De-escape the string.
+ */
+ char quote;
+ char *q;
+
+ p = argv[0];
+ q = buffer;
+
+ quote = *(p++);
+
+ while (true) {
+ if (!*p) {
+ error = "Unexpected end of string";
+ slen = -strlen(argv[0]);
+ p = argv[0];
+
+ goto parse_error;
+ }
+
+ if (*p == quote) {
+ if (p[1]) {
+ error = "Unexpected text after end of string";
+ slen = -(p - argv[0]);
+ p = argv[0];
+
+ goto parse_error;
+ }
+ *q = '\0';
+ break;
+ }
+
+ if (*p == '\\') {
+ *(q++) = p[1];
+ p += 2;
+ continue;
+ }
+
+ *(q++) = *(p++);
+ }
+ }
+
+ p = buffer;
+
+ slen = fr_condition_tokenize(NULL, NULL, p, &new_condition, &error, FR_COND_ONE_PASS);
+ if (slen <= 0) {
+ char *spaces, *text;
+
+ parse_error:
+ fr_canonicalize_error(NULL, &spaces, &text, slen, p);
+
+ ERROR("Parse error in condition");
+ ERROR("%s", p);
+ ERROR("%s^ %s", spaces, error);
+
+ cprintf_error(listener, "Parse error in condition \"%s\": %s\n", p, error);
+
+ talloc_free(spaces);
+ talloc_free(text);
+ return CMD_FAIL;
+ }
+
+ (void) modcall_pass2_condition(new_condition);
+
+ /*
+ * Delete old condition.
+ *
+ * This is thread-safe because the condition is evaluated
+ * in the main server thread, along with this code.
+ */
+ TALLOC_FREE(debug_condition);
+ debug_condition = new_condition;
+
+ return CMD_OK;
+}
+
+static int command_show_debug_condition(rad_listen_t *listener,
+ UNUSED int argc, UNUSED char *argv[])
+{
+ char buffer[1024];
+
+ if (!debug_condition) {
+ cprintf(listener, "\n");
+ return CMD_OK;
+ }
+
+ fr_cond_sprint(buffer, sizeof(buffer), debug_condition);
+
+ cprintf(listener, "%s\n", buffer);
+ return CMD_OK;
+}
+
+
+static int command_show_debug_file(rad_listen_t *listener,
+ UNUSED int argc, UNUSED char *argv[])
+{
+ if (!default_log.debug_file) return CMD_FAIL;
+
+ cprintf(listener, "%s\n", default_log.debug_file);
+ return CMD_OK;
+}
+
+
+static int command_show_debug_level(rad_listen_t *listener,
+ UNUSED int argc, UNUSED char *argv[])
+{
+ cprintf(listener, "%d\n", rad_debug_lvl);
+ return CMD_OK;
+}
+
+
+static RADCLIENT *get_client(rad_listen_t *listener, int argc, char *argv[])
+{
+ RADCLIENT *client;
+ fr_ipaddr_t ipaddr;
+ int myarg;
+ int proto = IPPROTO_UDP;
+ RADCLIENT_LIST *list = NULL;
+
+ if (argc < 1) {
+ cprintf_error(listener, "Must specify <ipaddr>\n");
+ return NULL;
+ }
+
+ /*
+ * First arg is IP address.
+ */
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return NULL;
+ }
+ myarg = 1;
+
+ while (myarg < argc) {
+ if (strcmp(argv[myarg], "udp") == 0) {
+ proto = IPPROTO_UDP;
+ myarg++;
+ continue;
+ }
+
+#ifdef WITH_TCP
+ if (strcmp(argv[myarg], "tcp") == 0) {
+ proto = IPPROTO_TCP;
+ myarg++;
+ continue;
+ }
+#endif
+
+ if (strcmp(argv[myarg], "listen") == 0) {
+ uint16_t server_port;
+ fr_ipaddr_t server_ipaddr;
+
+ if ((argc - myarg) < 2) {
+ cprintf_error(listener, "Must specify listen <ipaddr> <port>\n");
+ return NULL;
+ }
+
+ if (ip_hton(&server_ipaddr, ipaddr.af, argv[myarg + 1], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return NULL;
+ }
+
+ server_port = atoi(argv[myarg + 2]);
+
+ list = listener_find_client_list(&server_ipaddr, server_port, proto);
+ if (!list) {
+ cprintf_error(listener, "No such listener %s %s\n", argv[myarg + 1], argv[myarg + 2]);
+ return NULL;
+ }
+ myarg += 3;
+ continue;
+ }
+
+ cprintf_error(listener, "Unknown argument %s.\n", argv[myarg]);
+ return NULL;
+ }
+
+ client = client_find(list, &ipaddr, proto);
+ if (!client) {
+ cprintf_error(listener, "No such client\n");
+ return NULL;
+ }
+
+ return client;
+}
+
+#ifdef WITH_PROXY
+static home_server_t *get_home_server(rad_listen_t *listener, int argc,
+ char *argv[], int *last)
+{
+ int myarg = 2;
+ home_server_t *home;
+ uint16_t port;
+ int proto = IPPROTO_UDP;
+ fr_ipaddr_t ipaddr, src_ipaddr;
+
+ if (argc < 2) {
+ cprintf_error(listener, "Must specify <ipaddr> <port> [udp|tcp] OR <name> <type>\n");
+ return NULL;
+ }
+
+ if (isdigit((uint8_t) *argv[1])) {
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return NULL;
+ }
+
+ memset(&src_ipaddr, 0, sizeof(src_ipaddr));
+ src_ipaddr.af = ipaddr.af;
+
+ port = atoi(argv[1]);
+
+ while (myarg < argc) {
+ if (strcmp(argv[myarg], "udp") == 0) {
+ proto = IPPROTO_UDP;
+ myarg++;
+ continue;
+ }
+
+#ifdef WITH_TCP
+ if (strcmp(argv[myarg], "tcp") == 0) {
+ proto = IPPROTO_TCP;
+ myarg++;
+ continue;
+ }
+#endif
+
+ /*
+ * Allow the caller to specify src, too.
+ */
+ if (strcmp(argv[myarg], "src") == 0) {
+ if ((myarg + 2) < argc) {
+ cprintf_error(listener, "You must specify an address after 'src' \n");
+ return NULL;
+ }
+
+ if (ip_hton(&src_ipaddr, ipaddr.af, argv[myarg + 1], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return NULL;
+ }
+
+ myarg += 2;
+ continue;
+ }
+
+ /*
+ * Unknown argument. Leave it for the caller.
+ */
+ break;
+ }
+
+ home = home_server_find_bysrc(&ipaddr, port, proto, &src_ipaddr);
+ } else {
+ int type;
+
+ static const FR_NAME_NUMBER home_server_types[] = {
+ { "auth", HOME_TYPE_AUTH },
+ { "acct", HOME_TYPE_ACCT },
+ { "auth+acct", HOME_TYPE_AUTH_ACCT },
+ { "coa", HOME_TYPE_COA },
+#ifdef WITH_COA_TUNNEL
+ { "auth+coa", HOME_TYPE_AUTH_COA },
+ { "auth+acct+coa", HOME_TYPE_AUTH_ACCT_COA },
+#endif
+ { NULL, 0 }
+ };
+
+ type = fr_str2int(home_server_types, argv[1], HOME_TYPE_INVALID);
+ if (type == HOME_TYPE_INVALID) {
+ cprintf_error(listener, "Invalid home server type '%s'\n", argv[1]);
+ return NULL;
+ }
+
+ home = home_server_byname(argv[0], type);
+ }
+
+ if (!home) {
+ cprintf_error(listener, "No such home server - %s %s\n", argv[0], argv[1]);
+ return NULL;
+ }
+
+ if (last) *last = myarg;
+
+ return home;
+}
+
+static int command_set_home_server_state(rad_listen_t *listener, int argc, char *argv[])
+{
+ int last;
+ home_server_t *home;
+
+ if (argc < 3) {
+ cprintf_error(listener, "Must specify <ipaddr> <port> [udp|tcp] <state>\n");
+ return CMD_FAIL;
+ }
+
+ home = get_home_server(listener, argc, argv, &last);
+ if (!home) {
+ return CMD_FAIL;
+ }
+
+ if (strcmp(argv[last], "alive") == 0) {
+ revive_home_server(home);
+
+ } else if (strcmp(argv[last], "dead") == 0) {
+ struct timeval now;
+
+ gettimeofday(&now, NULL); /* we do this WAY too often */
+ mark_home_server_dead(home, &now, false);
+
+ } else if (strcmp(argv[last], "down") == 0) {
+ struct timeval now;
+
+ gettimeofday(&now, NULL); /* we do this WAY too often */
+ mark_home_server_dead(home, &now, true);
+
+ } else {
+ cprintf_error(listener, "Unknown state \"%s\"\n", argv[last]);
+ return CMD_FAIL;
+ }
+
+ return CMD_OK;
+}
+
+static int command_show_home_server_state(rad_listen_t *listener, int argc, char *argv[])
+{
+ home_server_t *home;
+
+ home = get_home_server(listener, argc, argv, NULL);
+ if (!home) return CMD_FAIL;
+
+ switch (home->state) {
+ case HOME_STATE_ALIVE:
+ cprintf(listener, "alive\n");
+ break;
+
+ case HOME_STATE_IS_DEAD:
+ cprintf(listener, "dead\n");
+ break;
+
+ case HOME_STATE_ZOMBIE:
+ cprintf(listener, "zombie\n");
+ break;
+
+ case HOME_STATE_ADMIN_DOWN:
+ cprintf(listener, "down\n");
+ break;
+
+ case HOME_STATE_UNKNOWN:
+ cprintf(listener, "unknown\n");
+ break;
+
+ default:
+ cprintf(listener, "invalid\n");
+ break;
+ }
+
+ return CMD_OK;
+}
+#endif
+
+/*
+ * For encode/decode stuff
+ */
+static int null_socket_dencode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+static int null_socket_send(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ vp_cursor_t cursor;
+ char *output_file;
+ FILE *fp;
+
+ output_file = request_data_reference(request, (void *)null_socket_send, 0);
+ if (!output_file) {
+ ERROR("No output file for injected packet %d", request->number);
+ return 0;
+ }
+
+ fp = fopen(output_file, "w");
+ if (!fp) {
+ ERROR("Failed to send injected file to %s: %s", output_file, fr_syserror(errno));
+ return 0;
+ }
+
+ if (request->reply->code != 0) {
+ char const *what = "reply";
+ VALUE_PAIR *vp;
+ char buffer[1024];
+
+ if (request->reply->code < FR_MAX_PACKET_CODE) {
+ what = fr_packet_codes[request->reply->code];
+ }
+
+ fprintf(fp, "%s\n", what);
+
+ if (rad_debug_lvl) {
+ RDEBUG("Injected %s packet to host %s port 0 code=%d, id=%d", what,
+ inet_ntop(request->reply->src_ipaddr.af,
+ &request->reply->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->reply->code, request->reply->id);
+ }
+
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &request->reply->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vp_prints(buffer, sizeof(buffer), vp);
+ fprintf(fp, "%s\n", buffer);
+ RDEBUG("%s", buffer);
+ }
+ REXDENT();
+ }
+ fclose(fp);
+
+ return 0;
+}
+
+static rad_listen_t *get_socket(rad_listen_t *listener, int argc,
+ char *argv[], int *last)
+{
+ rad_listen_t *sock;
+ uint16_t port;
+ int proto = IPPROTO_UDP;
+ fr_ipaddr_t ipaddr;
+
+ if (argc < 2) {
+ cprintf_error(listener, "Must specify <ipaddr> <port> [udp|tcp]\n");
+ return NULL;
+ }
+
+ if (ip_hton(&ipaddr, AF_UNSPEC, argv[0], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return NULL;
+ }
+
+ port = atoi(argv[1]);
+
+ if (last) *last = 2;
+ if (argc > 2) {
+ if (strcmp(argv[2], "udp") == 0) {
+ proto = IPPROTO_UDP;
+ if (last) *last = 3;
+ }
+#ifdef WITH_TCP
+ if (strcmp(argv[2], "tcp") == 0) {
+ proto = IPPROTO_TCP;
+ if (last) *last = 3;
+ }
+#endif
+ }
+
+ sock = listener_find_byipaddr(&ipaddr, port, proto);
+ if (!sock) {
+ cprintf_error(listener, "No such listen section\n");
+ return NULL;
+ }
+
+ return sock;
+}
+
+
+static int command_inject_to(rad_listen_t *listener, int argc, char *argv[])
+{
+ fr_command_socket_t *sock;
+ listen_socket_t *data;
+ rad_listen_t *found;
+
+ if (listener->recv == command_tcp_recv) {
+ cprintf_error(listener, "Cannot inject from command socket over TCP");
+ return CMD_FAIL;
+ }
+
+ found = get_socket(listener, argc, argv, NULL);
+ if (!found) {
+ return 0;
+ }
+
+ sock = listener->data;
+ data = found->data;
+ sock->inject_listener = found;
+ sock->dst_ipaddr = data->my_ipaddr;
+ sock->dst_port = data->my_port;
+
+ return CMD_OK;
+}
+
+static int command_inject_from(rad_listen_t *listener, int argc, char *argv[])
+{
+ RADCLIENT *client;
+ fr_command_socket_t *sock;
+
+ if (argc < 1) {
+ cprintf_error(listener, "No <ipaddr> was given\n");
+ return 0;
+ }
+
+ if (listener->recv == command_tcp_recv) {
+ cprintf_error(listener, "Cannot inject from command socket over TCP");
+ return CMD_FAIL;
+ }
+
+ sock = listener->data;
+ if (!sock->inject_listener) {
+ cprintf_error(listener, "You must specify \"inject to\" before using \"inject from\"\n");
+ return 0;
+ }
+
+ sock->src_ipaddr.af = AF_UNSPEC;
+ if (ip_hton(&sock->src_ipaddr, AF_UNSPEC, argv[0], false) < 0) {
+ cprintf_error(listener, "Failed parsing IP address; %s\n",
+ fr_strerror());
+ return 0;
+ }
+
+ client = client_listener_find(sock->inject_listener, &sock->src_ipaddr,
+ 0);
+ if (!client) {
+ cprintf_error(listener, "No such client %s\n", argv[0]);
+ return 0;
+ }
+ sock->inject_client = client;
+
+ return CMD_OK;
+}
+
+static int command_inject_file(rad_listen_t *listener, int argc, char *argv[])
+{
+ static int inject_id = 0;
+ int ret;
+ bool filedone;
+ fr_command_socket_t *sock;
+ rad_listen_t *fake;
+ RADIUS_PACKET *packet;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ FILE *fp;
+ RAD_REQUEST_FUNP fun = NULL;
+ char buffer[2048];
+
+ if (argc < 2) {
+ cprintf_error(listener, "You must specify <input-file> <output-file>\n");
+ return 0;
+ }
+
+ if (listener->recv == command_tcp_recv) {
+ cprintf_error(listener, "Cannot inject from command socket over TCP");
+ return CMD_FAIL;
+ }
+
+ sock = listener->data;
+ if (!sock->inject_listener) {
+ cprintf_error(listener, "You must specify \"inject to\" before using \"inject file\"\n");
+ return 0;
+ }
+
+ if (!sock->inject_client) {
+ cprintf_error(listener, "You must specify \"inject from\" before using \"inject file\"\n");
+ return 0;
+ }
+
+ /*
+ * Output files always go to the logging directory.
+ */
+ snprintf(buffer, sizeof(buffer), "%s/%s", radlog_dir, argv[1]);
+
+ fp = fopen(argv[0], "r");
+ if (!fp ) {
+ cprintf_error(listener, "Failed opening %s: %s\n",
+ argv[0], fr_syserror(errno));
+ return 0;
+ }
+
+ ret = fr_pair_list_afrom_file(NULL, &vp, fp, &filedone);
+ fclose(fp);
+ if (ret < 0) {
+ cprintf_error(listener, "Failed reading attributes from %s: %s\n",
+ argv[0], fr_strerror());
+ return 0;
+ }
+
+ fake = talloc(NULL, rad_listen_t);
+ memcpy(fake, sock->inject_listener, sizeof(*fake));
+
+ /*
+ * Re-write the IO for the listener.
+ */
+ fake->encode = null_socket_dencode;
+ fake->decode = null_socket_dencode;
+ fake->send = null_socket_send;
+
+ packet = rad_alloc(NULL, false);
+ packet->src_ipaddr = sock->src_ipaddr;
+ packet->src_port = 0;
+
+ packet->dst_ipaddr = sock->dst_ipaddr;
+ packet->dst_port = sock->dst_port;
+ packet->vps = vp;
+ packet->id = inject_id++;
+
+ if (fake->type == RAD_LISTEN_AUTH) {
+ packet->code = PW_CODE_ACCESS_REQUEST;
+ fun = rad_authenticate;
+
+ } else {
+#ifdef WITH_ACCOUNTING
+ packet->code = PW_CODE_ACCOUNTING_REQUEST;
+ fun = rad_accounting;
+#else
+ cprintf_error(listener, "This server was built without accounting support.\n");
+ rad_free(&packet);
+ free(fake);
+ return 0;
+#endif
+ }
+
+ if (rad_debug_lvl) {
+ DEBUG("Injecting %s packet from host %s port 0 code=%d, id=%d",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->code, packet->id);
+
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vp_prints(buffer, sizeof(buffer), vp);
+ DEBUG("\t%s", buffer);
+ }
+
+ WARN("INJECTION IS LEAKING MEMORY!");
+ }
+
+ if (!request_receive(NULL, fake, packet, sock->inject_client, fun)) {
+ cprintf_error(listener, "Failed to inject request. See log file for details\n");
+ rad_free(&packet);
+ free(fake);
+ return 0;
+ }
+
+#if 0
+ /*
+ * Remember what the output file is, and remember to
+ * delete the fake listener when done.
+ */
+ request_data_add(request, null_socket_send, 0, talloc_typed_strdup(NULL, buffer), true);
+ request_data_add(request, null_socket_send, 1, fake, true);
+
+#endif
+
+ return CMD_OK;
+}
+
+
+static fr_command_table_t command_table_inject[] = {
+ { "to", FR_WRITE,
+ "inject to <ipaddr> <port> - Inject packets to the destination IP and port.",
+ command_inject_to, NULL },
+
+ { "from", FR_WRITE,
+ "inject from <ipaddr> - Inject packets as if they came from <ipaddr>",
+ command_inject_from, NULL },
+
+ { "file", FR_WRITE,
+ "inject file <input-file> <output-file> - Inject packet from <input-file>, with results sent to <output-file>",
+ command_inject_file, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_debug[] = {
+ { "condition", FR_WRITE,
+ "debug condition [condition] - Enable debugging for requests matching [condition]",
+ command_debug_condition, NULL },
+
+ { "level", FR_WRITE,
+ "debug level <number> - Set debug level to <number>. Higher is more debugging.",
+ command_debug_level, NULL },
+
+ { "file", FR_WRITE,
+ "debug file [filename] - Send all debugging output to [filename]",
+ command_debug_file, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_show_debug[] = {
+ { "condition", FR_READ,
+ "show debug condition - Shows current debugging condition.",
+ command_show_debug_condition, NULL },
+
+ { "level", FR_READ,
+ "show debug level - Shows current debugging level.",
+ command_show_debug_level, NULL },
+
+ { "file", FR_READ,
+ "show debug file - Shows current debugging file.",
+ command_show_debug_file, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_show_module[] = {
+ { "config", FR_READ,
+ "show module config <module> - show configuration for given module",
+ command_show_module_config, NULL },
+ { "flags", FR_READ,
+ "show module flags <module> - show other module properties",
+ command_show_module_flags, NULL },
+ { "list", FR_READ,
+ "show module list - shows list of loaded modules",
+ command_show_modules, NULL },
+ { "methods", FR_READ,
+ "show module methods <module> - show sections where <module> may be used",
+ command_show_module_methods, NULL },
+ { "status", FR_READ,
+ "show module status <module> - show the module status",
+ command_show_module_status, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_show_client[] = {
+ { "config", FR_READ,
+ "show client config <ipaddr> "
+#ifdef WITH_TCP
+ "[udp|tcp] "
+#endif
+ "- show configuration for given client",
+ command_show_client_config, NULL },
+ { "list", FR_READ,
+ "show client list [verbose] - shows list of global clients",
+ command_show_clients, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+#ifdef WITH_PROXY
+static fr_command_table_t command_table_show_home[] = {
+ { "list", FR_READ,
+ "show home_server list [all] - shows list of home servers",
+ command_show_home_servers, NULL },
+ { "state", FR_READ,
+ "show home_server state <ipaddr> <port> [udp|tcp] [src <ipaddr>] - shows state of given home server",
+ command_show_home_server_state, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+#endif
+
+
+static fr_command_table_t command_table_show[] = {
+ { "client", FR_READ,
+ "show client <command> - do sub-command of client",
+ NULL, command_table_show_client },
+ { "config", FR_READ,
+ "show config <path> - shows the value of configuration option <path>",
+ command_show_config, NULL },
+ { "debug", FR_READ,
+ "show debug <command> - show debug properties",
+ NULL, command_table_show_debug },
+#ifdef WITH_PROXY
+ { "home_server", FR_READ,
+ "show home_server <command> - do sub-command of home_server",
+ NULL, command_table_show_home },
+#endif
+ { "module", FR_READ,
+ "show module <command> - do sub-command of module",
+ NULL, command_table_show_module },
+ { "uptime", FR_READ,
+ "show uptime - shows time at which server started",
+ command_uptime, NULL },
+ { "version", FR_READ,
+ "show version - Prints version of the running server",
+ command_show_version, NULL },
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
+static int command_set_module_config(rad_listen_t *listener, int argc, char *argv[])
+{
+ int i, rcode;
+ CONF_PAIR *cp;
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+ CONF_PARSER const *variables;
+ void *data;
+
+ if (argc < 3) {
+ cprintf_error(listener, "No module name or variable was given\n");
+ return 0;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return 0;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return 0;
+ }
+
+ if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) {
+ cprintf_error(listener, "Cannot change configuration of module as it is cannot be HUP'd.\n");
+ return 0;
+ }
+
+ variables = cf_section_parse_table(mi->cs);
+ if (!variables) {
+ cprintf_error(listener, "Cannot find configuration for module\n");
+ return 0;
+ }
+
+ rcode = -1;
+ for (i = 0; variables[i].name != NULL; i++) {
+ /*
+ * FIXME: Recurse into sub-types somehow...
+ */
+ if (variables[i].type == PW_TYPE_SUBSECTION) continue;
+
+ if (strcmp(variables[i].name, argv[1]) == 0) {
+ rcode = i;
+ break;
+ }
+ }
+
+ if (rcode < 0) {
+ cprintf_error(listener, "No such variable \"%s\"\n", argv[1]);
+ return 0;
+ }
+
+ i = rcode; /* just to be safe */
+
+ /*
+ * It's not part of the dynamic configuration. The module
+ * needs to re-parse && validate things.
+ */
+ if (variables[i].data) {
+ cprintf_error(listener, "Variable cannot be dynamically updated\n");
+ return 0;
+ }
+
+ data = ((char *) mi->insthandle) + variables[i].offset;
+
+ cp = cf_pair_find(mi->cs, argv[1]);
+ if (!cp) return 0;
+
+ /*
+ * Replace the OLD value in the configuration file with
+ * the NEW value.
+ *
+ * FIXME: Parse argv[2] depending on it's data type!
+ * If it's a string, look for leading single/double quotes,
+ * end then call tokenize functions???
+ */
+ cf_pair_replace(mi->cs, cp, argv[2]);
+
+ rcode = cf_item_parse(mi->cs, argv[1], variables[i].type, data, argv[2]);
+ if (rcode < 0) {
+ cprintf_error(listener, "Failed to parse value\n");
+ return 0;
+ }
+
+ return CMD_OK;
+}
+
+static int command_set_module_status(rad_listen_t *listener, int argc, char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+
+ if (argc < 2) {
+ cprintf_error(listener, "No module name or status was given\n");
+ return 0;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return 0;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return 0;
+ }
+
+
+ if (strcmp(argv[1], "alive") == 0) {
+ mi->force = false;
+
+ } else if (strcmp(argv[1], "dead") == 0) {
+ mi->code = RLM_MODULE_FAIL;
+ mi->force = true;
+
+ } else {
+ int rcode;
+
+ rcode = fr_str2int(mod_rcode_table, argv[1], -1);
+ if (rcode < 0) {
+ cprintf_error(listener, "Unknown status \"%s\"\n", argv[1]);
+ return 0;
+ }
+
+ mi->code = rcode;
+ mi->force = true;
+ }
+
+ return CMD_OK;
+}
+
+#ifdef WITH_STATS
+static char const *elapsed_names[8] = {
+ "1us", "10us", "100us", "1ms", "10ms", "100ms", "1s", "10s"
+};
+
+static int command_print_stats(rad_listen_t *listener, fr_stats_t *stats,
+ int auth, int server)
+{
+ int i;
+
+ cprintf(listener, "requests\t%" PRIu64 "\n", stats->total_requests);
+ cprintf(listener, "responses\t%" PRIu64 "\n", stats->total_responses);
+
+ if (auth) {
+ cprintf(listener, "accepts\t\t%" PRIu64 "\n",
+ stats->total_access_accepts);
+ cprintf(listener, "rejects\t\t%" PRIu64 "\n",
+ stats->total_access_rejects);
+ cprintf(listener, "challenges\t%" PRIu64 "\n",
+ stats->total_access_challenges);
+ }
+
+ cprintf(listener, "dup\t\t%" PRIu64 "\n", stats->total_dup_requests);
+ cprintf(listener, "invalid\t\t%" PRIu64 "\n", stats->total_invalid_requests);
+ cprintf(listener, "malformed\t%" PRIu64 "\n", stats->total_malformed_requests);
+ cprintf(listener, "bad_authenticator\t%" PRIu64 "\n", stats->total_bad_authenticators);
+ cprintf(listener, "dropped\t\t%" PRIu64 "\n", stats->total_packets_dropped);
+ cprintf(listener, "unknown_types\t%" PRIu64 "\n", stats->total_unknown_types);
+
+ if (server) {
+ cprintf(listener, "timeouts\t%" PRIu64 "\n", stats->total_timeouts);
+ } else {
+ cprintf(listener, "conflicts\t%" PRIu64 "\n", stats->total_conflicts);
+ cprintf(listener, "unresponsive_child\t%" PRIu64 "\n", stats->unresponsive_child);
+ }
+
+ cprintf(listener, "last_packet\t%" PRId64 "\n", (int64_t) stats->last_packet);
+ for (i = 0; i < 8; i++) {
+ cprintf(listener, "elapsed.%s\t%" PRIu64 "\n",
+ elapsed_names[i], stats->elapsed[i]);
+ }
+
+ return CMD_OK;
+}
+
+
+#ifdef HAVE_PTHREAD_H
+static int command_stats_queue(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
+{
+ int array[RAD_LISTEN_MAX], pps[2];
+
+ thread_pool_queue_stats(array, pps);
+
+ cprintf(listener, "queue_len_internal\t%d\n", array[0]);
+ cprintf(listener, "queue_len_proxy\t\t%d\n", array[1]);
+ cprintf(listener, "queue_len_auth\t\t%d\n", array[2]);
+ cprintf(listener, "queue_len_acct\t\t%d\n", array[3]);
+ cprintf(listener, "queue_len_detail\t%d\n", array[4]);
+
+ cprintf(listener, "queue_pps_in\t\t%d\n", pps[0]);
+ cprintf(listener, "queue_pps_out\t\t%d\n", pps[1]);
+
+ return CMD_OK;
+}
+
+static int command_stats_threads(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
+{
+ int stats[3];
+
+ thread_pool_thread_stats(stats);
+
+ cprintf(listener, "threads_active\t%d\n", stats[0]);
+ cprintf(listener, "threads_total\t\t%d\n", stats[1]);
+ cprintf(listener, "threads_max\t\t%d\n", stats[2]);
+
+ return CMD_OK;
+}
+#endif
+
+#ifndef NDEBUG
+static int command_stats_memory(rad_listen_t *listener, int argc, char *argv[])
+{
+
+ if (!main_config.debug_memory || !main_config.memory_report) {
+ cprintf(listener, "No memory debugging was enabled.\n");
+ return CMD_OK;
+ }
+
+ if (argc == 0) goto fail;
+
+ if (strcmp(argv[0], "total") == 0) {
+ cprintf(listener, "%zd\n", talloc_total_size(NULL));
+ return CMD_OK;
+ }
+
+ if (strcmp(argv[0], "blocks") == 0) {
+ cprintf(listener, "%zd\n", talloc_total_blocks(NULL));
+ return CMD_OK;
+ }
+
+ if (strcmp(argv[0], "full") == 0) {
+ cprintf(listener, "see stdout of the server for the full report.\n");
+ fr_log_talloc_report(NULL);
+ return CMD_OK;
+ }
+
+fail:
+ cprintf_error(listener, "Must use 'stats memory [blocks|full|total]'\n");
+ return CMD_FAIL;
+}
+#endif
+
+#ifdef WITH_DETAIL
+static FR_NAME_NUMBER state_names[] = {
+ { "unopened", STATE_UNOPENED },
+ { "unlocked", STATE_UNLOCKED },
+ { "header", STATE_HEADER },
+ { "reading", STATE_READING },
+ { "queued", STATE_QUEUED },
+ { "running", STATE_RUNNING },
+ { "no-reply", STATE_NO_REPLY },
+ { "replied", STATE_REPLIED },
+
+ { NULL, 0 }
+};
+
+static int command_stats_detail(rad_listen_t *listener, int argc, char *argv[])
+{
+ rad_listen_t *this;
+ listen_detail_t *data, *needle;
+ struct stat buf;
+
+ if (argc == 0) {
+ cprintf_error(listener, "Must specify <filename>\n");
+ return 0;
+ }
+
+ data = NULL;
+ for (this = main_config.listen; this != NULL; this = this->next) {
+ if (this->type != RAD_LISTEN_DETAIL) continue;
+
+ needle = this->data;
+ if (!strcmp(argv[0], needle->filename)) {
+ data = needle;
+ break;
+ }
+ }
+
+ if (!data) {
+ cprintf_error(listener, "No detail file listener\n");
+ return 0;
+ }
+
+ cprintf(listener, "state\t%s\n",
+ fr_int2str(state_names, data->state, "?"));
+
+ if ((data->state == STATE_UNOPENED) ||
+ (data->state == STATE_UNLOCKED)) {
+ return CMD_OK;
+ }
+
+ /*
+ * Race conditions: file might not exist.
+ */
+ if (stat(data->filename_work, &buf) < 0) {
+ cprintf(listener, "packets\t0\n");
+ cprintf(listener, "tries\t0\n");
+ cprintf(listener, "offset\t0\n");
+ cprintf(listener, "size\t0\n");
+ return CMD_OK;
+ }
+
+ cprintf(listener, "packets\t%d\n", data->packets);
+ cprintf(listener, "tries\t%d\n", data->tries);
+ cprintf(listener, "offset\t%u\n", (unsigned int) data->offset);
+ cprintf(listener, "size\t%u\n", (unsigned int) buf.st_size);
+
+ return CMD_OK;
+}
+#endif
+
+#ifdef WITH_PROXY
+static int command_stats_home_server(rad_listen_t *listener, int argc, char *argv[])
+{
+ home_server_t *home;
+
+ if (argc == 0) {
+ cprintf_error(listener, "Must specify [auth|acct|coa|disconnect] OR <ipaddr> <port>\n");
+ return 0;
+ }
+
+ if (argc == 1) {
+ if (strcmp(argv[0], "auth") == 0) {
+ return command_print_stats(listener,
+ &proxy_auth_stats, 1, 1);
+ }
+
+#ifdef WITH_ACCOUNTING
+ if (strcmp(argv[0], "acct") == 0) {
+ return command_print_stats(listener,
+ &proxy_acct_stats, 0, 1);
+ }
+#endif
+
+#ifdef WITH_ACCOUNTING
+ if (strcmp(argv[0], "coa") == 0) {
+ return command_print_stats(listener,
+ &proxy_coa_stats, 0, 1);
+ }
+#endif
+
+#ifdef WITH_ACCOUNTING
+ if (strcmp(argv[0], "disconnect") == 0) {
+ return command_print_stats(listener,
+ &proxy_dsc_stats, 0, 1);
+ }
+#endif
+
+ cprintf_error(listener, "Should specify [auth|acct|coa|disconnect]\n");
+ return 0;
+ }
+
+ home = get_home_server(listener, argc, argv, NULL);
+ if (!home) return 0;
+
+ command_print_stats(listener, &home->stats,
+ (home->type == HOME_TYPE_AUTH), 1);
+ cprintf(listener, "outstanding\t%d\n", home->currently_outstanding);
+ return CMD_OK;
+}
+#endif
+
+static int command_stats_client(rad_listen_t *listener, int argc, char *argv[])
+{
+ bool auth = true;
+ fr_stats_t *stats;
+ RADCLIENT *client, fake;
+
+ if (argc < 1) {
+ cprintf_error(listener, "Must specify [auth/acct]\n");
+ return 0;
+ }
+
+ if (argc == 1) {
+ /*
+ * Global statistics.
+ */
+ fake.auth = radius_auth_stats;
+#ifdef WITH_ACCOUNTING
+ fake.acct = radius_acct_stats;
+#endif
+#ifdef WITH_COA
+ fake.coa = radius_coa_stats;
+ fake.dsc = radius_dsc_stats;
+#endif
+ client = &fake;
+
+ } else {
+ /*
+ * Per-client statistics.
+ */
+ client = get_client(listener, argc - 1, argv + 1);
+ if (!client) return 0;
+ }
+
+ if (strcmp(argv[0], "auth") == 0) {
+ auth = true;
+ stats = &client->auth;
+
+ } else if (strcmp(argv[0], "acct") == 0) {
+#ifdef WITH_ACCOUNTING
+ auth = false;
+ stats = &client->acct;
+#else
+ cprintf_error(listener, "This server was built without accounting support.\n");
+ return 0;
+#endif
+
+ } else if (strcmp(argv[0], "coa") == 0) {
+#ifdef WITH_COA
+ auth = false;
+ stats = &client->coa;
+#else
+ cprintf_error(listener, "This server was built without CoA support.\n");
+ return 0;
+#endif
+
+ } else if (strcmp(argv[0], "disconnect") == 0) {
+#ifdef WITH_COA
+ auth = false;
+ stats = &client->dsc;
+#else
+ cprintf_error(listener, "This server was built without CoA support.\n");
+ return 0;
+#endif
+
+ } else {
+ cprintf_error(listener, "Unknown statistics type\n");
+ return 0;
+ }
+
+ /*
+ * Global results for all client.
+ */
+ if (argc == 1) {
+#ifdef WITH_ACCOUNTING
+ if (!auth) {
+ return command_print_stats(listener,
+ &radius_acct_stats, auth, 0);
+ }
+#endif
+ return command_print_stats(listener, &radius_auth_stats, auth, 0);
+ }
+
+ return command_print_stats(listener, stats, auth, 0);
+}
+
+
+static int command_stats_socket(rad_listen_t *listener, int argc, char *argv[])
+{
+ bool auth = true;
+ rad_listen_t *sock;
+
+ sock = get_socket(listener, argc, argv, NULL);
+ if (!sock) return 0;
+
+ if (sock->type != RAD_LISTEN_AUTH) auth = false;
+
+ return command_print_stats(listener, &sock->stats, auth, 0);
+}
+
+static int command_stats_pool(rad_listen_t *listener, UNUSED int argc, UNUSED char *argv[])
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+ fr_connection_pool_stats_t const *stats;
+
+ if (argc < 1) {
+ cprintf_error(listener, "Must specify <name>\n");
+ return CMD_FAIL;
+ }
+
+ cs = cf_section_find("modules");
+ if (!cs) return CMD_FAIL;
+
+ mi = module_find(cs, argv[0]);
+ if (!mi) {
+ cprintf_error(listener, "No such module \"%s\"\n", argv[0]);
+ return CMD_FAIL;
+ }
+
+ stats = fr_connection_pool_stats(mi->cs);
+ if (!stats) {
+ cprintf_error(listener, "Module %s has no pool statistics", argv[0]);
+ return CMD_FAIL;
+ }
+
+ cprintf(listener, "last_checked\t\t%zu\n", stats->last_checked);
+ cprintf(listener, "last_opened\t\t%zu\n", stats->last_opened);
+ cprintf(listener, "last_closed\t\t%zu\n", stats->last_closed);
+ cprintf(listener, "last_failed\t\t%zu\n", stats->last_failed);
+ cprintf(listener, "last_throttled\t\t%zu\n", stats->last_throttled);
+ cprintf(listener, "total_opened\t\t%" PRIu64 "\n", stats->opened);
+ cprintf(listener, "total_closed\t\t%" PRIu64 "\n", stats->closed);
+ cprintf(listener, "total_failed\t\t%" PRIu64 "\n", stats->failed);
+ cprintf(listener, "num_open\t\t%u\n", stats->num);
+ cprintf(listener, "num_in_use\t\t%u\n", stats->active);
+
+ return CMD_OK;
+}
+#endif /* WITH_STATS */
+
+
+#ifdef WITH_DYNAMIC_CLIENTS
+static int command_add_client_file(rad_listen_t *listener, int argc, char *argv[])
+{
+ RADCLIENT *c;
+
+ if (argc < 1) {
+ cprintf_error(listener, "<file> is required\n");
+ return 0;
+ }
+
+ /*
+ * Read the file and generate the client.
+ */
+ c = client_read(argv[0], false, false);
+ if (!c) {
+ cprintf_error(listener, "Unknown error reading client file.\n");
+ return 0;
+ }
+
+ if (!client_add(NULL, c)) {
+ cprintf_error(listener, "Unknown error inserting new client.\n");
+ client_free(c);
+ return 0;
+ }
+
+ return CMD_OK;
+}
+
+
+static int command_del_client(rad_listen_t *listener, int argc, char *argv[])
+{
+ RADCLIENT *client;
+
+ client = get_client(listener, argc, argv);
+ if (!client) return 0;
+
+ if (!client->dynamic) {
+ cprintf_error(listener, "Client %s was not dynamically defined.\n", argv[0]);
+ return 0;
+ }
+
+ /*
+ * DON'T delete it. Instead, mark it as "dead now". The
+ * next time we receive a packet for the client, it will
+ * be deleted.
+ *
+ * If we don't receive a packet from it, the client
+ * structure will stick around for a while. Oh well...
+ */
+ client->lifetime = 1;
+
+ return CMD_OK;
+}
+
+
+static int command_del_home_server(rad_listen_t *listener, int argc, char *argv[])
+{
+ if (argc < 2) {
+ cprintf_error(listener, "<name> and <type> are required\n");
+ return 0;
+ }
+
+ if (home_server_delete(argv[0], argv[1]) < 0) {
+ cprintf_error(listener, "Failed deleted home_server %s - %s\n", argv[1], fr_strerror());
+ return 0;
+ }
+
+ return CMD_OK;
+}
+
+static int command_add_home_server_file(rad_listen_t *listener, int argc, char *argv[])
+{
+ if (argc < 1) {
+ cprintf_error(listener, "<file> is required\n");
+ return 0;
+ }
+
+ if (home_server_afrom_file(argv[0]) < 0) {
+ cprintf_error(listener, "Unable to add home server - %s\n", fr_strerror());
+ return 0;
+ }
+
+ return CMD_OK;
+}
+
+static fr_command_table_t command_table_del_client[] = {
+ { "ipaddr", FR_WRITE,
+ "del client ipaddr <ipaddr> [udp|tcp] [listen <ipaddr> <port>] - Delete a dynamically created client",
+ command_del_client, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_del_home_server[] = {
+ { "file", FR_WRITE,
+ "del home_server file <name> [auth|acct|coa] - Delete a dynamically created home_server",
+ command_del_home_server, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_del[] = {
+ { "client", FR_WRITE,
+ "del client <command> - Delete client configuration commands",
+ NULL, command_table_del_client },
+
+ { "home_server", FR_WRITE,
+ "del home_server <command> - Delete home_server configuration commands",
+ NULL, command_table_del_home_server },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_add_client[] = {
+ { "file", FR_WRITE,
+ "add client file <filename> - Add new client definition from <filename>",
+ command_add_client_file, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_add_home_server[] = {
+ { "file", FR_WRITE,
+ "add home_server file <filename> - Add new home serverdefinition from <filename>",
+ command_add_home_server_file, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+static fr_command_table_t command_table_add[] = {
+ { "client", FR_WRITE,
+ "add client <command> - Add client configuration commands",
+ NULL, command_table_add_client },
+
+ { "home_server", FR_WRITE,
+ "add home_server <command> - Add home server configuration commands",
+ NULL, command_table_add_home_server },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+#endif
+
+#ifdef WITH_PROXY
+static fr_command_table_t command_table_set_home[] = {
+ { "state", FR_WRITE,
+ "set home_server state <ipaddr> <port> [udp|tcp] [src <ipaddr>] [alive|dead|down] - set state for given home server",
+ command_set_home_server_state, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+#endif
+
+static fr_command_table_t command_table_set_module[] = {
+ { "config", FR_WRITE,
+ "set module config <module> variable value - set configuration for <module>",
+ command_set_module_config, NULL },
+
+ { "status", FR_WRITE,
+ "set module status <module> [alive|...] - set the module status to be alive (operating normally), or force a particular code (ok,fail, etc.)",
+ command_set_module_status, NULL },
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
+static fr_command_table_t command_table_set[] = {
+ { "module", FR_WRITE,
+ "set module <command> - set module commands",
+ NULL, command_table_set_module },
+#ifdef WITH_PROXY
+ { "home_server", FR_WRITE,
+ "set home_server <command> - set home server commands",
+ NULL, command_table_set_home },
+#endif
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
+#ifdef WITH_STATS
+static fr_command_table_t command_table_stats[] = {
+ { "client", FR_READ,
+ "stats client [auth/acct/coa] <ipaddr> [udp|tcp] [listen <ipaddr> <port>] "
+ "- show statistics for given client, or for all clients (auth or acct)",
+ command_stats_client, NULL },
+
+#ifdef WITH_DETAIL
+ { "detail", FR_READ,
+ "stats detail <filename> - show statistics for the given detail file",
+ command_stats_detail, NULL },
+#endif
+
+#ifdef WITH_PROXY
+ { "home_server", FR_READ,
+ "stats home_server [<ipaddr>|auth|acct|coa|disconnect] <port> [udp|tcp] [src <ipaddr>] - show statistics for given home server (ipaddr and port), or for all home servers (auth or acct)",
+ command_stats_home_server, NULL },
+#endif
+
+ { "pool", FR_READ,
+ "stats pool <name> "
+ "- show pool statistics for given module",
+ command_stats_pool, NULL },
+
+#ifdef HAVE_PTHREAD_H
+ { "queue", FR_READ,
+ "stats queue - show statistics for packet queues",
+ command_stats_queue, NULL },
+ { "threads", FR_READ,
+ "stats threads - show statistics for the worker threads",
+ command_stats_threads, NULL },
+#endif
+
+ { "socket", FR_READ,
+ "stats socket <ipaddr> <port> [udp|tcp] "
+ "- show statistics for given socket",
+ command_stats_socket, NULL },
+
+#ifndef NDEBUG
+ { "memory", FR_READ,
+ "stats memory [blocks|full|total] - show statistics on used memory",
+ command_stats_memory, NULL },
+#endif
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+#endif
+
+static fr_command_table_t command_table[] = {
+#ifdef WITH_DYNAMIC_CLIENTS
+ { "add", FR_WRITE, NULL, NULL, command_table_add },
+#endif
+ { "debug", FR_WRITE,
+ "debug <command> - debugging commands",
+ NULL, command_table_debug },
+#ifdef WITH_DYNAMIC_CLIENTS
+ { "del", FR_WRITE, NULL, NULL, command_table_del },
+#endif
+ { "hup", FR_WRITE,
+ "hup [module] - sends a HUP signal to the server, or optionally to one module",
+ command_hup, NULL },
+ { "inject", FR_WRITE,
+ "inject <command> - commands to inject packets into a running server",
+ NULL, command_table_inject },
+ { "reconnect", FR_READ,
+ "reconnect - reconnect to a running server",
+ NULL, NULL }, /* just here for "help" */
+ { "terminate", FR_WRITE,
+ "terminate - terminates the server, and cause it to exit",
+ command_terminate, NULL },
+ { "set", FR_WRITE, NULL, NULL, command_table_set },
+ { "show", FR_READ, NULL, NULL, command_table_show },
+#ifdef WITH_STATS
+ { "stats", FR_READ, NULL, NULL, command_table_stats },
+#endif
+
+ { NULL, 0, NULL, NULL, NULL }
+};
+
+
+static void command_socket_free(rad_listen_t *this)
+{
+ fr_command_socket_t *cmd = this->data;
+
+ /*
+ * If it's a TCP socket, don't do anything.
+ */
+ if (cmd->magic != COMMAND_SOCKET_MAGIC) {
+ return;
+ }
+
+ if (!cmd->copy) return;
+ unlink(cmd->copy);
+}
+
+
+/*
+ * Parse the unix domain sockets.
+ *
+ * FIXME: TCP + SSL, after RadSec is in.
+ */
+static int command_socket_parse_unix(CONF_SECTION *cs, rad_listen_t *this)
+{
+ fr_command_socket_t *sock;
+
+ if (check_config) return 0;
+
+ sock = this->data;
+
+ if (cf_section_parse(cs, sock, command_config) < 0) return -1;
+
+ /*
+ * Can't get uid or gid of connecting user, so can't do
+ * peercred authentication.
+ */
+#ifndef HAVE_GETPEEREID
+ if (sock->peercred && (sock->uid_name || sock->gid_name)) {
+ ERROR("System does not support uid or gid authentication for sockets");
+ return -1;
+ }
+#endif
+
+ sock->magic = COMMAND_SOCKET_MAGIC;
+ sock->copy = NULL;
+ if (sock->path) sock->copy = talloc_typed_strdup(sock, sock->path);
+
+ if (sock->uid_name) {
+ struct passwd *pwd;
+
+ if (rad_getpwnam(cs, &pwd, sock->uid_name) < 0) {
+ ERROR("Failed getting uid for %s: %s", sock->uid_name, fr_strerror());
+ return -1;
+ }
+ sock->uid = pwd->pw_uid;
+ talloc_free(pwd);
+ } else {
+ sock->uid = -1;
+ }
+
+ if (sock->gid_name) {
+ if (rad_getgid(cs, &sock->gid, sock->gid_name) < 0) {
+ ERROR("Failed getting gid for %s: %s", sock->gid_name, fr_strerror());
+ return -1;
+ }
+ } else {
+ sock->gid = -1;
+ }
+
+ if (!sock->mode_name) {
+ sock->co.mode = FR_READ;
+ } else {
+ sock->co.mode = fr_str2int(mode_names, sock->mode_name, 0);
+ if (!sock->co.mode) {
+ ERROR("Invalid mode name \"%s\"",
+ sock->mode_name);
+ return -1;
+ }
+ }
+
+ if (sock->peercred) {
+ this->fd = fr_server_domain_socket_peercred(sock->path, sock->uid, sock->gid);
+ } else {
+ uid_t uid = sock->uid;
+ gid_t gid = sock->gid;
+
+ if (uid == ((uid_t)-1)) uid = 0;
+ if (gid == ((gid_t)-1)) gid = 0;
+
+ this->fd = fr_server_domain_socket_perm(sock->path, uid, gid);
+ }
+
+ if (this->fd < 0) {
+ ERROR("Failed creating control socket \"%s\": %s", sock->path, fr_strerror());
+ if (sock->copy) talloc_free(sock->copy);
+ sock->copy = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+{
+ int rcode;
+ CONF_PAIR const *cp;
+ listen_socket_t *sock;
+
+ cp = cf_pair_find(cs, "socket");
+ if (cp) return command_socket_parse_unix(cs, this);
+
+ rcode = common_socket_parse(cs, this);
+ if (rcode < 0) return -1;
+
+#ifdef WITH_TLS
+ if (this->tls) {
+ cf_log_err_cs(cs,
+ "TLS is not supported for control sockets");
+ return -1;
+ }
+#endif
+
+ sock = this->data;
+ if (sock->proto != IPPROTO_TCP) {
+ cf_log_err_cs(cs,
+ "UDP is not supported for control sockets");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int command_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
+{
+ fr_command_socket_t *sock = this->data;
+
+ if (sock->magic != COMMAND_SOCKET_MAGIC) {
+ return common_socket_print(this, buffer, bufsize);
+ }
+
+ snprintf(buffer, bufsize, "command file %s", sock->path);
+ return 1;
+}
+
+
+/*
+ * String split routine. Splits an input string IN PLACE
+ * into pieces, based on spaces.
+ */
+static int str2argvX(char *str, char **argv, int max_argc)
+{
+ int argc = 0;
+
+ while (*str) {
+ if (argc >= max_argc) return argc;
+
+ /*
+ * Chop out comments early.
+ */
+ if (*str == '#') {
+ *str = '\0';
+ break;
+ }
+
+ while ((*str == ' ') ||
+ (*str == '\t') ||
+ (*str == '\r') ||
+ (*str == '\n')) *(str++) = '\0';
+
+ if (!*str) return argc;
+
+ argv[argc++] = str;
+
+ if ((*str == '\'') || (*str == '"')) {
+ char quote = *str;
+ char *p = str + 1;
+
+ while (true) {
+ if (!*p) return -1;
+
+ if (*p == quote) {
+ str = p + 1;
+ break;
+ }
+
+ /*
+ * Handle \" and nothing else.
+ */
+ if (*p == '\\') {
+ p += 2;
+ continue;
+ }
+
+ p++;
+ }
+ }
+
+ while (*str &&
+ (*str != ' ') &&
+ (*str != '\t') &&
+ (*str != '\r') &&
+ (*str != '\n')) str++;
+ }
+
+ return argc;
+}
+
+static void print_help(rad_listen_t *listener, int argc, char *argv[],
+ fr_command_table_t *table, int recursive)
+{
+ int i;
+
+ /* this should never happen, but if it does then just return gracefully */
+ if (!table) return;
+
+ for (i = 0; table[i].command != NULL; i++) {
+ if (argc > 0) {
+ if (strcmp(table[i].command, argv[0]) == 0) {
+ if (table[i].table) {
+ print_help(listener, argc - 1, argv + 1, table[i].table, recursive);
+ } else {
+ if (table[i].help) {
+ cprintf(listener, "%s\n", table[i].help);
+ }
+ }
+ return;
+ }
+
+ continue;
+ }
+
+ if (table[i].help) {
+ cprintf(listener, "%s\n",
+ table[i].help);
+ } else {
+ cprintf(listener, "%s <command> - do sub-command of %s\n",
+ table[i].command, table[i].command);
+ }
+
+ if (recursive && table[i].table) {
+ print_help(listener, 0, NULL, table[i].table, recursive);
+ }
+ }
+}
+
+#define MAX_ARGV (16)
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int command_domain_recv_co(rad_listen_t *listener, fr_cs_buffer_t *co)
+{
+ int i;
+ uint32_t status;
+ ssize_t r, len;
+ int argc;
+ fr_channel_type_t channel;
+ char *my_argv[MAX_ARGV], **argv;
+ fr_command_table_t *table;
+ uint8_t *command;
+
+ r = fr_channel_drain(listener->fd, &channel, co->buffer, sizeof(co->buffer) - 1, &command, co->offset);
+
+ if (r <= 0) {
+ do_close:
+ command_close_socket(listener);
+ return 0;
+ }
+
+ /*
+ * We need more data. Go read it.
+ */
+ if (channel == FR_CHANNEL_WANT_MORE) {
+ co->offset = r;
+ return 0;
+ }
+
+ status = 0;
+ command[r] = '\0';
+ DEBUG("radmin> %s", command);
+
+ argc = str2argvX((char *) command, my_argv, MAX_ARGV);
+ if (argc == 0) goto do_next; /* empty strings are OK */
+
+ if (argc < 0) {
+ cprintf_error(listener, "Failed parsing command.\n");
+ goto do_next;
+ }
+
+ argv = my_argv;
+
+ for (len = 0; len <= co->offset; len++) {
+ if (command[len] < 0x20) {
+ command[len] = '\0';
+ break;
+ }
+ }
+
+ /*
+ * Hard-code exit && quit.
+ */
+ if ((strcmp(argv[0], "exit") == 0) ||
+ (strcmp(argv[0], "quit") == 0)) goto do_close;
+
+ table = command_table;
+ retry:
+ len = 0;
+ for (i = 0; table[i].command != NULL; i++) {
+ if (strcmp(table[i].command, argv[0]) == 0) {
+ /*
+ * Check permissions.
+ */
+ if (((co->mode & FR_WRITE) == 0) &&
+ ((table[i].mode & FR_WRITE) != 0)) {
+ cprintf_error(listener, "You do not have write permission. See \"mode = rw\" in the \"listen\" section for this socket.\n");
+ goto do_next;
+ }
+
+ if (table[i].table) {
+ /*
+ * This is the last argument, but
+ * there's a sub-table. Print help.
+ *
+ */
+ if (argc == 1) {
+ table = table[i].table;
+ goto do_help;
+ }
+
+ argc--;
+ argv++;
+ table = table[i].table;
+ goto retry;
+ }
+
+ if ((argc == 2) && (strcmp(argv[1], "?") == 0)) goto do_help;
+
+ if (!table[i].func) {
+ cprintf_error(listener, "Invalid command\n");
+ goto do_next;
+ }
+
+ status = table[i].func(listener, argc - 1, argv + 1);
+ goto do_next;
+ }
+ }
+
+ /*
+ * No such command
+ */
+ if (!len) {
+ if ((strcmp(argv[0], "help") == 0) ||
+ (strcmp(argv[0], "?") == 0)) {
+ int recursive;
+
+ do_help:
+ if ((argc > 1) && (strcmp(argv[1], "-r") == 0)) {
+ recursive = true;
+ argc--;
+ argv++;
+ } else {
+ recursive = false;
+ }
+
+ print_help(listener, argc - 1, argv + 1, table, recursive);
+ goto do_next;
+ }
+
+ cprintf_error(listener, "Unknown command \"%s\"\n",
+ argv[0]);
+ }
+
+ do_next:
+ r = fr_channel_write(listener->fd, FR_CHANNEL_CMD_STATUS, &status, sizeof(status));
+ if (r <= 0) goto do_close;
+
+ return 0;
+}
+
+
+/*
+ * Write 32-bit magic number && version information.
+ */
+static int command_write_magic(int newfd,
+#ifndef WITH_TCP
+ UNUSED
+#endif
+ listen_socket_t *sock
+ )
+{
+ ssize_t r;
+ uint32_t magic;
+ fr_channel_type_t channel;
+ char buffer[16];
+
+ r = fr_channel_read(newfd, &channel, buffer, 8);
+ if (r <= 0) {
+ do_close:
+ ERROR("Cannot talk to socket: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ magic = htonl(0xf7eead16);
+ if ((r != 8) || (channel != FR_CHANNEL_INIT_ACK) ||
+ (memcmp(&magic, &buffer, sizeof(magic)) != 0)) {
+ ERROR("Incompatible versions");
+ return -1;
+ }
+
+ r = fr_channel_write(newfd, FR_CHANNEL_INIT_ACK, buffer, 8);
+ if (r <= 0) goto do_close;
+
+#ifdef WITH_TCP
+ /*
+ * Write an initial challenge
+ */
+ if (sock) {
+ int i;
+ fr_cs_buffer_t *co;
+
+ co = talloc_zero(sock, fr_cs_buffer_t);
+ sock->packet = (void *) co;
+
+ for (i = 0; i < 16; i++) {
+ co->buffer[i] = fr_rand();
+ }
+
+ r = fr_channel_write(newfd, FR_CHANNEL_AUTH_CHALLENGE, co->buffer, 16);
+ if (r <= 0) goto do_close;
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef WITH_TCP
+static int command_tcp_recv(rad_listen_t *this)
+{
+ ssize_t r;
+ listen_socket_t *sock = this->data;
+ fr_cs_buffer_t *co = (void *) sock->packet;
+ fr_channel_type_t channel;
+
+ if (!co) {
+ do_close:
+ command_close_socket(this);
+ return 0;
+ }
+
+ if (!co->auth) {
+ uint8_t expected[16];
+
+ r = fr_channel_read(this->fd, &channel, co->buffer, 16);
+ if ((r != 16) || (channel != FR_CHANNEL_AUTH_RESPONSE)) {
+ goto do_close;
+ }
+
+ fr_hmac_md5(expected, (void const *) sock->client->secret,
+ strlen(sock->client->secret),
+ (uint8_t *) co->buffer, 16);
+
+ if (rad_digest_cmp(expected,
+ (uint8_t *) co->buffer + 16, 16 != 0)) {
+ ERROR("radmin failed challenge: Closing socket");
+ goto do_close;
+ }
+
+ co->auth = true;
+ co->offset = 0;
+ }
+
+ return command_domain_recv_co(this, co);
+}
+
+
+/*
+ * Should never be called. The functions should just call write().
+ */
+static int command_tcp_send(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
+{
+ return 0;
+}
+#endif
+
+static int command_domain_recv(rad_listen_t *listener)
+{
+ fr_command_socket_t *sock = listener->data;
+
+ return command_domain_recv_co(listener, &sock->co);
+}
+
+static int command_domain_accept(rad_listen_t *listener)
+{
+ int newfd;
+ rad_listen_t *this;
+ socklen_t salen;
+ struct sockaddr_storage src;
+ fr_command_socket_t *sock = listener->data;
+
+ salen = sizeof(src);
+
+ DEBUG2(" ... new connection request on command socket");
+
+ newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
+ if (newfd < 0) {
+ /*
+ * Non-blocking sockets must handle this.
+ */
+ if (errno == EWOULDBLOCK) {
+ return 0;
+ }
+
+ DEBUG2(" ... failed to accept connection");
+ return 0;
+ }
+
+#ifdef HAVE_GETPEEREID
+ /*
+ * Perform user authentication.
+ */
+ if (sock->peercred && (sock->uid_name || sock->gid_name)) {
+ uid_t uid;
+ gid_t gid;
+
+ if (getpeereid(newfd, &uid, &gid) < 0) {
+ ERROR("Failed getting peer credentials for %s: %s",
+ sock->path, fr_syserror(errno));
+ close(newfd);
+ return 0;
+ }
+
+ /*
+ * Only do UID checking if the caller is
+ * non-root. The superuser can do anything, so
+ * we might as well let them.
+ */
+ if (uid != 0) do {
+ /*
+ * Allow entry if UID or GID matches.
+ */
+ if (sock->uid_name && (sock->uid == uid)) break;
+ if (sock->gid_name && (sock->gid == gid)) break;
+
+ if (sock->uid_name && (sock->uid != uid)) {
+ ERROR("Unauthorized connection to %s from uid %ld",
+
+ sock->path, (long int) uid);
+ close(newfd);
+ return 0;
+ }
+
+ if (sock->gid_name && (sock->gid != gid)) {
+ ERROR("Unauthorized connection to %s from gid %ld",
+ sock->path, (long int) gid);
+ close(newfd);
+ return 0;
+ }
+
+ } while (0);
+ }
+#endif
+
+ if (command_write_magic(newfd, NULL) < 0) {
+ close(newfd);
+ return 0;
+ }
+
+ /*
+ * Add the new listener.
+ */
+ this = listen_alloc(listener, listener->type);
+ if (!this) return 0;
+
+ /*
+ * Copy everything, including the pointer to the socket
+ * information.
+ */
+ sock = this->data;
+ memcpy(this, listener, sizeof(*this));
+ this->status = RAD_LISTEN_STATUS_INIT;
+ this->next = NULL;
+ this->data = sock; /* fix it back */
+
+ sock->magic = COMMAND_SOCKET_MAGIC;
+ sock->user[0] = '\0';
+ sock->path = ((fr_command_socket_t *) listener->data)->path;
+ sock->co.offset = 0;
+ sock->co.mode = ((fr_command_socket_t *) listener->data)->co.mode;
+
+ this->fd = newfd;
+ this->recv = command_domain_recv;
+
+ /*
+ * Tell the event loop that we have a new FD
+ */
+ radius_update_listener(this);
+
+ return 0;
+}
+
+
+/*
+ * Send an authentication response packet
+ */
+static int command_domain_send(UNUSED rad_listen_t *listener,
+ UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+
+static int command_socket_encode(UNUSED rad_listen_t *listener,
+ UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+
+static int command_socket_decode(UNUSED rad_listen_t *listener,
+ UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+#endif /* WITH_COMMAND_SOCKET */
diff --git a/src/main/conffile.c b/src/main/conffile.c
new file mode 100644
index 0000000..7bb206c
--- /dev/null
+++ b/src/main/conffile.c
@@ -0,0 +1,3821 @@
+/*
+ * conffile.c Read the radiusd.conf file.
+ *
+ * Yep I should learn to use lex & yacc, or at least
+ * write a decent parser. I know how to do that, really :)
+ * miquels@cistron.nl
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include <ctype.h>
+
+bool check_config = false;
+
+typedef enum conf_property {
+ CONF_PROPERTY_INVALID = 0,
+ CONF_PROPERTY_NAME,
+ CONF_PROPERTY_INSTANCE,
+} CONF_PROPERTY;
+
+static const FR_NAME_NUMBER conf_property_name[] = {
+ { "name", CONF_PROPERTY_NAME},
+ { "instance", CONF_PROPERTY_INSTANCE},
+
+ { NULL , -1 }
+};
+
+typedef enum conf_type {
+ CONF_ITEM_INVALID = 0,
+ CONF_ITEM_PAIR,
+ CONF_ITEM_SECTION,
+ CONF_ITEM_DATA
+} CONF_ITEM_TYPE;
+
+struct conf_item {
+ struct conf_item *next; //!< Sibling.
+ struct conf_part *parent; //!< Parent.
+ int lineno; //!< The line number the config item began on.
+ char const *filename; //!< The file the config item was parsed from.
+ CONF_ITEM_TYPE type; //!< Whether the config item is a config_pair, conf_section or conf_data.
+};
+
+/** Configuration AVP similar to a VALUE_PAIR
+ *
+ */
+struct conf_pair {
+ CONF_ITEM item;
+ char const *attr; //!< Attribute name
+ char const *value; //!< Attribute value
+ FR_TOKEN op; //!< Operator e.g. =, :=
+ FR_TOKEN lhs_type; //!< Name quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
+ FR_TOKEN rhs_type; //!< Value Quoting style T_(DOUBLE|SINGLE|BACK)_QUOTE_STRING or T_BARE_WORD.
+ bool pass2; //!< do expansion in pass2.
+ bool parsed; //!< Was this item used during parsing?
+};
+
+/** Internal data that is associated with a configuration section
+ *
+ */
+struct conf_data {
+ CONF_ITEM item;
+ char const *name;
+ int flag;
+ void *data; //!< User data
+ void (*free)(void *); //!< Free user data function
+};
+
+struct conf_part {
+ CONF_ITEM item;
+ char const *name1; //!< First name token. Given ``foo bar {}`` would be ``foo``.
+ char const *name2; //!< Second name token. Given ``foo bar {}`` would be ``bar``.
+
+ FR_TOKEN name2_type; //!< The type of quoting around name2.
+
+ CONF_ITEM *children;
+ CONF_ITEM *tail; //!< For speed.
+ CONF_SECTION *template;
+
+ rbtree_t *pair_tree; //!< and a partridge..
+ rbtree_t *section_tree; //!< no jokes here.
+ rbtree_t *name2_tree; //!< for sections of the same name2
+ rbtree_t *data_tree;
+
+ void *base;
+ int depth;
+
+ CONF_PARSER const *variables;
+};
+
+typedef struct cf_file_t {
+ char const *filename;
+ CONF_SECTION *cs;
+ struct stat buf;
+ bool from_dir;
+} cf_file_t;
+
+CONF_SECTION *root_config = NULL;
+bool cf_new_escape = true;
+
+
+static int cf_data_add_internal(CONF_SECTION *cs, char const *name, void *data,
+ void (*data_free)(void *), int flag);
+
+static void *cf_data_find_internal(CONF_SECTION const *cs, char const *name, int flag);
+
+static char const *cf_expand_variables(char const *cf, int *lineno,
+ CONF_SECTION *outercs,
+ char *output, size_t outsize,
+ char const *input, bool *soft_fail);
+
+static int cf_file_include(CONF_SECTION *cs, char const *filename_in, bool from_dir);
+
+
+
+/*
+ * Isolate the scary casts in these tiny provably-safe functions
+ */
+
+/** Cast a CONF_ITEM to a CONF_PAIR
+ *
+ */
+CONF_PAIR *cf_item_to_pair(CONF_ITEM const *ci)
+{
+ CONF_PAIR *out;
+
+ if (ci == NULL) return NULL;
+
+ rad_assert(ci->type == CONF_ITEM_PAIR);
+
+ memcpy(&out, &ci, sizeof(out));
+ return out;
+}
+
+/** Cast a CONF_ITEM to a CONF_SECTION
+ *
+ */
+CONF_SECTION *cf_item_to_section(CONF_ITEM const *ci)
+{
+ CONF_SECTION *out;
+
+ if (ci == NULL) return NULL;
+
+ rad_assert(ci->type == CONF_ITEM_SECTION);
+
+ memcpy(&out, &ci, sizeof(out));
+ return out;
+}
+
+/** Cast a CONF_PAIR to a CONF_ITEM
+ *
+ */
+CONF_ITEM *cf_pair_to_item(CONF_PAIR const *cp)
+{
+ CONF_ITEM *out;
+
+ if (cp == NULL) return NULL;
+
+ memcpy(&out, &cp, sizeof(out));
+ return out;
+}
+
+/** Cast a CONF_SECTION to a CONF_ITEM
+ *
+ */
+CONF_ITEM *cf_section_to_item(CONF_SECTION const *cs)
+{
+ CONF_ITEM *out;
+
+ if (cs == NULL) return NULL;
+
+ memcpy(&out, &cs, sizeof(out));
+ return out;
+}
+
+/** Cast CONF_DATA to a CONF_ITEM
+ *
+ */
+static CONF_ITEM *cf_data_to_item(CONF_DATA const *cd)
+{
+ CONF_ITEM *out;
+
+ if (cd == NULL) {
+ return NULL;
+ }
+
+ memcpy(&out, &cd, sizeof(out));
+ return out;
+}
+
+static int _cf_data_free(CONF_DATA *cd)
+{
+ if (cd->free) cd->free(cd->data);
+
+ return 0;
+}
+
+/*
+ * rbtree callback function
+ */
+static int pair_cmp(void const *a, void const *b)
+{
+ CONF_PAIR const *one = a;
+ CONF_PAIR const *two = b;
+
+ return strcmp(one->attr, two->attr);
+}
+
+
+/*
+ * rbtree callback function
+ */
+static int section_cmp(void const *a, void const *b)
+{
+ CONF_SECTION const *one = a;
+ CONF_SECTION const *two = b;
+
+ return strcmp(one->name1, two->name1);
+}
+
+
+/*
+ * rbtree callback function
+ */
+static int name2_cmp(void const *a, void const *b)
+{
+ CONF_SECTION const *one = a;
+ CONF_SECTION const *two = b;
+
+ rad_assert(strcmp(one->name1, two->name1) == 0);
+
+ if (!one->name2 && !two->name2) return 0;
+ if (one->name2 && !two->name2) return -1;
+ if (!one->name2 && two->name2) return +1;
+
+ return strcmp(one->name2, two->name2);
+}
+
+
+/*
+ * rbtree callback function
+ */
+static int data_cmp(void const *a, void const *b)
+{
+ int rcode;
+
+ CONF_DATA const *one = a;
+ CONF_DATA const *two = b;
+
+ rcode = one->flag - two->flag;
+ if (rcode != 0) return rcode;
+
+ return strcmp(one->name, two->name);
+}
+
+/*
+ * Functions for tracking filenames.
+ */
+static int filename_cmp(void const *a, void const *b)
+{
+ cf_file_t const *one = a;
+ cf_file_t const *two = b;
+
+ if (one->buf.st_dev < two->buf.st_dev) return -1;
+ if (one->buf.st_dev > two->buf.st_dev) return +1;
+
+ if (one->buf.st_ino < two->buf.st_ino) return -1;
+ if (one->buf.st_ino > two->buf.st_ino) return +1;
+
+ return 0;
+}
+
+static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
+{
+ cf_file_t *file;
+ CONF_DATA *cd;
+ CONF_SECTION *top;
+ rbtree_t *tree;
+ int fd;
+ FILE *fp;
+
+ top = cf_top_section(cs);
+ cd = cf_data_find_internal(top, "filename", 0);
+ if (!cd) return -1;
+
+ tree = cd->data;
+
+ /*
+ * If we're including a wildcard directory, then ignore
+ * any files the users has already explicitly loaded in
+ * that directory.
+ */
+ if (from_dir) {
+ cf_file_t my_file;
+
+ my_file.cs = cs;
+ my_file.filename = filename;
+
+ if (stat(filename, &my_file.buf) < 0) goto error;
+
+ file = rbtree_finddata(tree, &my_file);
+ if (file && !file->from_dir) return 0;
+ }
+
+ DEBUG2("including configuration file %s", filename);
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+error:
+ ERROR("Unable to open file \"%s\": %s",
+ filename, fr_syserror(errno));
+ return -1;
+ }
+
+ fd = fileno(fp);
+
+ file = talloc(tree, cf_file_t);
+ if (!file) {
+ fclose(fp);
+ return -1;
+ }
+
+ file->filename = filename;
+ file->cs = cs;
+ file->from_dir = from_dir;
+
+ if (fstat(fd, &file->buf) == 0) {
+#ifdef S_IWOTH
+ if ((file->buf.st_mode & S_IWOTH) != 0) {
+ ERROR("Configuration file %s is globally writable. "
+ "Refusing to start due to insecure configuration.", filename);
+
+ fclose(fp);
+ talloc_free(file);
+ return -1;
+ }
+#endif
+ }
+
+ /*
+ * We can include the same file twice. e.g. when it
+ * contains common definitions, such as for SQL.
+ *
+ * Though the admin should really use templates for that.
+ */
+ if (!rbtree_insert(tree, file)) {
+ talloc_free(file);
+ }
+
+ *fp_p = fp;
+ return 1;
+}
+
+/*
+ * Do some checks on the file
+ */
+static bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_perms)
+{
+ cf_file_t *file;
+ CONF_DATA *cd;
+ CONF_SECTION *top;
+ rbtree_t *tree;
+
+ top = cf_top_section(cs);
+ cd = cf_data_find_internal(top, "filename", 0);
+ if (!cd) return false;
+
+ tree = cd->data;
+
+ file = talloc(tree, cf_file_t);
+ if (!file) return false;
+
+ file->filename = filename;
+ file->cs = cs;
+
+ if (stat(filename, &file->buf) < 0) {
+ ERROR("Unable to check file \"%s\": %s", filename, fr_syserror(errno));
+ talloc_free(file);
+ return false;
+ }
+
+ if (!check_perms) {
+ talloc_free(file);
+ return true;
+ }
+
+#ifdef S_IWOTH
+ if ((file->buf.st_mode & S_IWOTH) != 0) {
+ ERROR("Configuration file %s is globally writable. "
+ "Refusing to start due to insecure configuration.", filename);
+ talloc_free(file);
+ return false;
+ }
+#endif
+
+ /*
+ * It's OK to include the same file twice...
+ */
+ if (!rbtree_insert(tree, file)) {
+ talloc_free(file);
+ }
+
+ return true;
+
+}
+
+
+typedef struct cf_file_callback_t {
+ int rcode;
+ rb_walker_t callback;
+ CONF_SECTION *modules;
+} cf_file_callback_t;
+
+
+/*
+ * Return 0 for keep going, 1 for stop.
+ */
+static int file_callback(void *ctx, void *data)
+{
+ cf_file_callback_t *cb = ctx;
+ cf_file_t *file = data;
+ struct stat buf;
+
+ /*
+ * The file doesn't exist or we can no longer read it.
+ */
+ if (stat(file->filename, &buf) < 0) {
+ cb->rcode = CF_FILE_ERROR;
+ return 1;
+ }
+
+ /*
+ * The file changed, we'll need to re-read it.
+ */
+ if (file->buf.st_mtime != buf.st_mtime) {
+ if (cb->callback(cb->modules, file->cs)) {
+ cb->rcode |= CF_FILE_MODULE;
+ DEBUG3("HUP: Changed module file %s", file->filename);
+ } else {
+ DEBUG3("HUP: Changed config file %s", file->filename);
+ cb->rcode |= CF_FILE_CONFIG;
+ }
+
+ /*
+ * Presume that the file will be immediately
+ * re-read, so we update the mtime appropriately.
+ */
+ file->buf.st_mtime = buf.st_mtime;
+ }
+
+ return 0;
+}
+
+
+/*
+ * See if any of the files have changed.
+ */
+int cf_file_changed(CONF_SECTION *cs, rb_walker_t callback)
+{
+ CONF_DATA *cd;
+ CONF_SECTION *top;
+ cf_file_callback_t cb;
+ rbtree_t *tree;
+
+ top = cf_top_section(cs);
+ cd = cf_data_find_internal(top, "filename", 0);
+ if (!cd) return true;
+
+ tree = cd->data;
+
+ cb.rcode = CF_FILE_NONE;
+ cb.callback = callback;
+ cb.modules = cf_section_sub_find(cs, "modules");
+
+ (void) rbtree_walk(tree, RBTREE_IN_ORDER, file_callback, &cb);
+
+ return cb.rcode;
+}
+
+static int _cf_section_free(CONF_SECTION *cs)
+{
+ /*
+ * Name1 and name2 are allocated contiguous with
+ * cs.
+ */
+ if (cs->pair_tree) {
+ rbtree_free(cs->pair_tree);
+ cs->pair_tree = NULL;
+ }
+ if (cs->section_tree) {
+ rbtree_free(cs->section_tree);
+ cs->section_tree = NULL;
+ }
+ if (cs->name2_tree) {
+ rbtree_free(cs->name2_tree);
+ cs->name2_tree = NULL;
+ }
+ if (cs->data_tree) {
+ rbtree_free(cs->data_tree);
+ cs->data_tree = NULL;
+ }
+
+ return 0;
+}
+
+/** Allocate a CONF_PAIR
+ *
+ * @param parent CONF_SECTION to hang this CONF_PAIR off of.
+ * @param attr name.
+ * @param value of CONF_PAIR.
+ * @param op T_OP_EQ, T_OP_SET etc.
+ * @param lhs_type T_BARE_WORD, T_DOUBLE_QUOTED_STRING, T_BACK_QUOTED_STRING
+ * @param rhs_type T_BARE_WORD, T_DOUBLE_QUOTED_STRING, T_BACK_QUOTED_STRING
+ * @return NULL on error, else a new CONF_SECTION parented by parent.
+ */
+CONF_PAIR *cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value,
+ FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type)
+{
+ CONF_PAIR *cp;
+
+ rad_assert(fr_equality_op[op] || fr_assignment_op[op]);
+ if (!attr) return NULL;
+
+ cp = talloc_zero(parent, CONF_PAIR);
+ if (!cp) return NULL;
+
+ cp->item.type = CONF_ITEM_PAIR;
+ cp->item.parent = parent;
+ cp->lhs_type = lhs_type;
+ cp->rhs_type = rhs_type;
+ cp->op = op;
+
+ cp->attr = talloc_typed_strdup(cp, attr);
+ if (!cp->attr) {
+ error:
+ talloc_free(cp);
+ return NULL;
+ }
+
+ if (value) {
+ cp->value = talloc_typed_strdup(cp, value);
+ if (!cp->value) goto error;
+ }
+
+ return cp;
+}
+
+/** Duplicate a CONF_PAIR
+ *
+ * @param parent to allocate new pair in.
+ * @param cp to duplicate.
+ * @return NULL on error, else a duplicate of the input pair.
+ */
+CONF_PAIR *cf_pair_dup(CONF_SECTION *parent, CONF_PAIR *cp)
+{
+ CONF_PAIR *new;
+
+ rad_assert(parent);
+ rad_assert(cp);
+
+ new = cf_pair_alloc(parent, cp->attr, cf_pair_value(cp),
+ cp->op, cp->lhs_type, cp->rhs_type);
+ if (!new) return NULL;
+
+ new->parsed = cp->parsed;
+ new->item.lineno = cp->item.lineno;
+
+ /*
+ * Avoid mallocs if possible.
+ */
+ if (!cp->item.filename || (parent->item.filename && !strcmp(parent->item.filename, cp->item.filename))) {
+ new->item.filename = parent->item.filename;
+ } else {
+ new->item.filename = talloc_strdup(new, cp->item.filename);
+ }
+
+ return new;
+}
+
+/** Add a configuration pair to a section
+ *
+ * @param parent section to add pair to.
+ * @param cp to add.
+ */
+void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp)
+{
+ cf_item_add(parent, cf_pair_to_item(cp));
+}
+
+/** Allocate a CONF_SECTION
+ *
+ * @param parent CONF_SECTION to hang this CONF_SECTION off of.
+ * @param name1 Primary name.
+ * @param name2 Secondary name.
+ * @return NULL on error, else a new CONF_SECTION parented by parent.
+ */
+CONF_SECTION *cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
+{
+ CONF_SECTION *cs;
+ char buffer[1024];
+
+ if (!name1) return NULL;
+
+ if (name2 && parent) {
+ if (strchr(name2, '$')) {
+ name2 = cf_expand_variables(parent->item.filename,
+ &parent->item.lineno,
+ parent,
+ buffer, sizeof(buffer), name2, NULL);
+ if (!name2) {
+ ERROR("Failed expanding section name");
+ return NULL;
+ }
+ }
+ }
+
+ cs = talloc_zero(parent, CONF_SECTION);
+ if (!cs) return NULL;
+
+ cs->item.type = CONF_ITEM_SECTION;
+ cs->item.parent = parent;
+
+ cs->name1 = talloc_typed_strdup(cs, name1);
+ if (!cs->name1) {
+ error:
+ talloc_free(cs);
+ return NULL;
+ }
+
+ if (name2) {
+ cs->name2 = talloc_typed_strdup(cs, name2);
+ if (!cs->name2) goto error;
+ }
+
+ cs->pair_tree = rbtree_create(cs, pair_cmp, NULL, 0);
+ if (!cs->pair_tree) goto error;
+
+ talloc_set_destructor(cs, _cf_section_free);
+
+ /*
+ * Don't create a data tree, it may not be needed.
+ */
+
+ /*
+ * Don't create the section tree here, it may not
+ * be needed.
+ */
+
+ if (parent) cs->depth = parent->depth + 1;
+
+ return cs;
+}
+
+/** Duplicate a configuration section
+ *
+ * @note recursively duplicates any child sections.
+ * @note does not duplicate any data associated with a section, or its child sections.
+ *
+ * @param parent section (may be NULL).
+ * @param cs to duplicate.
+ * @param name1 of new section.
+ * @param name2 of new section.
+ * @param copy_meta Copy additional meta data for a section (like template, base, depth and variables).
+ * @return a duplicate of the existing section, or NULL on error.
+ */
+CONF_SECTION *cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs,
+ char const *name1, char const *name2, bool copy_meta)
+{
+ CONF_SECTION *new, *subcs;
+ CONF_PAIR *cp;
+ CONF_ITEM *ci;
+
+ new = cf_section_alloc(parent, name1, name2);
+
+ if (copy_meta) {
+ new->template = cs->template;
+ new->base = cs->base;
+ new->depth = cs->depth;
+ new->variables = cs->variables;
+ }
+
+ new->item.lineno = cs->item.lineno;
+
+ if (!cs->item.filename || (parent && (strcmp(parent->item.filename, cs->item.filename) == 0))) {
+ new->item.filename = parent->item.filename;
+ } else {
+ new->item.filename = talloc_strdup(new, cs->item.filename);
+ }
+
+ for (ci = cs->children; ci; ci = ci->next) {
+ switch (ci->type) {
+ case CONF_ITEM_SECTION:
+ subcs = cf_item_to_section(ci);
+ subcs = cf_section_dup(new, subcs,
+ cf_section_name1(subcs), cf_section_name2(subcs),
+ copy_meta);
+ if (!subcs) {
+ talloc_free(new);
+ return NULL;
+ }
+ cf_section_add(new, subcs);
+ break;
+
+ case CONF_ITEM_PAIR:
+ cp = cf_pair_dup(new, cf_item_to_pair(ci));
+ if (!cp) {
+ talloc_free(new);
+ return NULL;
+ }
+ cf_pair_add(new, cp);
+ break;
+
+ case CONF_ITEM_DATA: /* Skip data */
+ break;
+
+ case CONF_ITEM_INVALID:
+ rad_assert(0);
+ }
+ }
+
+ return new;
+}
+
+void cf_section_add(CONF_SECTION *parent, CONF_SECTION *cs)
+{
+ cf_item_add(parent, &(cs->item));
+}
+
+/** Replace pair in a given section with a new pair, of the given value.
+ *
+ * @param cs to replace pair in.
+ * @param cp to replace.
+ * @param value New value to assign to cp.
+ * @return 0 on success, -1 on failure.
+ */
+int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
+{
+ CONF_PAIR *newp;
+ CONF_ITEM *ci, *cn, **last;
+
+ newp = cf_pair_alloc(cs, cp->attr, value, cp->op, cp->lhs_type, cp->rhs_type);
+ if (!newp) return -1;
+
+ ci = &(cp->item);
+ cn = &(newp->item);
+
+ /*
+ * Find the old one from the linked list, and replace it
+ * with the new one.
+ */
+ for (last = &cs->children; (*last) != NULL; last = &(*last)->next) {
+ if (*last == ci) {
+ cn->next = (*last)->next;
+ *last = cn;
+ ci->next = NULL;
+ break;
+ }
+ }
+
+ rbtree_deletebydata(cs->pair_tree, ci);
+
+ rbtree_insert(cs->pair_tree, cn);
+
+ return 0;
+}
+
+
+/*
+ * Add an item to a configuration section.
+ */
+void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci)
+{
+#ifndef NDEBUG
+ CONF_ITEM *first = ci;
+#endif
+
+ rad_assert((void *)cs != (void *)ci);
+
+ if (!cs || !ci) return;
+
+ if (!cs->children) {
+ rad_assert(cs->tail == NULL);
+ cs->children = ci;
+ } else {
+ rad_assert(cs->tail != NULL);
+ cs->tail->next = ci;
+ }
+
+ /*
+ * Update the trees (and tail) for each item added.
+ */
+ for (/* nothing */; ci != NULL; ci = ci->next) {
+ rad_assert(ci->next != first); /* simple cycle detection */
+
+ cs->tail = ci;
+
+ /*
+ * For fast lookups, pairs and sections get
+ * added to rbtree's.
+ */
+ switch (ci->type) {
+ case CONF_ITEM_PAIR:
+ if (!rbtree_insert(cs->pair_tree, ci)) {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+
+ if (strcmp(cp->attr, "confdir") == 0) break;
+ if (!cp->value) break; /* module name, "ok", etc. */
+ }
+ break;
+
+ case CONF_ITEM_SECTION: {
+ CONF_SECTION *cs_new = cf_item_to_section(ci);
+ CONF_SECTION *name1_cs;
+
+ if (!cs->section_tree) {
+ cs->section_tree = rbtree_create(cs, section_cmp, NULL, 0);
+ if (!cs->section_tree) {
+ ERROR("Out of memory");
+ fr_exit_now(1);
+ }
+ }
+
+ name1_cs = rbtree_finddata(cs->section_tree, cs_new);
+ if (!name1_cs) {
+ if (!rbtree_insert(cs->section_tree, cs_new)) {
+ ERROR("Failed inserting section into tree");
+ fr_exit_now(1);
+ }
+ break;
+ }
+
+ /*
+ * We already have a section of
+ * this "name1". Add a new
+ * sub-section based on name2.
+ */
+ if (!name1_cs->name2_tree) {
+ name1_cs->name2_tree = rbtree_create(name1_cs, name2_cmp, NULL, 0);
+ if (!name1_cs->name2_tree) {
+ ERROR("Out of memory");
+ fr_exit_now(1);
+ }
+ }
+
+ /*
+ * We don't care if this fails.
+ * If the user tries to create
+ * two sections of the same
+ * name1/name2, the duplicate
+ * section is just silently
+ * ignored.
+ */
+ rbtree_insert(name1_cs->name2_tree, cs_new);
+ break;
+ } /* was a section */
+
+ case CONF_ITEM_DATA:
+ if (!cs->data_tree) {
+ cs->data_tree = rbtree_create(cs, data_cmp, NULL, 0);
+ }
+ if (cs->data_tree) {
+ rbtree_insert(cs->data_tree, ci);
+ }
+ break;
+
+ default: /* FIXME: assert & error! */
+ break;
+
+ } /* switch over conf types */
+ } /* loop over ci */
+}
+
+
+CONF_ITEM *cf_reference_item(CONF_SECTION const *parentcs,
+ CONF_SECTION *outercs,
+ char const *ptr)
+{
+ CONF_PAIR *cp;
+ CONF_SECTION *next;
+ CONF_SECTION const *cs = outercs;
+ char name[8192];
+ char *p;
+
+ if (!cs) goto no_such_item;
+
+ strlcpy(name, ptr, sizeof(name));
+ p = name;
+
+ /*
+ * ".foo" means "foo from the current section"
+ */
+ if (*p == '.') {
+ p++;
+
+ /*
+ * Just '.' means the current section
+ */
+ if (*p == '\0') {
+ return cf_section_to_item(cs);
+ }
+
+ /*
+ * ..foo means "foo from the section
+ * enclosing this section" (etc.)
+ */
+ while (*p == '.') {
+ if (cs->item.parent) {
+ cs = cs->item.parent;
+ }
+
+ /*
+ * .. means the section
+ * enclosing this section
+ */
+ if (!*++p) {
+ return cf_section_to_item(cs);
+ }
+ }
+
+ /*
+ * "foo.bar.baz" means "from the root"
+ */
+ } else if (strchr(p, '.') != NULL) {
+ if (!parentcs) goto no_such_item;
+
+ cs = parentcs;
+ }
+
+ while (*p) {
+ char *q, *r;
+
+ r = strchr(p, '[');
+ q = strchr(p, '.');
+ if (!r && !q) break;
+
+ if (r && q > r) q = NULL;
+ if (q && q < r) r = NULL;
+
+ /*
+ * Split off name2.
+ */
+ if (r) {
+ q = strchr(r + 1, ']');
+ if (!q) return NULL; /* parse error */
+
+ /*
+ * Points to foo[bar]xx: parse error,
+ * it should be foo[bar] or foo[bar].baz
+ */
+ if (q[1] && q[1] != '.') goto no_such_item;
+
+ *r = '\0';
+ *q = '\0';
+ next = cf_section_sub_find_name2(cs, p, r + 1);
+ *r = '[';
+ *q = ']';
+
+ /*
+ * Points to a named instance of a section.
+ */
+ if (!q[1]) {
+ if (!next) goto no_such_item;
+ return &(next->item);
+ }
+
+ q++; /* ensure we skip the ']' and '.' */
+
+ } else {
+ *q = '\0';
+ next = cf_section_sub_find(cs, p);
+ *q = '.';
+ }
+
+ if (!next) break; /* it MAY be a pair in this section! */
+
+ cs = next;
+ p = q + 1;
+ }
+
+ if (!*p) goto no_such_item;
+
+ retry:
+ /*
+ * Find it in the current referenced
+ * section.
+ */
+ cp = cf_pair_find(cs, p);
+ if (cp) {
+ cp->parsed = true; /* conf pairs which are referenced count as parsed */
+ return &(cp->item);
+ }
+
+ next = cf_section_sub_find(cs, p);
+ if (next) return &(next->item);
+
+ /*
+ * "foo" is "in the current section, OR in main".
+ */
+ if ((p == name) && (parentcs != NULL) && (cs != parentcs)) {
+ cs = parentcs;
+ goto retry;
+ }
+
+no_such_item:
+ return NULL;
+}
+
+
+CONF_SECTION *cf_top_section(CONF_SECTION *cs)
+{
+ if (!cs) return NULL;
+
+ while (cs->item.parent != NULL) {
+ cs = cs->item.parent;
+ }
+
+ return cs;
+}
+
+
+/*
+ * Expand the variables in an input string.
+ */
+static char const *cf_expand_variables(char const *cf, int *lineno,
+ CONF_SECTION *outercs,
+ char *output, size_t outsize,
+ char const *input, bool *soft_fail)
+{
+ char *p;
+ char const *end, *ptr;
+ CONF_SECTION const *parentcs;
+ char name[8192];
+
+ if (soft_fail) *soft_fail = false;
+
+ /*
+ * Find the master parent conf section.
+ * We can't use main_config.config, because we're in the
+ * process of re-building it, and it isn't set up yet...
+ */
+ parentcs = cf_top_section(outercs);
+
+ p = output;
+ ptr = input;
+ while (*ptr) {
+ /*
+ * Ignore anything other than "${"
+ */
+ if ((*ptr == '$') && (ptr[1] == '{')) {
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+ char *q;
+
+ /*
+ * FIXME: Add support for ${foo:-bar},
+ * like in xlat.c
+ */
+
+ /*
+ * Look for trailing '}', and log a
+ * warning for anything that doesn't match,
+ * and exit with a fatal error.
+ */
+ end = strchr(ptr, '}');
+ if (end == NULL) {
+ *p = '\0';
+ ERROR("%s[%d]: Variable expansion missing }",
+ cf, *lineno);
+ return NULL;
+ }
+
+ ptr += 2;
+
+ /*
+ * Can't really happen because input lines are
+ * capped at 8k, which is sizeof(name)
+ */
+ if ((size_t) (end - ptr) >= sizeof(name)) {
+ ERROR("%s[%d]: Reference string is too large",
+ cf, *lineno);
+ return NULL;
+ }
+
+ memcpy(name, ptr, end - ptr);
+ name[end - ptr] = '\0';
+
+ q = strchr(name, ':');
+ if (q) {
+ *(q++) = '\0';
+ }
+
+ ci = cf_reference_item(parentcs, outercs, name);
+ if (!ci) {
+ if (soft_fail) *soft_fail = true;
+ ERROR("%s[%d]: Reference \"${%s}\" not found", cf, *lineno, name);
+ return NULL;
+ }
+
+ /*
+ * The expansion doesn't refer to another item or section
+ * it's the property of a section.
+ */
+ if (q) {
+ CONF_SECTION *mycs = cf_item_to_section(ci);
+
+ if (ci->type != CONF_ITEM_SECTION) {
+ ERROR("%s[%d]: Can only reference properties of sections", cf, *lineno);
+ return NULL;
+ }
+
+ switch (fr_str2int(conf_property_name, q, CONF_PROPERTY_INVALID)) {
+ case CONF_PROPERTY_NAME:
+ strcpy(p, mycs->name1);
+ break;
+
+ case CONF_PROPERTY_INSTANCE:
+ strcpy(p, mycs->name2 ? mycs->name2 : mycs->name1);
+ break;
+
+ default:
+ ERROR("%s[%d]: Invalid property '%s'", cf, *lineno, q);
+ return NULL;
+ }
+ p += strlen(p);
+ ptr = end + 1;
+
+ } else if (ci->type == CONF_ITEM_PAIR) {
+ /*
+ * Substitute the value of the variable.
+ */
+ cp = cf_item_to_pair(ci);
+
+ /*
+ * If the thing we reference is
+ * marked up as being expanded in
+ * pass2, don't expand it now.
+ * Let it be expanded in pass2.
+ */
+ if (cp->pass2) {
+ if (soft_fail) *soft_fail = true;
+
+ ERROR("%s[%d]: Reference \"%s\" points to a variable which has not been expanded.",
+ cf, *lineno, input);
+ return NULL;
+ }
+
+ /*
+ * Might as well make
+ * non-existent string be the
+ * empty string.
+ */
+ if (!cp->value) {
+ *p = '\0';
+ goto skip_value;
+ }
+
+ if (p + strlen(cp->value) >= output + outsize) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
+
+ strcpy(p, cp->value);
+ p += strlen(p);
+ skip_value:
+ ptr = end + 1;
+
+ } else if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs;
+
+ /*
+ * Adding an entry again to a
+ * section is wrong. We don't
+ * want an infinite loop.
+ */
+ if (ci->parent == outercs) {
+ ERROR("%s[%d]: Cannot reference different item in same section", cf, *lineno);
+ return NULL;
+ }
+
+ /*
+ * Copy the section instead of
+ * referencing it.
+ */
+ subcs = cf_item_to_section(ci);
+ subcs = cf_section_dup(outercs, subcs,
+ cf_section_name1(subcs), cf_section_name2(subcs),
+ false);
+ if (!subcs) {
+ ERROR("%s[%d]: Failed copying reference %s", cf, *lineno, name);
+ return NULL;
+ }
+
+ subcs->item.filename = ci->filename;
+ subcs->item.lineno = ci->lineno;
+ cf_item_add(outercs, &(subcs->item));
+
+ ptr = end + 1;
+
+ } else {
+ ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, *lineno, input);
+ return NULL;
+ }
+ } else if (strncmp(ptr, "$ENV{", 5) == 0) {
+ char *env;
+
+ ptr += 5;
+
+ /*
+ * Look for trailing '}', and log a
+ * warning for anything that doesn't match,
+ * and exit with a fatal error.
+ */
+ end = strchr(ptr, '}');
+ if (end == NULL) {
+ *p = '\0';
+ ERROR("%s[%d]: Environment variable expansion missing }",
+ cf, *lineno);
+ return NULL;
+ }
+
+ /*
+ * Can't really happen because input lines are
+ * capped at 8k, which is sizeof(name)
+ */
+ if ((size_t) (end - ptr) >= sizeof(name)) {
+ ERROR("%s[%d]: Environment variable name is too large",
+ cf, *lineno);
+ return NULL;
+ }
+
+ memcpy(name, ptr, end - ptr);
+ name[end - ptr] = '\0';
+
+ /*
+ * Get the environment variable.
+ * If none exists, then make it an empty string.
+ */
+ env = getenv(name);
+ if (env == NULL) {
+ *name = '\0';
+ env = name;
+ }
+
+ if (p + strlen(env) >= output + outsize) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
+
+ strcpy(p, env);
+ p += strlen(p);
+ ptr = end + 1;
+
+ } else {
+ /*
+ * Copy it over verbatim.
+ */
+ *(p++) = *(ptr++);
+ }
+
+
+ if (p >= (output + outsize)) {
+ ERROR("%s[%d]: Reference \"%s\" is too long",
+ cf, *lineno, input);
+ return NULL;
+ }
+ } /* loop over all of the input string. */
+
+ *p = '\0';
+
+ return output;
+}
+
+static char const parse_spaces[] = " ";
+
+/** Validation function for ipaddr conffile types
+ *
+ */
+static inline int fr_item_validate_ipaddr(CONF_SECTION *cs, char const *name, PW_TYPE type, char const *value,
+ fr_ipaddr_t *ipaddr)
+{
+ char ipbuf[128];
+
+ if (strcmp(value, "*") == 0) {
+ cf_log_info(cs, "%.*s\t%s = *", cs->depth, parse_spaces, name);
+ } else if (strspn(value, ".0123456789abdefABCDEF:%[]/") == strlen(value)) {
+ cf_log_info(cs, "%.*s\t%s = %s", cs->depth, parse_spaces, name, value);
+ } else {
+ cf_log_info(cs, "%.*s\t%s = %s IPv%s address [%s]", cs->depth, parse_spaces, name, value,
+ (ipaddr->af == AF_INET ? "4" : " 6"), ip_ntoh(ipaddr, ipbuf, sizeof(ipbuf)));
+ }
+
+ switch (type) {
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_COMBO_IP_ADDR:
+ switch (ipaddr->af) {
+ case AF_INET:
+ if (ipaddr->prefix == 32) return 0;
+
+ cf_log_err(&(cs->item), "Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted for non-prefix types",
+ ipaddr->prefix);
+ break;
+
+ case AF_INET6:
+ if (ipaddr->prefix == 128) return 0;
+
+ cf_log_err(&(cs->item), "Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted for non-prefix types",
+ ipaddr->prefix);
+ break;
+
+
+ default:
+ cf_log_err(&(cs->item), "Unknown address (%d) family passed for parsing IP address.", ipaddr->af);
+ break;
+ }
+
+ return -1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/** Parses a #CONF_PAIR into a C data type, with a default value.
+ *
+ * Takes fields from a #CONF_PARSER struct and uses them to parse the string value
+ * of a #CONF_PAIR into a C data type matching the type argument.
+ *
+ * The format of the types are the same as #value_data_t types.
+ *
+ * @note The dflt value will only be used if no matching #CONF_PAIR is found. Empty strings will not
+ * result in the dflt value being used.
+ *
+ * **PW_TYPE to data type mappings**
+ * | PW_TYPE | Data type | Dynamically allocated |
+ * | ----------------------- | ------------------ | ---------------------- |
+ * | PW_TYPE_TMPL | ``vp_tmpl_t`` | Yes |
+ * | PW_TYPE_BOOLEAN | ``bool`` | No |
+ * | PW_TYPE_INTEGER | ``uint32_t`` | No |
+ * | PW_TYPE_SHORT | ``uint16_t`` | No |
+ * | PW_TYPE_INTEGER64 | ``uint64_t`` | No |
+ * | PW_TYPE_SIGNED | ``int32_t`` | No |
+ * | PW_TYPE_STRING | ``char const *`` | Yes |
+ * | PW_TYPE_IPV4_ADDR | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_IPV4_PREFIX | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_IPV6_ADDR | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_IPV6_PREFIX | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_COMBO_IP_ADDR | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_COMBO_IP_PREFIX | ``fr_ipaddr_t`` | No |
+ * | PW_TYPE_TIMEVAL | ``struct timeval`` | No |
+ *
+ * @param cs to search for matching #CONF_PAIR in.
+ * @param name of #CONF_PAIR to search for.
+ * @param type Data type to parse #CONF_PAIR value as.
+ * Should be one of the following ``data`` types, and one or more of the following ``flag`` types or'd together:
+ * - ``data`` #PW_TYPE_TMPL - @copybrief PW_TYPE_TMPL
+ * Feeds the value into #tmpl_afrom_str. Value can be
+ * obtained when processing requests, with #tmpl_expand or #tmpl_aexpand.
+ * - ``data`` #PW_TYPE_BOOLEAN - @copybrief PW_TYPE_BOOLEAN
+ * - ``data`` #PW_TYPE_INTEGER - @copybrief PW_TYPE_INTEGER
+ * - ``data`` #PW_TYPE_SHORT - @copybrief PW_TYPE_SHORT
+ * - ``data`` #PW_TYPE_INTEGER64 - @copybrief PW_TYPE_INTEGER64
+ * - ``data`` #PW_TYPE_SIGNED - @copybrief PW_TYPE_SIGNED
+ * - ``data`` #PW_TYPE_STRING - @copybrief PW_TYPE_STRING
+ * - ``data`` #PW_TYPE_IPV4_ADDR - @copybrief PW_TYPE_IPV4_ADDR (IPv4 address with prefix 32).
+ * - ``data`` #PW_TYPE_IPV4_PREFIX - @copybrief PW_TYPE_IPV4_PREFIX (IPv4 address with variable prefix).
+ * - ``data`` #PW_TYPE_IPV6_ADDR - @copybrief PW_TYPE_IPV6_ADDR (IPv6 address with prefix 128).
+ * - ``data`` #PW_TYPE_IPV6_PREFIX - @copybrief PW_TYPE_IPV6_PREFIX (IPv6 address with variable prefix).
+ * - ``data`` #PW_TYPE_COMBO_IP_ADDR - @copybrief PW_TYPE_COMBO_IP_ADDR (IPv4/IPv6 address with
+ * prefix 32/128).
+ * - ``data`` #PW_TYPE_COMBO_IP_PREFIX - @copybrief PW_TYPE_COMBO_IP_PREFIX (IPv4/IPv6 address with
+ * variable prefix).
+ * - ``data`` #PW_TYPE_TIMEVAL - @copybrief PW_TYPE_TIMEVAL
+ * - ``flag`` #PW_TYPE_DEPRECATED - @copybrief PW_TYPE_DEPRECATED
+ * - ``flag`` #PW_TYPE_REQUIRED - @copybrief PW_TYPE_REQUIRED
+ * - ``flag`` #PW_TYPE_ATTRIBUTE - @copybrief PW_TYPE_ATTRIBUTE
+ * - ``flag`` #PW_TYPE_SECRET - @copybrief PW_TYPE_SECRET
+ * - ``flag`` #PW_TYPE_FILE_INPUT - @copybrief PW_TYPE_FILE_INPUT
+ * - ``flag`` #PW_TYPE_NOT_EMPTY - @copybrief PW_TYPE_NOT_EMPTY
+ * @param data Pointer to a global variable, or pointer to a field in the struct being populated with values.
+ * @param dflt value to use, if no #CONF_PAIR is found.
+ * @return
+ * - 1 if default value was used.
+ * - 0 on success.
+ * - -1 on error.
+ * - -2 if deprecated.
+ */
+int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt)
+{
+ int rcode;
+ bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi, file_exists;
+ char **q;
+ char const *value;
+ CONF_PAIR *cp = NULL;
+ fr_ipaddr_t *ipaddr;
+ char buffer[8192];
+ CONF_ITEM *c_item;
+
+ if (!cs) {
+ cf_log_err(&(cs->item), "No enclosing section for configuration item \"%s\"", name);
+ return -1;
+ }
+
+ c_item = &cs->item;
+
+ deprecated = (type & PW_TYPE_DEPRECATED);
+ required = (type & PW_TYPE_REQUIRED);
+ attribute = (type & PW_TYPE_ATTRIBUTE);
+ secret = (type & PW_TYPE_SECRET);
+ file_input = (type == PW_TYPE_FILE_INPUT); /* check, not and */
+ file_exists = (type == PW_TYPE_FILE_EXISTS); /* check, not and */
+ cant_be_empty = (type & PW_TYPE_NOT_EMPTY);
+ tmpl = (type & PW_TYPE_TMPL);
+ multi = (type & PW_TYPE_MULTI);
+
+ if (attribute) required = true;
+ if (required) cant_be_empty = true; /* May want to review this in the future... */
+
+ /*
+ * Everything except templates must have a base type.
+ */
+ if (!(type & 0xff) && !tmpl) {
+ cf_log_err(c_item, "Configuration item \"%s\" must have a data type", name);
+ return -1;
+ }
+
+ type &= 0xff; /* normal types are small */
+
+ rcode = 0;
+
+ cp = cf_pair_find(cs, name);
+
+ /*
+ * No pairs match the configuration item name in the current
+ * section, use the default value.
+ */
+ if (!cp) {
+ if (deprecated) return 0; /* Don't set the default value */
+
+ rcode = 1;
+ value = dflt;
+ /*
+ * Something matched, used the CONF_PAIR value.
+ */
+ } else {
+ CONF_PAIR *next = cp;
+
+ value = cp->value;
+ cp->parsed = true;
+ c_item = &cp->item;
+
+ if (deprecated) {
+ cf_log_err(c_item, "Configuration item \"%s\" is deprecated", name);
+ return -2;
+ }
+
+ /*
+ * A quick check to see if the next item is the same.
+ */
+ if (!multi && cp->item.next && (cp->item.next->type == CONF_ITEM_PAIR)) {
+ next = cf_item_to_pair(cp->item.next);
+
+ if (strcmp(next->attr, name) == 0) {
+ WARN("%s[%d]: Ignoring duplicate configuration item '%s'",
+ next->item.filename ? next->item.filename : "unknown",
+ next->item.lineno, name);
+ }
+ }
+
+ if (multi) {
+ while ((next = cf_pair_find_next(cs, next, name)) != NULL) {
+ /*
+ * @fixme We should actually validate
+ * the value of the pairs too
+ */
+ next->parsed = true;
+ };
+ }
+ }
+
+ if (!value) {
+ if (required) {
+ cf_log_err(c_item, "Configuration item \"%s\" must have a value", name);
+
+ return -1;
+ }
+ return rcode;
+ }
+
+ if ((value[0] == '\0') && cant_be_empty) {
+ cant_be_empty:
+ cf_log_err(c_item, "Configuration item \"%s\" must not be empty (zero length)", name);
+ if (!required) cf_log_err(c_item, "Comment item to silence this message");
+
+ return -1;
+ }
+
+
+ /*
+ * Process a value as a LITERAL template. Once all of
+ * the attrs and xlats are defined, the pass2 code
+ * converts it to the appropriate type.
+ */
+ if (tmpl) {
+ vp_tmpl_t *vpt;
+
+ if (!value) {
+ *(vp_tmpl_t **)data = NULL;
+ return 0;
+ }
+
+ rad_assert(!attribute);
+ vpt = tmpl_alloc(cs, TMPL_TYPE_LITERAL, value, strlen(value));
+ *(vp_tmpl_t **)data = vpt;
+
+ return 0;
+ }
+
+ switch (type) {
+ case PW_TYPE_BOOLEAN:
+ /*
+ * Allow yes/no, true/false, and on/off
+ */
+ if ((strcasecmp(value, "yes") == 0) ||
+ (strcasecmp(value, "true") == 0) ||
+ (strcasecmp(value, "on") == 0)) {
+ *(bool *)data = true;
+ } else if ((strcasecmp(value, "no") == 0) ||
+ (strcasecmp(value, "false") == 0) ||
+ (strcasecmp(value, "off") == 0)) {
+ *(bool *)data = false;
+ } else {
+ *(bool *)data = false;
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for boolean "
+ "variable %s", value, name);
+ return -1;
+ }
+ cf_log_info(cs, "%.*s\t%s = %s",
+ cs->depth, parse_spaces, name, value);
+ break;
+
+ case PW_TYPE_INTEGER:
+ {
+ unsigned long v = strtoul(value, 0, 0);
+
+ /*
+ * Restrict integer values to 0-INT32_MAX, this means
+ * it will always be safe to cast them to a signed type
+ * for comparisons, and imposes the same range limit as
+ * before we switched to using an unsigned type to
+ * represent config item integers.
+ */
+ if (v > INT32_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", value,
+ name, INT32_MAX);
+ return -1;
+ }
+
+ *(uint32_t *)data = v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, name, *(uint32_t *)data);
+ }
+ break;
+
+ case PW_TYPE_BYTE:
+ {
+ unsigned long v = strtoul(value, 0, 0);
+
+ if (v > UINT8_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", value,
+ name, UINT8_MAX);
+ return -1;
+ }
+ *(uint8_t *)data = (uint8_t) v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, name, *(uint8_t *)data);
+ }
+ break;
+
+ case PW_TYPE_SHORT:
+ {
+ unsigned long v = strtoul(value, 0, 0);
+
+ if (v > UINT16_MAX) {
+ cf_log_err(&(cs->item), "Invalid value \"%s\" for variable %s, must be between 0-%u", value,
+ name, UINT16_MAX);
+ return -1;
+ }
+ *(uint16_t *)data = (uint16_t) v;
+ cf_log_info(cs, "%.*s\t%s = %u", cs->depth, parse_spaces, name, *(uint16_t *)data);
+ }
+ break;
+
+ case PW_TYPE_INTEGER64:
+ *(uint64_t *)data = strtoull(value, 0, 0);
+ cf_log_info(cs, "%.*s\t%s = %" PRIu64, cs->depth, parse_spaces, name, *(uint64_t *)data);
+ break;
+
+ case PW_TYPE_SIGNED:
+ *(int32_t *)data = strtol(value, 0, 0);
+ cf_log_info(cs, "%.*s\t%s = %d", cs->depth, parse_spaces, name, *(int32_t *)data);
+ break;
+
+ case PW_TYPE_STRING:
+ q = (char **) data;
+ if (*q != NULL) {
+ talloc_free(*q);
+ }
+
+ /*
+ * Expand variables which haven't already been
+ * expanded automagically when the configuration
+ * file was read.
+ */
+ if (value == dflt) {
+ int lineno = 0;
+
+ lineno = cs->item.lineno;
+
+ value = cf_expand_variables("<internal>",
+ &lineno,
+ cs, buffer, sizeof(buffer),
+ value, NULL);
+ if (!value) {
+ cf_log_err(&(cs->item),"Failed expanding variable %s", name);
+ return -1;
+ }
+ }
+
+ if (cant_be_empty && (value[0] == '\0')) goto cant_be_empty;
+
+ if (attribute) {
+ if (!dict_attrbyname(value)) {
+ if (!cp) {
+ cf_log_err(&(cs->item), "No such attribute '%s' for configuration '%s'",
+ value, name);
+ } else {
+ cf_log_err(&(cp->item), "No such attribute '%s'", value);
+ }
+ return -1;
+ }
+ }
+
+ /*
+ * Hide secrets when using "radiusd -X".
+ */
+ if (secret && (rad_debug_lvl <= 2)) {
+ cf_log_info(cs, "%.*s\t%s = <<< secret >>>",
+ cs->depth, parse_spaces, name);
+ } else {
+ cf_log_info(cs, "%.*s\t%s = \"%s\"",
+ cs->depth, parse_spaces, name, value ? value : "(null)");
+ }
+ *q = value ? talloc_typed_strdup(cs, value) : NULL;
+
+ /*
+ * If there's data AND it's an input file, check
+ * that we can read it. This check allows errors
+ * to be caught as early as possible, during
+ * server startup.
+ */
+ if (*q && file_input && !cf_file_check(cs, *q, true)) {
+ cf_log_err(&(cs->item), "Failed parsing configuration item \"%s\"", name);
+ return -1;
+ }
+
+ if (*q && file_exists && !cf_file_check(cs, *q, false)) {
+ cf_log_err(&(cs->item), "Failed parsing configuration item \"%s\"", name);
+ return -1;
+ }
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton4(ipaddr, value, -1, true, false) < 0) {
+ failed:
+ cf_log_err(&(cs->item), "Failed parsing configuration item \"%s\" - %s", name, fr_strerror());
+ return -1;
+ }
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV6_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton6(ipaddr, value, -1, true, false) < 0) goto failed;
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
+ break;
+
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_COMBO_IP_PREFIX:
+ ipaddr = data;
+
+ if (fr_pton(ipaddr, value, -1, AF_UNSPEC, true) < 0) goto failed;
+ if (fr_item_validate_ipaddr(cs, name, type, value, ipaddr) < 0) return -1;
+ break;
+
+ case PW_TYPE_TIMEVAL: {
+ int sec;
+ char *end;
+ struct timeval tv;
+
+ sec = strtoul(value, &end, 10);
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ if (*end == '.') {
+ size_t len;
+
+ len = strlen(end + 1);
+
+ if (len > 6) {
+ cf_log_err(&(cs->item), "Too much precision for timeval");
+ return -1;
+ }
+
+ /*
+ * If they write "0.1", that means
+ * "10000" microseconds.
+ */
+ sec = strtoul(end + 1, NULL, 10);
+ while (len < 6) {
+ sec *= 10;
+ len++;
+ }
+
+ tv.tv_usec = sec;
+ }
+ cf_log_info(cs, "%.*s\t%s = %d.%06d",
+ cs->depth, parse_spaces, name, (int) tv.tv_sec, (int) tv.tv_usec);
+ memcpy(data, &tv, sizeof(tv));
+ }
+ break;
+
+ default:
+ /*
+ * If we get here, it's a sanity check error.
+ * It's not an error parsing the configuration
+ * file.
+ */
+ rad_assert(type > PW_TYPE_INVALID);
+ rad_assert(type < PW_TYPE_MAX);
+
+ cf_log_err(&(cs->item), "type '%s' is not supported in the configuration files",
+ fr_int2str(dict_attr_types, type, "?Unknown?"));
+ return -1;
+ } /* switch over variable type */
+
+ if (!cp) {
+ CONF_PAIR *cpn;
+
+ cpn = cf_pair_alloc(cs, name, value, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ if (!cpn) return -1;
+ cpn->parsed = true;
+ cpn->item.filename = "<internal>";
+ cpn->item.lineno = 0;
+ cf_item_add(cs, &(cpn->item));
+ }
+
+ return rcode;
+}
+
+
+/*
+ * A copy of cf_section_parse that initializes pointers before
+ * parsing them.
+ */
+static void cf_section_parse_init(CONF_SECTION *cs, void *base,
+ CONF_PARSER const *variables)
+{
+ int i;
+ void *data;
+
+ for (i = 0; variables[i].name != NULL; i++) {
+ if (variables[i].type == PW_TYPE_SUBSECTION) {
+ CONF_SECTION *subcs;
+
+ if (!variables[i].dflt) continue;
+
+ subcs = cf_section_sub_find(cs, variables[i].name);
+
+ /*
+ * If there's no subsection in the
+ * config, BUT the CONF_PARSER wants one,
+ * then create an empty one. This is so
+ * that we can track the strings,
+ * etc. allocated in the subsection.
+ */
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, variables[i].name, NULL);
+ if (!subcs) return;
+
+ subcs->item.filename = cs->item.filename;
+ subcs->item.lineno = cs->item.lineno;
+ cf_item_add(cs, &(subcs->item));
+ }
+ if (base) {
+ data = ((uint8_t *)base) + variables[i].offset;
+ } else {
+ data = NULL;
+ }
+
+ cf_section_parse_init(subcs, data, (CONF_PARSER const *) variables[i].dflt);
+ continue;
+ }
+
+ if ((variables[i].type != PW_TYPE_STRING) &&
+ (variables[i].type != PW_TYPE_FILE_INPUT) &&
+ (variables[i].type != PW_TYPE_FILE_OUTPUT)) {
+ continue;
+ }
+
+ if (variables[i].data) {
+ *(char **) variables[i].data = NULL;
+ } else if (base) {
+ *(char **) (((char *)base) + variables[i].offset) = NULL;
+ } else {
+ continue;
+ }
+ } /* for all variables in the configuration section */
+}
+
+
+static void cf_section_parse_warn(CONF_SECTION *cs)
+{
+ CONF_ITEM *ci;
+
+ for (ci = cs->children; ci; ci = ci->next) {
+ /*
+ * Don't recurse on sections. We can only safely
+ * check conf pairs at the same level as the
+ * section that was just parsed.
+ */
+ if (ci->type == CONF_ITEM_SECTION) continue;
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp;
+
+ cp = cf_item_to_pair(ci);
+ if (cp->parsed) continue;
+
+ WARN("%s[%d]: The item '%s' is defined, but is unused by the configuration",
+ cp->item.filename ? cp->item.filename : "unknown",
+ cp->item.lineno ? cp->item.lineno : 0,
+ cp->attr);
+ }
+
+ /*
+ * Skip everything else.
+ */
+ }
+}
+
+/** Parse a configuration section into user-supplied variables
+ *
+ * @param cs to parse.
+ * @param base pointer to a struct to fill with data. Any buffers will also be talloced
+ * using this parent as a pointer.
+ * @param variables mappings between struct fields and #CONF_ITEM s.
+ * @return
+ * - 0 on success.
+ * - -1 on general error.
+ * - -2 if a deprecated #CONF_ITEM was found.
+ */
+int cf_section_parse(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
+{
+ int ret = 0;
+ int i;
+ void *data;
+
+ cs->variables = variables; /* this doesn't hurt anything */
+
+ if (!cs->name2) {
+ cf_log_info(cs, "%.*s%s {", cs->depth, parse_spaces, cs->name1);
+ } else {
+ cf_log_info(cs, "%.*s%s %s {", cs->depth, parse_spaces, cs->name1, cs->name2);
+ }
+
+ cf_section_parse_init(cs, base, variables);
+
+ /*
+ * Handle the known configuration parameters.
+ */
+ for (i = 0; variables[i].name != NULL; i++) {
+ /*
+ * Handle subsections specially
+ */
+ if (variables[i].type == PW_TYPE_SUBSECTION) {
+ CONF_SECTION *subcs;
+
+ subcs = cf_section_sub_find(cs, variables[i].name);
+ /*
+ * Default in this case is overloaded to mean a pointer
+ * to the CONF_PARSER struct for the subsection.
+ */
+ if (!variables[i].dflt || !subcs) {
+ ERROR("Internal sanity check 1 failed in cf_section_parse %s", variables[i].name);
+ ret = -1;
+ goto finish;
+ }
+
+ if (base) {
+ data = ((uint8_t *)base) + variables[i].offset;
+ } else {
+ data = NULL;
+ }
+
+ ret = cf_section_parse(subcs, data, (CONF_PARSER const *) variables[i].dflt);
+ if (ret < 0) goto finish;
+ continue;
+ } /* else it's a CONF_PAIR */
+
+ if (variables[i].data) {
+ data = variables[i].data; /* prefer this. */
+ } else if (base) {
+ data = ((char *)base) + variables[i].offset;
+ } else {
+ ERROR("Internal sanity check 2 failed in cf_section_parse");
+ ret = -1;
+ goto finish;
+ }
+
+ /*
+ * Parse the pair we found, or a default value.
+ */
+ ret = cf_item_parse(cs, variables[i].name, variables[i].type, data, variables[i].dflt);
+ switch (ret) {
+ case 1: /* Used default */
+ ret = 0;
+ break;
+
+ case 0: /* OK */
+ break;
+
+ case -1: /* Parse error */
+ goto finish;
+
+ case -2: /* Deprecated CONF ITEM */
+ if ((variables[i + 1].offset == variables[i].offset) &&
+ (variables[i + 1].data == variables[i].data)) {
+ cf_log_err(&(cs->item), "Replace \"%s\" with \"%s\"", variables[i].name,
+ variables[i + 1].name);
+ } else {
+ cf_log_err(&(cs->item), "Cannot use deprecated configuration item \"%s\"", variables[i].name);
+ }
+ goto finish;
+ }
+ } /* for all variables in the configuration section */
+
+ /*
+ * Ensure we have a proper terminator, type so we catch
+ * missing terminators reliably
+ */
+ rad_assert(variables[i].type == -1);
+
+ /*
+ * Warn about items in the configuration which weren't
+ * checked during parsing.
+ */
+ if (rad_debug_lvl >= 3) cf_section_parse_warn(cs);
+
+ cs->base = base;
+
+ cf_log_info(cs, "%.*s}", cs->depth, parse_spaces);
+
+finish:
+ return ret;
+}
+
+
+/*
+ * Check XLAT things in pass 2. But don't cache the xlat stuff anywhere.
+ */
+int cf_section_parse_pass2(CONF_SECTION *cs, void *base, CONF_PARSER const *variables)
+{
+ int i;
+ ssize_t slen;
+ char const *error;
+ char *value = NULL;
+ xlat_exp_t *xlat;
+
+ /*
+ * Handle the known configuration parameters.
+ */
+ for (i = 0; variables[i].name != NULL; i++) {
+ CONF_PAIR *cp;
+ void *data;
+
+ /*
+ * Handle subsections specially
+ */
+ if (variables[i].type == PW_TYPE_SUBSECTION) {
+ CONF_SECTION *subcs;
+ subcs = cf_section_sub_find(cs, variables[i].name);
+
+ if (cf_section_parse_pass2(subcs, (uint8_t *)base + variables[i].offset,
+ (CONF_PARSER const *) variables[i].dflt) < 0) {
+ return -1;
+ }
+ continue;
+ } /* else it's a CONF_PAIR */
+
+ /*
+ * Figure out which data we need to fix.
+ */
+ if (variables[i].data) {
+ data = variables[i].data; /* prefer this. */
+ } else if (base) {
+ data = ((char *)base) + variables[i].offset;
+ } else {
+ data = NULL;
+ }
+
+ cp = cf_pair_find(cs, variables[i].name);
+ xlat = NULL;
+
+ redo:
+ if (!cp || !cp->value || !data) continue;
+
+ if ((cp->rhs_type != T_DOUBLE_QUOTED_STRING) &&
+ (cp->rhs_type != T_BARE_WORD)) continue;
+
+ /*
+ * Non-xlat expansions shouldn't have xlat!
+ */
+ if (((variables[i].type & PW_TYPE_XLAT) == 0) &&
+ ((variables[i].type & PW_TYPE_TMPL) == 0)) {
+ /*
+ * Ignore %{... in shared secrets.
+ * They're never dynamically expanded.
+ */
+ if ((variables[i].type & PW_TYPE_SECRET) != 0) continue;
+
+ if (strstr(cp->value, "%{") != NULL) {
+ WARN("%s[%d]: Found dynamic expansion in string which will not be dynamically expanded",
+ cp->item.filename ? cp->item.filename : "unknown",
+ cp->item.lineno ? cp->item.lineno : 0);
+ }
+ continue;
+ }
+
+ /*
+ * Parse (and throw away) the xlat string.
+ *
+ * FIXME: All of these should be converted from PW_TYPE_XLAT
+ * to PW_TYPE_TMPL.
+ */
+ if ((variables[i].type & PW_TYPE_XLAT) != 0) {
+ /*
+ * xlat expansions should be parseable.
+ */
+ value = talloc_strdup(cs, cp->value); /* modified by xlat_tokenize */
+ xlat = NULL;
+
+ slen = xlat_tokenize(cs, value, &xlat, &error);
+ if (slen < 0) {
+ char *spaces, *text;
+
+ error:
+ fr_canonicalize_error(cs, &spaces, &text, slen, cp->value);
+
+ cf_log_err(&cp->item, "Failed parsing expanded string:");
+ cf_log_err(&cp->item, "%s", text);
+ cf_log_err(&cp->item, "%s^ %s", spaces, error);
+
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(value);
+ talloc_free(xlat);
+ return -1;
+ }
+
+ talloc_free(value);
+ talloc_free(xlat);
+ }
+
+ /*
+ * Convert the LITERAL template to the actual
+ * type.
+ */
+ if ((variables[i].type & PW_TYPE_TMPL) != 0) {
+ vp_tmpl_t *vpt;
+
+ slen = tmpl_afrom_str(cs, &vpt, cp->value, talloc_array_length(cp->value) - 1,
+ cp->rhs_type,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) {
+ error = fr_strerror();
+ goto error;
+ }
+
+ /*
+ * Sanity check
+ *
+ * Don't add default - update with new types.
+ */
+ switch (vpt->type) {
+ /*
+ * All attributes should have been defined by this point.
+ */
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ cf_log_err(&cp->item, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
+ return -1;
+
+ case TMPL_TYPE_LITERAL:
+ case TMPL_TYPE_ATTR:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_DATA:
+ case TMPL_TYPE_EXEC:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ break;
+
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_REGEX_STRUCT:
+ case TMPL_TYPE_NULL:
+ rad_assert(0);
+ }
+
+ talloc_free(*(vp_tmpl_t **)data);
+ *(vp_tmpl_t **)data = vpt;
+ }
+
+ /*
+ * If the "multi" flag is set, check all of them.
+ */
+ if ((variables[i].type & PW_TYPE_MULTI) != 0) {
+ cp = cf_pair_find_next(cs, cp, cp->attr);
+ goto redo;
+ }
+ } /* for all variables in the configuration section */
+
+ return 0;
+}
+
+/*
+ * Merge the template so everyting else "just works".
+ */
+static bool cf_template_merge(CONF_SECTION *cs, CONF_SECTION const *template)
+{
+ CONF_ITEM *ci;
+
+ if (!cs || !template) return true;
+
+ cs->template = NULL;
+
+ /*
+ * Walk over the template, adding its' entries to the
+ * current section. But only if the entries don't
+ * already exist in the current section.
+ */
+ for (ci = template->children; ci; ci = ci->next) {
+ if (ci->type == CONF_ITEM_PAIR) {
+ CONF_PAIR *cp1, *cp2;
+
+ /*
+ * It exists, don't over-write it.
+ */
+ cp1 = cf_item_to_pair(ci);
+ if (cf_pair_find(cs, cp1->attr)) {
+ continue;
+ }
+
+ /*
+ * Create a new pair with all of the data
+ * of the old one.
+ */
+ cp2 = cf_pair_dup(cs, cp1);
+ if (!cp2) return false;
+
+ cp2->item.filename = cp1->item.filename;
+ cp2->item.lineno = cp1->item.lineno;
+
+ cf_item_add(cs, &(cp2->item));
+ continue;
+ }
+
+ if (ci->type == CONF_ITEM_SECTION) {
+ CONF_SECTION *subcs1, *subcs2;
+
+ subcs1 = cf_item_to_section(ci);
+ rad_assert(subcs1 != NULL);
+
+ subcs2 = cf_section_sub_find_name2(cs, subcs1->name1, subcs1->name2);
+ if (subcs2) {
+ /*
+ * sub-sections get merged.
+ */
+ if (!cf_template_merge(subcs2, subcs1)) {
+ return false;
+ }
+ continue;
+ }
+
+ /*
+ * Our section doesn't have a matching
+ * sub-section. Copy it verbatim from
+ * the template.
+ */
+ subcs2 = cf_section_dup(cs, subcs1,
+ cf_section_name1(subcs1), cf_section_name2(subcs1),
+ false);
+ if (!subcs2) return false;
+
+ subcs2->item.filename = subcs1->item.filename;
+ subcs2->item.lineno = subcs1->item.lineno;
+
+ cf_item_add(cs, &(subcs2->item));
+ continue;
+ }
+
+ /* ignore everything else */
+ }
+
+ return true;
+}
+
+static char const *cf_local_file(char const *base, char const *filename,
+ char *buffer, size_t bufsize)
+{
+ size_t dirsize;
+ char *p;
+
+ strlcpy(buffer, base, bufsize);
+
+ p = strrchr(buffer, FR_DIR_SEP);
+ if (!p) return filename;
+ if (p[1]) { /* ./foo */
+ p[1] = '\0';
+ }
+
+ dirsize = (p - buffer) + 1;
+
+ if ((dirsize + strlen(filename)) >= bufsize) {
+ return NULL;
+ }
+
+ strlcpy(p + 1, filename, bufsize - dirsize);
+
+ return buffer;
+}
+
+
+/*
+ * Read a part of the config file.
+ */
+static int cf_section_read(char const *filename, int *lineno, FILE *fp,
+ CONF_SECTION *current)
+
+{
+ CONF_SECTION *this, *css;
+ CONF_PAIR *cpn;
+ char const *ptr;
+ char const *value;
+ char buf[8192];
+ char buf1[8192];
+ char buf2[8192];
+ char buf3[8192];
+ char buf4[8192];
+ FR_TOKEN t1 = T_INVALID, t2, t3;
+ bool has_spaces = false;
+ bool pass2;
+ char *cbuf = buf;
+ size_t len;
+
+ this = current; /* add items here */
+
+ /*
+ * Read, checking for line continuations ('\\' at EOL)
+ */
+ for (;;) {
+ int at_eof;
+ css = NULL;
+
+ /*
+ * Get data, and remember if we are at EOF.
+ */
+ at_eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL);
+ (*lineno)++;
+
+ /*
+ * We read the entire 8k worth of data: complain.
+ * Note that we don't care if the last character
+ * is \n: it's still forbidden. This means that
+ * the maximum allowed length of text is 8k-1, which
+ * should be plenty.
+ */
+ len = strlen(cbuf);
+ if ((cbuf + len + 1) >= (buf + sizeof(buf))) {
+ ERROR("%s[%d]: Line too long",
+ filename, *lineno);
+ return -1;
+ }
+
+ if (has_spaces) {
+ ptr = cbuf;
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ if (ptr > cbuf) {
+ memmove(cbuf, ptr, len - (ptr - cbuf));
+ len -= (ptr - cbuf);
+ }
+ }
+
+ /*
+ * Not doing continuations: check for edge
+ * conditions.
+ */
+ if (cbuf == buf) {
+ if (at_eof) break;
+
+ ptr = buf;
+ while (*ptr && isspace((uint8_t) *ptr)) ptr++;
+
+ if (!*ptr || (*ptr == '#')) continue;
+
+ } else if (at_eof || (len == 0)) {
+ ERROR("%s[%d]: Continuation at EOF is illegal",
+ filename, *lineno);
+ return -1;
+ }
+
+ /*
+ * See if there's a continuation.
+ */
+ while ((len > 0) &&
+ ((cbuf[len - 1] == '\n') || (cbuf[len - 1] == '\r'))) {
+ len--;
+ cbuf[len] = '\0';
+ }
+
+ if ((len > 0) && (cbuf[len - 1] == '\\')) {
+ /*
+ * Check for "suppress spaces" magic.
+ */
+ if (!has_spaces && (len > 2) && (cbuf[len - 2] == '"')) {
+ has_spaces = true;
+ }
+
+ cbuf[len - 1] = '\0';
+ cbuf += len - 1;
+ continue;
+ }
+
+ ptr = cbuf = buf;
+ has_spaces = false;
+
+ get_more:
+ pass2 = false;
+
+ /*
+ * The parser is getting to be evil.
+ */
+ while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
+
+ if (((ptr[0] == '%') && (ptr[1] == '{')) ||
+ (ptr[0] == '`')) {
+ int hack;
+
+ if (ptr[0] == '%') {
+ hack = rad_copy_variable(buf1, ptr);
+ } else {
+ hack = rad_copy_string(buf1, ptr);
+ }
+ if (hack < 0) {
+ ERROR("%s[%d]: Invalid expansion: %s",
+ filename, *lineno, ptr);
+ return -1;
+ }
+
+ ptr += hack;
+
+ t2 = gettoken(&ptr, buf2, sizeof(buf2), true);
+ switch (t2) {
+ case T_EOL:
+ case T_HASH:
+ goto do_bare_word;
+
+ default:
+ ERROR("%s[%d]: Invalid expansion: %s",
+ filename, *lineno, ptr);
+ return -1;
+ }
+ } else {
+ t1 = gettoken(&ptr, buf1, sizeof(buf1), true);
+ }
+
+ /*
+ * The caller eats "name1 name2 {", and calls us
+ * for the data inside of the section. So if we
+ * receive a closing brace, then it must mean the
+ * end of the section.
+ */
+ if (t1 == T_RCBRACE) {
+ if (this == current) {
+ ERROR("%s[%d]: Too many closing braces",
+ filename, *lineno);
+ return -1;
+ }
+
+ /*
+ * Merge the template into the existing
+ * section. This uses more memory, but
+ * means that templates now work with
+ * sub-sections, etc.
+ */
+ if (!cf_template_merge(this, this->template)) {
+ return -1;
+ }
+
+ this = this->item.parent;
+ goto check_for_more;
+ }
+
+ if (t1 != T_BARE_WORD) goto skip_keywords;
+
+ /*
+ * Allow for $INCLUDE files
+ *
+ * This *SHOULD* work for any level include.
+ * I really really really hate this file. -cparker
+ */
+ if ((strcasecmp(buf1, "$INCLUDE") == 0) ||
+ (strcasecmp(buf1, "$-INCLUDE") == 0)) {
+ bool relative = true;
+
+ t2 = getword(&ptr, buf2, sizeof(buf2), true);
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $INCLUDE",
+ filename, *lineno);
+ return -1;
+ }
+
+ if (buf2[0] == '$') relative = false;
+
+ value = cf_expand_variables(filename, lineno, this, buf4, sizeof(buf4), buf2, NULL);
+ if (!value) return -1;
+
+ if (!FR_DIR_IS_RELATIVE(value)) relative = false;
+
+ if (relative) {
+ value = cf_local_file(filename, value, buf3,
+ sizeof(buf3));
+ if (!value) {
+ ERROR("%s[%d]: Directories too deep.",
+ filename, *lineno);
+ return -1;
+ }
+ }
+
+
+#ifdef HAVE_DIRENT_H
+ /*
+ * $INCLUDE foo/
+ *
+ * Include ALL non-"dot" files in the directory.
+ * careful!
+ */
+ if (value[strlen(value) - 1] == '/') {
+ DIR *dir;
+ struct dirent *dp;
+ struct stat stat_buf;
+
+ DEBUG2("including files in directory %s", value );
+#ifdef S_IWOTH
+ /*
+ * Security checks.
+ */
+ if (stat(value, &stat_buf) < 0) {
+ ERROR("%s[%d]: Failed reading directory %s: %s",
+ filename, *lineno,
+ value, fr_syserror(errno));
+ return -1;
+ }
+
+ if ((stat_buf.st_mode & S_IWOTH) != 0) {
+ ERROR("%s[%d]: Directory %s is globally writable. Refusing to start due to "
+ "insecure configuration", filename, *lineno, value);
+ return -1;
+ }
+#endif
+ dir = opendir(value);
+ if (!dir) {
+ ERROR("%s[%d]: Error reading directory %s: %s",
+ filename, *lineno, value,
+ fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Read the directory, ignoring "." files.
+ */
+ while ((dp = readdir(dir)) != NULL) {
+ char const *p;
+ int slen;
+
+ if (dp->d_name[0] == '.') continue;
+
+ /*
+ * Check for valid characters
+ */
+ for (p = dp->d_name; *p != '\0'; p++) {
+ if (isalpha((uint8_t)*p) ||
+ isdigit((uint8_t)*p) ||
+ (*p == '-') ||
+ (*p == '_') ||
+ (*p == '.')) continue;
+ break;
+ }
+ if (*p != '\0') continue;
+
+ slen = snprintf(buf2, sizeof(buf2), "%s%s",
+ value, dp->d_name);
+ if (slen >= (int) sizeof(buf2) || slen < 0) {
+ ERROR("%s: Full file path is too long.", dp->d_name);
+ return -1;
+ }
+ if ((stat(buf2, &stat_buf) != 0) ||
+ S_ISDIR(stat_buf.st_mode)) continue;
+
+ /*
+ * Read the file into the current
+ * configuration section.
+ */
+ if (cf_file_include(this, buf2, true) < 0) {
+ closedir(dir);
+ return -1;
+ }
+ }
+ closedir(dir);
+ } else
+#endif
+ { /* it was a normal file */
+ if (buf1[1] == '-') {
+ struct stat statbuf;
+
+ if (stat(value, &statbuf) < 0) {
+ WARN("Not including file %s: %s", value, fr_syserror(errno));
+ continue;
+ }
+ }
+
+ if (cf_file_include(this, value, false) < 0) {
+ return -1;
+ }
+ }
+ continue;
+ } /* we were in an include */
+
+ if (strcasecmp(buf1, "$template") == 0) {
+ CONF_ITEM *ci;
+ CONF_SECTION *parentcs, *templatecs;
+ t2 = getword(&ptr, buf2, sizeof(buf2), true);
+
+ if (t2 != T_EOL) {
+ ERROR("%s[%d]: Unexpected text after $TEMPLATE", filename, *lineno);
+ return -1;
+ }
+
+ parentcs = cf_top_section(current);
+
+ templatecs = cf_section_sub_find(parentcs, "templates");
+ if (!templatecs) {
+ ERROR("%s[%d]: No \"templates\" section for reference \"%s\"", filename, *lineno, buf2);
+ return -1;
+ }
+
+ ci = cf_reference_item(parentcs, templatecs, buf2);
+ if (!ci || (ci->type != CONF_ITEM_SECTION)) {
+ ERROR("%s[%d]: Reference \"%s\" not found", filename, *lineno, buf2);
+ return -1;
+ }
+
+ if (!this) {
+ ERROR("%s[%d]: Internal sanity check error in template reference", filename, *lineno);
+ return -1;
+ }
+
+ if (this->template) {
+ ERROR("%s[%d]: Section already has a template", filename, *lineno);
+ return -1;
+ }
+
+ this->template = cf_item_to_section(ci);
+ continue;
+ }
+
+ /*
+ * Ensure that the user can't add CONF_PAIRs
+ * with 'internal' names;
+ */
+ if (buf1[0] == '_') {
+ ERROR("%s[%d]: Illegal configuration pair name \"%s\"", filename, *lineno, buf1);
+ return -1;
+ }
+
+ /*
+ * Handle if/elsif specially.
+ */
+ if ((strcmp(buf1, "if") == 0) || (strcmp(buf1, "elsif") == 0)) {
+ ssize_t slen;
+ char const *error = NULL;
+ char *p;
+ CONF_SECTION *server;
+ fr_cond_t *cond = NULL;
+
+ /*
+ * if / elsif MUST be inside of a
+ * processing section, which MUST in turn
+ * be inside of a "server" directive.
+ */
+ if (!this->item.parent) {
+ invalid_location:
+ ERROR("%s[%d]: Invalid location for '%s'",
+ filename, *lineno, buf1);
+ return -1;
+ }
+
+ /*
+ * Can only have "if" in 3 named sections.
+ */
+ server = this->item.parent;
+ while (server &&
+ (strcmp(server->name1, "server") != 0) &&
+ (strcmp(server->name1, "policy") != 0) &&
+ (strcmp(server->name1, "instantiate") != 0)) {
+ server = server->item.parent;
+ if (!server) goto invalid_location;
+ }
+
+ /*
+ * Skip (...) to find the {
+ */
+ slen = fr_condition_tokenize(this, cf_section_to_item(this), ptr, &cond,
+ &error, FR_COND_TWO_PASS);
+ memcpy(&p, &ptr, sizeof(p));
+
+ if (slen < 0) {
+ if (p[-slen] != '{') goto cond_error;
+ slen = -slen;
+ }
+ TALLOC_FREE(cond);
+
+ /*
+ * This hack is so that the NEXT stage
+ * doesn't go "too far" in expanding the
+ * variable. We can parse the conditions
+ * without expanding the ${...} stuff.
+ * BUT we don't want to expand all of the
+ * stuff AFTER the condition. So we do
+ * two passes.
+ *
+ * The first pass is to discover the end
+ * of the condition. We then expand THAT
+ * string, and do a second pass parsing
+ * the expanded condition.
+ */
+ p += slen;
+ *p = '\0';
+
+ /*
+ * If there's a ${...}. If so, expand it.
+ */
+ if (strchr(ptr, '$') != NULL) {
+ ptr = cf_expand_variables(filename, lineno,
+ this,
+ buf3, sizeof(buf3),
+ ptr, NULL);
+ if (!ptr) {
+ ERROR("%s[%d]: Parse error expanding ${...} in condition",
+ filename, *lineno);
+ return -1;
+ }
+ } /* else leave it alone */
+
+ css = cf_section_alloc(this, buf1, ptr);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section",
+ filename, *lineno);
+ return -1;
+ }
+ css->item.filename = filename;
+ css->item.lineno = *lineno;
+
+ slen = fr_condition_tokenize(css, cf_section_to_item(css), ptr, &cond,
+ &error, FR_COND_TWO_PASS);
+ *p = '{'; /* put it back */
+
+ cond_error:
+ if (slen < 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(this, &spaces, &text, slen, ptr);
+
+ ERROR("%s[%d]: Parse error in condition",
+ filename, *lineno);
+ ERROR("%s[%d]: %s", filename, *lineno, text);
+ ERROR("%s[%d]: %s^ %s", filename, *lineno, spaces, error);
+
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(css);
+ return -1;
+ }
+
+ if ((size_t) slen >= (sizeof(buf2) - 1)) {
+ talloc_free(css);
+ ERROR("%s[%d]: Condition is too large after \"%s\"",
+ filename, *lineno, buf1);
+ return -1;
+ }
+
+ /*
+ * Copy the expanded and parsed condition
+ * into buf2. Then, parse the text after
+ * the condition, which now MUST be a '{.
+ *
+ * If it wasn't '{' it would have been
+ * caught in the first pass of
+ * conditional parsing, above.
+ */
+ memcpy(buf2, ptr, slen);
+ buf2[slen] = '\0';
+ ptr = p;
+
+ if ((t3 = gettoken(&ptr, buf3, sizeof(buf3), true)) != T_LCBRACE) {
+ talloc_free(css);
+ ERROR("%s[%d]: Expected '{' %d",
+ filename, *lineno, t3);
+ return -1;
+ }
+
+ /*
+ * Swap the condition with trailing stuff for
+ * the final condition.
+ */
+ memcpy(&p, &css->name2, sizeof(css->name2));
+ talloc_free(p);
+ css->name2 = talloc_typed_strdup(css, buf2);
+
+ cf_item_add(this, &(css->item));
+ cf_data_add_internal(css, "if", cond, NULL, false);
+
+ /*
+ * The current section is now the child section.
+ */
+ this = css;
+ css = NULL;
+ goto check_for_more;
+ }
+
+ skip_keywords:
+ /*
+ * Grab the next token.
+ */
+ t2 = gettoken(&ptr, buf2, sizeof(buf2), !cf_new_escape);
+ switch (t2) {
+ case T_EOL:
+ case T_HASH:
+ case T_COMMA:
+ do_bare_word:
+ t3 = t2;
+ t2 = T_OP_EQ;
+ value = NULL;
+ goto do_set;
+
+ case T_OP_INCRM:
+ case T_OP_ADD:
+ case T_OP_CMP_EQ:
+ case T_OP_SUB:
+ case T_OP_LE:
+ case T_OP_GE:
+ case T_OP_CMP_FALSE:
+ if (!this || (strcmp(this->name1, "update") != 0)) {
+ ERROR("%s[%d]: Invalid operator in assignment",
+ filename, *lineno);
+ return -1;
+ }
+ /* FALL-THROUGH */
+
+ case T_OP_EQ:
+ case T_OP_SET:
+ case T_OP_PREPEND:
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ /*
+ * Be a little more forgiving.
+ */
+ if (*ptr == '#') {
+ t3 = T_HASH;
+ } else
+
+ /*
+ * New parser: non-quoted strings are
+ * bare words, and we parse everything
+ * until the next newline, or the next
+ * comma. If they have { or } in a bare
+ * word, well... too bad.
+ */
+ if (cf_new_escape && (*ptr != '"') && (*ptr != '\'')
+ && (*ptr != '`') && (*ptr != '/')) {
+ const char *q = ptr;
+
+ t3 = T_BARE_WORD;
+ while (*q && (*q >= ' ') && (*q != ',') &&
+ !isspace((uint8_t) *q)) q++;
+
+ if ((size_t) (q - ptr) >= sizeof(buf3)) {
+ ERROR("%s[%d]: Parse error: value too long",
+ filename, *lineno);
+ return -1;
+ }
+
+ memcpy(buf3, ptr, (q - ptr));
+ buf3[q - ptr] = '\0';
+ ptr = q;
+
+ } else {
+ t3 = getstring(&ptr, buf3, sizeof(buf3), !cf_new_escape);
+ }
+
+ if (t3 == T_INVALID) {
+ ERROR("%s[%d]: Parse error: %s",
+ filename, *lineno,
+ fr_strerror());
+ return -1;
+ }
+
+ /*
+ * Allow "foo" by itself, or "foo = bar"
+ */
+ switch (t3) {
+ bool soft_fail;
+
+ case T_BARE_WORD:
+ case T_DOUBLE_QUOTED_STRING:
+ case T_BACK_QUOTED_STRING:
+ value = cf_expand_variables(filename, lineno, this, buf4, sizeof(buf4), buf3, &soft_fail);
+ if (!value) {
+ if (!soft_fail) return -1;
+
+ /*
+ * References an item which doesn't exist,
+ * or which is already marked up as being
+ * expanded in pass2. Wait for pass2 to
+ * do the expansions.
+ */
+ pass2 = true;
+ value = buf3;
+ }
+ break;
+
+ case T_EOL:
+ case T_HASH:
+ value = NULL;
+ break;
+
+ default:
+ value = buf3;
+ break;
+ }
+
+ /*
+ * Add this CONF_PAIR to our CONF_SECTION
+ */
+ do_set:
+ cpn = cf_pair_alloc(this, buf1, value, t2, t1, t3);
+ if (!cpn) return -1;
+ cpn->item.filename = filename;
+ cpn->item.lineno = *lineno;
+ cpn->pass2 = pass2;
+ cf_item_add(this, &(cpn->item));
+
+ /*
+ * Require a comma, unless there's a comment.
+ */
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ if (*ptr == ',') {
+ ptr++;
+ break;
+ }
+
+ /*
+ * module # stuff!
+ * foo = bar # other stuff
+ */
+ if ((t3 == T_HASH) || (t3 == T_COMMA) || (t3 == T_EOL) || (*ptr == '#')) continue;
+
+ if (!*ptr || (*ptr == '}')) break;
+
+ ERROR("%s[%d]: Syntax error: Expected comma after '%s': %s",
+ filename, *lineno, value, ptr);
+ return -1;
+
+ /*
+ * No '=', must be a section or sub-section.
+ */
+ case T_BARE_WORD:
+ case T_DOUBLE_QUOTED_STRING:
+ case T_SINGLE_QUOTED_STRING:
+ t3 = gettoken(&ptr, buf3, sizeof(buf3), true);
+ if (t3 != T_LCBRACE) {
+ ERROR("%s[%d]: Expecting section start brace '{' after \"%s %s\"",
+ filename, *lineno, buf1, buf2);
+ return -1;
+ }
+ /* FALL-THROUGH */
+
+ case T_LCBRACE:
+ css = cf_section_alloc(this, buf1,
+ t2 == T_LCBRACE ? NULL : buf2);
+ if (!css) {
+ ERROR("%s[%d]: Failed allocating memory for section",
+ filename, *lineno);
+ return -1;
+ }
+
+ css->item.filename = filename;
+ css->item.lineno = *lineno;
+ cf_item_add(this, &(css->item));
+
+ /*
+ * There may not be a name2
+ */
+ css->name2_type = (t2 == T_LCBRACE) ? T_INVALID : t2;
+
+ /*
+ * The current section is now the child section.
+ */
+ this = css;
+ break;
+
+ case T_INVALID:
+ ERROR("%s[%d]: Syntax error in '%s': %s", filename, *lineno, ptr, fr_strerror());
+
+ return -1;
+
+ default:
+ ERROR("%s[%d]: Parse error after \"%s\": unexpected token \"%s\"",
+ filename, *lineno, buf1, fr_int2str(fr_tokens, t2, "<INVALID>"));
+
+ return -1;
+ }
+
+ check_for_more:
+ /*
+ * Done parsing one thing. Skip to EOL if possible.
+ */
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ if (*ptr == '#') continue;
+
+ if (*ptr) {
+ goto get_more;
+ }
+
+ }
+
+ /*
+ * See if EOF was unexpected ..
+ */
+ if (feof(fp) && (this != current)) {
+ ERROR("%s[%d]: EOF reached without closing brace for section %s starting at line %d",
+ filename, *lineno, cf_section_name1(this), cf_section_lineno(this));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Include one config file in another.
+ */
+static int cf_file_include(CONF_SECTION *cs, char const *filename_in, bool from_dir)
+{
+ FILE *fp;
+ int rcode;
+ int lineno = 0;
+ char const *filename;
+
+ /*
+ * So we only need to do this once.
+ */
+ filename = talloc_strdup(cs, filename_in);
+
+ /*
+ * This may return "0" if we already loaded the file.
+ */
+ rcode = cf_file_open(cs, filename, from_dir, &fp);
+ if (rcode <= 0) return rcode;
+
+ if (!cs->item.filename) cs->item.filename = filename;
+
+ /*
+ * Read the section. It's OK to have EOF without a
+ * matching close brace.
+ */
+ if (cf_section_read(filename, &lineno, fp, cs) < 0) {
+ fclose(fp);
+ return -1;
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+
+/*
+ * Do variable expansion in pass2.
+ *
+ * This is a breadth-first expansion. "deep
+ */
+static int cf_section_pass2(CONF_SECTION *cs)
+{
+ CONF_ITEM *ci;
+
+ for (ci = cs->children; ci; ci = ci->next) {
+ char const *value;
+ CONF_PAIR *cp;
+ char buffer[8192];
+
+ if (ci->type != CONF_ITEM_PAIR) continue;
+
+ cp = cf_item_to_pair(ci);
+ if (!cp->value || !cp->pass2) continue;
+
+ rad_assert((cp->rhs_type == T_BARE_WORD) ||
+ (cp->rhs_type == T_DOUBLE_QUOTED_STRING) ||
+ (cp->rhs_type == T_BACK_QUOTED_STRING));
+
+ value = cf_expand_variables(ci->filename, &ci->lineno, cs, buffer, sizeof(buffer), cp->value, NULL);
+ if (!value) return -1;
+
+ rad_const_free(cp->value);
+ cp->value = talloc_typed_strdup(cp, value);
+ }
+
+ for (ci = cs->children; ci; ci = ci->next) {
+ if (ci->type != CONF_ITEM_SECTION) continue;
+
+ if (cf_section_pass2(cf_item_to_section(ci)) < 0) return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Bootstrap a config file.
+ */
+int cf_file_read(CONF_SECTION *cs, char const *filename)
+{
+ char *p;
+ CONF_PAIR *cp;
+ rbtree_t *tree;
+
+ cp = cf_pair_alloc(cs, "confdir", filename, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (!cp) return -1;
+
+ p = strrchr(cp->value, FR_DIR_SEP);
+ if (p) *p = '\0';
+
+ cp->item.filename = "<internal>";
+ cp->item.lineno = -1;
+ cf_item_add(cs, &(cp->item));
+
+ tree = rbtree_create(cs, filename_cmp, NULL, 0);
+ if (!tree) return -1;
+
+ cf_data_add_internal(cs, "filename", tree, NULL, 0);
+
+ if (cf_file_include(cs, filename, false) < 0) return -1;
+
+ /*
+ * Now that we've read the file, go back through it and
+ * expand the variables.
+ */
+ if (cf_section_pass2(cs) < 0) return -1;
+
+ return 0;
+}
+
+
+void cf_file_free(CONF_SECTION *cs)
+{
+ talloc_free(cs);
+}
+
+
+/*
+ * Return a CONF_PAIR within a CONF_SECTION.
+ */
+CONF_PAIR *cf_pair_find(CONF_SECTION const *cs, char const *name)
+{
+ CONF_PAIR *cp, mycp;
+
+ if (!cs || !name) return NULL;
+
+ mycp.attr = name;
+ cp = rbtree_finddata(cs->pair_tree, &mycp);
+ if (cp) return cp;
+
+ if (!cs->template) return NULL;
+
+ return rbtree_finddata(cs->template->pair_tree, &mycp);
+}
+
+/*
+ * Return the attr of a CONF_PAIR
+ */
+
+char const *cf_pair_attr(CONF_PAIR const *pair)
+{
+ return (pair ? pair->attr : NULL);
+}
+
+/*
+ * Return the value of a CONF_PAIR
+ */
+
+char const *cf_pair_value(CONF_PAIR const *pair)
+{
+ return (pair ? pair->value : NULL);
+}
+
+FR_TOKEN cf_pair_operator(CONF_PAIR const *pair)
+{
+ return (pair ? pair->op : T_INVALID);
+}
+
+/** Return the value (lhs) type
+ *
+ * @param pair to extract value type from.
+ * @return one of T_BARE_WORD, T_SINGLE_QUOTED_STRING, T_BACK_QUOTED_STRING
+ * T_DOUBLE_QUOTED_STRING or T_INVALID if the pair is NULL.
+ */
+FR_TOKEN cf_pair_attr_type(CONF_PAIR const *pair)
+{
+ return (pair ? pair->lhs_type : T_INVALID);
+}
+
+/** Return the value (rhs) type
+ *
+ * @param pair to extract value type from.
+ * @return one of T_BARE_WORD, T_SINGLE_QUOTED_STRING, T_BACK_QUOTED_STRING
+ * T_DOUBLE_QUOTED_STRING or T_INVALID if the pair is NULL.
+ */
+FR_TOKEN cf_pair_value_type(CONF_PAIR const *pair)
+{
+ return (pair ? pair->rhs_type : T_INVALID);
+}
+
+/*
+ * Turn a CONF_PAIR into a VALUE_PAIR
+ * For now, ignore the "value_type" field...
+ */
+VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair)
+{
+ if (!pair) {
+ fr_strerror_printf("Internal error");
+ return NULL;
+ }
+
+ if (!pair->value) {
+ fr_strerror_printf("No value given for attribute %s", pair->attr);
+ return NULL;
+ }
+
+ /*
+ * false comparisons never match. BUT if it's a "string"
+ * or `string`, then remember to expand it later.
+ */
+ if ((pair->op != T_OP_CMP_FALSE) &&
+ ((pair->rhs_type == T_DOUBLE_QUOTED_STRING) ||
+ (pair->rhs_type == T_BACK_QUOTED_STRING))) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_make(pair, NULL, pair->attr, NULL, pair->op);
+ if (!vp) {
+ return NULL;
+ }
+
+ if (fr_pair_mark_xlat(vp, pair->value) < 0) {
+ talloc_free(vp);
+
+ return NULL;
+ }
+
+ return vp;
+ }
+
+ return fr_pair_make(pair, NULL, pair->attr, pair->value, pair->op);
+}
+
+/*
+ * Return the first label of a CONF_SECTION
+ */
+
+char const *cf_section_name1(CONF_SECTION const *cs)
+{
+ return (cs ? cs->name1 : NULL);
+}
+
+/*
+ * Return the second label of a CONF_SECTION
+ */
+
+char const *cf_section_name2(CONF_SECTION const *cs)
+{
+ return (cs ? cs->name2 : NULL);
+}
+
+/** Return name2 if set, else name1
+ *
+ */
+char const *cf_section_name(CONF_SECTION const *cs)
+{
+ char const *name;
+
+ name = cf_section_name2(cs);
+ if (name) return name;
+
+ return cf_section_name1(cs);
+}
+
+/*
+ * Find a value in a CONF_SECTION
+ */
+char const *cf_section_value_find(CONF_SECTION const *cs, char const *attr)
+{
+ CONF_PAIR *cp;
+
+ cp = cf_pair_find(cs, attr);
+
+ return (cp ? cp->value : NULL);
+}
+
+
+CONF_SECTION *cf_section_find_name2(CONF_SECTION const *cs,
+ char const *name1, char const *name2)
+{
+ char const *their2;
+ CONF_ITEM const *ci;
+
+ if (!cs || !name1) return NULL;
+
+ for (ci = &(cs->item); ci; ci = ci->next) {
+ if (ci->type != CONF_ITEM_SECTION)
+ continue;
+
+ if (strcmp(cf_item_to_section(ci)->name1, name1) != 0) {
+ continue;
+ }
+
+ their2 = cf_item_to_section(ci)->name2;
+
+ if ((!name2 && !their2) ||
+ (name2 && their2 && (strcmp(name2, their2) == 0))) {
+ return cf_item_to_section(ci);
+ }
+ }
+
+ return NULL;
+}
+
+/** Find a pair with a name matching attr, after specified pair.
+ *
+ * @param cs to search in.
+ * @param pair to search from (may be NULL).
+ * @param attr to find (may be NULL in which case any attribute matches).
+ * @return the next matching CONF_PAIR or NULL if none matched.
+ */
+CONF_PAIR *cf_pair_find_next(CONF_SECTION const *cs,
+ CONF_PAIR const *pair, char const *attr)
+{
+ CONF_ITEM *ci;
+
+ if (!cs) return NULL;
+
+ /*
+ * If pair is NULL and we're trying to find a specific
+ * attribute this must be a first time run.
+ *
+ * Find the pair with correct name.
+ */
+ if (!pair && attr) return cf_pair_find(cs, attr);
+
+ /*
+ * Start searching from the next child, or from the head
+ * of the list of children (if no pair was provided).
+ */
+ for (ci = pair ? pair->item.next : cs->children;
+ ci;
+ ci = ci->next) {
+ if (ci->type != CONF_ITEM_PAIR) continue;
+
+ if (!attr || strcmp(cf_item_to_pair(ci)->attr, attr) == 0) break;
+ }
+
+ return cf_item_to_pair(ci);
+}
+
+/*
+ * Find a CONF_SECTION, or return the root if name is NULL
+ */
+
+CONF_SECTION *cf_section_find(char const *name)
+{
+ if (name)
+ return cf_section_sub_find(root_config, name);
+ else
+ return root_config;
+}
+
+/** Find a sub-section in a section
+ *
+ * This finds ANY section having the same first name.
+ * The second name is ignored.
+ */
+CONF_SECTION *cf_section_sub_find(CONF_SECTION const *cs, char const *name)
+{
+ CONF_SECTION mycs;
+
+ if (!cs || !name) return NULL; /* can't find an un-named section */
+
+ /*
+ * No sub-sections have been defined, so none exist.
+ */
+ if (!cs->section_tree) return NULL;
+
+ mycs.name1 = name;
+ mycs.name2 = NULL;
+ return rbtree_finddata(cs->section_tree, &mycs);
+}
+
+
+/** Find a CONF_SECTION with both names.
+ *
+ */
+CONF_SECTION *cf_section_sub_find_name2(CONF_SECTION const *cs,
+ char const *name1, char const *name2)
+{
+ CONF_ITEM *ci;
+
+ if (!cs) cs = root_config;
+ if (!cs) return NULL;
+
+ if (name1) {
+ CONF_SECTION mycs, *master_cs;
+
+ if (!cs->section_tree) return NULL;
+
+ mycs.name1 = name1;
+ mycs.name2 = name2;
+
+ master_cs = rbtree_finddata(cs->section_tree, &mycs);
+ if (!master_cs) return NULL;
+
+ /*
+ * Look it up in the name2 tree. If it's there,
+ * return it.
+ */
+ if (master_cs->name2_tree) {
+ CONF_SECTION *subcs;
+
+ subcs = rbtree_finddata(master_cs->name2_tree, &mycs);
+ if (subcs) return subcs;
+ }
+
+ /*
+ * We don't insert ourselves into the name2 tree.
+ * So if there's nothing in the name2 tree, maybe
+ * *we* are the answer.
+ */
+ if (!master_cs->name2 && name2) return NULL;
+ if (master_cs->name2 && !name2) return NULL;
+ if (!master_cs->name2 && !name2) return master_cs;
+
+ if (strcmp(master_cs->name2, name2) == 0) {
+ return master_cs;
+ }
+
+ return NULL;
+ }
+
+ /*
+ * Else do it the old-fashioned way.
+ */
+ for (ci = cs->children; ci; ci = ci->next) {
+ CONF_SECTION *subcs;
+
+ if (ci->type != CONF_ITEM_SECTION)
+ continue;
+
+ subcs = cf_item_to_section(ci);
+ if (!subcs->name2) {
+ if (strcmp(subcs->name1, name2) == 0) break;
+ } else {
+ if (strcmp(subcs->name2, name2) == 0) break;
+ }
+ }
+
+ return cf_item_to_section(ci);
+}
+
+/*
+ * Return the next subsection after a CONF_SECTION
+ * with a certain name1 (char *name1). If the requested
+ * name1 is NULL, any name1 matches.
+ */
+
+CONF_SECTION *cf_subsection_find_next(CONF_SECTION const *section,
+ CONF_SECTION const *subsection,
+ char const *name1)
+{
+ CONF_ITEM *ci;
+
+ if (!section) return NULL;
+
+ /*
+ * If subsection is NULL this must be a first time run
+ * Find the subsection with correct name
+ */
+
+ if (!subsection) {
+ ci = section->children;
+ } else {
+ ci = subsection->item.next;
+ }
+
+ for (; ci; ci = ci->next) {
+ if (ci->type != CONF_ITEM_SECTION)
+ continue;
+ if ((name1 == NULL) ||
+ (strcmp(cf_item_to_section(ci)->name1, name1) == 0))
+ break;
+ }
+
+ return cf_item_to_section(ci);
+}
+
+
+/*
+ * Return the next section after a CONF_SECTION
+ * with a certain name1 (char *name1). If the requested
+ * name1 is NULL, any name1 matches.
+ */
+
+CONF_SECTION *cf_section_find_next(CONF_SECTION const *section,
+ CONF_SECTION const *subsection,
+ char const *name1)
+{
+ if (!section) return NULL;
+
+ if (!section->item.parent) return NULL;
+
+ return cf_subsection_find_next(section->item.parent, subsection, name1);
+}
+
+/** Return the next item after a CONF_ITEM.
+ *
+ */
+CONF_ITEM *cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
+{
+ if (!section) return NULL;
+
+ /*
+ * If item is NULL this must be a first time run
+ * Return the first item
+ */
+ if (item == NULL) {
+ return section->children;
+ } else {
+ return item->next;
+ }
+}
+
+static void _pair_count(int *count, CONF_SECTION const *cs)
+{
+ CONF_ITEM const *ci;
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+
+ if (cf_item_is_section(ci)) {
+ _pair_count(count, cf_item_to_section(ci));
+ continue;
+ }
+
+ (*count)++;
+ }
+}
+
+/** Count the number of conf pairs beneath a section
+ *
+ * @param[in] cs to search for items in.
+ * @return number of pairs nested within section.
+ */
+int cf_pair_count(CONF_SECTION const *cs)
+{
+ int count = 0;
+
+ _pair_count(&count, cs);
+
+ return count;
+}
+
+CONF_SECTION *cf_item_parent(CONF_ITEM const *ci)
+{
+ if (!ci) return NULL;
+
+ return ci->parent;
+}
+
+int cf_section_lineno(CONF_SECTION const *section)
+{
+ return section->item.lineno;
+}
+
+char const *cf_pair_filename(CONF_PAIR const *pair)
+{
+ return pair->item.filename;
+}
+
+char const *cf_section_filename(CONF_SECTION const *section)
+{
+ return section->item.filename;
+}
+
+int cf_pair_lineno(CONF_PAIR const *pair)
+{
+ return pair->item.lineno;
+}
+
+bool cf_item_is_section(CONF_ITEM const *item)
+{
+ return item->type == CONF_ITEM_SECTION;
+}
+
+bool cf_item_is_pair(CONF_ITEM const *item)
+{
+ return item->type == CONF_ITEM_PAIR;
+}
+
+bool cf_item_is_data(CONF_ITEM const *item)
+{
+ return item->type == CONF_ITEM_DATA;
+}
+
+static CONF_DATA *cf_data_alloc(CONF_SECTION *parent, char const *name,
+ void *data, void (*data_free)(void *))
+{
+ CONF_DATA *cd;
+
+ cd = talloc_zero(parent, CONF_DATA);
+ if (!cd) return NULL;
+
+ cd->item.type = CONF_ITEM_DATA;
+ cd->item.parent = parent;
+ cd->name = talloc_typed_strdup(cd, name);
+ if (!cd->name) {
+ talloc_free(cd);
+ return NULL;
+ }
+
+ cd->data = data;
+ cd->free = data_free;
+
+ if (cd->free) {
+ talloc_set_destructor(cd, _cf_data_free);
+ }
+
+ return cd;
+}
+
+static void *cf_data_find_internal(CONF_SECTION const *cs, char const *name, int flag)
+{
+ if (!cs || !name) return NULL;
+
+ /*
+ * Find the name in the tree, for speed.
+ */
+ if (cs->data_tree) {
+ CONF_DATA mycd;
+
+ mycd.name = name;
+ mycd.flag = flag;
+ return rbtree_finddata(cs->data_tree, &mycd);
+ }
+
+ return NULL;
+}
+
+/*
+ * Find data from a particular section.
+ */
+void *cf_data_find(CONF_SECTION const *cs, char const *name)
+{
+ CONF_DATA *cd = cf_data_find_internal(cs, name, 0);
+
+ if (cd) return cd->data;
+ return NULL;
+}
+
+
+/*
+ * Add named data to a configuration section.
+ */
+static int cf_data_add_internal(CONF_SECTION *cs, char const *name,
+ void *data, void (*data_free)(void *),
+ int flag)
+{
+ CONF_DATA *cd;
+
+ if (!cs || !name) return -1;
+
+ /*
+ * Already exists. Can't add it.
+ */
+ if (cf_data_find_internal(cs, name, flag) != NULL) return -1;
+
+ cd = cf_data_alloc(cs, name, data, data_free);
+ if (!cd) return -1;
+ cd->flag = flag;
+
+ cf_item_add(cs, cf_data_to_item(cd));
+
+ return 0;
+}
+
+/*
+ * Add named data to a configuration section.
+ */
+int cf_data_add(CONF_SECTION *cs, char const *name,
+ void *data, void (*data_free)(void *))
+{
+ return cf_data_add_internal(cs, name, data, data_free, 0);
+}
+
+/** Remove named data from a configuration section
+ *
+ */
+void *cf_data_remove(CONF_SECTION *cs, char const *name)
+{
+ CONF_DATA mycd;
+ CONF_DATA *cd;
+ CONF_ITEM *ci, *it;
+ void *data;
+
+ if (!cs || !name) return NULL;
+ if (!cs->data_tree) return NULL;
+
+ /*
+ * Find the name in the tree, for speed.
+ */
+ mycd.name = name;
+ mycd.flag = 0;
+ cd = rbtree_finddata(cs->data_tree, &mycd);
+ if (!cd) return NULL;
+
+ ci = cf_data_to_item(cd);
+ if (cs->children == ci) {
+ cs->children = ci->next;
+ if (cs->tail == ci) cs->tail = NULL;
+ } else {
+ for (it = cs->children; it; it = it->next) {
+ if (it->next == ci) {
+ it->next = ci->next;
+ if (cs->tail == ci) cs->tail = it;
+ break;
+ }
+ }
+ }
+
+ talloc_set_destructor(cd, NULL); /* Disarm the destructor */
+ rbtree_deletebydata(cs->data_tree, &mycd);
+
+ data = cd->data;
+ talloc_free(cd);
+
+ return data;
+}
+
+/*
+ * This is here to make the rest of the code easier to read. It
+ * ties conffile.c to log.c, but it means we don't have to
+ * pollute every other function with the knowledge of the
+ * configuration internals.
+ */
+void cf_log_err(CONF_ITEM const *ci, char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ if (ci) {
+ ERROR("%s[%d]: %s",
+ ci->filename ? ci->filename : "unknown",
+ ci->lineno ? ci->lineno : 0,
+ buffer);
+ } else {
+ ERROR("<unknown>[*]: %s", buffer);
+ }
+}
+
+void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ rad_assert(cs != NULL);
+
+ ERROR("%s[%d]: %s",
+ cs->item.filename ? cs->item.filename : "unknown",
+ cs->item.lineno ? cs->item.lineno : 0,
+ buffer);
+}
+
+void cf_log_err_cp(CONF_PAIR const *cp, char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ rad_assert(cp != NULL);
+
+ ERROR("%s[%d]: %s",
+ cp->item.filename ? cp->item.filename : "unknown",
+ cp->item.lineno ? cp->item.lineno : 0,
+ buffer);
+}
+
+void cf_log_info(CONF_SECTION const *cs, char const *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if ((rad_debug_lvl > 1) && cs) vradlog(L_DBG, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Wrapper to simplify the code.
+ */
+void cf_log_module(CONF_SECTION const *cs, char const *fmt, ...)
+{
+ va_list ap;
+ char buffer[256];
+
+ va_start(ap, fmt);
+ if (rad_debug_lvl > 1 && cs) {
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+
+ DEBUG("%.*s# %s", cs->depth, parse_spaces, buffer);
+ }
+ va_end(ap);
+}
+
+const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs)
+{
+ if (!cs) return NULL;
+
+ return cs->variables;
+}
+
+/*
+ * For "switch" and "case" statements.
+ */
+FR_TOKEN cf_section_name2_type(CONF_SECTION const *cs)
+{
+ if (!cs) return T_INVALID;
+
+ return cs->name2_type;
+}
diff --git a/src/main/connection.c b/src/main/connection.c
new file mode 100644
index 0000000..7ae4a2a
--- /dev/null
+++ b/src/main/connection.c
@@ -0,0 +1,1520 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file connection.c
+ * @brief Handle pools of connections (threads, sockets, etc.)
+ * @note This API must be used by all modules in the public distribution that
+ * maintain pools of connections.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ * @copyright 2012 Alan DeKok <aland@deployingradius.com>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/heap.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/rad_assert.h>
+
+typedef struct fr_connection fr_connection_t;
+
+static int fr_connection_pool_check(fr_connection_pool_t *pool);
+
+#ifndef NDEBUG
+#ifdef HAVE_PTHREAD_H
+/* #define PTHREAD_DEBUG (1) */
+#endif
+#endif
+
+/*
+ * We don't need to pollute the logs with "open / close"
+ * connection information. Instead, only print these messages
+ * when debugging.
+ */
+#undef INFO
+#define INFO(fmt, ...) if (rad_debug_lvl) radlog(L_INFO, fmt, ## __VA_ARGS__)
+
+/** An individual connection within the connection pool
+ *
+ * Defines connection counters, timestamps, and holds a pointer to the
+ * connection handle itself.
+ *
+ * @see fr_connection_pool_t
+ */
+struct fr_connection {
+ fr_connection_t *prev; //!< Previous connection in list.
+ fr_connection_t *next; //!< Next connection in list.
+
+ time_t created; //!< Time connection was created.
+ struct timeval last_reserved; //!< Last time the connection was reserved.
+
+ struct timeval last_released; //!< Time the connection was released.
+
+ uint32_t num_uses; //!< Number of times the connection has been reserved.
+ uint64_t number; //!< Unique ID assigned when the connection is created,
+ //!< these will monotonically increase over the
+ //!< lifetime of the connection pool.
+ void *connection; //!< Pointer to whatever the module uses for a connection
+ //!< handle.
+ bool in_use; //!< Whether the connection is currently reserved.
+
+ int heap; //!< For the next connection heap.
+
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id; //!< When 'in_use == true'.
+#endif
+};
+
+/** A connection pool
+ *
+ * Defines the configuration of the connection pool, all the counters and
+ * timestamps related to the connection pool, the mutex that stops multiple
+ * threads leaving the pool in an inconsistent state, and the callbacks
+ * required to open, close and check the status of connections within the pool.
+ *
+ * @see fr_connection
+ */
+struct fr_connection_pool_t {
+ int ref; //!< Reference counter to prevent connection
+ //!< pool being freed multiple times.
+ uint32_t start; //!< Number of initial connections.
+ uint32_t min; //!< Minimum number of concurrent connections to keep open.
+ uint32_t max; //!< Maximum number of concurrent connections to allow.
+ uint32_t spare; //!< Number of spare connections to try.
+ uint32_t pending; //!< Number of pending open connections.
+ uint32_t retry_delay; //!< seconds to delay re-open after a failed open.
+ uint32_t max_retries; //!< Maximum number of retries to attempt for any given
+ //!< operation (e.g. query or bind)
+ uint32_t cleanup_interval; //!< Initial timer for how often we sweep the pool
+ //!< for free connections. (0 is infinite).
+ int delay_interval; //!< When we next do a cleanup. Initialized to
+ //!< cleanup_interval, and increase from there based
+ //!< on the delay.
+ int next_delay; //!< The next delay time. cleanup. Initialized to
+ //!< cleanup_interval, and decays from there.
+ uint64_t max_uses; //!< Maximum number of times a connection can be used
+ //!< before being closed.
+ uint32_t lifetime; //!< How long a connection can be open before being
+ //!< closed (irrespective of whether it's idle or not).
+ uint32_t idle_timeout; //!< How long a connection can be idle before
+ //!< being closed.
+
+ uint32_t max_pending; //!< Max number of connections to open.
+
+ bool spread; //!< If true we spread requests over the connections,
+ //!< using the connection released longest ago, first.
+
+ fr_connection_pool_stats_t stats; //!< various statistics
+
+ fr_heap_t *heap; //!< For the next connection heap
+
+ fr_connection_t *head; //!< Start of the connection list.
+ fr_connection_t *tail; //!< End of the connection list.
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex; //!< Mutex used to keep consistent state when making
+ //!< modifications in threaded mode.
+#endif
+
+ CONF_SECTION *cs; //!< Configuration section holding the section of parsed
+ //!< config file that relates to this pool.
+ void *opaque; //!< Pointer to context data that will be passed to callbacks.
+
+ char const *log_prefix; //!< Log prefix to prepend to all log messages created
+ //!< by the connection pool code.
+
+ char const *trigger_prefix; //!< Prefix to prepend to names of all triggers
+ //!< fired by the connection pool code.
+
+ fr_connection_create_t create; //!< Function used to create new connections.
+ fr_connection_alive_t alive; //!< Function used to check status of connections.
+};
+
+#ifndef HAVE_PTHREAD_H
+# define pthread_mutex_lock(_x)
+# define pthread_mutex_unlock(_x)
+#endif
+
+static const CONF_PARSER connection_config[] = {
+ { "start", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, start), "5" },
+ { "min", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, min), "5" },
+ { "max", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, max), "10" },
+ { "spare", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, spare), "3" },
+ { "uses", FR_CONF_OFFSET(PW_TYPE_INTEGER64, fr_connection_pool_t, max_uses), "0" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, lifetime), "0" },
+ { "cleanup_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), NULL},
+ { "cleanup_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, cleanup_interval), "30" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, idle_timeout), "60" },
+ { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, retry_delay), "1" },
+ { "max_retries", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_connection_pool_t, max_retries), "5" },
+ { "spread", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_connection_pool_t, spread), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Order connections by reserved most recently
+ */
+static int last_reserved_cmp(void const *one, void const *two)
+{
+ fr_connection_t const *a = one;
+ fr_connection_t const *b = two;
+
+ if (a->last_reserved.tv_sec < b->last_reserved.tv_sec) return -1;
+ if (a->last_reserved.tv_sec > b->last_reserved.tv_sec) return +1;
+
+ if (a->last_reserved.tv_usec < b->last_reserved.tv_usec) return -1;
+ if (a->last_reserved.tv_usec > b->last_reserved.tv_usec) return +1;
+
+ return 0;
+}
+
+/** Order connections by released longest ago
+ */
+static int last_released_cmp(void const *one, void const *two)
+{
+ fr_connection_t const *a = one;
+ fr_connection_t const *b = two;
+
+ if (b->last_released.tv_sec < a->last_released.tv_sec) return -1;
+ if (b->last_released.tv_sec > a->last_released.tv_sec) return +1;
+
+ if (b->last_released.tv_usec < a->last_released.tv_usec) return -1;
+ if (b->last_released.tv_usec > a->last_released.tv_usec) return +1;
+
+ return 0;
+}
+
+/** Removes a connection from the connection list
+ *
+ * @note Must be called with the mutex held.
+ *
+ * @param[in,out] pool to modify.
+ * @param[in] this Connection to delete.
+ */
+static void fr_connection_unlink(fr_connection_pool_t *pool, fr_connection_t *this)
+{
+ if (this->prev) {
+ rad_assert(pool->head != this);
+ this->prev->next = this->next;
+ } else {
+ rad_assert(pool->head == this);
+ pool->head = this->next;
+ }
+ if (this->next) {
+ rad_assert(pool->tail != this);
+ this->next->prev = this->prev;
+ } else {
+ rad_assert(pool->tail == this);
+ pool->tail = this->prev;
+ }
+
+ this->prev = this->next = NULL;
+}
+
+/** Adds a connection to the head of the connection list
+ *
+ * @note Must be called with the mutex held.
+ *
+ * @param[in,out] pool to modify.
+ * @param[in] this Connection to add.
+ */
+static void fr_connection_link_head(fr_connection_pool_t *pool, fr_connection_t *this)
+{
+ rad_assert(pool != NULL);
+ rad_assert(this != NULL);
+ rad_assert(pool->head != this);
+ rad_assert(pool->tail != this);
+
+ if (pool->head) {
+ pool->head->prev = this;
+ }
+
+ this->next = pool->head;
+ this->prev = NULL;
+ pool->head = this;
+ if (!pool->tail) {
+ rad_assert(this->next == NULL);
+ pool->tail = this;
+ } else {
+ rad_assert(this->next != NULL);
+ }
+}
+
+/** Send a connection pool trigger.
+ *
+ * @param[in] pool to send trigger for.
+ * @param[in] name_suffix trigger name suffix.
+ */
+static void fr_connection_exec_trigger(fr_connection_pool_t *pool, char const *name_suffix)
+{
+ char name[64];
+ rad_assert(pool != NULL);
+ rad_assert(name_suffix != NULL);
+ snprintf(name, sizeof(name), "%s%s", pool->trigger_prefix, name_suffix);
+ exec_trigger(NULL, pool->cs, name, true);
+}
+
+/** Find a connection handle in the connection list
+ *
+ * Walks over the list of connections searching for a specified connection
+ * handle and returns the first connection that contains that pointer.
+ *
+ * @note Will lock mutex and only release mutex if connection handle
+ * is not found, so will usually return will mutex held.
+ * @note Must be called with the mutex free.
+ *
+ * @param[in] pool to search in.
+ * @param[in] conn handle to search for.
+ * @return
+ * - Connection containing the specified handle.
+ * - NULL if non if connection was found.
+ */
+static fr_connection_t *fr_connection_find(fr_connection_pool_t *pool, void *conn)
+{
+ fr_connection_t *this;
+
+ if (!pool || !conn) return NULL;
+
+ pthread_mutex_lock(&pool->mutex);
+
+ /*
+ * FIXME: This loop could be avoided if we passed a 'void
+ * **connection' instead. We could use "offsetof" in
+ * order to find top of the parent structure.
+ */
+ for (this = pool->head; this != NULL; this = this->next) {
+ if (this->connection == conn) {
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id;
+
+ pthread_id = pthread_self();
+ rad_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
+#endif
+
+ rad_assert(this->in_use == true);
+ return this;
+ }
+ }
+
+ pthread_mutex_unlock(&pool->mutex);
+ return NULL;
+}
+
+/** Spawns a new connection
+ *
+ * Spawns a new connection using the create callback, and returns it for
+ * adding to the connection list.
+ *
+ * @note Will call the 'open' trigger.
+ * @note Must be called with the mutex free.
+ *
+ * @param[in] pool to modify.
+ * @param[in] now Current time.
+ * @param[in] in_use whether the new connection should be "in_use" or not
+ * @return
+ * - New connection struct.
+ * - NULL on error.
+ */
+static fr_connection_t *fr_connection_spawn(fr_connection_pool_t *pool, time_t now, bool in_use)
+{
+ uint64_t number;
+ uint32_t max_pending;
+ TALLOC_CTX *ctx;
+
+ fr_connection_t *this;
+ void *conn;
+
+ rad_assert(pool != NULL);
+
+ /*
+ * If we have NO connections, and we've previously failed
+ * opening connections, don't open multiple connections until
+ * we successfully open at least one.
+ */
+ if ((pool->stats.num == 0) && pool->pending && pool->stats.last_failed) return NULL;
+
+ pthread_mutex_lock(&pool->mutex);
+ rad_assert(pool->stats.num <= pool->max);
+
+ /*
+ * Don't spawn too many connections at the same time.
+ */
+ if ((pool->stats.num + pool->pending) >= pool->max) {
+ pthread_mutex_unlock(&pool->mutex);
+
+ ERROR("%s: Cannot open new connection, already at max", pool->log_prefix);
+ return NULL;
+ }
+
+ /*
+ * If the last attempt failed, wait a bit before
+ * retrying.
+ */
+ if (pool->stats.last_failed && ((pool->stats.last_failed + pool->retry_delay) > now)) {
+ bool complain = false;
+
+ if (pool->stats.last_throttled != now) {
+ complain = true;
+
+ pool->stats.last_throttled = now;
+ }
+
+ pthread_mutex_unlock(&pool->mutex);
+
+ if (!RATE_LIMIT_ENABLED || complain) {
+ ERROR("%s: Last connection attempt failed, waiting %d seconds before retrying",
+ pool->log_prefix, pool->retry_delay);
+ }
+
+ return NULL;
+ }
+
+ /*
+ * We limit the rate of new connections after a failed attempt.
+ */
+ if (pool->pending > pool->max_pending) {
+ pthread_mutex_unlock(&pool->mutex);
+ RATE_LIMIT(WARN("%s: Cannot open a new connection due to rate limit after failure",
+ pool->log_prefix));
+ return NULL;
+ }
+
+ pool->pending++;
+ number = pool->stats.opened++;
+
+ /*
+ * Unlock the mutex while we try to open a new
+ * connection. If there are issues with the back-end,
+ * opening a new connection may take a LONG time. In
+ * that case, we want the other connections to continue
+ * to be used.
+ */
+ pthread_mutex_unlock(&pool->mutex);
+
+ /*
+ * The true value for max_pending is the smaller of
+ * free connection slots, or pool->max_pending.
+ */
+ max_pending = (pool->max - pool->stats.num);
+ if (pool->max_pending < max_pending) max_pending = pool->max_pending;
+ INFO("%s: Opening additional connection (%" PRIu64 "), %u of %u pending slots used",
+ pool->log_prefix, number, pool->pending, max_pending);
+
+ /*
+ * Allocate a new top level ctx for the create callback
+ * to hang its memory off of.
+ */
+ ctx = talloc_init("fr_connection_ctx");
+ if (!ctx) return NULL;
+
+ /*
+ * This may take a long time, which prevents other
+ * threads from releasing connections. We don't care
+ * about other threads opening new connections, as we
+ * already have no free connections.
+ */
+ conn = pool->create(ctx, pool->opaque);
+ if (!conn) {
+ ERROR("%s: Opening connection failed (%" PRIu64 ")", pool->log_prefix, number);
+
+ pool->stats.last_failed = now;
+ pthread_mutex_lock(&pool->mutex);
+ pool->max_pending = 1;
+ pool->pending--;
+ pool->stats.failed++;
+ pthread_mutex_unlock(&pool->mutex);
+
+ talloc_free(ctx);
+
+ return NULL;
+ }
+
+ /*
+ * And lock the mutex again while we link the new
+ * connection back into the pool.
+ */
+ pthread_mutex_lock(&pool->mutex);
+
+ this = talloc_zero(pool, fr_connection_t);
+ if (!this) {
+ pthread_mutex_unlock(&pool->mutex);
+ talloc_free(ctx);
+
+ return NULL;
+ }
+ fr_link_talloc_ctx_free(this, ctx);
+
+ this->created = now;
+ this->connection = conn;
+ this->in_use = in_use;
+
+ this->number = number;
+ gettimeofday(&this->last_reserved, NULL);
+ this->last_released = this->last_reserved;
+
+ /*
+ * The connection pool is starting up. Insert the
+ * connection into the heap.
+ */
+ if (!in_use) fr_heap_insert(pool->heap, this);
+
+ fr_connection_link_head(pool, this);
+
+ /*
+ * Do NOT insert the connection into the heap. That's
+ * done when the connection is released.
+ */
+
+ pool->stats.num++;
+
+ rad_assert(pool->pending > 0);
+ pool->pending--;
+
+ /*
+ * We've successfully opened one more connection. Allow
+ * more connections to open in parallel.
+ */
+ if (pool->max_pending < pool->max) pool->max_pending++;
+
+ pool->stats.last_opened = time(NULL);
+ pool->delay_interval = pool->cleanup_interval;
+ pool->next_delay = pool->cleanup_interval;
+ pool->stats.last_failed = 0;
+
+ pthread_mutex_unlock(&pool->mutex);
+
+ fr_connection_exec_trigger(pool, "open");
+
+ return this;
+}
+
+/** Close an existing connection.
+ *
+ * Removes the connection from the list, calls the delete callback to close
+ * the connection, then frees memory allocated to the connection.
+ *
+ * @note Will call the 'close' trigger.
+ * @note Must be called with the mutex held.
+ *
+ * @param[in,out] pool to modify.
+ * @param[in] this Connection to delete.
+ * @param[in] reason to close the connection
+ * @param[in] msg optional message
+ */
+static void fr_connection_close_internal(fr_connection_pool_t *pool, fr_connection_t *this,
+ char const *reason, char const *msg)
+{
+ if (!msg) {
+ INFO("%s: %s (%" PRIu64 ")", pool->log_prefix, reason, this->number);
+ } else {
+ INFO("%s: %s (%" PRIu64 ") - %s", pool->log_prefix, reason, this->number, msg);
+ }
+
+
+ /*
+ * If it's in use, release it.
+ */
+ if (this->in_use) {
+#ifdef PTHREAD_DEBUG
+ pthread_t pthread_id = pthread_self();
+ rad_assert(pthread_equal(this->pthread_id, pthread_id) != 0);
+#endif
+
+ this->in_use = false;
+
+ rad_assert(pool->stats.active != 0);
+ pool->stats.active--;
+
+ } else {
+ /*
+ * Connection isn't used, remove it from the heap.
+ */
+ fr_heap_extract(pool->heap, this);
+ }
+
+ fr_connection_exec_trigger(pool, "close");
+
+ fr_connection_unlink(pool, this);
+
+ rad_assert(pool->stats.num > 0);
+ pool->stats.num--;
+ pool->stats.closed++;
+ pool->stats.last_closed = time(NULL);
+ talloc_free(this);
+}
+
+/** Check whether a connection needs to be removed from the pool
+ *
+ * Will verify that the connection is within idle_timeout, max_uses, and
+ * lifetime values. If it is not, the connection will be closed.
+ *
+ * @note Will only close connections not in use.
+ * @note Must be called with the mutex held.
+ *
+ * @param[in,out] pool to modify.
+ * @param[in,out] this Connection to manage.
+ * @param[in] now Current time.
+ * @param[in] get whether we want to get a connection
+ * @return
+ * - 0 if connection was closed.
+ * - 1 if connection handle was left open.
+ */
+static int fr_connection_manage(fr_connection_pool_t *pool,
+ fr_connection_t *this,
+ time_t now, bool get)
+{
+ rad_assert(pool != NULL);
+ rad_assert(this != NULL);
+ char const *reason = "Closing expired connection";
+ char const *msg = NULL;
+
+ /*
+ * Don't terminate in-use connections
+ */
+ if (this->in_use) return 1;
+
+ if ((pool->max_uses > 0) &&
+ (this->num_uses >= pool->max_uses)) {
+ msg = "Hit max_uses limit";
+
+ do_delete:
+ if (pool->stats.num <= pool->min) {
+ DEBUG("%s: You probably need to lower \"min\"", pool->log_prefix);
+ }
+ fr_connection_close_internal(pool, this, reason, msg);
+ return 0;
+ }
+
+ if ((pool->lifetime > 0) &&
+ ((this->created + pool->lifetime) < now)) {
+ msg = "Hit lifetime limit";
+ goto do_delete;
+ }
+
+ /*
+ * The connection WAS idle, but the caller is interested
+ * in getting a new one. Instead of closing the old one
+ * and opening a new one, we just return the old one.
+ */
+ if (get) return 1;
+
+ if ((pool->idle_timeout > 0) &&
+ ((this->last_released.tv_sec + pool->idle_timeout) < now)) {
+ msg = "Hit idle_timeout limit";
+ goto do_delete;
+ }
+
+ return 1;
+}
+
+
+/** Check whether any connections need to be removed from the pool
+ *
+ * Maintains the number of connections in the pool as per the configuration
+ * parameters for the connection pool.
+ *
+ * @note Will only run checks the first time it's called in a given second,
+ * to throttle connection spawning/closing.
+ * @note Will only close connections not in use.
+ * @note Must be called with the mutex held, will release mutex before
+ * returning.
+ *
+ * @param[in,out] pool to manage.
+ * @return 1
+ */
+static int fr_connection_pool_check(fr_connection_pool_t *pool)
+{
+ uint32_t num, spare;
+ time_t now = time(NULL);
+ fr_connection_t *this, *next;
+
+ if (pool->stats.last_checked == now) {
+ pthread_mutex_unlock(&pool->mutex);
+ return 1;
+ }
+
+ /*
+ * Get "real" number of connections, and count pending
+ * connections as spare.
+ */
+ num = pool->stats.num + pool->pending;
+ spare = pool->pending + (pool->stats.num - pool->stats.active);
+
+ /*
+ * The other end can close connections. If so, we'll
+ * have fewer than "min". When that happens, open more
+ * connections to enforce "min".
+ *
+ * The code for spawning connections enforces that
+ * num + pending <= max.
+ */
+ if (num < pool->min) {
+ INFO("Need %u more connections to reach min connections (%i)", pool->min - num, pool->min);
+ goto add_connection;
+ }
+
+ /*
+ * On the odd chance that we've opened too many
+ * connections, take care of that.
+ */
+ if (num > pool->max) {
+ /*
+ * Pending connections don't get closed as "spare".
+ */
+ if (pool->pending > 0) goto manage_connections;
+
+ /*
+ * Otherwise close one of the connections to
+ * bring us down to "max".
+ */
+ goto close_connection;
+ }
+
+ /*
+ * Now that we've enforced min/max connections, try to
+ * keep the "spare" connections at the correct number.
+ */
+
+ /*
+ * Nothing to do? Go check all of the connections for
+ * timeouts, etc.
+ */
+ if (spare == pool->spare) goto manage_connections;
+
+ /*
+ * Too many spare connections, delete some.
+ */
+ if (spare > pool->spare) {
+ fr_connection_t *found;
+
+ /*
+ * Pending connections don't get closed as "spare".
+ */
+ if (pool->pending > 0) goto manage_connections;
+
+ /*
+ * Don't close too many connections, even they
+ * are spare.
+ */
+ if (num <= pool->min) goto manage_connections;
+
+ /*
+ * Too many spares, go close one.
+ */
+
+ close_connection:
+ /*
+ * Don't close connections too often, in order to
+ * prevent flapping.
+ */
+ if (now < (pool->stats.last_opened + pool->delay_interval)) goto manage_connections;
+
+ /*
+ * Find a connection to close.
+ */
+ found = NULL;
+ for (this = pool->tail; this != NULL; this = this->prev) {
+ if (this->in_use) continue;
+
+ if (!found ||
+ timercmp(&this->last_reserved, &found->last_reserved, <)) {
+ found = this;
+ }
+ }
+
+ rad_assert(found != NULL);
+
+ fr_connection_close_internal(pool, found, "Closing connection", "Too many unused connections.");
+
+ /*
+ * Decrease the delay for the next time we clean
+ * up.
+ */
+ pool->next_delay >>= 1;
+ if (pool->next_delay == 0) pool->next_delay = 1;
+ pool->delay_interval += pool->next_delay;
+
+ goto manage_connections;
+ }
+
+ /*
+ * Too few connections, open some more.
+ */
+ if (spare < pool->spare) {
+ /*
+ * Don't open too many pending connections.
+ */
+ if (pool->pending >= pool->max_pending) goto manage_connections;
+
+ /*
+ * Don't open too many connections, even if we
+ * need more spares.
+ */
+ if (num >= pool->max) goto manage_connections;
+
+ /*
+ * Too few spares, go add one.
+ */
+
+ add_connection:
+ INFO("Need more connections to reach %i spares", pool->spare);
+
+ /*
+ * Only try to open spares if we're not already attempting to open
+ * a connection. Avoids spurious log messages.
+ */
+ pthread_mutex_unlock(&pool->mutex);
+ fr_connection_spawn(pool, now, false); /* ignore return code */
+ pthread_mutex_lock(&pool->mutex);
+ goto manage_connections;
+ }
+
+ /*
+ * Pass over all of the connections in the pool, limiting
+ * lifetime, idle time, max requests, etc.
+ */
+manage_connections:
+ for (this = pool->head; this != NULL; this = next) {
+ next = this->next;
+ fr_connection_manage(pool, this, now, false);
+ }
+
+ pool->stats.last_checked = now;
+ pthread_mutex_unlock(&pool->mutex);
+
+ return 1;
+}
+
+/** Get a connection from the connection pool
+ *
+ * @note Must be called with the mutex free.
+ *
+ * @param[in,out] pool to reserve the connection from.
+ * @param[in] spawn whether to spawn a new connection
+ * @return
+ * - A pointer to the connection handle.
+ * - NULL on error.
+ */
+static void *fr_connection_get_internal(fr_connection_pool_t *pool, bool spawn)
+{
+ time_t now;
+ fr_connection_t *this;
+
+ if (!pool) return NULL;
+
+ /*
+ * Allow CTRL-C to kill the server in debugging mode.
+ */
+ if (main_config.exiting) return NULL;
+
+#ifdef HAVE_PTHREAD_H
+ if (spawn) pthread_mutex_lock(&pool->mutex);
+#endif
+
+ now = time(NULL);
+
+ /*
+ * Grab the link with the lowest latency, and check it
+ * for limits. If "connection manage" says the link is
+ * no longer usable, go grab another one.
+ */
+ do {
+ this = fr_heap_peek(pool->heap);
+ if (!this) break;
+
+ fr_assert(!this->in_use);
+ } while (!fr_connection_manage(pool, this, now, true));
+
+ /*
+ * We have a working connection. Extract it from the
+ * heap and use it.
+ */
+ if (this) {
+ fr_heap_extract(pool->heap, this);
+ goto do_return;
+ }
+
+ /*
+ * We were asked to avoid spawning a new connection, by
+ * fr_connection_reconnect_internal(). So we just return
+ * here.
+ */
+ if (!spawn) return NULL;
+
+ if (pool->stats.num == pool->max) {
+ bool complain = false;
+
+ /*
+ * Rate-limit complaints.
+ */
+ if (pool->stats.last_at_max != now) {
+ complain = true;
+ pool->stats.last_at_max = now;
+ }
+
+ pthread_mutex_unlock(&pool->mutex);
+
+ if (!RATE_LIMIT_ENABLED || complain) {
+ ERROR("%s: No connections available and at max connection limit", pool->log_prefix);
+ }
+
+ return NULL;
+ }
+
+ pthread_mutex_unlock(&pool->mutex);
+
+ DEBUG("%s: %i of %u connections in use. You may need to increase \"spare\"", pool->log_prefix,
+ pool->stats.active, pool->stats.num);
+ this = fr_connection_spawn(pool, now, true); /* MY connection! */
+ if (!this) return NULL;
+
+ pthread_mutex_lock(&pool->mutex);
+
+do_return:
+ pool->stats.active++;
+ this->num_uses++;
+ gettimeofday(&this->last_reserved, NULL);
+ this->in_use = true;
+
+#ifdef PTHREAD_DEBUG
+ this->pthread_id = pthread_self();
+#endif
+
+#ifdef HAVE_PTHREAD_H
+ if (spawn) pthread_mutex_unlock(&pool->mutex);
+#endif
+
+ DEBUG("%s: Reserved connection (%" PRIu64 ")", pool->log_prefix, this->number);
+
+ return this->connection;
+}
+
+/** Reconnect a suspected inviable connection
+ *
+ * @note Must be called with the mutex held, will not release mutex.
+ *
+ * @see fr_connection_get
+ * @param[in,out] pool to reconnect the connection in.
+ * @param[in,out] conn to reconnect.
+ * @return new connection handle if successful else NULL.
+ */
+static fr_connection_t *fr_connection_reconnect_internal(fr_connection_pool_t *pool, fr_connection_t *conn)
+{
+ void *new_conn;
+ uint64_t conn_number;
+ TALLOC_CTX *ctx;
+
+ conn_number = conn->number;
+
+ /*
+ * Destroy any handles associated with the fr_connection_t
+ */
+ talloc_free_children(conn);
+
+ DEBUG("%s: Reconnecting (%" PRIu64 ")", pool->log_prefix, conn_number);
+
+ /*
+ * Allocate a new top level ctx for the create callback
+ * to hang its memory off of.
+ */
+ ctx = talloc_init("fr_connection_ctx");
+ if (!ctx) return NULL;
+ fr_link_talloc_ctx_free(conn, ctx);
+
+ new_conn = pool->create(ctx, pool->opaque);
+ if (!new_conn) {
+ /*
+ * We can't create a new connection, so close the current one.
+ */
+ fr_connection_close_internal(pool, conn, "Closing connection", "Failed to reconnect");
+
+ /*
+ * Maybe there's a connection which is unused and
+ * available. If so, return it.
+ */
+ new_conn = fr_connection_get_internal(pool, false);
+ if (new_conn) return new_conn;
+
+ RATE_LIMIT(ERROR("%s: Failed to reconnect (%" PRIu64 "), no free connections are available",
+ pool->log_prefix, conn_number));
+
+ return NULL;
+ }
+
+ fr_connection_exec_trigger(pool, "close");
+ conn->connection = new_conn;
+
+ return new_conn;
+}
+
+/** Create a new connection pool
+ *
+ * Allocates structures used by the connection pool, initialises the various
+ * configuration options and counters, and sets the callback functions.
+ *
+ * Will also spawn the number of connections specified by the 'start'
+ * configuration options.
+ *
+ * @note Will call the 'start' trigger.
+ *
+ * @param[in] ctx Context to link pool's destruction to.
+ * @param[in] cs pool section.
+ * @param[in] opaque data pointer to pass to callbacks.
+ * @param[in] c Callback to create new connections.
+ * @param[in] a Callback to check the status of connections.
+ * @param[in] log_prefix prefix to prepend to all log messages.
+ * @param[in] trigger_prefix prefix to prepend to all trigger names.
+ * @return
+ * - New connection pool.
+ * - NULL on error.
+ */
+static fr_connection_pool_t *fr_connection_pool_init(TALLOC_CTX *ctx,
+ CONF_SECTION *cs,
+ void *opaque,
+ fr_connection_create_t c,
+ fr_connection_alive_t a,
+ char const *log_prefix,
+ char const *trigger_prefix)
+{
+ uint32_t i;
+ fr_connection_pool_t *pool;
+ fr_connection_t *this;
+ time_t now;
+
+ if (!cs || !opaque || !c) return NULL;
+
+ now = time(NULL);
+
+ /*
+ * Pool is allocated in the NULL context as
+ * threads are likely to allocate memory
+ * beneath the pool.
+ */
+ pool = talloc_zero(NULL, fr_connection_pool_t);
+ if (!pool) return NULL;
+
+ /*
+ * Ensure the pool is freed at the same time
+ * as its parent.
+ */
+ if (fr_link_talloc_ctx_free(ctx, pool) < 0) {
+ talloc_free(pool);
+
+ return NULL;
+ }
+
+ pool->cs = cs;
+ pool->opaque = opaque;
+ pool->create = c;
+ pool->alive = a;
+
+ pool->head = pool->tail = NULL;
+
+ /*
+ * We keep a heap of connections, sorted by the last time
+ * we STARTED using them. Newly opened connections
+ * aren't in the heap. They're only inserted in the list
+ * once they're released.
+ *
+ * We do "most recently started" instead of "most
+ * recently used", because MRU is done as most recently
+ * *released*. We want to order connections by
+ * responsiveness, and MRU prioritizes high latency
+ * connections.
+ *
+ * We want most recently *started*, which gives
+ * preference to low latency links, and pushes high
+ * latency links down in the priority heap.
+ *
+ * https://code.facebook.com/posts/1499322996995183/solving-the-mystery-of-link-imbalance-a-metastable-failure-state-at-scale/
+ */
+ if (!pool->spread) {
+ pool->heap = fr_heap_create(last_reserved_cmp, offsetof(fr_connection_t, heap));
+ /*
+ * For some types of connections we need to used a different
+ * algorithm, because load balancing benefits are secondary
+ * to maintaining a cache of open connections.
+ *
+ * With libcurl's multihandle, connections can only be reused
+ * if all handles that make up the multhandle are done processing
+ * their requests.
+ *
+ * We can't tell when that's happened using libcurl, and even
+ * if we could, blocking until all servers had responded
+ * would have huge cost.
+ *
+ * The solution is to order the heap so that the connection that
+ * was released longest ago is at the top.
+ *
+ * That way we maximise time between connection use.
+ */
+ } else {
+ pool->heap = fr_heap_create(last_released_cmp, offsetof(fr_connection_t, heap));
+ }
+ if (!pool->heap) {
+ talloc_free(pool);
+ return NULL;
+ }
+
+ pool->log_prefix = log_prefix ? talloc_typed_strdup(pool, log_prefix) : "core";
+ pool->trigger_prefix = trigger_prefix ? talloc_typed_strdup(pool, trigger_prefix) : "";
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_init(&pool->mutex, NULL);
+#endif
+
+ DEBUG("%s: Initialising connection pool", pool->log_prefix);
+
+ if (cf_section_parse(cs, pool, connection_config) < 0) goto error;
+
+ /*
+ * Some simple limits
+ */
+ if (pool->max == 0) {
+ cf_log_err_cs(cs, "Cannot set 'max' to zero");
+ goto error;
+ }
+ pool->max_pending = pool->max; /* can open all connections now */
+
+ if (pool->min > pool->max) {
+ cf_log_err_cs(cs, "Cannot set 'min' to more than 'max'");
+ goto error;
+ }
+
+ FR_INTEGER_BOUND_CHECK("max", pool->max, <=, 1024);
+ FR_INTEGER_BOUND_CHECK("start", pool->start, <=, pool->max);
+ FR_INTEGER_BOUND_CHECK("spare", pool->spare, <=, (pool->max - pool->min));
+
+ if (pool->lifetime > 0) {
+ FR_INTEGER_COND_CHECK("idle_timeout", pool->idle_timeout, (pool->idle_timeout <= pool->lifetime), 0);
+ }
+
+ if (pool->idle_timeout > 0) {
+ FR_INTEGER_BOUND_CHECK("cleanup_interval", pool->cleanup_interval, <=, pool->idle_timeout);
+ }
+
+ /*
+ * Don't open any connections. Instead, force the limits
+ * to only 1 connection.
+ *
+ */
+ if (check_config) {
+ pool->start = pool->min = pool->max = 1;
+ return pool;
+ }
+
+ /*
+ * Create all of the connections, unless the admin says
+ * not to.
+ */
+ for (i = 0; i < pool->start; i++) {
+ this = fr_connection_spawn(pool, now, false);
+ if (!this) {
+ error:
+ fr_connection_pool_free(pool);
+ return NULL;
+ }
+ }
+
+ fr_connection_exec_trigger(pool, "start");
+
+ return pool;
+}
+
+/** Initialise a module specific connection pool
+ *
+ * @see fr_connection_pool_init
+ *
+ * @param[in] module section.
+ * @param[in] opaque data pointer to pass to callbacks.
+ * @param[in] c Callback to create new connections.
+ * @param[in] a Callback to check the status of connections.
+ * @param[in] log_prefix override, if NULL will be set automatically from the module CONF_SECTION.
+ * @return
+ * - New connection pool.
+ * - NULL on error.
+ */
+fr_connection_pool_t *fr_connection_pool_module_init(CONF_SECTION *module,
+ void *opaque,
+ fr_connection_create_t c,
+ fr_connection_alive_t a,
+ char const *log_prefix)
+{
+ CONF_SECTION *cs, *mycs;
+ char buff[128];
+ char trigger_prefix[64];
+
+ fr_connection_pool_t *pool;
+ char const *cs_name1, *cs_name2;
+
+ int ret;
+
+#define CONNECTION_POOL_CF_KEY "connection_pool"
+#define parent_name(_x) cf_section_name(cf_item_parent(cf_section_to_item(_x)))
+
+ cs_name1 = cf_section_name1(module);
+ cs_name2 = cf_section_name2(module);
+ if (!cs_name2) cs_name2 = cs_name1;
+
+ snprintf(trigger_prefix, sizeof(trigger_prefix), "modules.%s.", cs_name1);
+
+ if (!log_prefix) {
+ snprintf(buff, sizeof(buff), "rlm_%s (%s)", cs_name1, cs_name2);
+ log_prefix = buff;
+ }
+
+ /*
+ * Get sibling's pool config section
+ */
+ ret = find_module_sibling_section(&cs, module, "pool");
+ switch (ret) {
+ case -1:
+ return NULL;
+
+ case 1:
+ DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
+ break;
+
+ case 0:
+ DEBUG4("%s: Using local pool section", log_prefix);
+ break;
+ }
+
+ /*
+ * Get our pool config section
+ */
+ mycs = cf_section_sub_find(module, "pool");
+ if (!mycs) {
+ DEBUG4("%s: Adding pool section to config item \"%s\" to store pool references", log_prefix,
+ cf_section_name(module));
+
+ mycs = cf_section_alloc(module, "pool", NULL);
+ cf_section_add(module, mycs);
+ }
+
+ /*
+ * Sibling didn't have a pool config section
+ * Use our own local pool.
+ */
+ if (!cs) {
+ DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
+ parent_name(cs), parent_name(mycs));
+ cs = mycs;
+ }
+
+ /*
+ * If fr_connection_pool_init has already been called
+ * for this config section, reuse the previous instance.
+ *
+ * This allows modules to pass in the config sections
+ * they would like to use the connection pool from.
+ */
+ pool = cf_data_find(cs, CONNECTION_POOL_CF_KEY);
+ if (!pool) {
+ DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
+ pool = fr_connection_pool_init(cs, cs, opaque, c, a, log_prefix, trigger_prefix);
+ if (!pool) return NULL;
+
+ DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
+ cf_data_add(cs, CONNECTION_POOL_CF_KEY, pool, NULL);
+ return pool;
+ }
+ pool->ref++;
+
+ DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
+
+ /*
+ * We're reusing pool data add it to our local config
+ * section. This allows other modules to transitively
+ * re-use a pool through this module.
+ */
+ if (mycs != cs) {
+ DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
+ log_prefix, pool, parent_name(cs), parent_name(mycs));
+ cf_data_add(mycs, CONNECTION_POOL_CF_KEY, pool, NULL);
+ }
+
+ return pool;
+}
+
+/** Get the number of connections currently in the pool
+ *
+ * @param pool to count connections for.
+ * @return the number of connections in the pool
+ */
+int fr_connection_pool_get_num(fr_connection_pool_t *pool)
+{
+ return pool->stats.num;
+}
+
+/** Get the number of times an operation should be retried
+ *
+ * The lower of either the number of available connections or
+ * the configured max_retries.
+ *
+ * @param pool to get the retry count for.
+ * @return the number of times an operation can be retried.
+ */
+int fr_connection_pool_get_retries(fr_connection_pool_t *pool)
+{
+ return (pool->max_retries < pool->stats.num) ? pool->max_retries : pool->stats.num;
+}
+
+/** Get the number of connections currently in the pool
+ *
+ * @param module the module configuration which should contain the pool
+ * @return the stats, or NULL on "not found"
+ */
+fr_connection_pool_stats_t const *fr_connection_pool_stats(CONF_SECTION *module)
+{
+ fr_connection_pool_t *pool = NULL;
+ CONF_SECTION *cs;
+
+ cs = cf_section_sub_find(module, "pool");
+ if (!cs) {
+ CONF_PAIR *cp;
+ module_instance_t *mi;
+ char const *value;
+
+ /*
+ * This is the name of the module, not a
+ * reference. <sigh>.
+ */
+ cp = cf_pair_find(module, "pool");
+ if (!cp) return NULL;
+
+ value = cf_pair_value(cp);
+ if (!value) return NULL;
+
+ mi = module_find(cf_item_parent(cf_section_to_item(module)), value);
+ if (!mi) return NULL;
+
+ cs = cf_section_sub_find(mi->cs, "pool");
+ if (!cs) return NULL;
+ }
+
+ pool = cf_data_find(cs, CONNECTION_POOL_CF_KEY);
+ if (!pool) return NULL;
+
+ return &pool->stats;
+}
+
+
+/** Delete a connection pool
+ *
+ * Closes, unlinks and frees all connections in the connection pool, then frees
+ * all memory used by the connection pool.
+ *
+ * @note Will call the 'stop' trigger.
+ * @note Must be called with the mutex free.
+ *
+ * @param[in,out] pool to delete.
+ */
+void fr_connection_pool_free(fr_connection_pool_t *pool)
+{
+ fr_connection_t *this;
+
+ if (!pool) return;
+
+ /*
+ * More modules hold a reference to this pool, don't free
+ * it yet.
+ */
+ if (pool->ref > 0) {
+ pool->ref--;
+ return;
+ }
+
+ DEBUG("%s: Removing connection pool", pool->log_prefix);
+
+ pthread_mutex_lock(&pool->mutex);
+
+ /*
+ * Don't loop over the list. Just keep removing the head
+ * until they're all gone.
+ */
+ while ((this = pool->head) != NULL) {
+ fr_connection_close_internal(pool, this, "Closing connection", "Shutting down connection pool");
+ }
+
+ fr_heap_delete(pool->heap);
+
+ fr_connection_exec_trigger(pool, "stop");
+
+ rad_assert(pool->head == NULL);
+ rad_assert(pool->tail == NULL);
+ rad_assert(pool->stats.num == 0);
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&pool->mutex);
+#endif
+
+ talloc_free(pool);
+}
+
+/** Reserve a connection in the connection pool
+ *
+ * Will attempt to find an unused connection in the connection pool, if one is
+ * found, will mark it as in in use increment the number of active connections
+ * and return the connection handle.
+ *
+ * If no free connections are found will attempt to spawn a new one, conditional
+ * on a connection spawning not already being in progress, and not being at the
+ * 'max' connection limit.
+ *
+ * @note fr_connection_release must be called once the caller has finished
+ * using the connection.
+ *
+ * @see fr_connection_release
+ * @param[in,out] pool to reserve the connection from.
+ * @return
+ * - A pointer to the connection handle.
+ * - NULL on error.
+ */
+void *fr_connection_get(fr_connection_pool_t *pool)
+{
+ return fr_connection_get_internal(pool, true);
+}
+
+/** Release a connection
+ *
+ * Will mark a connection as unused and decrement the number of active
+ * connections.
+ *
+ * @see fr_connection_get
+ * @param[in,out] pool to release the connection in.
+ * @param[in,out] conn to release.
+ */
+void fr_connection_release(fr_connection_pool_t *pool, void *conn)
+{
+ fr_connection_t *this;
+
+ this = fr_connection_find(pool, conn);
+ if (!this) return;
+
+ this->in_use = false;
+
+ /*
+ * Record when the connection was last released
+ */
+ gettimeofday(&this->last_released, NULL);
+
+ /*
+ * Insert the connection in the heap.
+ *
+ * This will either be based on when we *started* using it
+ * (allowing fast links to be re-used, and slow links to be
+ * gradually expired), or when we released it (allowing
+ * the maximum amount of time between connection use).
+ */
+ fr_heap_insert(pool->heap, this);
+
+ rad_assert(pool->stats.active != 0);
+ pool->stats.active--;
+
+ DEBUG("%s: Released connection (%" PRIu64 ")", pool->log_prefix, this->number);
+
+ /*
+ * We mirror the "spawn on get" functionality by having
+ * "delete on release". If there are too many spare
+ * connections, go manage the pool && clean some up.
+ */
+ fr_connection_pool_check(pool);
+}
+
+/** Reconnect a suspected inviable connection
+ *
+ * This should be called by the module if it suspects that a connection is
+ * not viable (e.g. the server has closed it).
+ *
+ * Will attempt to create a new connection handle using the create callback,
+ * and if this is successful the new handle will be assigned to the existing
+ * pool connection.
+ *
+ * If this is not successful, the connection will be removed from the pool.
+ *
+ * When implementing a module that uses the connection pool API, it is advisable
+ * to pass a pointer to the pointer to the handle (void **conn)
+ * to all functions which may call reconnect. This is so that if a new handle
+ * is created and returned, the handle pointer can be updated up the callstack,
+ * and a function higher up the stack doesn't attempt to use a now invalid
+ * connection handle.
+ *
+ * @note Will free any talloced memory hung off the context of the connection,
+ * being reconnected.
+ *
+ * @warning After calling reconnect the caller *MUST NOT* attempt to use
+ * the old handle in any other operations, as its memory will have been
+ * freed.
+ *
+ * @see fr_connection_get
+ * @param[in,out] pool to reconnect the connection in.
+ * @param[in,out] conn to reconnect.
+ * @return new connection handle if successful else NULL.
+ */
+void *fr_connection_reconnect(fr_connection_pool_t *pool, void *conn)
+{
+ void *new_conn;
+ fr_connection_t *this;
+
+ if (!pool || !conn) return NULL;
+
+ /*
+ * Don't allow opening of new connections if we're trying
+ * to exit.
+ */
+ if (main_config.exiting) {
+ fr_connection_release(pool, conn);
+ return NULL;
+ }
+
+ /*
+ * If fr_connection_find is successful the pool is now locked
+ */
+ this = fr_connection_find(pool, conn);
+ if (!this) return NULL;
+
+ new_conn = fr_connection_reconnect_internal(pool, this);
+ pthread_mutex_unlock(&pool->mutex);
+
+ return new_conn;
+}
+
+/** Delete a connection from the connection pool.
+ *
+ * Resolves the connection handle to a connection, then (if found)
+ * closes, unlinks and frees that connection.
+ *
+ * @note Must be called with the mutex free.
+ *
+ * @param[in,out] pool Connection pool to modify.
+ * @param[in] conn to delete.
+ * @param[in] msg why the connection was closed.
+ * @return
+ * - 0 If the connection could not be found.
+ * - 1 if the connection was deleted.
+ */
+int fr_connection_close(fr_connection_pool_t *pool, void *conn, char const *msg)
+{
+ fr_connection_t *this;
+
+ this = fr_connection_find(pool, conn);
+ if (!this) return 0;
+
+ fr_connection_close_internal(pool, this, "Deleting connection", msg);
+ fr_connection_pool_check(pool);
+ return 1;
+}
diff --git a/src/main/crypt.c b/src/main/crypt.c
new file mode 100644
index 0000000..99c66d8
--- /dev/null
+++ b/src/main/crypt.c
@@ -0,0 +1,97 @@
+/*
+ * crypt.c A thread-safe crypt wrapper
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+
+/*
+ * No pthreads, no mutex.
+ */
+static bool fr_crypt_init = false;
+static pthread_mutex_t fr_crypt_mutex;
+#endif
+
+
+/*
+ * performs a crypt password check in an thread-safe way.
+ *
+ * returns: 0 -- check succeeded
+ * -1 -- failed to crypt
+ * 1 -- check failed
+ */
+int fr_crypt_check(char const *key, char const *crypted)
+{
+ char *passwd;
+ int cmp = 0;
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Ensure we're thread-safe, as crypt() isn't.
+ */
+ if (fr_crypt_init == false) {
+ pthread_mutex_init(&fr_crypt_mutex, NULL);
+ fr_crypt_init = true;
+ }
+
+ pthread_mutex_lock(&fr_crypt_mutex);
+#endif
+
+ passwd = crypt(key, crypted);
+
+ /*
+ * Got something, check it within the lock. This is
+ * faster than copying it to a local buffer, and the
+ * time spent within the lock is critical.
+ */
+ if (passwd) {
+ cmp = strcmp(crypted, passwd);
+ }
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_unlock(&fr_crypt_mutex);
+#endif
+
+ /*
+ * Error.
+ */
+ if (!passwd) {
+ return -1;
+ }
+
+ /*
+ * OK, return OK.
+ */
+ if (cmp == 0) {
+ return 0;
+ }
+
+ /*
+ * Comparison failed.
+ */
+ return 1;
+}
diff --git a/src/main/detail.c b/src/main/detail.c
new file mode 100644
index 0000000..a5e8437
--- /dev/null
+++ b/src/main/detail.c
@@ -0,0 +1,1266 @@
+/*
+ * detail.c Process the detail file
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/detail.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+
+#include <fcntl.h>
+
+#ifdef WITH_DETAIL
+
+#define USEC (1000000)
+
+static FR_NAME_NUMBER state_names[] = {
+ { "unopened", STATE_UNOPENED },
+ { "unlocked", STATE_UNLOCKED },
+ { "header", STATE_HEADER },
+ { "reading", STATE_READING },
+ { "queued", STATE_QUEUED },
+ { "running", STATE_RUNNING },
+ { "no-reply", STATE_NO_REPLY },
+ { "replied", STATE_REPLIED },
+
+ { NULL, 0 }
+};
+
+
+/*
+ * If we're limiting outstanding packets, then mark the response
+ * as being sent.
+ */
+int detail_send(rad_listen_t *listener, REQUEST *request)
+{
+#ifdef WITH_DETAIL_THREAD
+ char c = 0;
+#endif
+ listen_detail_t *data = listener->data;
+
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == detail_send);
+
+ /*
+ * This request timed out. Remember that, and tell the
+ * caller it's OK to read more "detail" file stuff.
+ */
+ if (request->reply->code == 0) {
+ data->delay_time = data->retry_interval * USEC;
+ data->signal = 1;
+ data->state = STATE_NO_REPLY;
+
+ RDEBUG("detail (%s): No response to request. Will retry in %d seconds",
+ data->name, data->retry_interval);
+ } else {
+ int rtt;
+ struct timeval now;
+
+ RDEBUG("detail (%s): Done %s packet.", data->name, fr_packet_codes[request->packet->code]);
+
+ /*
+ * We call gettimeofday a lot. But it should be OK,
+ * because there's nothing else to do.
+ */
+ gettimeofday(&now, NULL);
+
+ /*
+ * If we haven't sent a packet in the last second, reset
+ * the RTT.
+ */
+ now.tv_sec -= 1;
+ if (timercmp(&data->last_packet, &now, <)) {
+ data->has_rtt = false;
+ }
+ now.tv_sec += 1;
+
+ /*
+ * Only one detail packet may be outstanding at a time,
+ * so it's safe to update some entries in the detail
+ * structure.
+ *
+ * We keep smoothed round trip time (SRTT), but not round
+ * trip timeout (RTO). We use SRTT to calculate a rough
+ * load factor.
+ */
+ rtt = now.tv_sec - request->packet->timestamp.tv_sec;
+ rtt *= USEC;
+ rtt += now.tv_usec;
+ rtt -= request->packet->timestamp.tv_usec;
+
+ /*
+ * If we're proxying, the RTT is our processing time,
+ * plus the network delay there and back, plus the time
+ * on the other end to process the packet. Ideally, we
+ * should remove the network delays from the RTT, but we
+ * don't know what they are.
+ *
+ * So, to be safe, we over-estimate the total cost of
+ * processing the packet.
+ */
+ if (!data->has_rtt) {
+ data->has_rtt = true;
+ data->srtt = rtt;
+ data->rttvar = rtt / 2;
+
+ } else {
+ data->rttvar -= data->rttvar >> 2;
+ data->rttvar += (data->srtt - rtt);
+ data->srtt -= data->srtt >> 3;
+ data->srtt += rtt >> 3;
+ }
+
+ /*
+ * Calculate the time we wait before sending the next
+ * packet.
+ *
+ * rtt / (rtt + delay) = load_factor / 100
+ */
+ data->delay_time = (data->srtt * (100 - data->load_factor)) / (data->load_factor);
+
+ /*
+ * Cap delay at no less than 4 packets/s. If the
+ * end system can't handle this, then it's very
+ * broken.
+ */
+ if (data->delay_time > (USEC / 4)) data->delay_time= USEC / 4;
+
+ RDEBUG3("detail (%s): Received response for request %d. Will read the next packet in %d seconds",
+ data->name, request->number, data->delay_time / USEC);
+
+ data->last_packet = now;
+ data->signal = 1;
+ data->state = STATE_REPLIED;
+ data->counter++;
+ }
+
+#ifdef WITH_DETAIL_THREAD
+ if (write(data->child_pipe[1], &c, 1) < 0) {
+ RERROR("detail (%s): Failed writing ack to reader thread: %s", data->name, fr_syserror(errno));
+ }
+#else
+ radius_signal_self(RADIUS_SIGNAL_SELF_DETAIL);
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Open the detail file, if we can.
+ *
+ * FIXME: create it, if it's not already there, so that the main
+ * server select() will wake us up if there's anything to read.
+ */
+static int detail_open(rad_listen_t *this)
+{
+ struct stat st;
+ listen_detail_t *data = this->data;
+
+ rad_assert(data->state == STATE_UNOPENED);
+ data->delay_time = USEC;
+
+ /*
+ * Open detail.work first, so we don't lose
+ * accounting packets. It's probably better to
+ * duplicate them than to lose them.
+ *
+ * Note that we're not writing to the file, but
+ * we've got to open it for writing in order to
+ * establish the lock, to prevent rlm_detail from
+ * writing to it.
+ *
+ * This also means that if we're doing globbing,
+ * this file will be read && processed before the
+ * file globbing is done.
+ */
+ data->fp = NULL;
+ data->work_fd = open(data->filename_work, O_RDWR);
+
+ /*
+ * Couldn't open it for a reason OTHER than "it doesn't
+ * exist". Complain and tell the admin.
+ */
+ if ((data->work_fd < 0) && (errno != ENOENT)) {
+ ERROR("Failed opening detail file %s: %s",
+ data->filename_work, fr_syserror(errno));
+ return 0;
+ }
+
+ /*
+ * The file doesn't exist. Poll for it again.
+ */
+ if (data->work_fd < 0) {
+#ifndef HAVE_GLOB_H
+ return 0;
+#else
+ unsigned int i;
+ int found;
+ time_t chtime;
+ char const *filename;
+ glob_t files;
+
+ DEBUG2("detail (%s): Polling for detail file", data->name);
+
+ memset(&files, 0, sizeof(files));
+ if (glob(data->filename, 0, NULL, &files) != 0) {
+ noop:
+ globfree(&files);
+ return 0;
+ }
+
+ /*
+ * Loop over the glob'd files, looking for the
+ * oldest one.
+ */
+ chtime = 0;
+ found = -1;
+ for (i = 0; i < files.gl_pathc; i++) {
+ if (stat(files.gl_pathv[i], &st) < 0) continue;
+
+ if ((i == 0) || (st.st_ctime < chtime)) {
+ chtime = st.st_ctime;
+ found = i;
+ }
+ }
+
+ if (found < 0) goto noop;
+
+ /*
+ * Rename detail to detail.work
+ */
+ filename = files.gl_pathv[found];
+
+ DEBUG("detail (%s): Renaming %s -> %s", data->name, filename, data->filename_work);
+ if (rename(filename, data->filename_work) < 0) {
+ ERROR("detail (%s): Failed renaming %s to %s: %s",
+ data->name, filename, data->filename_work, fr_syserror(errno));
+ goto noop;
+ }
+
+ globfree(&files); /* Shouldn't be using anything in files now */
+
+ /*
+ * And try to open the filename.
+ */
+ data->work_fd = open(data->filename_work, O_RDWR);
+ if (data->work_fd < 0) {
+ ERROR("Failed opening detail file %s: %s",
+ data->filename_work, fr_syserror(errno));
+ return 0;
+ }
+#endif
+ } /* else detail.work existed, and we opened it */
+
+ rad_assert(data->vps == NULL);
+ rad_assert(data->fp == NULL);
+
+ data->state = STATE_UNLOCKED;
+
+ data->client_ip.af = AF_UNSPEC;
+ data->timestamp = 0;
+ data->offset = data->last_offset = data->timestamp_offset = 0;
+ data->packets = 0;
+ data->tries = 0;
+ data->done_entry = false;
+
+ return 1;
+}
+
+
+/*
+ * FIXME: add a configuration "exit when done" so that the detail
+ * file reader can be used as a one-off tool to update stuff.
+ *
+ * The time sequence for reading from the detail file is:
+ *
+ * t_0 signalled that the server is idle, and we
+ * can read from the detail file.
+ *
+ * t_rtt the packet has been processed successfully,
+ * wait for t_delay to enforce load factor.
+ *
+ * t_rtt + t_delay wait for signal that the server is idle.
+ *
+ */
+#ifndef WITH_DETAIL_THREAD
+static RADIUS_PACKET *detail_poll(rad_listen_t *listener);
+
+int detail_recv(rad_listen_t *listener)
+{
+ RADIUS_PACKET *packet;
+ listen_detail_t *data = listener->data;
+ RAD_REQUEST_FUNP fun = NULL;
+
+ /*
+ * We may be in the main thread. It needs to update the
+ * timers before we try to read from the file again.
+ */
+ if (data->signal) return 0;
+
+ packet = detail_poll(listener);
+ if (!packet) return -1;
+
+ if (DEBUG_ENABLED2) {
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ DEBUG2("detail (%s): Read packet from %s", data->name, data->filename_work);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ debug_pair(vp);
+ }
+ }
+
+ switch (packet->code) {
+ case PW_CODE_ACCOUNTING_REQUEST:
+ fun = rad_accounting;
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ fun = rad_coa_recv;
+ break;
+
+ default:
+ rad_free(&packet);
+ data->state = STATE_REPLIED;
+ return 0;
+ }
+
+ /*
+ * Don't bother doing limit checks, etc.
+ */
+ if (!request_receive(NULL, listener, packet, &data->detail_client, fun)) {
+ rad_free(&packet);
+ data->state = STATE_NO_REPLY; /* try again later */
+ return 0;
+ }
+
+ return 1;
+}
+#else
+int detail_recv(rad_listen_t *listener)
+{
+ char c = 0;
+ ssize_t rcode;
+ RADIUS_PACKET *packet;
+ listen_detail_t *data = listener->data;
+ RAD_REQUEST_FUNP fun = NULL;
+
+ /*
+ * Block until there's a packet ready.
+ */
+ rcode = read(data->master_pipe[0], &packet, sizeof(packet));
+ if (rcode <= 0) return rcode;
+
+ rad_assert(packet != NULL);
+
+ if (DEBUG_ENABLED2) {
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ DEBUG2("detail (%s): Read packet from %s", data->name, data->filename_work);
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ debug_pair(vp);
+ }
+ }
+
+ switch (packet->code) {
+ case PW_CODE_ACCOUNTING_REQUEST:
+ fun = rad_accounting;
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ fun = rad_coa_recv;
+ break;
+
+ default:
+ data->state = STATE_REPLIED;
+ goto signal_thread;
+ }
+
+ if (!request_receive(NULL, listener, packet, &data->detail_client, fun)) {
+ data->state = STATE_NO_REPLY; /* try again later */
+
+ signal_thread:
+ rad_free(&packet);
+ if (write(data->child_pipe[1], &c, 1) < 0) {
+ ERROR("detail (%s): Failed writing ack to reader thread: %s", data->name,
+ fr_syserror(errno));
+ }
+ }
+
+ /*
+ * Wait for the child thread to write an answer to the pipe
+ */
+ return 0;
+}
+#endif
+
+static RADIUS_PACKET *detail_poll(rad_listen_t *listener)
+{
+ int y;
+ char key[256], op[8], value[1024];
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ RADIUS_PACKET *packet;
+ char buffer[2048];
+ listen_detail_t *data = listener->data;
+
+ switch (data->state) {
+ case STATE_UNOPENED:
+open_file:
+ rad_assert(data->work_fd < 0);
+
+ if (!detail_open(listener)) return NULL;
+
+ rad_assert(data->state == STATE_UNLOCKED);
+ rad_assert(data->work_fd >= 0);
+
+ /* FALL-THROUGH */
+
+ /*
+ * Try to lock fd. If we can't, return.
+ * If we can, continue. This means that
+ * the server doesn't block while waiting
+ * for the lock to open...
+ */
+ case STATE_UNLOCKED:
+ /*
+ * Note that we do NOT block waiting for
+ * the lock. We've re-named the file
+ * above, so we've already guaranteed
+ * that any *new* detail writer will not
+ * be opening this file. The only
+ * purpose of the lock is to catch a race
+ * condition where the execution
+ * "ping-pongs" between radiusd &
+ * radrelay.
+ */
+ if (rad_lockfd_nonblock(data->work_fd, 0) < 0) {
+ /*
+ * Close the FD. The main loop
+ * will wake up in a second and
+ * try again.
+ */
+ close(data->work_fd);
+ data->fp = NULL;
+ data->work_fd = -1;
+ data->state = STATE_UNOPENED;
+ return NULL;
+ }
+
+ /*
+ * Only open for writing if we're
+ * marking requests as completed.
+ */
+ data->fp = fdopen(data->work_fd, data->track ? "r+" : "r");
+ if (!data->fp) {
+ ERROR("detail (%s): FATAL: Failed to re-open detail file: %s",
+ data->name, fr_syserror(errno));
+ fr_exit(1);
+ }
+
+ /*
+ * Look for the header
+ */
+ data->state = STATE_HEADER;
+ data->delay_time = USEC;
+ data->vps = NULL;
+
+ /* FALL-THROUGH */
+
+ case STATE_HEADER:
+ do_header:
+ rad_assert(data->ctx == NULL);
+ MEM(data->ctx = talloc_init("detail"));
+
+ data->done_entry = false;
+ data->timestamp_offset = 0;
+
+ data->tries = 0;
+ if (!data->fp) {
+ data->state = STATE_UNOPENED;
+ goto open_file;
+ }
+
+ {
+ struct stat buf;
+
+ if (fstat(data->work_fd, &buf) < 0) {
+ ERROR("detail (%s): Failed to stat detail file: %s",
+ data->name, fr_syserror(errno));
+
+ goto cleanup;
+ }
+ if (((off_t) ftell(data->fp)) == buf.st_size) {
+ goto cleanup;
+ }
+ }
+
+ /*
+ * End of file. Delete it, and re-set
+ * everything.
+ */
+ if (feof(data->fp)) {
+ cleanup:
+ DEBUG("detail (%s): Unlinking %s", data->name, data->filename_work);
+ unlink(data->filename_work);
+ if (data->fp) fclose(data->fp);
+ TALLOC_FREE(data->ctx);
+ data->fp = NULL;
+ data->work_fd = -1;
+ data->state = STATE_UNOPENED;
+ rad_assert(data->vps == NULL);
+
+ if (data->one_shot) {
+ INFO("detail (%s): Finished reading \"one shot\" detail file - Exiting", data->name);
+ radius_signal_self(RADIUS_SIGNAL_SELF_EXIT);
+ }
+
+ return NULL;
+ }
+
+ /*
+ * Else go read something.
+ */
+ if (!fgets(buffer, sizeof(buffer), data->fp)) {
+ DEBUG("detail (%s): Failed reading header from file - %s",
+ data->name, data->filename_work);
+ goto cleanup;
+ }
+
+ /*
+ * Badly formatted file: delete it.
+ */
+ if (!strchr(buffer, '\n')) {
+ DEBUG("detail (%s): Invalid line without trailing LF - %s", data->name, buffer);
+ goto cleanup;
+ }
+
+ if (!sscanf(buffer, "%*s %*s %*d %*d:%*d:%*d %d", &y)) {
+ DEBUG("detail (%s): Failed reading detail file header in line - %s", data->name, buffer);
+ goto cleanup;
+ }
+
+ data->state = STATE_READING;
+ /* FALL-THROUGH */
+
+
+ /*
+ * Read more value-pair's, unless we're
+ * at EOF. In that case, queue whatever
+ * we have.
+ */
+ case STATE_READING:
+ rad_assert(data->fp != NULL);
+
+ fr_cursor_init(&cursor, &data->vps);
+
+ /*
+ * Read a header, OR a value-pair.
+ */
+ while (fgets(buffer, sizeof(buffer), data->fp)) {
+ data->last_offset = data->offset;
+ data->offset = ftell(data->fp); /* for statistics */
+
+ /*
+ * Badly formatted file: delete it.
+ */
+ if (!strchr(buffer, '\n')) {
+ WARN("detail (%s): Skipping line without trailing LF - %s", data->name, buffer);
+ fr_pair_list_free(&data->vps);
+ goto cleanup;
+ }
+
+ /*
+ * We're reading VP's, and got a blank line.
+ * That indicates the end of an entry. Queue the
+ * packet.
+ */
+ if (buffer[0] == '\n') {
+ data->state = STATE_QUEUED;
+ data->tries = 0;
+ data->packets++;
+ goto alloc_packet;
+ }
+
+ /*
+ * We have a full "attribute = value" line.
+ * If it doesn't look reasonable, skip it.
+ *
+ * FIXME: print an error for badly formatted attributes?
+ */
+ if (sscanf(buffer, "%255s %7s %1023s", key, op, value) != 3) {
+ DEBUG("detail (%s): Skipping badly formatted line - %s", data->name, buffer);
+ continue;
+ }
+
+ /*
+ * Should be =, :=, +=, ...
+ */
+ if (!strchr(op, '=')) {
+ DEBUG("detail (%s): Skipping line without operator - %s", data->name, buffer);
+ continue;
+ }
+
+ /*
+ * Skip non-protocol attributes.
+ */
+ if (!strcasecmp(key, "Request-Authenticator")) continue;
+
+ /*
+ * Set the original client IP address, based on
+ * what's in the detail file.
+ *
+ * Hmm... we don't set the server IP address.
+ * or port. Oh well.
+ */
+ if (!strcasecmp(key, "Client-IP-Address")) {
+ data->client_ip.af = AF_INET;
+ if (ip_hton(&data->client_ip, AF_INET, value, false) < 0) {
+ DEBUG("detail (%s): Failed parsing Client-IP-Address", data->name);
+ fr_pair_list_free(&data->vps);
+ goto cleanup;
+ }
+ continue;
+ }
+
+ /*
+ * The original time at which we received the
+ * packet. We need this to properly calculate
+ * Acct-Delay-Time.
+ */
+ if (!strcasecmp(key, "Timestamp")) {
+ data->timestamp = atoi(value);
+ data->timestamp_offset = data->last_offset;
+
+ vp = fr_pair_afrom_num(data->ctx, PW_PACKET_ORIGINAL_TIMESTAMP, 0);
+ if (vp) {
+ vp->vp_date = (uint32_t) data->timestamp;
+ vp->type = VT_DATA;
+ fr_cursor_insert(&cursor, vp);
+ }
+ continue;
+ }
+
+ if (!strcasecmp(key, "Donestamp")) {
+ data->timestamp = atoi(value);
+ data->done_entry = true;
+ continue;
+ }
+
+ DEBUG3("detail (%s): Trying to read VP from line - %s", data->name, buffer);
+
+ /*
+ * Read one VP.
+ *
+ * FIXME: do we want to check for non-protocol
+ * attributes like radsqlrelay does?
+ */
+ vp = NULL;
+ if ((fr_pair_list_afrom_str(data->ctx, buffer, &vp) > 0) &&
+ (vp != NULL)) {
+ fr_cursor_merge(&cursor, vp);
+ } else {
+ DEBUG("detail (%s): Failed reading VP from line - %s", data->name, buffer);
+ goto cleanup;
+ }
+ }
+
+ /*
+ * The writer doesn't check that the
+ * record was completely written. If the
+ * disk is full, this can result in a
+ * truncated record which has no trailing
+ * blank line. When that happens, it's a
+ * bad record, and we ignore it.
+ */
+ if (feof(data->fp)) {
+ DEBUG("detail (%s): Truncated record: treating it as EOF for detail file %s",
+ data->name, data->filename_work);
+ fr_pair_list_free(&data->vps);
+ goto cleanup;
+ }
+
+ /*
+ * Some kind of non-eof error.
+ *
+ * FIXME: Leave the file in-place, and warn the
+ * administrator?
+ */
+ DEBUG("detail (%s): Unknown error, deleting detail file %s",
+ data->name, data->filename_work);
+ goto cleanup;
+
+ case STATE_QUEUED:
+ goto alloc_packet;
+
+ /*
+ * Periodically check what's going on.
+ * If the request is taking too long,
+ * retry it.
+ */
+ case STATE_RUNNING:
+ if (time(NULL) < (data->running + (int)data->retry_interval)) {
+ return NULL;
+ }
+
+ DEBUG("detail (%s): No response to detail request. Retrying", data->name);
+ /* FALL-THROUGH */
+
+ /*
+ * If there's no reply, keep
+ * retransmitting the current packet
+ * forever.
+ */
+ case STATE_NO_REPLY:
+ data->state = STATE_QUEUED;
+ goto alloc_packet;
+
+ /*
+ * We have a reply. Clean up the old
+ * request, and go read another one.
+ */
+ case STATE_REPLIED:
+ if (data->track) {
+ rad_assert(data->fp != NULL);
+
+ if (fseek(data->fp, data->timestamp_offset, SEEK_SET) < 0) {
+ DEBUG("detail (%s): Failed seeking to timestamp offset: %s",
+ data->name, fr_syserror(errno));
+ } else if (fwrite("\tDone", 1, 5, data->fp) < 5) {
+ DEBUG("detail (%s): Failed marking request as done: %s",
+ data->name, fr_syserror(errno));
+ } else if (fflush(data->fp) != 0) {
+ DEBUG("detail (%s): Failed flushing marked detail file to disk: %s",
+ data->name, fr_syserror(errno));
+ }
+
+ if (fseek(data->fp, data->offset, SEEK_SET) < 0) {
+ DEBUG("detail (%s): Failed seeking to next detail request: %s",
+ data->name, fr_syserror(errno));
+ }
+ }
+
+ fr_pair_list_free(&data->vps);
+ TALLOC_FREE(data->ctx);
+ data->state = STATE_HEADER;
+ goto do_header;
+ }
+
+ /*
+ * Process the packet.
+ */
+ alloc_packet:
+ if (data->done_entry) {
+ DEBUG2("detail (%s): Skipping record for timestamp %lu", data->name, data->timestamp);
+ fr_pair_list_free(&data->vps);
+ TALLOC_FREE(data->ctx);
+ data->state = STATE_HEADER;
+ goto do_header;
+ }
+
+ data->tries++;
+
+ /*
+ * We're done reading the file, but we didn't read
+ * anything. Clean up, and don't return anything.
+ */
+ if (!data->vps) {
+ WARN("detail (%s): Read empty packet from file %s",
+ data->name, data->filename_work);
+ data->state = STATE_HEADER;
+ return NULL;
+ }
+
+ /*
+ * Allocate the packet. If we fail, it's a serious
+ * problem.
+ */
+ packet = rad_alloc(NULL, true);
+ if (!packet) {
+ ERROR("detail (%s): FATAL: Failed allocating memory for detail", data->name);
+ fr_exit(1);
+ }
+
+ memset(packet, 0, sizeof(*packet));
+ packet->sockfd = -1;
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
+
+ /*
+ * If everything's OK, this is a waste of memory.
+ * Otherwise, it lets us re-send the original packet
+ * contents, unmolested.
+ */
+ packet->vps = fr_pair_list_copy(packet, data->vps);
+
+ packet->code = PW_CODE_ACCOUNTING_REQUEST;
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (vp) packet->code = vp->vp_integer;
+
+ gettimeofday(&packet->timestamp, NULL);
+
+ /*
+ * Remember where it came from, so that we don't
+ * proxy it to the place it came from...
+ */
+ if (data->client_ip.af != AF_UNSPEC) {
+ packet->src_ipaddr = data->client_ip;
+ }
+
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_SRC_IP_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ packet->src_ipaddr.prefix = 32;
+ } else {
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_SRC_IPV6_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ packet->src_ipaddr.af = AF_INET6;
+ memcpy(&packet->src_ipaddr.ipaddr.ip6addr,
+ &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+ packet->src_ipaddr.prefix = 128;
+ }
+ }
+
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ packet->dst_ipaddr.af = AF_INET;
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ packet->dst_ipaddr.prefix = 32;
+ } else {
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ packet->dst_ipaddr.af = AF_INET6;
+ memcpy(&packet->dst_ipaddr.ipaddr.ip6addr,
+ &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+ packet->dst_ipaddr.prefix = 128;
+ }
+ }
+
+ /*
+ * Generate packet ID, ports, IP via a counter.
+ */
+ packet->id = data->counter & 0xff;
+ packet->src_port = 1024 + ((data->counter >> 8) & 0xff);
+ packet->dst_port = 1024 + ((data->counter >> 16) & 0xff);
+
+ packet->dst_ipaddr.af = AF_INET;
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl((INADDR_LOOPBACK & ~0xffffff) | ((data->counter >> 24) & 0xff));
+
+ /*
+ * Create / update accounting attributes.
+ */
+ if (packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ /*
+ * Prefer the Event-Timestamp in the packet, if it
+ * exists. That is when the event occurred, whereas the
+ * "Timestamp" field is when we wrote the packet to the
+ * detail file, which could have been much later.
+ */
+ vp = fr_pair_find_by_num(packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY);
+ if (vp) {
+ data->timestamp = vp->vp_integer;
+ }
+
+ /*
+ * Look for Acct-Delay-Time, and update
+ * based on Acct-Delay-Time += (time(NULL) - timestamp)
+ */
+ vp = fr_pair_find_by_num(packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(packet, PW_ACCT_DELAY_TIME, 0);
+ rad_assert(vp != NULL);
+ fr_pair_add(&packet->vps, vp);
+ }
+ if (data->timestamp != 0) {
+ vp->vp_integer += time(NULL) - data->timestamp;
+ }
+ }
+
+ /*
+ * Set the transmission count.
+ */
+ vp = fr_pair_find_by_num(packet->vps, PW_PACKET_TRANSMIT_COUNTER, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(packet, PW_PACKET_TRANSMIT_COUNTER, 0);
+ rad_assert(vp != NULL);
+ fr_pair_add(&packet->vps, vp);
+ }
+ vp->vp_integer = data->tries;
+
+ data->state = STATE_RUNNING;
+ data->running = packet->timestamp.tv_sec;
+
+ return packet;
+}
+
+/*
+ * Free detail-specific stuff.
+ */
+void detail_free(rad_listen_t *this)
+{
+ listen_detail_t *data = this->data;
+
+#ifdef WITH_DETAIL_THREAD
+ if (!check_config) {
+ ssize_t ret;
+ void *arg = NULL;
+
+ /*
+ * Mark the child pipes as unusable
+ */
+ close(data->child_pipe[0]);
+ close(data->child_pipe[1]);
+ data->child_pipe[0] = -1;
+
+ /*
+ * Tell it to stop (interrupting its sleep)
+ */
+ pthread_kill(data->pthread_id, SIGTERM);
+
+ /*
+ * Wait for it to acknowledge that it's stopped.
+ */
+ ret = read(data->master_pipe[0], &arg, sizeof(arg));
+ if (ret < 0) {
+ ERROR("detail (%s): Reader thread exited without informing the master: %s",
+ data->name, fr_syserror(errno));
+ } else if (ret != sizeof(arg)) {
+ ERROR("detail (%s): Invalid thread pointer received from reader thread during exit",
+ data->name);
+ ERROR("detail (%s): Expected %zu bytes, got %zi bytes", data->name, sizeof(arg), ret);
+ }
+
+ close(data->master_pipe[0]);
+ close(data->master_pipe[1]);
+
+ if (arg) pthread_join(data->pthread_id, &arg);
+ }
+#endif
+
+ if (data->fp != NULL) {
+ fclose(data->fp);
+ data->fp = NULL;
+ }
+}
+
+
+int detail_print(rad_listen_t const *this, char *buffer, size_t bufsize)
+{
+ if (!this->server) {
+ return snprintf(buffer, bufsize, "%s",
+ ((listen_detail_t *)(this->data))->filename);
+ }
+
+ return snprintf(buffer, bufsize, "detail file %s as server %s",
+ ((listen_detail_t *)(this->data))->filename,
+ this->server);
+}
+
+
+/*
+ * Delay while waiting for a file to be ready
+ */
+static int detail_delay(listen_detail_t *data)
+{
+ int delay = (data->poll_interval - 1) * USEC;
+
+ /*
+ * Add +/- 0.25s of jitter
+ */
+ delay += (USEC * 3) / 4;
+ delay += fr_rand() % (USEC / 2);
+
+ DEBUG2("detail (%s): Detail listener state %s waiting %d.%06d sec",
+ data->name,
+ fr_int2str(state_names, data->state, "?"),
+ (delay / USEC), delay % USEC);
+
+ return delay;
+}
+
+/*
+ * Overloaded to return delay times.
+ */
+int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
+{
+#ifdef WITH_DETAIL_THREAD
+ return 0;
+#else
+ listen_detail_t *data = this->data;
+
+ /*
+ * We haven't sent a packet... delay things a bit.
+ */
+ if (!data->signal) return detail_delay(data);
+
+ data->signal = 0;
+
+ DEBUG2("detail (%s): Detail listener state %s signalled %d waiting %d.%06d sec",
+ data->name,
+ fr_int2str(state_names, data->state, "?"),
+ data->signal,
+ data->delay_time / USEC,
+ data->delay_time % USEC);
+
+ return data->delay_time;
+#endif
+}
+
+/*
+ * Overloaded to return "should we fix delay times"
+ */
+int detail_decode(rad_listen_t *this, REQUEST *request)
+{
+#ifdef WITH_DETAIL_THREAD
+ listen_detail_t *data = this->data;
+
+ RDEBUG("Received %s from detail file %s",
+ fr_packet_codes[request->packet->code], data->filename_work);
+
+ rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, "\t");
+
+ return 0;
+#else
+ listen_detail_t *data = this->data;
+
+ RDEBUG("Received %s from detail file %s",
+ fr_packet_codes[request->packet->code], data->filename_work);
+
+ rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, "\t");
+
+ return data->signal;
+#endif
+}
+
+
+#ifdef WITH_DETAIL_THREAD
+static void *detail_handler_thread(void *arg)
+{
+ char c;
+ rad_listen_t *this = arg;
+ listen_detail_t *data = this->data;
+
+ while (true) {
+ RADIUS_PACKET *packet;
+
+ while ((packet = detail_poll(this)) == NULL) {
+ usleep(detail_delay(data));
+
+ /*
+ * If we're supposed to exit then tell
+ * the master thread we've exited.
+ */
+ if (data->child_pipe[0] < 0) {
+ packet = NULL;
+ if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
+ ERROR("detail (%s): Failed writing exit status to master: %s",
+ data->name, fr_syserror(errno));
+ }
+ return NULL;
+ }
+ }
+
+ /*
+ * Keep retrying forever.
+ *
+ * FIXME: cap the retries.
+ */
+ do {
+ if (write(data->master_pipe[1], &packet, sizeof(packet)) < 0) {
+ ERROR("detail (%s): Failed passing detail packet pointer to master: %s",
+ data->name, fr_syserror(errno));
+ }
+
+ if (read(data->child_pipe[0], &c, 1) < 0) {
+ ERROR("detail (%s): Failed getting detail packet ack from master: %s",
+ data->name, fr_syserror(errno));
+ break;
+ }
+
+ if (data->delay_time > 0) usleep(data->delay_time);
+
+ packet = detail_poll(this);
+ if (!packet) break;
+ } while (data->state != STATE_REPLIED);
+ }
+
+ return NULL;
+}
+#endif
+
+
+static const CONF_PARSER detail_config[] = {
+ { "detail", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, listen_detail_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, listen_detail_t, filename), NULL },
+ { "load_factor", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, load_factor), STRINGIFY(10) },
+ { "poll_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, poll_interval), STRINGIFY(1) },
+ { "retry_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_detail_t, retry_interval), STRINGIFY(30) },
+ { "one_shot", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, listen_detail_t, one_shot), "no" },
+ { "track", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, listen_detail_t, track), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Parse a detail section.
+ */
+int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
+{
+ int rcode;
+ listen_detail_t *data;
+ RADCLIENT *client;
+ char buffer[2048];
+
+ data = this->data;
+
+ rcode = cf_section_parse(cs, data, detail_config);
+ if (rcode < 0) {
+ cf_log_err_cs(cs, "Failed parsing listen section");
+ return -1;
+ }
+
+ data->name = cf_section_name2(cs);
+ if (!data->name) data->name = data->filename;
+
+ /*
+ * We don't do duplicate detection for "detail" sockets.
+ */
+ this->nodup = true;
+ this->synchronous = false;
+
+ if (!data->filename) {
+ cf_log_err_cs(cs, "No detail file specified in listen section");
+ return -1;
+ }
+
+ FR_INTEGER_BOUND_CHECK("load_factor", data->load_factor, >=, 1);
+ FR_INTEGER_BOUND_CHECK("load_factor", data->load_factor, <=, 100);
+
+ FR_INTEGER_BOUND_CHECK("poll_interval", data->poll_interval, >=, 1);
+ FR_INTEGER_BOUND_CHECK("poll_interval", data->poll_interval, <=, 60);
+
+ FR_INTEGER_BOUND_CHECK("retry_interval", data->retry_interval, >=, 4);
+ FR_INTEGER_BOUND_CHECK("retry_interval", data->retry_interval, <=, 3600);
+
+ /*
+ * Only checking the config. Don't start threads or anything else.
+ */
+ if (check_config) return 0;
+
+ /*
+ * If the filename is a glob, use "detail.work" as the
+ * work file name.
+ */
+ if ((strchr(data->filename, '*') != NULL) ||
+ (strchr(data->filename, '[') != NULL)) {
+ char *p;
+
+#ifndef HAVE_GLOB_H
+ WARN("detail (%s): File \"%s\" appears to use file globbing, but it is not supported on this system",
+ data->name, data->filename);
+#endif
+ strlcpy(buffer, data->filename, sizeof(buffer));
+ p = strrchr(buffer, FR_DIR_SEP);
+ if (p) {
+ p[1] = '\0';
+ } else {
+ buffer[0] = '\0';
+ }
+
+ /*
+ * Globbing cannot be done across directories.
+ */
+ if ((strchr(buffer, '*') != NULL) ||
+ (strchr(buffer, '[') != NULL)) {
+ cf_log_err_cs(cs, "Wildcard directories are not supported");
+ return -1;
+ }
+
+ strlcat(buffer, "detail.work",
+ sizeof(buffer) - strlen(buffer));
+
+ } else {
+ snprintf(buffer, sizeof(buffer), "%s.work", data->filename);
+ }
+
+ data->filename_work = talloc_strdup(data, buffer);
+
+ data->work_fd = -1;
+ data->vps = NULL;
+ data->fp = NULL;
+ data->state = STATE_UNOPENED;
+ data->delay_time = data->poll_interval * USEC;
+ data->signal = 1;
+
+ /*
+ * Initialize the fake client.
+ */
+ client = &data->detail_client;
+ memset(client, 0, sizeof(*client));
+ client->ipaddr.af = AF_INET;
+ client->ipaddr.ipaddr.ip4addr.s_addr = INADDR_NONE;
+ client->ipaddr.prefix = 0;
+ client->longname = client->shortname = data->filename;
+ client->secret = client->shortname;
+ client->nas_type = talloc_strdup(data, "none"); /* Part of 'data' not dynamically allocated */
+
+#ifdef WITH_DETAIL_THREAD
+ /*
+ * Create the communication pipes.
+ */
+ if (pipe(data->master_pipe) < 0) {
+ ERROR("detail (%s): Error opening internal pipe: %s", data->name, fr_syserror(errno));
+ fr_exit(1);
+ }
+
+ if (pipe(data->child_pipe) < 0) {
+ ERROR("detail (%s): Error opening internal pipe: %s", data->name, fr_syserror(errno));
+ fr_exit(1);
+ }
+
+ pthread_create(&data->pthread_id, NULL, detail_handler_thread, this);
+
+ this->fd = data->master_pipe[0];
+#endif
+
+ return 0;
+}
+#endif
diff --git a/src/main/evaluate.c b/src/main/evaluate.c
new file mode 100644
index 0000000..c8585b6
--- /dev/null
+++ b/src/main/evaluate.c
@@ -0,0 +1,1144 @@
+/*
+ * evaluate.c Evaluate complex conditions
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#ifdef WITH_UNLANG
+#ifdef WITH_EVAL_DEBUG
+# define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
+#else
+# define EVAL_DEBUG(...)
+#endif
+
+FR_NAME_NUMBER const modreturn_table[] = {
+ { "reject", RLM_MODULE_REJECT },
+ { "fail", RLM_MODULE_FAIL },
+ { "ok", RLM_MODULE_OK },
+ { "handled", RLM_MODULE_HANDLED },
+ { "invalid", RLM_MODULE_INVALID },
+ { "userlock", RLM_MODULE_USERLOCK },
+ { "notfound", RLM_MODULE_NOTFOUND },
+ { "noop", RLM_MODULE_NOOP },
+ { "updated", RLM_MODULE_UPDATED },
+ { NULL, 0 }
+};
+
+
+static bool all_digits(char const *string)
+{
+ char const *p = string;
+
+ rad_assert(p != NULL);
+
+ if (*p == '\0') return false;
+
+ if (*p == '-') p++;
+
+ while (isdigit((uint8_t) *p)) p++;
+
+ return (*p == '\0');
+}
+
+/** Evaluate a template
+ *
+ * Converts a vp_tmpl_t to a boolean value.
+ *
+ * @param[in] request the REQUEST
+ * @param[in] modreturn the previous module return code
+ * @param[in] depth of the recursion (only used for debugging)
+ * @param[in] vpt the template to evaluate
+ * @return -1 on error, 0 for "no match", 1 for "match".
+ */
+int radius_evaluate_tmpl(REQUEST *request, int modreturn, UNUSED int depth, vp_tmpl_t const *vpt)
+{
+ int rcode;
+ int modcode;
+ value_data_t data;
+
+ switch (vpt->type) {
+ case TMPL_TYPE_LITERAL:
+ modcode = fr_str2int(modreturn_table, vpt->name, RLM_MODULE_UNKNOWN);
+ if (modcode != RLM_MODULE_UNKNOWN) {
+ rcode = (modcode == modreturn);
+ break;
+ }
+
+ /*
+ * Else it's a literal string. Empty string is
+ * false, non-empty string is true.
+ *
+ * @todo: Maybe also check for digits?
+ *
+ * The VPT *doesn't* have a "bare word" type,
+ * which arguably it should.
+ */
+ rcode = (*vpt->name != '\0');
+ break;
+
+ case TMPL_TYPE_ATTR:
+ case TMPL_TYPE_LIST:
+ if (tmpl_find_vp(NULL, request, vpt) == 0) {
+ rcode = true;
+ } else {
+ rcode = false;
+ }
+ break;
+
+ case TMPL_TYPE_XLAT_STRUCT:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_EXEC:
+ {
+ char *p;
+
+ if (!*vpt->name) return false;
+ rcode = tmpl_aexpand(request, &p, request, vpt, NULL, NULL);
+ if (rcode < 0) {
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ return -1;
+ }
+ data.strvalue = p;
+ rcode = (data.strvalue && (*data.strvalue != '\0'));
+ talloc_free(data.ptr);
+ }
+ break;
+
+ /*
+ * Can't have a bare ... (/foo/) ...
+ */
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_REGEX_STRUCT:
+ rad_assert(0 == 1);
+ /* FALL-THROUGH */
+
+ default:
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ rcode = -1;
+ break;
+ }
+
+ return rcode;
+}
+
+#ifdef HAVE_REGEX
+/** Perform a regular expressions comparison between two operands
+ *
+ * @return -1 on error, 0 for "no match", 1 for "match".
+ */
+static int cond_do_regex(REQUEST *request, fr_cond_t const *c,
+ PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
+ PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
+{
+ vp_map_t const *map = c->data.map;
+
+ ssize_t slen;
+ int ret;
+
+ regex_t *preg, *rreg = NULL;
+ regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* +1 for %{0} (whole match) capture group */
+ size_t nmatch = sizeof(rxmatch) / sizeof(regmatch_t);
+
+ if (!lhs || (lhs_type != PW_TYPE_STRING)) return -1;
+
+ EVAL_DEBUG("CMP WITH REGEX %s %s",
+ map->rhs->tmpl_iflag ? "CASE INSENSITIVE" : "CASE SENSITIVE",
+ map->rhs->tmpl_mflag ? "MULTILINE" : "SINGLELINE");
+
+ switch (map->rhs->type) {
+ case TMPL_TYPE_REGEX_STRUCT: /* pre-compiled to a regex */
+ preg = map->rhs->tmpl_preg;
+#ifdef HAVE_PCRE
+ rad_assert(preg->precompiled);
+#endif
+ break;
+
+ default:
+ rad_assert(rhs_type == PW_TYPE_STRING);
+ rad_assert(rhs->strvalue);
+ slen = regex_compile(request, &rreg, rhs->strvalue, rhs_len,
+ map->rhs->tmpl_iflag, map->rhs->tmpl_mflag, true, true);
+ if (slen <= 0) {
+ REMARKER(rhs->strvalue, -slen, fr_strerror());
+ EVAL_DEBUG("FAIL %d", __LINE__);
+
+ return -1;
+ }
+ preg = rreg;
+#ifdef HAVE_PCRE
+ rad_assert(!preg->precompiled);
+#endif
+ break;
+ }
+
+ ret = regex_exec(preg, lhs->strvalue, lhs_len, rxmatch, &nmatch);
+ switch (ret) {
+ case 0:
+ EVAL_DEBUG("CLEARING SUBCAPTURES");
+ regex_sub_to_request(request, NULL, NULL, 0, NULL, 0); /* clear out old entries */
+ break;
+
+ case 1:
+ EVAL_DEBUG("SETTING SUBCAPTURES");
+ regex_sub_to_request(request, &preg, lhs->strvalue, lhs_len, rxmatch, nmatch);
+ break;
+
+ case -1:
+ EVAL_DEBUG("REGEX ERROR");
+ REDEBUG("regex failed: %s", fr_strerror());
+ break;
+
+ default:
+ break;
+ }
+
+ if (preg) talloc_free(rreg);
+
+ return ret;
+}
+#endif
+
+#ifdef WITH_EVAL_DEBUG
+static void cond_print_operands(REQUEST *request,
+ PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
+ PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
+{
+ if (lhs) {
+ if (lhs_type == PW_TYPE_STRING) {
+ EVAL_DEBUG("LHS: \"%s\" (%zu)" , lhs->strvalue, lhs_len);
+ } else {
+ char *lhs_hex;
+
+ lhs_hex = talloc_array(request, char, (lhs_len * 2) + 1);
+
+ if (lhs_type == PW_TYPE_OCTETS) {
+ fr_bin2hex(lhs_hex, lhs->octets, lhs_len);
+ } else {
+ fr_bin2hex(lhs_hex, (uint8_t const *)lhs, lhs_len);
+ }
+
+ EVAL_DEBUG("LHS: 0x%s (%zu)", lhs_hex, lhs_len);
+
+ talloc_free(lhs_hex);
+ }
+ } else {
+ EVAL_DEBUG("LHS: VIRTUAL");
+ }
+
+ if (rhs) {
+ if (rhs_type == PW_TYPE_STRING) {
+ EVAL_DEBUG("RHS: \"%s\" (%zu)" , rhs->strvalue, rhs_len);
+ } else {
+ char *rhs_hex;
+
+ rhs_hex = talloc_array(request, char, (rhs_len * 2) + 1);
+
+ if (rhs_type == PW_TYPE_OCTETS) {
+ fr_bin2hex(rhs_hex, rhs->octets, rhs_len);
+ } else {
+ fr_bin2hex(rhs_hex, (uint8_t const *)rhs, rhs_len);
+ }
+
+ EVAL_DEBUG("RHS: 0x%s (%zu)", rhs_hex, rhs_len);
+
+ talloc_free(rhs_hex);
+ }
+ } else {
+ EVAL_DEBUG("RHS: COMPILED");
+ }
+}
+#endif
+
+/** Call the correct data comparison function for the condition
+ *
+ * Deals with regular expression comparisons, virtual attribute
+ * comparisons, and data comparisons.
+ *
+ * @return -1 on error, 0 for "no match", 1 for "match".
+ */
+static int cond_cmp_values(REQUEST *request, fr_cond_t const *c,
+ PW_TYPE lhs_type, value_data_t const *lhs, size_t lhs_len,
+ PW_TYPE rhs_type, value_data_t const *rhs, size_t rhs_len)
+{
+ vp_map_t const *map = c->data.map;
+ int rcode;
+
+#ifdef WITH_EVAL_DEBUG
+ EVAL_DEBUG("CMP OPERANDS");
+ cond_print_operands(request, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+#endif
+
+#ifdef HAVE_REGEX
+ /*
+ * Regex comparison
+ */
+ if (map->op == T_OP_REG_EQ) {
+ rcode = cond_do_regex(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+ goto finish;
+ }
+#endif
+ /*
+ * Virtual attribute comparison.
+ */
+ if (c->pass2_fixup == PASS2_PAIRCOMPARE) {
+ VALUE_PAIR *vp;
+
+ EVAL_DEBUG("CMP WITH PAIRCOMPARE");
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+
+ vp = fr_pair_afrom_da(request, map->lhs->tmpl_da);
+ vp->op = c->data.map->op;
+
+ value_data_copy(vp, &vp->data, rhs_type, rhs, rhs_len);
+ vp->vp_length = rhs_len;
+
+ rcode = paircompare(request, request->packet->vps, vp, NULL);
+ rcode = (rcode == 0) ? 1 : 0;
+ talloc_free(vp);
+ goto finish;
+ }
+
+ /*
+ * At this point both operands should have been normalised
+ * to the same type, and there's no special comparisons
+ * left.
+ */
+ rad_assert(lhs_type == rhs_type);
+
+ EVAL_DEBUG("CMP WITH VALUE DATA");
+ rcode = value_data_cmp_op(map->op, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+finish:
+ switch (rcode) {
+ case 0:
+ EVAL_DEBUG("FALSE");
+ break;
+
+ case 1:
+ EVAL_DEBUG("TRUE");
+ break;
+
+ default:
+ EVAL_DEBUG("ERROR %i", rcode);
+ break;
+ }
+
+ return rcode;
+}
+
+
+static size_t regex_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ char *p = out;
+
+ while (*in && (outlen > 2)) {
+ switch (*in) {
+ case '\\':
+ case '.':
+ case '*':
+ case '+':
+ case '?':
+ case '|':
+ case '^':
+ case '$':
+ case '[': /* we don't list close braces */
+ case '{':
+ case '(':
+ *(p++) = '\\';
+ outlen--;
+ /* FALL-THROUGH */
+
+ default:
+ *(p++) = *(in++);
+ outlen--;
+ break;
+ }
+ }
+
+ *(p++) = '\0';
+ return p - out;
+}
+
+
+/** Convert both operands to the same type
+ *
+ * If casting is successful, we call cond_cmp_values to do the comparison
+ *
+ * @return -1 on error, 0 for "no match", 1 for "match".
+ */
+static int cond_normalise_and_cmp(REQUEST *request, fr_cond_t const *c,
+ PW_TYPE lhs_type, DICT_ATTR const *lhs_enumv,
+ value_data_t const *lhs, size_t lhs_len)
+{
+ vp_map_t const *map = c->data.map;
+
+ DICT_ATTR const *cast = NULL;
+ PW_TYPE cast_type = PW_TYPE_INVALID;
+
+ int rcode;
+
+ PW_TYPE rhs_type = PW_TYPE_INVALID;
+ DICT_ATTR const *rhs_enumv = NULL;
+ value_data_t const *rhs = NULL;
+ size_t rhs_len;
+
+ value_data_t lhs_cast, rhs_cast;
+ void *lhs_cast_buff = NULL, *rhs_cast_buff = NULL;
+
+ xlat_escape_t escape = NULL;
+
+ /*
+ * Cast operand to correct type.
+ *
+ * With hack for strings that look like integers, to cast them
+ * to 64 bit unsigned integers.
+ *
+ * @fixme For things like this it'd be useful to have a 64bit signed type.
+ */
+#define CAST(_s) \
+do {\
+ if ((cast_type != PW_TYPE_INVALID) && (_s ## _type != PW_TYPE_INVALID) && (cast_type != _s ## _type)) {\
+ ssize_t r;\
+ EVAL_DEBUG("CASTING " #_s " FROM %s TO %s",\
+ fr_int2str(dict_attr_types, _s ## _type, "<INVALID>"),\
+ fr_int2str(dict_attr_types, cast_type, "<INVALID>"));\
+ r = value_data_cast(request, &_s ## _cast, cast_type, cast, _s ## _type, _s ## _enumv, _s, _s ## _len);\
+ if (r < 0) {\
+ REDEBUG("Failed casting " #_s " operand: %s", fr_strerror());\
+ rcode = -1;\
+ goto finish;\
+ }\
+ if (cast && cast->flags.is_pointer) _s ## _cast_buff = _s ## _cast.ptr;\
+ _s ## _type = cast_type;\
+ _s ## _len = (size_t)r;\
+ _s = &_s ## _cast;\
+ }\
+} while (0)
+
+#define CHECK_INT_CAST(_l, _r) \
+do {\
+ if ((cast_type == PW_TYPE_INVALID) &&\
+ _l && (_l ## _type == PW_TYPE_STRING) &&\
+ _r && (_r ## _type == PW_TYPE_STRING) &&\
+ all_digits(lhs->strvalue) && all_digits(rhs->strvalue)) {\
+ cast_type = PW_TYPE_INTEGER64;\
+ EVAL_DEBUG("OPERANDS ARE NUMBER STRINGS, SETTING CAST TO integer64");\
+ }\
+} while (0)
+
+ /*
+ * Regular expressions need both operands to be strings
+ */
+#ifdef HAVE_REGEX
+ if (map->op == T_OP_REG_EQ) {
+ cast_type = PW_TYPE_STRING;
+
+ if (map->rhs->type == TMPL_TYPE_XLAT_STRUCT) escape = regex_escape;
+ }
+ else
+#endif
+ /*
+ * If it's a pair comparison, data gets cast to the
+ * type of the pair comparison attribute.
+ *
+ * Magic attribute is always the LHS.
+ */
+ if (c->pass2_fixup == PASS2_PAIRCOMPARE) {
+ rad_assert(!c->cast);
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+#ifndef NDEBUG
+ /* expensive assert */
+ rad_assert((map->rhs->type != TMPL_TYPE_ATTR) || !radius_find_compare(map->rhs->tmpl_da));
+#endif
+ cast = map->lhs->tmpl_da;
+ cast_type = cast->type;
+
+ EVAL_DEBUG("NORMALISATION TYPE %s (PAIRCMP TYPE)",
+ fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
+ /*
+ * Otherwise we use the explicit cast, or implicit
+ * cast (from an attribute reference).
+ * We already have the data for the lhs, so we convert
+ * it here.
+ */
+ } else if (c->cast) {
+ cast = c->cast;
+ EVAL_DEBUG("NORMALISATION TYPE %s (EXPLICIT CAST)",
+ fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
+ } else if (map->lhs->type == TMPL_TYPE_ATTR) {
+ cast = map->lhs->tmpl_da;
+ EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM LHS REF)",
+ fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
+ } else if (map->rhs->type == TMPL_TYPE_ATTR) {
+ cast = map->rhs->tmpl_da;
+ EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM RHS REF)",
+ fr_int2str(dict_attr_types, cast->type, "<INVALID>"));
+ } else if (map->lhs->type == TMPL_TYPE_DATA) {
+ cast_type = map->lhs->tmpl_data_type;
+ EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM LHS DATA)",
+ fr_int2str(dict_attr_types, cast_type, "<INVALID>"));
+ } else if (map->rhs->type == TMPL_TYPE_DATA) {
+ cast_type = map->rhs->tmpl_data_type;
+ EVAL_DEBUG("NORMALISATION TYPE %s (IMPLICIT FROM RHS DATA)",
+ fr_int2str(dict_attr_types, cast_type, "<INVALID>"));
+ }
+
+ if (cast) cast_type = cast->type;
+
+ switch (map->rhs->type) {
+ case TMPL_TYPE_ATTR:
+ {
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ for (vp = tmpl_cursor_init(&rcode, &cursor, request, map->rhs);
+ vp;
+ vp = tmpl_cursor_next(&cursor, map->rhs)) {
+ rhs_type = vp->da->type;
+ rhs_enumv = vp->da;
+ rhs = &vp->data;
+ rhs_len = vp->vp_length;
+
+ CHECK_INT_CAST(lhs, rhs);
+ CAST(lhs);
+ CAST(rhs);
+
+ rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+ if (rcode != 0) break;
+
+ TALLOC_FREE(rhs_cast_buff);
+ }
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ rhs_type = map->rhs->tmpl_data_type;
+ rhs = &map->rhs->tmpl_data_value;
+ rhs_len = map->rhs->tmpl_data_length;
+
+ CHECK_INT_CAST(lhs, rhs);
+ CAST(lhs);
+ CAST(rhs);
+
+ rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+ break;
+
+ /*
+ * Expanded types start as strings, then get converted
+ * to the type of the attribute or the explicit cast.
+ */
+ case TMPL_TYPE_LITERAL:
+ case TMPL_TYPE_EXEC:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ {
+ ssize_t ret;
+ value_data_t data;
+
+ if (map->rhs->type != TMPL_TYPE_LITERAL) {
+ char *p;
+
+ ret = tmpl_aexpand(request, &p, request, map->rhs, escape, NULL);
+ if (ret < 0) {
+ EVAL_DEBUG("FAIL [%i]", __LINE__);
+ rcode = -1;
+ goto finish;
+ }
+ data.strvalue = p;
+ rhs_len = ret;
+
+ } else {
+ data.strvalue = map->rhs->name;
+ rhs_len = map->rhs->len;
+ }
+ rad_assert(data.strvalue);
+
+ rhs_type = PW_TYPE_STRING;
+ rhs = &data;
+
+ CHECK_INT_CAST(lhs, rhs);
+ CAST(lhs);
+ CAST(rhs);
+
+ rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, rhs_type, rhs, rhs_len);
+ if (map->rhs->type != TMPL_TYPE_LITERAL)talloc_free(data.ptr);
+
+ break;
+ }
+
+ /*
+ * RHS is a compiled regex, we don't need to do anything with it.
+ */
+ case TMPL_TYPE_REGEX_STRUCT:
+ CAST(lhs);
+ rcode = cond_cmp_values(request, c, lhs_type, lhs, lhs_len, PW_TYPE_INVALID, NULL, 0);
+ break;
+ /*
+ * Unsupported types (should have been parse errors)
+ */
+ case TMPL_TYPE_NULL:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ case TMPL_TYPE_REGEX: /* Should now be a TMPL_TYPE_REGEX_STRUCT or TMPL_TYPE_XLAT_STRUCT */
+ rad_assert(0);
+ rcode = -1;
+ break;
+ }
+
+finish:
+ talloc_free(lhs_cast_buff);
+ talloc_free(rhs_cast_buff);
+
+ return rcode;
+}
+
+
+/** Evaluate a map
+ *
+ * @param[in] request the REQUEST
+ * @param[in] modreturn the previous module return code
+ * @param[in] depth of the recursion (only used for debugging)
+ * @param[in] c the condition to evaluate
+ * @return -1 on error, 0 for "no match", 1 for "match".
+ */
+int radius_evaluate_map(REQUEST *request, UNUSED int modreturn, UNUSED int depth, fr_cond_t const *c)
+{
+ int rcode = 0;
+
+ vp_map_t const *map = c->data.map;
+
+ EVAL_DEBUG(">>> MAP TYPES LHS: %s, RHS: %s",
+ fr_int2str(tmpl_names, map->lhs->type, "???"),
+ fr_int2str(tmpl_names, map->rhs->type, "???"));
+
+ switch (map->lhs->type) {
+ /*
+ * LHS is an attribute or list
+ */
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_ATTR:
+ {
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ /*
+ * Legacy paircompare call, skip processing the magic attribute
+ * if it's the LHS and cast RHS to the same type.
+ */
+ if ((c->pass2_fixup == PASS2_PAIRCOMPARE) && (map->op != T_OP_REG_EQ)) {
+#ifndef NDEBUG
+ rad_assert(radius_find_compare(map->lhs->tmpl_da)); /* expensive assert */
+#endif
+ rcode = cond_normalise_and_cmp(request, c, PW_TYPE_INVALID, NULL, NULL, 0);
+ break;
+ }
+ for (vp = tmpl_cursor_init(&rcode, &cursor, request, map->lhs);
+ vp;
+ vp = tmpl_cursor_next(&cursor, map->lhs)) {
+ /*
+ * Evaluate all LHS values, condition evaluates to true
+ * if we get at least one set of operands that
+ * evaluates to true.
+ */
+ rcode = cond_normalise_and_cmp(request, c, vp->da->type, vp->da, &vp->data, vp->vp_length);
+ if (rcode != 0) break;
+ }
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ rcode = cond_normalise_and_cmp(request, c,
+ map->lhs->tmpl_data_type, NULL, &map->lhs->tmpl_data_value,
+ map->lhs->tmpl_data_length);
+ break;
+
+ case TMPL_TYPE_LITERAL:
+ case TMPL_TYPE_EXEC:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ {
+ ssize_t ret;
+ value_data_t data;
+
+ if (map->lhs->type != TMPL_TYPE_LITERAL) {
+ char *p;
+
+ ret = tmpl_aexpand(request, &p, request, map->lhs, NULL, NULL);
+ if (ret < 0) {
+ EVAL_DEBUG("FAIL [%i]", __LINE__);
+ return ret;
+ }
+ data.strvalue = p;
+ } else {
+ data.strvalue = map->lhs->name;
+ ret = map->lhs->len;
+ }
+ rad_assert(data.strvalue);
+
+ rcode = cond_normalise_and_cmp(request, c, PW_TYPE_STRING, NULL, &data, ret);
+ if (map->lhs->type != TMPL_TYPE_LITERAL) talloc_free(data.ptr);
+ }
+ break;
+
+ /*
+ * Unsupported types (should have been parse errors)
+ */
+ case TMPL_TYPE_NULL:
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_REGEX: /* should now be a TMPL_TYPE_REGEX_STRUCT or TMPL_TYPE_XLAT_STRUCT */
+ case TMPL_TYPE_REGEX_STRUCT: /* not allowed as LHS */
+ rad_assert(0);
+ rcode = -1;
+ break;
+ }
+
+ EVAL_DEBUG("<<<");
+
+ return rcode;
+}
+
+/** Evaluate a fr_cond_t;
+ *
+ * @param[in] request the REQUEST
+ * @param[in] modreturn the previous module return code
+ * @param[in] depth of the recursion (only used for debugging)
+ * @param[in] c the condition to evaluate
+ * @return -1 on failure, -2 on attribute not found, 0 for "no match", 1 for "match".
+ */
+int radius_evaluate_cond(REQUEST *request, int modreturn, int depth, fr_cond_t const *c)
+{
+ int rcode = -1;
+#ifdef WITH_EVAL_DEBUG
+ char buffer[1024];
+
+ fr_cond_sprint(buffer, sizeof(buffer), c);
+ EVAL_DEBUG("%s", buffer);
+#endif
+
+ while (c) {
+ switch (c->type) {
+ case COND_TYPE_EXISTS:
+ rcode = radius_evaluate_tmpl(request, modreturn, depth, c->data.vpt);
+ /* Existence checks are special, because we expect them to fail */
+ if (rcode < 0) rcode = 0;
+ break;
+
+ case COND_TYPE_MAP:
+ rcode = radius_evaluate_map(request, modreturn, depth, c);
+ break;
+
+ case COND_TYPE_CHILD:
+ rcode = radius_evaluate_cond(request, modreturn, depth + 1, c->data.child);
+ break;
+
+ case COND_TYPE_TRUE:
+ rcode = true;
+ break;
+
+ case COND_TYPE_FALSE:
+ rcode = false;
+ break;
+ default:
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ return -1;
+ }
+
+ if (rcode < 0) return rcode;
+
+ if (c->negate) rcode = !rcode;
+
+ if (!c->next) break;
+
+ /*
+ * FALSE && ... = FALSE
+ */
+ if (!rcode && (c->next_op == COND_AND)) return false;
+
+ /*
+ * TRUE || ... = TRUE
+ */
+ if (rcode && (c->next_op == COND_OR)) return true;
+
+ c = c->next;
+ }
+
+ if (rcode < 0) {
+ EVAL_DEBUG("FAIL %d", __LINE__);
+ }
+ return rcode;
+}
+#endif
+
+
+/*
+ * The fr_pair_list_move() function in src/lib/pair.c does all sorts of
+ * extra magic that we don't want here.
+ *
+ * FIXME: integrate this with the code calling it, so that we
+ * only fr_pair_list_copy() those attributes that we're really going to
+ * use.
+ */
+void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat)
+{
+ int i, j, count, from_count, to_count, tailto;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp, *next, **last;
+ VALUE_PAIR **from_list, **to_list;
+ VALUE_PAIR *append, **append_tail;
+ VALUE_PAIR *prepend;
+ VALUE_PAIR *to_copy;
+ bool *edited = NULL;
+ REQUEST *fixup = NULL;
+ TALLOC_CTX *ctx;
+
+ /*
+ * Set up arrays for editing, to remove some of the
+ * O(N^2) dependencies. This also makes it easier to
+ * insert and remove attributes.
+ *
+ * It also means that the operators apply ONLY to the
+ * attributes in the original list. With the previous
+ * implementation of fr_pair_list_move(), adding two attributes
+ * via "+=" and then "=" would mean that the second one
+ * wasn't added, because of the existence of the first
+ * one in the "to" list. This implementation doesn't
+ * have that bug.
+ *
+ * Also, the previous implementation did NOT implement
+ * "-=" correctly. If two of the same attributes existed
+ * in the "to" list, and you tried to subtract something
+ * matching the *second* value, then the fr_pair_delete_by_num()
+ * function was called, and the *all* attributes of that
+ * number were deleted. With this implementation, only
+ * the matching attributes are deleted.
+ */
+ count = 0;
+ for (vp = fr_cursor_init(&cursor, &from); vp; vp = fr_cursor_next(&cursor)) count++;
+ from_list = talloc_array(request, VALUE_PAIR *, count);
+
+ for (vp = fr_cursor_init(&cursor, to); vp; vp = fr_cursor_next(&cursor)) count++;
+ to_list = talloc_array(request, VALUE_PAIR *, count);
+
+ prepend = NULL;
+
+ append = NULL;
+ append_tail = &append;
+
+ /*
+ * Move the lists to the arrays, and break the list
+ * chains.
+ */
+ from_count = 0;
+ for (vp = from; vp != NULL; vp = next) {
+ next = vp->next;
+ from_list[from_count++] = vp;
+ vp->next = NULL;
+ }
+
+ to_count = 0;
+ ctx = talloc_parent(*to);
+ to_copy = fr_pair_list_copy(ctx, *to);
+ for (vp = to_copy; vp != NULL; vp = next) {
+ next = vp->next;
+ to_list[to_count++] = vp;
+ vp->next = NULL;
+ }
+ tailto = to_count;
+ edited = talloc_zero_array(request, bool, to_count);
+
+ RDEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count);
+
+ /*
+ * Now that we have the lists initialized, start working
+ * over them.
+ */
+ for (i = 0; i < from_count; i++) {
+ int found;
+
+ RDEBUG4("::: Examining %s", from_list[i]->da->name);
+
+ if (do_xlat) radius_xlat_do(request, from_list[i]);
+
+ /*
+ * Attribute should be appended, OR the "to" list
+ * is empty, and we're supposed to replace or
+ * "add if not existing".
+ */
+ if (from_list[i]->op == T_OP_ADD) goto do_append;
+
+ /*
+ * The attribute needs to be prepended to the "to"
+ * list - store it in the prepend list
+ */
+
+ if (from_list[i]->op == T_OP_PREPEND) {
+ RDEBUG4("::: PREPENDING %s FROM %d TO %d",
+ from_list[i]->da->name, i, tailto);
+ from_list[i]->next = prepend;
+ prepend = from_list[i];
+ prepend->op = T_OP_EQ;
+ from_list[i] = NULL;
+ continue;
+ }
+ found = false;
+ for (j = 0; j < to_count; j++) {
+ if (edited[j] || !to_list[j] || !from_list[i]) continue;
+
+ /*
+ * Attributes aren't the same, skip them.
+ */
+ if (from_list[i]->da != to_list[j]->da) {
+ continue;
+ }
+
+ /*
+ * We don't use a "switch" statement here
+ * because we want to break out of the
+ * "for" loop over 'j' in most cases.
+ */
+
+ /*
+ * Over-write the FIRST instance of the
+ * matching attribute name. We free the
+ * one in the "to" list, and move over
+ * the one in the "from" list.
+ */
+ if (from_list[i]->op == T_OP_SET) {
+ RDEBUG4("::: OVERWRITING %s FROM %d TO %d",
+ to_list[j]->da->name, i, j);
+ fr_pair_list_free(&to_list[j]);
+ to_list[j] = from_list[i];
+ from_list[i] = NULL;
+ edited[j] = true;
+ break;
+ }
+
+ /*
+ * Add the attribute only if it does not
+ * exist... but it exists, so we stop
+ * looking.
+ */
+ if (from_list[i]->op == T_OP_EQ) {
+ found = true;
+ break;
+ }
+
+ /*
+ * Delete every attribute, independent
+ * of its value.
+ */
+ if (from_list[i]->op == T_OP_CMP_FALSE) {
+ goto delete;
+ }
+
+ /*
+ * Delete all matching attributes from
+ * "to"
+ */
+ if ((from_list[i]->op == T_OP_SUB) ||
+ (from_list[i]->op == T_OP_CMP_EQ) ||
+ (from_list[i]->op == T_OP_LE) ||
+ (from_list[i]->op == T_OP_GE)) {
+ int rcode;
+ int old_op = from_list[i]->op;
+
+ /*
+ * Check for equality.
+ */
+ from_list[i]->op = T_OP_CMP_EQ;
+
+ /*
+ * If equal, delete the one in
+ * the "to" list.
+ */
+ rcode = radius_compare_vps(NULL, from_list[i],
+ to_list[j]);
+ /*
+ * We may want to do more
+ * subtractions, so we re-set the
+ * operator back to it's original
+ * value.
+ */
+ from_list[i]->op = old_op;
+
+ switch (old_op) {
+ case T_OP_CMP_EQ:
+ if (rcode != 0) goto delete;
+ break;
+
+ case T_OP_SUB:
+ if (rcode == 0) {
+ delete:
+ RDEBUG4("::: DELETING %s FROM %d TO %d",
+ from_list[i]->da->name, i, j);
+ fr_pair_list_free(&to_list[j]);
+ to_list[j] = NULL;
+ }
+ break;
+
+ /*
+ * Enforce <=. If it's
+ * >, replace it.
+ */
+ case T_OP_LE:
+ if (rcode > 0) {
+ RDEBUG4("::: REPLACING %s FROM %d TO %d",
+ from_list[i]->da->name, i, j);
+ fr_pair_list_free(&to_list[j]);
+ to_list[j] = from_list[i];
+ from_list[i] = NULL;
+ edited[j] = true;
+ }
+ break;
+
+ case T_OP_GE:
+ if (rcode < 0) {
+ RDEBUG4("::: REPLACING %s FROM %d TO %d",
+ from_list[i]->da->name, i, j);
+ fr_pair_list_free(&to_list[j]);
+ to_list[j] = from_list[i];
+ from_list[i] = NULL;
+ edited[j] = true;
+ }
+ break;
+ }
+
+ continue;
+ }
+
+ rad_assert(0 == 1); /* panic! */
+ }
+
+ /*
+ * We were asked to add it if it didn't exist,
+ * and it doesn't exist. Move it over to the
+ * tail of the "to" list, UNLESS it was already
+ * moved by another operator.
+ */
+ if (!found && from_list[i]) {
+ if ((from_list[i]->op == T_OP_EQ) ||
+ (from_list[i]->op == T_OP_LE) ||
+ (from_list[i]->op == T_OP_GE) ||
+ (from_list[i]->op == T_OP_SET)) {
+ do_append:
+ RDEBUG4("::: APPENDING %s FROM %d TO %d",
+ from_list[i]->da->name, i, tailto);
+ *append_tail = from_list[i];
+ from_list[i]->op = T_OP_EQ;
+ from_list[i] = NULL;
+ append_tail = &(*append_tail)->next;
+ }
+ }
+ }
+
+ /*
+ * Delete attributes in the "from" list.
+ */
+ for (i = 0; i < from_count; i++) {
+ if (!from_list[i]) continue;
+ fr_pair_list_free(&from_list[i]);
+ }
+ talloc_free(from_list);
+
+ RDEBUG4("::: TO in %d out %d", to_count, tailto);
+
+ /*
+ * Re-chain the "to" list.
+ */
+ fr_pair_list_free(to);
+ last = to;
+
+ if (to == &request->packet->vps) {
+ fixup = request;
+ } else if (request->parent && (to == &request->parent->packet->vps)) {
+ fixup = request->parent;
+ }
+
+ /*
+ * Walk the list of "prepend" attributes first
+ */
+ for (vp = prepend; vp != NULL; vp = vp->next) {
+ *last = vp;
+ last = &(*last)->next;
+ }
+
+ /*
+ * Next add on remaining items in the "to" list
+ */
+ for (i = 0; i < tailto; i++) {
+ if (!to_list[i]) continue;
+
+ vp = to_list[i];
+ RDEBUG4("::: to[%d] = %s", i, vp->da->name);
+
+ /*
+ * Mash the operator to a simple '='. The
+ * operators in the "to" list aren't used for
+ * anything. BUT they're used in the "detail"
+ * file and debug output, where we don't want to
+ * see the operators.
+ */
+ vp->op = T_OP_EQ;
+
+ *last = vp;
+ last = &(*last)->next;
+ }
+
+ /*
+ * And finally add in the attributes we're appending to
+ * the tail of the "to" list.
+ */
+ *last = append;
+
+ /*
+ * Fix dumb cache issues
+ */
+ if (fixup) {
+ fixup->username = NULL;
+ fixup->password = NULL;
+
+ for (vp = fixup->packet->vps; vp != NULL; vp = vp->next) {
+ if (vp->da->vendor) continue;
+
+ if ((vp->da->attr == PW_USER_NAME) && !fixup->username) {
+ fixup->username = vp;
+
+ } else if (vp->da->attr == PW_STRIPPED_USER_NAME) {
+ fixup->username = vp;
+
+ } else if (vp->da->attr == PW_USER_PASSWORD) {
+ fixup->password = vp;
+ }
+ }
+ }
+
+ rad_assert(request->packet != NULL);
+
+ talloc_free(to_list);
+ talloc_free(edited);
+}
diff --git a/src/main/exec.c b/src/main/exec.c
new file mode 100644
index 0000000..67243f7
--- /dev/null
+++ b/src/main/exec.c
@@ -0,0 +1,633 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * $Id$
+ *
+ * @file exec.c
+ * @brief Execute external programs.
+ *
+ * @copyright 2000-2004,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/file.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#define MAX_ARGV (256)
+
+/** Start a process
+ *
+ * @param cmd Command to execute. This is parsed into argv[] parts,
+ * then each individual argv part is xlat'ed.
+ * @param request Current reuqest
+ * @param exec_wait set to 1 if you want to read from or write to child
+ * @param[in,out] input_fd pointer to int, receives the stdin file.
+ * descriptor. Set to NULL and the child will have /dev/null on stdin
+ * @param[in,out] output_fd pinter to int, receives the stdout file
+ * descriptor. Set to NULL and child will have /dev/null on stdout.
+ * @param input_pairs list of value pairs - these will be put into
+ * the environment variables of the child.
+ * @param shell_escape values before passing them as arguments.
+ * @return PID of the child process, -1 on error.
+ */
+pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
+ int *input_fd, int *output_fd,
+ VALUE_PAIR *input_pairs, bool shell_escape)
+{
+#ifndef __MINGW32__
+ VALUE_PAIR *vp;
+ int n;
+ int to_child[2] = {-1, -1};
+ int from_child[2] = {-1, -1};
+ pid_t pid;
+#endif
+ int argc;
+ int i;
+ char const **argv_p;
+ char *argv[MAX_ARGV], **argv_start = argv;
+ char argv_buf[4096];
+#define MAX_ENVP 1024
+ char *envp[MAX_ENVP];
+ int envlen = 0;
+
+ /*
+ * Stupid array decomposition...
+ *
+ * If we do memcpy(&argv_p, &argv, sizeof(argv_p)) src ends up being a char **
+ * pointing to the value of the first element.
+ */
+ memcpy(&argv_p, &argv_start, sizeof(argv_p));
+ argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv_p, true, sizeof(argv_buf), argv_buf);
+ if (argc <= 0) {
+ DEBUG("invalid command line '%s'.", cmd);
+ return -1;
+ }
+
+
+#ifndef NDEBUG
+ if (rad_debug_lvl > 2) {
+ DEBUG3("executing cmd %s", cmd);
+ for (i = 0; i < argc; i++) {
+ DEBUG3("\t[%d] %s", i, argv[i]);
+ }
+ }
+#endif
+
+#ifndef __MINGW32__
+ /*
+ * Open a pipe for child/parent communication, if necessary.
+ */
+ if (exec_wait) {
+ if (input_fd) {
+ if (pipe(to_child) != 0) {
+ DEBUG("Couldn't open pipe to child: %s", fr_syserror(errno));
+ return -1;
+ }
+ }
+ if (output_fd) {
+ if (pipe(from_child) != 0) {
+ DEBUG("Couldn't open pipe from child: %s", fr_syserror(errno));
+ /* safe because these either need closing or are == -1 */
+ close(to_child[0]);
+ close(to_child[1]);
+ return -1;
+ }
+ }
+ }
+
+ envp[0] = NULL;
+
+ if (input_pairs) {
+ vp_cursor_t cursor;
+ char buffer[1024];
+
+ /*
+ * Set up the environment variables in the
+ * parent, so we don't call libc functions that
+ * hold mutexes. They might be locked when we fork,
+ * and will remain locked in the child.
+ */
+ for (vp = fr_cursor_init(&cursor, &input_pairs);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Hmm... maybe we shouldn't pass the
+ * user's password in an environment
+ * variable...
+ */
+ snprintf(buffer, sizeof(buffer), "%s=", vp->da->name);
+ if (shell_escape) {
+ char *p;
+
+ for (p = buffer; *p != '='; p++) {
+ if (*p == '-') {
+ *p = '_';
+ } else if (isalpha((uint8_t) *p)) {
+ *p = toupper((uint8_t) *p);
+ }
+ }
+ }
+
+ n = strlen(buffer);
+ vp_prints_value(buffer + n, sizeof(buffer) - n, vp, shell_escape ? '"' : 0);
+
+ envp[envlen++] = strdup(buffer);
+
+ /*
+ * Don't add too many attributes.
+ */
+ if (envlen == (MAX_ENVP - 1)) break;
+
+ /*
+ * NULL terminate for execve
+ */
+ envp[envlen] = NULL;
+ }
+ }
+
+ if (exec_wait) {
+ pid = rad_fork(); /* remember PID */
+ } else {
+ pid = fork(); /* don't wait */
+ }
+
+ if (pid == 0) {
+ int devnull;
+
+ /*
+ * Child process.
+ *
+ * We try to be fail-safe here. So if ANYTHING
+ * goes wrong, we exit with status 1.
+ */
+
+ /*
+ * Open STDIN to /dev/null
+ */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ DEBUG("Failed opening /dev/null: %s\n", fr_syserror(errno));
+
+ /*
+ * Where the status code is interpreted as a module rcode
+ * one is subtracted from it, to allow 0 to equal success
+ *
+ * 2 is RLM_MODULE_FAIL + 1
+ */
+ exit(2);
+ }
+
+ /*
+ * Only massage the pipe handles if the parent
+ * has created them.
+ */
+ if (exec_wait) {
+ if (input_fd) {
+ close(to_child[1]);
+ dup2(to_child[0], STDIN_FILENO);
+ } else {
+ dup2(devnull, STDIN_FILENO);
+ }
+
+ if (output_fd) {
+ close(from_child[0]);
+ dup2(from_child[1], STDOUT_FILENO);
+ } else {
+ dup2(devnull, STDOUT_FILENO);
+ }
+
+ } else { /* no pipe, STDOUT should be /dev/null */
+ dup2(devnull, STDIN_FILENO);
+ dup2(devnull, STDOUT_FILENO);
+ }
+
+ /*
+ * If we're not debugging, then we can't do
+ * anything with the error messages, so we throw
+ * them away.
+ *
+ * If we are debugging, then we want the error
+ * messages to go to the STDERR of the server.
+ */
+ if (rad_debug_lvl == 0) {
+ dup2(devnull, STDERR_FILENO);
+ }
+ close(devnull);
+
+ /*
+ * The server may have MANY FD's open. We don't
+ * want to leave dangling FD's for the child process
+ * to play funky games with, so we close them.
+ */
+ closefrom(3);
+
+ /*
+ * I swear the signature for execve is wrong and should
+ * take 'char const * const argv[]'.
+ *
+ * Note: execve(), unlike system(), treats all the space
+ * delimited arguments as literals, so there's no need
+ * to perform additional escaping.
+ */
+ execve(argv[0], argv, envp);
+ printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */
+
+ /*
+ * Where the status code is interpreted as a module rcode
+ * one is subtracted from it, to allow 0 to equal success
+ *
+ * 2 is RLM_MODULE_FAIL + 1
+ */
+ exit(2);
+ }
+
+ /*
+ * Free child environment variables
+ */
+ for (i = 0; i < envlen; i++) {
+ free(envp[i]);
+ }
+
+ /*
+ * Parent process.
+ */
+ if (pid < 0) {
+ DEBUG("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
+ if (exec_wait) {
+ /* safe because these either need closing or are == -1 */
+ close(to_child[0]);
+ close(to_child[1]);
+ close(from_child[0]);
+ close(from_child[1]);
+ }
+ return -1;
+ }
+
+ /*
+ * We're not waiting, exit, and ignore any child's status.
+ */
+ if (exec_wait) {
+ /*
+ * Close the ends of the pipe(s) the child is using
+ * return the ends of the pipe(s) our caller wants
+ *
+ */
+ if (input_fd) {
+ *input_fd = to_child[1];
+ close(to_child[0]);
+ }
+ if (output_fd) {
+ *output_fd = from_child[0];
+ close(from_child[1]);
+ }
+ }
+
+ return pid;
+#else
+ if (exec_wait) {
+ DEBUG("Wait is not supported");
+ return -1;
+ }
+
+ {
+ /*
+ * The _spawn and _exec families of functions are
+ * found in Windows compiler libraries for
+ * portability from UNIX. There is a variety of
+ * functions, including the ability to pass
+ * either a list or array of parameters, to
+ * search in the PATH or otherwise, and whether
+ * or not to pass an environment (a set of
+ * environment variables). Using _spawn, you can
+ * also specify whether you want the new process
+ * to close your program (_P_OVERLAY), to wait
+ * until the new process is finished (_P_WAIT) or
+ * for the two to run concurrently (_P_NOWAIT).
+
+ * _spawn and _exec are useful for instances in
+ * which you have simple requirements for running
+ * the program, don't want the overhead of the
+ * Windows header file, or are interested
+ * primarily in portability.
+ */
+
+ /*
+ * FIXME: check return code... what is it?
+ */
+ _spawnve(_P_NOWAIT, argv[0], argv, envp);
+ }
+
+ return 0;
+#endif
+}
+
+/** Read from the child process.
+ *
+ * @param fd file descriptor to read from.
+ * @param pid pid of child, will be reaped if it dies.
+ * @param timeout amount of time to wait, in seconds.
+ * @param answer buffer to write into.
+ * @param left length of buffer.
+ * @return -1 on error, or length of output.
+ */
+int radius_readfrom_program(int fd, pid_t pid, int timeout,
+ char *answer, int left)
+{
+ int done = 0;
+#ifndef __MINGW32__
+ int status;
+ struct timeval start;
+#ifdef O_NONBLOCK
+ bool nonblock = true;
+#endif
+
+#ifdef O_NONBLOCK
+ /*
+ * Try to set it non-blocking.
+ */
+ do {
+ int flags;
+
+ if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
+ nonblock = false;
+ break;
+ }
+
+ flags |= O_NONBLOCK;
+ if( fcntl(fd, F_SETFL, flags) < 0) {
+ nonblock = false;
+ break;
+ }
+ } while (0);
+#endif
+
+
+ /*
+ * Read from the pipe until we doesn't get any more or
+ * until the message is full.
+ */
+ gettimeofday(&start, NULL);
+ while (1) {
+ int rcode;
+ fd_set fds;
+ struct timeval when, elapsed, wake;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ gettimeofday(&when, NULL);
+ rad_tv_sub(&when, &start, &elapsed);
+ if (elapsed.tv_sec >= timeout) goto too_long;
+
+ when.tv_sec = timeout;
+ when.tv_usec = 0;
+ rad_tv_sub(&when, &elapsed, &wake);
+
+ rcode = select(fd + 1, &fds, NULL, NULL, &wake);
+ if (rcode == 0) {
+ too_long:
+ DEBUG("Child PID %u is taking too much time: forcing failure and killing child.", (unsigned int) pid);
+ kill(pid, SIGTERM);
+ close(fd); /* should give SIGPIPE to child, too */
+
+ /*
+ * Clean up the child entry.
+ */
+ rad_waitpid(pid, &status);
+ return -1;
+ }
+ if (rcode < 0) {
+ if (errno == EINTR) continue;
+ break;
+ }
+
+#ifdef O_NONBLOCK
+ /*
+ * Read as many bytes as possible. The kernel
+ * will return the number of bytes available.
+ */
+ if (nonblock) {
+ status = read(fd, answer + done, left);
+ } else
+#endif
+ /*
+ * There's at least 1 byte ready: read it.
+ */
+ status = read(fd, answer + done, 1);
+
+ /*
+ * Nothing more to read: stop.
+ */
+ if (status == 0) {
+ break;
+ }
+
+ /*
+ * Error: See if we have to continue.
+ */
+ if (status < 0) {
+ /*
+ * We were interrupted: continue reading.
+ */
+ if (errno == EINTR) {
+ continue;
+ }
+
+ /*
+ * There was another error. Most likely
+ * The child process has finished, and
+ * exited.
+ */
+ break;
+ }
+
+ done += status;
+ left -= status;
+ if (left <= 0) break;
+ }
+#endif /* __MINGW32__ */
+
+ /* Strip trailing new lines */
+ while ((done > 0) && (answer[done - 1] == '\n')) {
+ answer[--done] = '\0';
+ }
+
+ return done;
+}
+
+/** Execute a program.
+ *
+ * @param[in,out] ctx to allocate new VALUE_PAIR (s) in.
+ * @param[out] out buffer to append plaintext (non valuepair) output.
+ * @param[in] outlen length of out buffer.
+ * @param[out] output_pairs list of value pairs - child stdout will be parsed and added into this list
+ * of value pairs.
+ * @param[in] request Current request (may be NULL).
+ * @param[in] cmd Command to execute. This is parsed into argv[] parts, then each individual argv part
+ * is xlat'ed.
+ * @param[in] input_pairs list of value pairs - these will be available in the environment of the child.
+ * @param[in] exec_wait set to 1 if you want to read from or write to child.
+ * @param[in] shell_escape values before passing them as arguments.
+ * @param[in] timeout amount of time to wait, in seconds.
+
+ * @return 0 if exec_wait==0, exit code if exec_wait!=0, -1 on error.
+ */
+int radius_exec_program(TALLOC_CTX *ctx, char *out, size_t outlen, VALUE_PAIR **output_pairs,
+ REQUEST *request, char const *cmd, VALUE_PAIR *input_pairs,
+ bool exec_wait, bool shell_escape, int timeout)
+
+{
+ pid_t pid;
+ int from_child;
+#ifndef __MINGW32__
+ char *p;
+ pid_t child_pid;
+ int comma = 0;
+ int status, ret = 0;
+ ssize_t len;
+ char answer[4096];
+#endif
+
+ RDEBUG2("Executing: %s:", cmd);
+
+ if (out) *out = '\0';
+
+ pid = radius_start_program(cmd, request, exec_wait, NULL, &from_child, input_pairs, shell_escape);
+ if (pid < 0) {
+ return -1;
+ }
+
+ if (!exec_wait) {
+ return 0;
+ }
+
+#ifndef __MINGW32__
+ len = radius_readfrom_program(from_child, pid, timeout, answer, sizeof(answer));
+ if (len < 0) {
+ /*
+ * Failure - radius_readfrom_program will
+ * have called close(from_child) for us
+ */
+ RERROR("Failed to read from child output");
+ return -1;
+
+ }
+ answer[len] = '\0';
+
+ /*
+ * Make sure that the writer can't block while writing to
+ * a pipe that no one is reading from anymore.
+ */
+ close(from_child);
+
+ if (len == 0) {
+ goto wait;
+ }
+
+ /*
+ * Parse the output, if any.
+ */
+ if (output_pairs) {
+ /*
+ * HACK: Replace '\n' with ',' so that
+ * fr_pair_list_afrom_str() can parse the buffer in
+ * one go (the proper way would be to
+ * fix fr_pair_list_afrom_str(), but oh well).
+ */
+ for (p = answer; *p; p++) {
+ if (*p == '\n') {
+ *p = comma ? ' ' : ',';
+ p++;
+ comma = 0;
+ }
+ if (*p == ',') {
+ comma++;
+ }
+ }
+
+ /*
+ * Replace any trailing comma by a NUL.
+ */
+ if (answer[len - 1] == ',') {
+ answer[--len] = '\0';
+ }
+
+ if (fr_pair_list_afrom_str(ctx, answer, output_pairs) == T_INVALID) {
+ RERROR("Failed parsing output from: %s: %s", cmd, fr_strerror());
+ if (out) strlcpy(out, answer, len);
+ ret = -1;
+ }
+
+ VERIFY_REQUEST(request);
+
+
+ /*
+ * We've not been told to extract output pairs,
+ * just copy the programs output to the out
+ * buffer.
+ */
+
+ } else if (out) {
+ strlcpy(out, answer, outlen);
+ }
+
+ /*
+ * Call rad_waitpid (should map to waitpid on non-threaded
+ * or single-server systems).
+ */
+wait:
+ child_pid = rad_waitpid(pid, &status);
+ if (child_pid == 0) {
+ RERROR("Timeout waiting for child");
+
+ return -2;
+ }
+
+ if (child_pid == pid) {
+ if (WIFEXITED(status)) {
+ status = WEXITSTATUS(status);
+ if ((status != 0) || (ret < 0)) {
+ RERROR("Program returned code (%d) and output '%s'", status, answer);
+ } else {
+ RDEBUG2("Program returned code (%d) and output '%s'", status, answer);
+ }
+
+ return ret < 0 ? ret : status;
+ }
+ }
+
+ RERROR("Abnormal child exit: %s", fr_syserror(errno));
+#endif /* __MINGW32__ */
+
+ return -1;
+}
diff --git a/src/main/exfile.c b/src/main/exfile.c
new file mode 100644
index 0000000..59e6a05
--- /dev/null
+++ b/src/main/exfile.c
@@ -0,0 +1,547 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * $Id$
+ *
+ * @file exfile.c
+ * @brief Allow multiple threads to write to the same set of files.
+ *
+ * @author Alan DeKok <aland@freeradius.org>
+ * @copyright 2014 The FreeRADIUS server project
+ */
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/exfile.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+typedef struct exfile_entry_t {
+ int fd; //!< File descriptor associated with an entry.
+ uint32_t hash; //!< Hash for cheap comparison.
+ time_t last_used; //!< Last time the entry was used.
+ dev_t st_dev; //!< device inode
+ ino_t st_ino; //!< inode number
+ char *filename; //!< Filename.
+} exfile_entry_t;
+
+
+struct exfile_t {
+ uint32_t max_entries; //!< How many file descriptors we keep track of.
+ uint32_t max_idle; //!< Maximum idle time for a descriptor.
+ time_t last_cleaned;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex;
+#endif
+ exfile_entry_t *entries;
+ bool locking;
+};
+
+
+#ifdef HAVE_PTHREAD_H
+#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+
+#else
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+#define MAX_TRY_LOCK 4 //!< How many times we attempt to acquire a lock
+ //!< before giving up.
+
+static int _exfile_free(exfile_t *ef)
+{
+ uint32_t i;
+
+ PTHREAD_MUTEX_LOCK(&ef->mutex);
+
+ for (i = 0; i < ef->max_entries; i++) {
+ if (!ef->entries[i].filename) continue;
+
+ close(ef->entries[i].fd);
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&ef->mutex);
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&ef->mutex);
+#endif
+
+ return 0;
+}
+
+
+/** Initialize a way for multiple threads to log to one or more files.
+ *
+ * @param ctx The talloc context
+ * @param max_entries Max file descriptors to cache, and manage locks for.
+ * @param max_idle Maximum time a file descriptor can be idle before it's closed.
+ * @param locking whether or not to lock the files.
+ * @return the new context, or NULL on error.
+ */
+exfile_t *exfile_init(TALLOC_CTX *ctx, uint32_t max_entries, uint32_t max_idle, bool locking)
+{
+ exfile_t *ef;
+
+ ef = talloc_zero(ctx, exfile_t);
+ if (!ef) return NULL;
+
+ ef->max_entries = max_entries;
+ ef->max_idle = max_idle;
+ ef->locking = locking;
+
+ /*
+ * If we're not locking the files, just return the
+ * handle. Each call to exfile_open() will just open a
+ * new file descriptor.
+ */
+ if (!locking) return ef;
+
+ ef->entries = talloc_zero_array(ef, exfile_entry_t, max_entries);
+ if (!ef->entries) {
+ talloc_free(ef);
+ return NULL;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&ef->mutex, NULL) != 0) {
+ talloc_free(ef);
+ return NULL;
+ }
+#endif
+
+ talloc_set_destructor(ef, _exfile_free);
+
+ return ef;
+}
+
+
+static void exfile_cleanup_entry(exfile_entry_t *entry)
+{
+ TALLOC_FREE(entry->filename);
+
+ if (entry->fd >= 0) close(entry->fd);
+ entry->hash = 0;
+ entry->fd = -1;
+}
+
+
+/*
+ * Try to open the file. If it doesn't exist, try to
+ * create it's parent directories.
+ */
+static int exfile_open_mkdir(exfile_t *ef, char const *filename, mode_t permissions)
+{
+ int fd;
+
+ /*
+ * Files in /dev/ are special. We don't try to create
+ * their parent directories, and we don't try to create
+ * the files.
+ */
+ if (strncmp(filename, "/dev/", 5) == 0) {
+ int oflag;
+
+ if (((permissions & 0222) == 0) && (permissions & 0444) != 0) { /* !W + R */
+ oflag = O_RDONLY;
+
+ } else if (((permissions & 0222) != 0) && (permissions & 0444) == 0) { /* W + !R */
+ oflag = O_WRONLY;
+
+ } else { /* unknown, make it R+W */
+ oflag = O_RDWR;
+ }
+
+ fd = open(filename, oflag, permissions);
+ if (fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ return -1;
+ }
+
+ return fd;
+ }
+
+ fd = open(filename, O_RDWR | O_CREAT, permissions);
+ if (fd < 0) {
+ mode_t dirperm;
+ char *p, *dir;
+
+ /*
+ * Maybe the directory doesn't exist. Try to
+ * create it.
+ */
+ dir = talloc_strdup(ef, filename);
+ if (!dir) return -1;
+ p = strrchr(dir, FR_DIR_SEP);
+ if (!p) {
+ fr_strerror_printf("No '/' in '%s'", filename);
+ talloc_free(dir);
+ return -1;
+ }
+ *p = '\0';
+
+ /*
+ * Ensure that the 'x' bit is set, so that we can
+ * read the directory.
+ */
+ dirperm = permissions;
+ if ((dirperm & 0600) != 0) dirperm |= 0100;
+ if ((dirperm & 0060) != 0) dirperm |= 0010;
+ if ((dirperm & 0006) != 0) dirperm |= 0001;
+
+ if (rad_mkdir(dir, dirperm, -1, -1) < 0) {
+ fr_strerror_printf("Failed to create directory %s: %s",
+ dir, strerror(errno));
+ talloc_free(dir);
+ return -1;
+ }
+ talloc_free(dir);
+
+ fd = open(filename, O_RDWR | O_CREAT, permissions);
+ if (fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ return -1;
+ }
+ }
+
+ return fd;
+}
+
+
+/** Open a new log file, or maybe an existing one.
+ *
+ * When multithreaded, the FD is locked via a mutex. This way we're
+ * sure that no other thread is writing to the file.
+ *
+ * @param ef The logfile context returned from exfile_init().
+ * @param filename the file to open.
+ * @param permissions to use.
+ * @return an FD used to write to the file, or -1 on error.
+ */
+int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
+{
+ int i, found, tries, unused, oldest;
+ uint32_t hash;
+ time_t now;
+ struct stat st;
+ off_t real_offset;
+
+ if (!ef || !filename) return -1;
+
+ /*
+ * No locking: just return a new FD.
+ */
+ if (!ef->locking) {
+ found = exfile_open_mkdir(ef, filename, permissions);
+ if (found < 0) return -1;
+
+ real_offset = lseek(found, 0, SEEK_END);
+ if (offset) *offset = real_offset;
+ return found;
+ }
+
+ /*
+ * It's faster to do hash comparisons of a string than
+ * full string comparisons.
+ */
+ hash = fr_hash_string(filename);
+ now = time(NULL);
+
+ PTHREAD_MUTEX_LOCK(&ef->mutex);
+
+ /*
+ * Clean up idle entries.
+ */
+ if (now > (ef->last_cleaned + 1)) {
+ ef->last_cleaned = now;
+
+ for (i = 0; i < (int) ef->max_entries; i++) {
+ if (!ef->entries[i].filename) continue;
+
+ if ((ef->entries[i].last_used + ef->max_idle) >= now) continue;
+
+ /*
+ * This will block forever if a thread is
+ * doing something stupid.
+ */
+ exfile_cleanup_entry(&ef->entries[i]);
+ }
+ }
+
+ /*
+ * Find the matching entry, or an unused one.
+ *
+ * Also track which entry is the oldest, in case there
+ * are no unused entries.
+ */
+ found = oldest = unused = -1;
+ for (i = 0; i < (int) ef->max_entries; i++) {
+ if (!ef->entries[i].filename) {
+ if (unused < 0) unused = i;
+ continue;
+ }
+
+ if ((oldest < 0) ||
+ (ef->entries[i].last_used < ef->entries[oldest].last_used)) {
+ oldest = i;
+ }
+
+ /*
+ * Hash comparisons are fast. String comparisons are slow.
+ */
+ if (ef->entries[i].hash != hash) continue;
+
+ /*
+ * But we still need to do string comparisons if
+ * the hash matches, because 1/2^16 filenames
+ * will result in a hash collision. And that's
+ * enough filenames in a long-running server to
+ * ensure that it happens.
+ */
+ if (strcmp(ef->entries[i].filename, filename) != 0) continue;
+
+ found = i;
+ break;
+ }
+
+ /*
+ * If it wasn't found, create a new entry.
+ */
+ if (found < 0) {
+ /*
+ * There are no unused entries. Clean up the
+ * oldest one.
+ */
+ if (unused < 0) {
+ exfile_cleanup_entry(&ef->entries[oldest]);
+ unused = oldest;
+ }
+
+ /*
+ * Create a new entry.
+ */
+ i = unused;
+
+ ef->entries[i].hash = hash;
+ ef->entries[i].filename = talloc_strdup(ef->entries, filename);
+ ef->entries[i].fd = -1;
+
+ /*
+ * We've just created the entry. Open the file
+ * and cache the FD.
+ */
+ reopen:
+ ef->entries[i].fd = exfile_open_mkdir(ef, filename, permissions);
+ if (ef->entries[i].fd < 0) {
+ error:
+ exfile_cleanup_entry(&ef->entries[i]);
+ PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
+ return -1;
+ }
+
+ if (fstat(ef->entries[i].fd, &st) < 0) goto error;
+
+ /*
+ * Remember which device and inode this file is
+ * for.
+ */
+ ef->entries[i].st_dev = st.st_dev;
+ ef->entries[i].st_ino = st.st_ino;
+
+ } else {
+ i = found;
+
+ /*
+ * Stat the *filename*, not the file we opened.
+ * If that's not the file we opened, then go back
+ * and re-open the file.
+ */
+ if (stat(ef->entries[i].filename, &st) == 0) {
+ if ((st.st_dev != ef->entries[i].st_dev) ||
+ (st.st_ino != ef->entries[i].st_ino)) {
+ /*
+ * No longer the same file; reopen.
+ */
+ close(ef->entries[i].fd);
+ goto reopen;
+ }
+ } else {
+ /*
+ * Error calling stat, likely the
+ * file has been moved. Reopen it.
+ */
+ close(ef->entries[i].fd);
+ goto reopen;
+ }
+ }
+
+ /*
+ * Try to lock it. If we can't lock it, it's because
+ * some reader has re-named the file to "foo.work" and
+ * locked it. So, we close the current file, re-open it,
+ * and try again.
+ */
+
+ /*
+ * Lock from the start of the file. It's the
+ * only point in the file which is guaranteed to
+ * exist, and to be consistent across all threads
+ * and processes.
+ */
+ if (lseek(ef->entries[i].fd, 0, SEEK_SET) < 0) {
+ fr_strerror_printf("Failed to seek in file %s: %s", filename, strerror(errno));
+ goto error;
+ }
+
+ /*
+ * Busy-loop trying to lock the file.
+ */
+ for (tries = 0; tries < MAX_TRY_LOCK; tries++) {
+ if (rad_lockfd_nonblock(ef->entries[i].fd, 0) >= 0) break;
+
+ if (errno != EAGAIN) {
+ fr_strerror_printf("Failed to lock file %s: %s", filename, strerror(errno));
+ goto error;
+ }
+
+ /*
+ * Close the file and re-open it. It may
+ * have been deleted. If it was deleted,
+ * then the new file should now be unlocked.
+ */
+ close(ef->entries[i].fd);
+ ef->entries[i].fd = open(filename, O_RDWR | O_CREAT, permissions);
+ if (ef->entries[i].fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s",
+ filename, strerror(errno));
+ goto error;
+ }
+ }
+
+ if (tries >= MAX_TRY_LOCK) {
+ fr_strerror_printf("Failed to lock file %s: too many tries", filename);
+ goto error;
+ }
+
+ /*
+ * See which file it really is.
+ */
+ if (fstat(ef->entries[i].fd, &st) < 0) {
+ fr_strerror_printf("Failed to stat file %s: %s", filename, strerror(errno));
+ goto error;
+ }
+
+ /*
+ * Maybe the file was unlinked from the file system, OR
+ * the file we opened is NOT the one we had cached. If
+ * so, close the file and re-open it from scratch.
+ */
+ if ((st.st_nlink == 0) ||
+ (st.st_dev != ef->entries[i].st_dev) ||
+ (st.st_ino != ef->entries[i].st_ino)) {
+ close(ef->entries[i].fd);
+ goto reopen;
+ }
+
+ /*
+ * Sometimes the file permissions are changed externally.
+ * just be sure to update the permission if necessary.
+ */
+ if ((st.st_mode & ~S_IFMT) != permissions) {
+ char str_need[10], oct_need[5];
+ char str_have[10], oct_have[5];
+
+ rad_mode_to_oct(oct_need, permissions);
+ rad_mode_to_str(str_need, permissions);
+
+ rad_mode_to_oct(oct_have, st.st_mode & ~S_IFMT);
+ rad_mode_to_str(str_have, st.st_mode & ~S_IFMT);
+
+ WARN("File %s permissions are %s (%s) not %s (%s))", filename,
+ oct_have, str_have, oct_need, str_need);
+
+ if (((st.st_mode | permissions) != st.st_mode) &&
+ (fchmod(ef->entries[i].fd, (st.st_mode & ~S_IFMT) | permissions) < 0)) {
+ rad_mode_to_oct(oct_need, (st.st_mode & ~S_IFMT) | permissions);
+ rad_mode_to_str(str_need, (st.st_mode & ~S_IFMT) | permissions);
+
+ WARN("Failed resetting file %s permissions to %s (%s): %s",
+ filename, oct_need, str_need, fr_syserror(errno));
+ }
+ }
+
+ /*
+ * If we're appending, seek to the end of the file before
+ * returning the FD to the caller.
+ */
+ real_offset = lseek(ef->entries[i].fd, 0, SEEK_END);
+ if (offset) *offset = real_offset;
+
+ /*
+ * Return holding the mutex for the entry.
+ */
+ ef->entries[i].last_used = now;
+
+ return ef->entries[i].fd;
+}
+
+/** Close the log file. Really just return it to the pool.
+ *
+ * When multithreaded, the FD is locked via a mutex. This way we're
+ * sure that no other thread is writing to the file. This function
+ * will unlock the mutex, so that other threads can write to the file.
+ *
+ * @param ef The logfile context returned from exfile_init()
+ * @param fd the FD to close (i.e. return to the pool)
+ * @return 0 on success, or -1 on error
+ */
+int exfile_close(exfile_t *ef, int fd)
+{
+ uint32_t i;
+
+ /*
+ * No locking: just close the file.
+ */
+ if (!ef->locking) {
+ close(fd);
+ return 0;
+ }
+
+ /*
+ * Unlock the bytes that we had previously locked.
+ */
+ for (i = 0; i < ef->max_entries; i++) {
+ if (ef->entries[i].fd == fd) {
+ (void) lseek(ef->entries[i].fd, 0, SEEK_SET);
+ (void) rad_unlockfd(ef->entries[i].fd, 0);
+
+ PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
+ return 0;
+ }
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&(ef->mutex));
+
+ fr_strerror_printf("Attempt to unlock file which is not tracked");
+ return -1;
+}
diff --git a/src/main/files.c b/src/main/files.c
new file mode 100644
index 0000000..25b6f0d
--- /dev/null
+++ b/src/main/files.c
@@ -0,0 +1,361 @@
+/*
+ * files.c Read config files into memory.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+
+/*
+ * Debug code.
+ */
+#if 0
+static void debug_pair_list(PAIR_LIST *pl)
+{
+ VALUE_PAIR *vp;
+
+ while(pl) {
+ printf("Pair list: %s\n", pl->name);
+ printf("** Check:\n");
+ for(vp = pl->check; vp; vp = vp->next) {
+ printf(" ");
+ fprint_attr_val(stdout, vp);
+ printf("\n");
+ }
+ printf("** Reply:\n");
+ for(vp = pl->reply; vp; vp = vp->next) {
+ printf(" ");
+ fprint_attr_val(stdout, vp);
+ printf("\n");
+ }
+ pl = pl->next;
+ }
+}
+#endif
+
+/*
+ * Free a PAIR_LIST
+ */
+void pairlist_free(PAIR_LIST **pl)
+{
+ talloc_free(*pl);
+ *pl = NULL;
+}
+
+
+#define FIND_MODE_NAME 0
+#define FIND_MODE_WANT_REPLY 1
+#define FIND_MODE_HAVE_REPLY 2
+
+/*
+ * Read the users, huntgroups or hints file.
+ * Return a PAIR_LIST.
+ */
+int pairlist_read(TALLOC_CTX *ctx, char const *file, PAIR_LIST **list, int complain)
+{
+ FILE *fp;
+ int mode = FIND_MODE_NAME;
+ char entry[256];
+ char buffer[8192];
+ char const *ptr;
+ VALUE_PAIR *check_tmp = NULL;
+ VALUE_PAIR *reply_tmp = NULL;
+ PAIR_LIST *pl = NULL, *t;
+ PAIR_LIST **last = &pl;
+ int order = 0;
+ int lineno = 0;
+ int entry_lineno = 0;
+ FR_TOKEN parsecode;
+#ifdef HAVE_REGEX_H
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+#endif
+ char newfile[8192];
+
+ DEBUG2("reading pairlist file %s", file);
+
+ /*
+ * Open the file. The error message should be a little
+ * more useful...
+ */
+ if ((fp = fopen(file, "r")) == NULL) {
+ if (!complain)
+ return -1;
+ ERROR("Couldn't open %s for reading: %s",
+ file, fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Read the entire file into memory for speed.
+ */
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ lineno++;
+
+ if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
+ fclose(fp);
+ ERROR("%s[%d]: line too long", file, lineno);
+ pairlist_free(&pl);
+ return -1;
+ }
+
+ /*
+ * If the line contains nothing but whitespace,
+ * ignore it.
+ */
+ ptr = buffer;
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ if (*ptr == '#' || *ptr == '\n' || !*ptr) continue;
+
+parse_again:
+ if (mode == FIND_MODE_NAME) {
+ /*
+ * The user's name MUST be the first text on the line.
+ */
+ if (isspace((uint8_t) buffer[0])) {
+ ERROR("%s[%d]: Entry does not begin with a user name",
+ file, lineno);
+ fclose(fp);
+ return -1;
+ }
+
+ /*
+ * Get the name.
+ */
+ ptr = buffer;
+ getword(&ptr, entry, sizeof(entry), false);
+ entry_lineno = lineno;
+
+ /*
+ * Include another file if we see
+ * $INCLUDE filename
+ */
+ if (strcasecmp(entry, "$INCLUDE") == 0) {
+ while (isspace((uint8_t) *ptr)) ptr++;
+
+ /*
+ * If it's an absolute pathname,
+ * then use it verbatim.
+ *
+ * If not, then make the $include
+ * files *relative* to the current
+ * file.
+ */
+ if (FR_DIR_IS_RELATIVE(ptr)) {
+ char *p;
+
+ strlcpy(newfile, file,
+ sizeof(newfile));
+ p = strrchr(newfile, FR_DIR_SEP);
+ if (!p) {
+ p = newfile + strlen(newfile);
+ *p = FR_DIR_SEP;
+ }
+ getword(&ptr, p + 1, sizeof(newfile) - 1 - (p - newfile), false);
+ } else {
+ getword(&ptr, newfile, sizeof(newfile), false);
+ }
+
+ t = NULL;
+
+ if (pairlist_read(ctx, newfile, &t, 0) != 0) {
+ pairlist_free(&pl);
+ ERROR("%s[%d]: Could not open included file %s: %s",
+ file, lineno, newfile, fr_syserror(errno));
+ fclose(fp);
+ return -1;
+ }
+ *last = t;
+
+ /*
+ * t may be NULL, it may have one
+ * entry, or it may be a linked list
+ * of entries. Go to the end of the
+ * list.
+ */
+ while (*last) {
+ (*last)->order = order++;
+ last = &((*last)->next);
+ }
+ continue;
+ } /* $INCLUDE ... */
+
+ /*
+ * Parse the check values
+ */
+ rad_assert(check_tmp == NULL);
+ rad_assert(reply_tmp == NULL);
+ parsecode = fr_pair_list_afrom_str(ctx, ptr, &check_tmp);
+ if (parsecode == T_INVALID) {
+ pairlist_free(&pl);
+ ERROR("%s[%d]: Parse error (check) for entry %s: %s",
+ file, lineno, entry, fr_strerror());
+ fclose(fp);
+ return -1;
+ }
+
+ if (parsecode != T_EOL) {
+ pairlist_free(&pl);
+ talloc_free(check_tmp);
+ ERROR("%s[%d]: Invalid text after check attributes for entry %s",
+ file, lineno, entry);
+ fclose(fp);
+ return -1;
+ }
+
+#ifdef HAVE_REGEX_H
+ /*
+ * Do some more sanity checks.
+ */
+ for (vp = fr_cursor_init(&cursor, &check_tmp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (((vp->op == T_OP_REG_EQ) ||
+ (vp->op == T_OP_REG_NE)) &&
+ (vp->da->type != PW_TYPE_STRING)) {
+ pairlist_free(&pl);
+ talloc_free(check_tmp);
+ ERROR("%s[%d]: Cannot use regular expressions for non-string attributes in entry %s",
+ file, lineno, entry);
+ fclose(fp);
+ return -1;
+ }
+ }
+#endif
+
+ /*
+ * The reply MUST be on a new line.
+ */
+ mode = FIND_MODE_WANT_REPLY;
+ continue;
+ }
+
+ /*
+ * We COULD have a reply, OR we could have a new entry.
+ */
+ if (mode == FIND_MODE_WANT_REPLY) {
+ if (!isspace((uint8_t) buffer[0])) goto create_entry;
+
+ mode = FIND_MODE_HAVE_REPLY;
+ }
+
+ /*
+ * mode == FIND_MODE_HAVE_REPLY
+ */
+
+ /*
+ * The previous line ended with a comma, and then
+ * we have the start of a new entry!
+ */
+ if (!isspace((uint8_t) buffer[0])) {
+ trailing_comma:
+ pairlist_free(&pl);
+ talloc_free(check_tmp);
+ talloc_free(reply_tmp);
+ ERROR("%s[%d]: Invalid comma after the reply attributes. Please delete it.",
+ file, lineno);
+ fclose(fp);
+ return -1;
+ }
+
+ /*
+ * Parse the reply values. If there's a trailing
+ * comma, keep parsing the reply values.
+ */
+ parsecode = fr_pair_list_afrom_str(ctx, buffer, &reply_tmp);
+ if (parsecode == T_COMMA) {
+ continue;
+ }
+
+ /*
+ * We expect an EOL. Anything else is an error.
+ */
+ if (parsecode != T_EOL) {
+ pairlist_free(&pl);
+ talloc_free(check_tmp);
+ talloc_free(reply_tmp);
+ ERROR("%s[%d]: Parse error (reply) for entry %s: %s",
+ file, lineno, entry, fr_strerror());
+ fclose(fp);
+ return -1;
+ }
+
+ create_entry:
+ /*
+ * Done with this entry...
+ */
+ MEM(t = talloc_zero(ctx, PAIR_LIST));
+
+ if (check_tmp) fr_pair_steal(t, check_tmp);
+ if (reply_tmp) fr_pair_steal(t, reply_tmp);
+
+ t->check = check_tmp;
+ t->reply = reply_tmp;
+ t->lineno = entry_lineno;
+ t->order = order++;
+ check_tmp = NULL;
+ reply_tmp = NULL;
+
+ t->name = talloc_typed_strdup(t, entry);
+
+ *last = t;
+ last = &(t->next);
+
+ /*
+ * Look for a name. If we came here because
+ * there were no reply attributes, then re-parse
+ * the current line, instead of reading another one.
+ */
+ mode = FIND_MODE_NAME;
+ if (feof(fp)) break;
+ if (!isspace((uint8_t) buffer[0])) goto parse_again;
+ }
+
+ /*
+ * We're at EOF. If we're supposed to read more, that's
+ * an error.
+ */
+ if (mode == FIND_MODE_HAVE_REPLY) goto trailing_comma;
+
+ /*
+ * We had an entry, but no reply attributes. That's OK.
+ */
+ if (mode == FIND_MODE_WANT_REPLY) goto create_entry;
+
+ /*
+ * Else we were looking for an entry. We didn't get one
+ * because we were at EOF, so that's OK.
+ */
+
+ fclose(fp);
+
+ *list = pl;
+ return 0;
+}
diff --git a/src/main/libfreeradius-server.mk b/src/main/libfreeradius-server.mk
new file mode 100644
index 0000000..4495f72
--- /dev/null
+++ b/src/main/libfreeradius-server.mk
@@ -0,0 +1,22 @@
+TARGET := libfreeradius-server.a
+
+SOURCES := conffile.c \
+ evaluate.c \
+ exec.c \
+ exfile.c \
+ log.c \
+ parser.c \
+ map.c \
+ regex.c \
+ tmpl.c \
+ util.c \
+ version.c \
+ pair.c \
+ xlat.c
+
+# This lets the linker determine which version of the SSLeay functions to use.
+TGT_LDLIBS := $(OPENSSL_LIBS)
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
diff --git a/src/main/listen.c b/src/main/listen.c
new file mode 100644
index 0000000..ee73a57
--- /dev/null
+++ b/src/main/listen.c
@@ -0,0 +1,4486 @@
+/*
+ * listen.c Handle socket stuff
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2005,2006 The FreeRADIUS server project
+ * Copyright 2005 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/protocol.h>
+#include <freeradius-devel/modpriv.h>
+
+#include <freeradius-devel/detail.h>
+
+#ifdef WITH_UDPFROMTO
+#include <freeradius-devel/udpfromto.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef WITH_TLS
+#include <netinet/tcp.h>
+
+# ifdef __APPLE__
+# if !defined(SOL_TCP) && defined(IPPROTO_TCP)
+# define SOL_TCP IPPROTO_TCP
+# endif
+# endif
+
+#endif
+
+#ifdef DEBUG_PRINT_PACKET
+static void print_packet(RADIUS_PACKET *packet)
+{
+ char src[256], dst[256];
+
+ ip_ntoh(&packet->src_ipaddr, src, sizeof(src));
+ ip_ntoh(&packet->dst_ipaddr, dst, sizeof(dst));
+
+ fprintf(stderr, "ID %d: %s %d -> %s %d\n", packet->id,
+ src, packet->src_port, dst, packet->dst_port);
+
+}
+#endif
+
+
+static rad_listen_t *listen_alloc(TALLOC_CTX *ctx, RAD_LISTEN_TYPE type);
+
+#ifdef WITH_COMMAND_SOCKET
+#ifdef WITH_TCP
+static int command_tcp_recv(rad_listen_t *listener);
+static int command_tcp_send(rad_listen_t *listener, REQUEST *request);
+static int command_write_magic(int newfd, listen_socket_t *sock);
+#endif
+#endif
+
+#ifdef WITH_COA_TUNNEL
+static int listen_coa_init(void);
+#endif
+
+static fr_protocol_t master_listen[];
+
+#ifdef WITH_DYNAMIC_CLIENTS
+static void client_timer_free(void *ctx)
+{
+ RADCLIENT *client = ctx;
+
+ client_free(client);
+}
+#endif
+
+/*
+ * Find a per-socket client.
+ */
+RADCLIENT *client_listener_find(rad_listen_t *listener,
+ fr_ipaddr_t const *ipaddr, uint16_t src_port)
+{
+#ifdef WITH_DYNAMIC_CLIENTS
+ int rcode;
+ REQUEST *request;
+ RADCLIENT *created;
+#endif
+ time_t now;
+ RADCLIENT *client;
+ RADCLIENT_LIST *clients;
+ listen_socket_t *sock;
+
+ rad_assert(listener != NULL);
+ rad_assert(ipaddr != NULL);
+
+ sock = listener->data;
+ clients = sock->clients;
+
+ /*
+ * This HAS to have been initialized previously.
+ */
+ rad_assert(clients != NULL);
+
+ client = client_find(clients, ipaddr, sock->proto);
+ if (!client) {
+ char name[256], buffer[128];
+
+#ifdef WITH_DYNAMIC_CLIENTS
+ unknown: /* used only for dynamic clients */
+#endif
+
+ /*
+ * DoS attack quenching, but only in daemon mode.
+ * If they're running in debug mode, show them
+ * every packet.
+ */
+ if (rad_debug_lvl == 0) {
+ static time_t last_printed = 0;
+
+ now = time(NULL);
+ if (last_printed == now) return NULL;
+
+ last_printed = now;
+ }
+
+ listener->print(listener, name, sizeof(name));
+
+ radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d"
+#ifdef WITH_TCP
+ " proto %s"
+#endif
+ , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr,
+ buffer, sizeof(buffer)), src_port
+#ifdef WITH_TCP
+ , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp"
+#endif
+ );
+ return NULL;
+ }
+
+#ifndef WITH_DYNAMIC_CLIENTS
+ return client; /* return the found client. */
+#else
+
+ /*
+ * No server defined, and it's not dynamic. Return it.
+ */
+ if (!client->client_server && !client->dynamic) return client;
+
+ now = time(NULL);
+
+ /*
+ * It's a dynamically generated client, check it.
+ */
+ if (client->dynamic && (src_port != 0)) {
+#ifdef HAVE_SYS_STAT_H
+ char const *filename;
+#endif
+ fr_event_list_t *el;
+ struct timeval when;
+
+ /*
+ * Lives forever. Return it.
+ */
+ if (client->lifetime == 0) return client;
+
+ /*
+ * Rate-limit the deletion of known clients.
+ * This makes them last a little longer, but
+ * prevents the server from melting down if (say)
+ * 10k clients all expire at once.
+ */
+ if (now == client->last_new_client) return client;
+
+ /*
+ * It's not dead yet. Return it.
+ */
+ if ((client->created + client->lifetime) > now) return client;
+
+#ifdef HAVE_SYS_STAT_H
+ /*
+ * The client was read from a file, and the file
+ * hasn't changed since the client was created.
+ * Just renew the creation time, and continue.
+ * We don't need to re-load the same information.
+ */
+ if (client->cs &&
+ (filename = cf_section_filename(client->cs)) != NULL) {
+ struct stat buf;
+
+ if ((stat(filename, &buf) >= 0) &&
+ (buf.st_mtime < client->created)) {
+ client->created = now;
+ return client;
+ }
+ }
+#endif
+
+
+ /*
+ * Delete the client from the known list.
+ */
+ client_delete(clients, client);
+
+ /*
+ * Add a timer to free the client 20s after it's already timed out.
+ */
+ el = radius_event_list_corral(EVENT_CORRAL_MAIN);
+
+ gettimeofday(&when, NULL);
+ when.tv_sec += main_config.max_request_time + 20;
+
+ /*
+ * If this fails, we leak memory. That's better than crashing...
+ */
+ (void) fr_event_insert(el, client_timer_free, client, &when, &client->ev);
+
+ /*
+ * Go find the enclosing network again.
+ */
+ client = client_find(clients, ipaddr, sock->proto);
+
+ /*
+ * WTF?
+ */
+ if (!client) goto unknown;
+ if (!client->client_server) goto unknown;
+
+ /*
+ * At this point, 'client' is the enclosing
+ * network that configures where dynamic clients
+ * can be defined.
+ */
+ rad_assert(client->dynamic == 0);
+
+ } else if (!client->dynamic && client->rate_limit) {
+ /*
+ * The IP is unknown, so we've found an enclosing
+ * network. Enable DoS protection. We only
+ * allow one new client per second. Known
+ * clients aren't subject to this restriction.
+ */
+ if (now == client->last_new_client) goto unknown;
+ }
+
+ client->last_new_client = now;
+
+ request = request_alloc(NULL);
+ if (!request) goto unknown;
+
+ request->listener = listener;
+ request->client = client;
+ request->packet = rad_recv(NULL, listener->fd, 0x02); /* MSG_PEEK */
+ if (!request->packet) { /* badly formed, etc */
+ talloc_free(request);
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ goto unknown;
+ }
+ (void) talloc_steal(request, request->packet);
+ request->reply = rad_alloc_reply(request, request->packet);
+ if (!request->reply) {
+ talloc_free(request);
+ goto unknown;
+ }
+ gettimeofday(&request->packet->timestamp, NULL);
+ request->number = 0;
+ request->priority = listener->type;
+ request->server = client->client_server;
+ request->root = &main_config;
+
+ /*
+ * Run a fake request through the given virtual server.
+ * Look for FreeRADIUS-Client-IP-Address
+ * FreeRADIUS-Client-Secret
+ * ...
+ *
+ * and create the RADCLIENT structure from that.
+ */
+ RDEBUG("server %s {", request->server);
+
+ rcode = process_authorize(0, request);
+
+ RDEBUG("} # server %s", request->server);
+
+ switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ break;
+
+ /*
+ * Likely a fatal error we want to warn the user about
+ */
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_FAIL:
+ ERROR("Virtual-Server %s returned %s, creating dynamic client failed", request->server,
+ fr_int2str(mod_rcode_table, rcode, "<INVALID>"));
+ talloc_free(request);
+ goto unknown;
+
+ /*
+ * Probably the result of policy, or the client not existing.
+ */
+ default:
+ DEBUG("Virtual-Server %s returned %s, ignoring client", request->server,
+ fr_int2str(mod_rcode_table, rcode, "<INVALID>"));
+ talloc_free(request);
+ goto unknown;
+ }
+
+ /*
+ * If the client was updated by rlm_dynamic_clients,
+ * don't create the client from attribute-value pairs.
+ */
+ if (request->client == client) {
+ created = client_afrom_request(clients, request);
+ } else {
+ created = request->client;
+
+ /*
+ * This frees the client if it isn't valid.
+ */
+ if (!client_add_dynamic(clients, client, created)) goto unknown;
+ }
+
+ request->server = client->server;
+ exec_trigger(request, NULL, "server.client.add", false);
+
+ talloc_free(request);
+
+ if (!created) goto unknown;
+
+ return created;
+#endif
+}
+
+static int listen_bind(rad_listen_t *this);
+
+#ifdef WITH_COA_TUNNEL
+static void listener_coa_update(rad_listen_t *this, VALUE_PAIR *vps);
+#endif
+
+/*
+ * Process and reply to a server-status request.
+ * Like rad_authenticate and rad_accounting this should
+ * live in it's own file but it's so small we don't bother.
+ */
+int rad_status_server(REQUEST *request)
+{
+ int rcode = RLM_MODULE_OK;
+ DICT_VALUE *dval;
+
+#ifdef WITH_TLS
+ if (request->listener->tls) {
+ listen_socket_t *sock = request->listener->data;
+
+ if (sock->state == LISTEN_TLS_CHECKING) {
+ int autz_type = PW_AUTZ_TYPE;
+ char const *name = "Autz-Type";
+
+ if (request->listener->type == RAD_LISTEN_ACCT) {
+ autz_type = PW_ACCT_TYPE;
+ name = "Acct-Type";
+ }
+
+ RDEBUG("(TLS) Checking connection to see if it is authorized.");
+
+ dval = dict_valbyname(autz_type, 0, "New-TLS-Connection");
+ if (dval) {
+ rcode = process_authorize(dval->value, request);
+ } else {
+ rcode = RLM_MODULE_OK;
+ RWDEBUG("(TLS) Did not find '%s New-TLS-Connection' - defaulting to accept", name);
+ }
+
+ if ((rcode == RLM_MODULE_OK) || (rcode == RLM_MODULE_UPDATED)) {
+ RDEBUG("(TLS) Connection is authorized");
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+ } else {
+ RWDEBUG("(TLS) Connection is not authorized - closing TCP socket.");
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ }
+
+ return 0;
+ }
+ }
+#endif
+
+#ifdef WITH_STATS
+ /*
+ * Full statistics are available only on a statistics
+ * socket.
+ */
+ if (request->listener->type == RAD_LISTEN_NONE) {
+ request_stats_reply(request);
+ }
+#endif
+
+ switch (request->listener->type) {
+#ifdef WITH_STATS
+ case RAD_LISTEN_NONE:
+#endif
+ case RAD_LISTEN_AUTH:
+ dval = dict_valbyname(PW_AUTZ_TYPE, 0, "Status-Server");
+ if (dval) {
+ rcode = process_authorize(dval->value, request);
+ } else {
+ rcode = RLM_MODULE_OK;
+ }
+
+ switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+
+#ifdef WITH_COA_TUNNEL
+ if (request->listener->send_coa) listener_coa_update(request->listener, request->packet->vps);
+#endif
+ break;
+
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_HANDLED:
+ request->reply->code = 0; /* don't reply */
+ break;
+
+ default:
+ case RLM_MODULE_REJECT:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case RAD_LISTEN_ACCT:
+ dval = dict_valbyname(PW_ACCT_TYPE, 0, "Status-Server");
+ if (dval) {
+ rcode = process_accounting(dval->value, request);
+ } else {
+ rcode = RLM_MODULE_OK;
+ }
+
+ switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
+
+#ifdef WITH_COA_TUNNEL
+ if (request->listener->send_coa) listener_coa_update(request->listener, request->packet->vps);
+#endif
+ break;
+
+ default:
+ request->reply->code = 0; /* don't reply */
+ break;
+ }
+ break;
+#endif
+
+#ifdef WITH_COA
+ /*
+ * This is a vendor extension. Suggested by Glen
+ * Zorn in IETF 72, and rejected by the rest of
+ * the WG. We like it, so it goes in here.
+ */
+ case RAD_LISTEN_COA:
+ dval = dict_valbyname(PW_RECV_COA_TYPE, 0, "Status-Server");
+ if (dval) {
+ rcode = process_recv_coa(dval->value, request);
+ } else {
+ rcode = RLM_MODULE_OK;
+ }
+
+ switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ request->reply->code = PW_CODE_COA_ACK;
+ break;
+
+ default:
+ request->reply->code = 0; /* don't reply */
+ break;
+ }
+ break;
+#endif
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+#ifdef WITH_TCP
+static int dual_tcp_recv(rad_listen_t *listener)
+{
+ int rcode;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ listen_socket_t *sock = listener->data;
+ RADCLIENT *client = sock->client;
+
+ rad_assert(client != NULL);
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+ /*
+ * Allocate a packet for partial reads.
+ */
+ if (!sock->packet) {
+ sock->packet = rad_alloc(sock, false);
+ if (!sock->packet) return 0;
+
+ sock->packet->sockfd = listener->fd;
+ sock->packet->src_ipaddr = sock->other_ipaddr;
+ sock->packet->src_port = sock->other_port;
+ sock->packet->dst_ipaddr = sock->my_ipaddr;
+ sock->packet->dst_port = sock->my_port;
+ sock->packet->proto = sock->proto;
+ }
+
+ /*
+ * Grab the packet currently being processed.
+ */
+ packet = sock->packet;
+
+ rcode = fr_tcp_read_packet(packet, 0);
+
+ /*
+ * Still only a partial packet. Put it back, and return,
+ * so that we'll read more data when it's ready.
+ */
+ if (rcode == 0) {
+ return 0;
+ }
+
+ if (rcode == -1) { /* error reading packet */
+ char buffer[256];
+
+ ERROR("Invalid packet from %s port %d, closing socket: %s",
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port, fr_strerror());
+ }
+
+ if (rcode < 0) { /* error or connection reset */
+ listener->status = RAD_LISTEN_STATUS_EOL;
+
+ /*
+ * Tell the event handler that an FD has disappeared.
+ */
+ DEBUG("Client has closed connection");
+ radius_update_listener(listener);
+
+ /*
+ * Do NOT free the listener here. It's in use by
+ * a request, and will need to hang around until
+ * all of the requests are done.
+ *
+ * It is instead free'd in remove_from_request_hash()
+ */
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
+ FR_STATS_INC(auth, total_requests);
+ fun = rad_authenticate;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (listener->type != RAD_LISTEN_ACCT) {
+ /*
+ * Allow auth + dual. Disallow
+ * everything else.
+ */
+ if (!((listener->type == RAD_LISTEN_AUTH) &&
+ (listener->dual))) {
+ goto bad_packet;
+ }
+ }
+ FR_STATS_INC(acct, total_requests);
+ fun = rad_accounting;
+ break;
+#endif
+
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
+ FR_STATS_INC(auth, total_unknown_types);
+ WARN("Ignoring Status-Server request due to security configuration");
+ rad_free(&sock->packet);
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ bad_packet:
+ FR_STATS_INC(auth, total_unknown_types);
+
+ DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED",
+ packet->code, client->shortname, packet->src_port);
+ rad_free(&sock->packet);
+ return 0;
+ } /* switch over packet types */
+
+ if (!request_receive(NULL, listener, packet, client, fun)) {
+ FR_STATS_INC(auth, total_packets_dropped);
+ rad_free(&sock->packet);
+ return 0;
+ }
+
+ sock->packet = NULL; /* we have no need for more partial reads */
+ return 1;
+}
+
+#ifdef WITH_TLS
+typedef struct {
+ char const *name;
+ SSL_CTX *ctx;
+} fr_realm_ctx_t; /* hack from tls. */
+
+static int tls_sni_callback(SSL *ssl, UNUSED int *al, void *arg)
+{
+ fr_tls_server_conf_t *conf = arg;
+ char const *name, *p;
+ int type;
+ fr_realm_ctx_t my_r, *r;
+ REQUEST *request;
+ char buffer[PATH_MAX];
+
+ /*
+ * No SNI, that's fine.
+ */
+ type = SSL_get_servername_type(ssl);
+ if (type < 0) return SSL_TLSEXT_ERR_OK;
+
+ /*
+ * No realms configured, just use the default context.
+ */
+ if (!conf->realms) return SSL_TLSEXT_ERR_OK;
+
+ name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (!name) return SSL_TLSEXT_ERR_OK;
+
+ /*
+ * RFC Section 6066 Section 3 says that the names are
+ * ASCII, without a trailing dot. i.e. punycode.
+ */
+ for (p = name; *p != '\0'; p++) {
+ if (*p == '-') continue;
+ if (*p == '.') continue;
+ if ((*p >= 'A') && (*p <= 'Z')) continue;
+ if ((*p >= 'a') && (*p <= 'z')) continue;
+ if ((*p >= '0') && (*p <= '9')) continue;
+
+ /*
+ * Anything else, fail.
+ */
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ /*
+ * Too long, fail.
+ */
+ if ((p - name) > 255) return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ snprintf(buffer, sizeof(buffer), "%s/%s.pem", conf->realm_dir, name);
+
+ my_r.name = buffer;
+ r = fr_hash_table_finddata(conf->realms, &my_r);
+
+ /*
+ * If found, switch certs. Otherwise use the default
+ * one.
+ */
+ if (r) (void) SSL_set_SSL_CTX(ssl, r->ctx);
+
+ /*
+ * Set an attribute saying which server has been selected.
+ */
+ request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+ if (request) {
+ (void) pair_make_config("TLS-Server-Name-Indication", name, T_OP_SET);
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+#ifdef WITH_RADIUSV11
+static const unsigned char radiusv11_alpn_protos[] = {
+ 10, 'r', 'a', 'd', 'i', 'u', 's', '/', '1', '.', '1',
+};
+
+/*
+ * On the server, get the ALPN list requested by the client.
+ */
+static int radiusv11_server_alpn_cb(SSL *ssl,
+ const unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen,
+ void *arg)
+{
+ rad_listen_t *this = arg;
+ listen_socket_t *sock = this->data;
+ unsigned char **hack;
+ const unsigned char *server;
+ unsigned int server_len, i;
+ int rcode;
+ REQUEST *request;
+
+ request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+ fr_assert(request != NULL);
+
+ fr_assert(inlen > 0);
+
+ memcpy(&hack, &out, sizeof(out)); /* const issues */
+
+ /*
+ * The RADIUSv11 configuration for this socket is a combination of what we require, and what we
+ * require of the client.
+ */
+ switch (this->radiusv11) {
+ /*
+ * If we forbid RADIUSv11, then we never advertised it via ALPN, and this callback should
+ * never have been registered.
+ */
+ case FR_RADIUSV11_FORBID:
+ *out = NULL;
+ *outlen = 0;
+ return SSL_TLSEXT_ERR_OK;
+
+ case FR_RADIUSV11_ALLOW:
+ case FR_RADIUSV11_REQUIRE:
+ server = radiusv11_alpn_protos;
+ server_len = sizeof(radiusv11_alpn_protos);
+ break;
+ }
+
+ for (i = 0; i < inlen; i += in[0] + 1) {
+ RDEBUG("(TLS) ALPN sent by client is \"%.*s\"", in[i], &in[i + 1]);
+ }
+
+ /*
+ * Select the next protocol.
+ */
+ rcode = SSL_select_next_proto(hack, outlen, server, server_len, in, inlen);
+ if (rcode == OPENSSL_NPN_NEGOTIATED) {
+ server = *out;
+
+ /*
+ * Tell our socket which protocol we negotiated.
+ */
+ fr_assert(*outlen == 10);
+ sock->radiusv11 = (server[9] == '1');
+
+ RDEBUG("(TLS) ALPN server negotiated application protocol \"%.*s\"", (int) *outlen, server);
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+ /*
+ * No common ALPN.
+ */
+ RDEBUG("(TLS) ALPN failure - no protocols in common");
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+}
+
+int fr_radiusv11_client_init(fr_tls_server_conf_t *tls);
+int fr_radiusv11_client_get_alpn(rad_listen_t *listener);
+
+int fr_radiusv11_client_init(fr_tls_server_conf_t *tls)
+{
+ switch (tls->radiusv11) {
+ case FR_RADIUSV11_ALLOW:
+ case FR_RADIUSV11_REQUIRE:
+ if (SSL_CTX_set_alpn_protos(tls->ctx, radiusv11_alpn_protos, sizeof(radiusv11_alpn_protos)) != 0) {
+ ERROR("Failed setting RADIUSv11 negotiation flags");
+ return -1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int fr_radiusv11_client_get_alpn(rad_listen_t *listener)
+{
+ const unsigned char *data;
+ unsigned int len;
+ listen_socket_t *sock = listener->data;
+
+ SSL_get0_alpn_selected(sock->ssn->ssl, &data, &len);
+ if (!data) {
+ DEBUG("(TLS) ALPN home server did not send any application protocol");
+ if (listener->radiusv11 == FR_RADIUSV11_REQUIRE) {
+ DEBUG("(TLS) We have 'radiusv11 = require', but the home server has not negotiated it - closing socket");
+ return -1;
+ }
+
+ DEBUG("(TLS) ALPN assuming historical RADIUS");
+ return 0;
+ }
+
+ DEBUG("(TLS) ALPN home server sent application protocol \"%.*s\"", (int) len, data);
+
+ if (len != 10) {
+ radiusv11_unknown:
+ DEBUG("(TLS) ALPN home server sent unknown application protocol - closing connection");
+ return -1;
+ }
+
+ /*
+ * Should always be "radius/1.1". The server MUST echo back one of the strings
+ * we sent. If it doesn't, it's a bad server.
+ */
+ if (memcmp(data, "radius/1.1", 10) != 0) goto radiusv11_unknown;
+
+ /*
+ * Double-check what the server sent us. It SHOULD be sane, but it never hurts to check.
+ */
+ switch (listener->radiusv11) {
+ case FR_RADIUSV11_FORBID:
+ DEBUG("(TLS) ALPN home server sent \"radius/v1.1\" but we forbid it - closing connection to home server");
+ return -1;
+
+ case FR_RADIUSV11_ALLOW:
+ case FR_RADIUSV11_REQUIRE:
+ DEBUG("(TLS) ALPN using \"radius/1.1\"");
+ sock->radiusv11 = true;
+ break;
+ }
+
+ sock->alpn_checked = true;
+ return 0;
+}
+#endif
+
+
+static int dual_tcp_accept(rad_listen_t *listener)
+{
+ int newfd;
+ uint16_t src_port;
+ rad_listen_t *this;
+ socklen_t salen;
+ struct sockaddr_storage src;
+ listen_socket_t *sock;
+ fr_ipaddr_t src_ipaddr;
+ RADCLIENT *client = NULL;
+
+ salen = sizeof(src);
+
+ DEBUG2(" ... new connection request on TCP socket");
+
+ newfd = accept(listener->fd, (struct sockaddr *) &src, &salen);
+ if (newfd < 0) {
+ /*
+ * Non-blocking sockets must handle this.
+ */
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK) {
+ return 0;
+ }
+#endif
+
+ DEBUG2(" ... failed to accept connection");
+ return -1;
+ }
+
+ if (!fr_sockaddr2ipaddr(&src, salen, &src_ipaddr, &src_port)) {
+ close(newfd);
+ DEBUG2(" ... unknown address family");
+ return 0;
+ }
+
+ /*
+ * Enforce client IP address checks on accept, not on
+ * every packet.
+ */
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ close(newfd);
+ FR_STATS_INC(auth, total_invalid_requests);
+ return 0;
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Enforce security restrictions.
+ *
+ * This shouldn't be necessary in practice. However, it
+ * serves as a double-check on configurations. Marking a
+ * client as "tls required" means that any accidental
+ * exposure of the client to non-TLS traffic is
+ * prevented.
+ */
+ if (client->tls_required && !listener->tls) {
+ INFO("Ignoring connection to TLS socket from non-TLS client");
+ close(newfd);
+ return 0;
+ }
+
+#ifdef WITH_RADIUSV11
+ if (listener->tls) {
+ switch (listener->tls->radiusv11) {
+ case FR_RADIUSV11_FORBID:
+ if (client->radiusv11 == FR_RADIUSV11_REQUIRE) {
+ INFO("Ignoring new connection as client is marked as 'radiusv11 = require', and this socket has 'radiusv11 = forbid'");
+ close(newfd);
+ return 0;
+ }
+ break;
+
+ case FR_RADIUSV11_ALLOW:
+ /*
+ * We negotiate it as per the client recommendations (forbid, allow, require)
+ */
+ break;
+
+ case FR_RADIUSV11_REQUIRE:
+ if (client->radiusv11 == FR_RADIUSV11_FORBID) {
+ INFO("Ignoring new connection as client is marked as 'radiusv11 = forbid', and this socket has 'radiusv11 = require'");
+ close(newfd);
+ return 0;
+ }
+ break;
+ }
+ }
+#endif
+
+#endif
+
+ /*
+ * Enforce max_connections on client && listen section.
+ */
+ if ((client->limit.max_connections != 0) &&
+ (client->limit.max_connections == client->limit.num_connections)) {
+ /*
+ * FIXME: Print client IP/port, and server IP/port.
+ */
+ INFO("Ignoring new connection due to client max_connections (%d)", client->limit.max_connections);
+ close(newfd);
+ return 0;
+ }
+
+ sock = listener->data;
+ if ((sock->limit.max_connections != 0) &&
+ (sock->limit.max_connections == sock->limit.num_connections)) {
+ /*
+ * FIXME: Print client IP/port, and server IP/port.
+ */
+ INFO("Ignoring new connection due to socket max_connections");
+ close(newfd);
+ return 0;
+ }
+ client->limit.num_connections++;
+ sock->limit.num_connections++;
+
+ /*
+ * Add the new listener. We require a new context here,
+ * because the allocations for the packet, etc. in the
+ * child listener will be done in a child thread.
+ */
+ this = listen_alloc(NULL, listener->type);
+ if (!this) return -1;
+
+ /*
+ * Copy everything, including the pointer to the socket
+ * information.
+ */
+ sock = this->data;
+ memcpy(this->data, listener->data, sizeof(*sock));
+ memcpy(this, listener, sizeof(*this));
+ this->next = NULL;
+ this->data = sock; /* fix it back */
+
+ sock->parent = listener->data;
+ sock->other_ipaddr = src_ipaddr;
+ sock->other_port = src_port;
+ sock->client = client;
+ sock->opened = sock->last_packet = time(NULL);
+
+ /*
+ * Set the limits. The defaults are the parent limits.
+ * Client limits on max_connections are enforced dynamically.
+ * Set the MINIMUM of client/socket idle timeout or lifetime.
+ */
+ memcpy(&sock->limit, &sock->parent->limit, sizeof(sock->limit));
+
+ if (client->limit.idle_timeout &&
+ ((sock->limit.idle_timeout == 0) ||
+ (client->limit.idle_timeout < sock->limit.idle_timeout))) {
+ sock->limit.idle_timeout = client->limit.idle_timeout;
+ }
+
+ if (client->limit.lifetime &&
+ ((sock->limit.lifetime == 0) ||
+ (client->limit.lifetime < sock->limit.lifetime))) {
+ sock->limit.lifetime = client->limit.lifetime;
+ }
+
+ this->fd = newfd;
+ this->status = RAD_LISTEN_STATUS_INIT;
+
+ this->parent = listener;
+ if (!rbtree_insert(listener->children, this)) {
+ ERROR("Failed inserting TCP socket into parent list.");
+ }
+
+#ifdef WITH_COMMAND_SOCKET
+ if (this->type == RAD_LISTEN_COMMAND) {
+ this->recv = command_tcp_recv;
+ this->send = command_tcp_send;
+ command_write_magic(this->fd, sock);
+ } else
+#endif
+ {
+
+ this->recv = dual_tcp_recv;
+
+#ifdef WITH_TLS
+ if (this->tls) {
+ this->recv = dual_tls_recv;
+ this->send = dual_tls_send;
+
+ /*
+ * Set up SNI callback. We don't do it
+ * in the main TLS code, because EAP
+ * doesn't need or use SNI.
+ */
+ SSL_CTX_set_tlsext_servername_callback(this->tls->ctx, tls_sni_callback);
+ SSL_CTX_set_tlsext_servername_arg(this->tls->ctx, this->tls);
+#ifdef WITH_RADIUSV11
+ /*
+ * Default is "forbid" (0). In which case we don't set any ALPN callbacks, and
+ * the ServerHello does not contain an ALPN section.
+ */
+ if (client->radiusv11 != FR_RADIUSV11_FORBID) {
+ SSL_CTX_set_alpn_select_cb(this->tls->ctx, radiusv11_server_alpn_cb, this);
+ DEBUG("(TLS) ALPN radiusv11 = allow / require");
+ } else {
+ DEBUG("(TLS) ALPN radiusv11 = forbid");
+ }
+#endif
+ }
+#endif
+ }
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Originate CoA requests to a NAS.
+ */
+ if (this->send_coa) {
+ home_server_t *home;
+
+ rad_assert(this->type != RAD_LISTEN_PROXY);
+
+ this->proxy_send = dual_tls_send_coa_request;
+ this->proxy_encode = master_listen[RAD_LISTEN_PROXY].encode;
+ this->proxy_decode = master_listen[RAD_LISTEN_PROXY].decode;
+
+ /*
+ * Automatically create a home server for this
+ * client. There MAY be one already one for that
+ * IP in the configuration files, but it will not
+ * have this particular port.
+ */
+ sock->home = home = talloc_zero(this, home_server_t);
+ home->ipaddr = sock->other_ipaddr;
+ home->port = sock->other_port;
+ home->proto = sock->proto;
+ home->secret = sock->client->secret;
+
+ home->coa_irt = this->coa_irt;
+ home->coa_mrt = this->coa_mrt;
+ home->coa_mrc = this->coa_mrc;
+ home->coa_mrd = this->coa_mrd;
+ home->recv_coa_server = this->server;
+ }
+#endif
+
+ /*
+ * FIXME: set O_NONBLOCK on the accept'd fd.
+ * See djb's portability rants for details.
+ */
+
+ /*
+ * Tell the event loop that we have a new FD.
+ * This can be called from a child thread...
+ */
+ radius_update_listener(this);
+
+ return 0;
+}
+#endif
+
+/*
+ * Ensure that we always keep the correct counters.
+ */
+#ifdef WITH_TCP
+static void common_socket_free(rad_listen_t *this)
+{
+ listen_socket_t *sock = this->data;
+
+ if (sock->proto != IPPROTO_TCP) return;
+
+ /*
+ * Decrement the number of connections.
+ */
+ if (sock->parent && (sock->parent->limit.num_connections > 0)) {
+ sock->parent->limit.num_connections--;
+ }
+ if (sock->client && sock->client->limit.num_connections > 0) {
+ sock->client->limit.num_connections--;
+ }
+ if (sock->home && sock->home->limit.num_connections > 0) {
+ sock->home->limit.num_connections--;
+ }
+}
+#else
+#define common_socket_free NULL
+#endif
+
+/*
+ * This function is stupid and complicated.
+ */
+int common_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
+{
+ size_t len;
+ listen_socket_t *sock = this->data;
+ char const *name = master_listen[this->type].name;
+
+#define FORWARD len = strlen(buffer); if (len >= (bufsize + 1)) return 0;buffer += len;bufsize -= len
+#define ADDSTRING(_x) strlcpy(buffer, _x, bufsize);FORWARD
+
+ ADDSTRING(name);
+
+#ifdef WITH_TCP
+ if (this->dual) {
+ ADDSTRING("+acct");
+ }
+#endif
+
+#ifdef WITH_COA_TUNNEL
+ if (this->send_coa) {
+ ADDSTRING("+coa");
+ }
+#endif
+
+ if (sock->interface) {
+ ADDSTRING(" interface ");
+ ADDSTRING(sock->interface);
+ }
+
+#ifdef WITH_TCP
+ if (this->recv == dual_tcp_accept) {
+ ADDSTRING(" proto tcp");
+ }
+#endif
+
+#ifdef WITH_TCP
+ /*
+ * TCP sockets get printed a little differently, to make
+ * it clear what's going on.
+ */
+ if (sock->client) {
+ ADDSTRING(" from client (");
+ ip_ntoh(&sock->other_ipaddr, buffer, bufsize);
+ FORWARD;
+
+ ADDSTRING(", ");
+ snprintf(buffer, bufsize, "%d", sock->other_port);
+ FORWARD;
+ ADDSTRING(") -> (");
+
+ if ((sock->my_ipaddr.af == AF_INET) &&
+ (sock->my_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {
+ strlcpy(buffer, "*", bufsize);
+ } else {
+ ip_ntoh(&sock->my_ipaddr, buffer, bufsize);
+ }
+ FORWARD;
+
+ ADDSTRING(", ");
+ snprintf(buffer, bufsize, "%d", sock->my_port);
+ FORWARD;
+
+ if (this->server) {
+ ADDSTRING(", virtual-server=");
+ ADDSTRING(this->server);
+ }
+
+ ADDSTRING(")");
+
+ return 1;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * Maybe it's a socket that we opened to a home server.
+ */
+ if ((sock->proto == IPPROTO_TCP) &&
+ (this->type == RAD_LISTEN_PROXY)) {
+ ADDSTRING(" (");
+ ip_ntoh(&sock->my_ipaddr, buffer, bufsize);
+ FORWARD;
+
+ ADDSTRING(", ");
+ snprintf(buffer, bufsize, "%d", sock->my_port);
+ FORWARD;
+ ADDSTRING(") -> home_server (");
+
+ if ((sock->other_ipaddr.af == AF_INET) &&
+ (sock->other_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {
+ strlcpy(buffer, "*", bufsize);
+ } else {
+ ip_ntoh(&sock->other_ipaddr, buffer, bufsize);
+ }
+ FORWARD;
+
+ ADDSTRING(", ");
+ snprintf(buffer, bufsize, "%d", sock->other_port);
+ FORWARD;
+
+ ADDSTRING(")");
+
+ return 1;
+ }
+#endif /* WITH_PROXY */
+#endif /* WITH_TCP */
+
+ ADDSTRING(" address ");
+
+ if ((sock->my_ipaddr.af == AF_INET) &&
+ (sock->my_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY))) {
+ strlcpy(buffer, "*", bufsize);
+ } else {
+ ip_ntoh(&sock->my_ipaddr, buffer, bufsize);
+ }
+ FORWARD;
+
+ ADDSTRING(" port ");
+ snprintf(buffer, bufsize, "%d", sock->my_port);
+ FORWARD;
+
+#ifdef WITH_TLS
+ if (this->tls) {
+ ADDSTRING(" (TLS)");
+ FORWARD;
+ }
+#endif
+
+ if (this->server) {
+ ADDSTRING(" bound to server ");
+ strlcpy(buffer, this->server, bufsize);
+ }
+
+#undef ADDSTRING
+#undef FORWARD
+
+ return 1;
+}
+
+static CONF_PARSER performance_config[] = {
+ { "skip_duplicate_checks", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rad_listen_t, nodup), NULL },
+
+ { "synchronous", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rad_listen_t, synchronous), NULL },
+
+ { "workers", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, workers), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static CONF_PARSER limit_config[] = {
+ { "max_pps", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, max_rate), NULL },
+
+#ifdef WITH_TCP
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.max_connections), "16" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.lifetime), "0" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, listen_socket_t, limit.idle_timeout), STRINGIFY(30) },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+#ifdef WITH_COA_TUNNEL
+static CONF_PARSER coa_config[] = {
+ { "irt", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, coa_irt), STRINGIFY(2) },
+ { "mrt", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, coa_mrt), STRINGIFY(16) },
+ { "mrc", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, coa_mrc), STRINGIFY(5) },
+ { "mrd", FR_CONF_OFFSET(PW_TYPE_INTEGER, rad_listen_t, coa_mrd), STRINGIFY(30) },
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+#ifdef WITH_TCP
+/*
+ * TLS requires child threads to handle the listeners. Which
+ * means that we need a separate talloc context per child thread.
+ * Which means that we need to manually clean up the child
+ * listeners. Which means we need to manually track them.
+ *
+ * All child thread linking/unlinking is done in the master
+ * thread. If we care, we can later add a mutex for the parent
+ * listener.
+ */
+static int listener_cmp(void const *one, void const *two)
+{
+ if (one < two) return -1;
+ if (one > two) return +1;
+ return 0;
+}
+
+static int listener_unlink(UNUSED void *ctx, UNUSED void *data)
+{
+ return 2; /* unlink this node from the tree */
+}
+#endif
+
+
+/*
+ * Parse an authentication or accounting socket.
+ */
+int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+{
+ int rcode;
+ uint16_t listen_port;
+ fr_ipaddr_t ipaddr;
+ listen_socket_t *sock = this->data;
+ char const *section_name = NULL;
+ CONF_SECTION *client_cs, *parentcs;
+ CONF_SECTION *subcs;
+ CONF_PAIR *cp;
+
+ this->cs = cs;
+
+ /*
+ * Try IPv4 first
+ */
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
+
+ rcode = cf_item_parse(cs, "ipaddr", FR_ITEM_POINTER(PW_TYPE_COMBO_IP_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) rcode = cf_item_parse(cs, "ipv4addr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) rcode = cf_item_parse(cs, "ipv6addr", FR_ITEM_POINTER(PW_TYPE_IPV6_ADDR, &ipaddr), NULL);
+ if (rcode < 0) return -1;
+ if (rcode != 0) {
+ cf_log_err_cs(cs, "No address specified in listen section");
+ return -1;
+ }
+
+ rcode = cf_item_parse(cs, "port", FR_ITEM_POINTER(PW_TYPE_SHORT, &listen_port), "0");
+ if (rcode < 0) return -1;
+
+ rcode = cf_item_parse(cs, "recv_buff", PW_TYPE_INTEGER, &sock->recv_buff, NULL);
+ if (rcode < 0) return -1;
+
+ sock->proto = IPPROTO_UDP;
+
+ if (cf_pair_find(cs, "proto")) {
+#ifndef WITH_TCP
+ cf_log_err_cs(cs,
+ "System does not support the TCP protocol. Delete this line from the configuration file");
+ return -1;
+#else
+ char const *proto = NULL;
+#ifdef WITH_TLS
+ CONF_SECTION *tls;
+#endif
+
+ rcode = cf_item_parse(cs, "proto", FR_ITEM_POINTER(PW_TYPE_STRING, &proto), "udp");
+ if (rcode < 0) return -1;
+
+ if (!proto || strcmp(proto, "udp") == 0) {
+ sock->proto = IPPROTO_UDP;
+
+ } else if (strcmp(proto, "tcp") == 0) {
+ sock->proto = IPPROTO_TCP;
+
+ } else {
+ cf_log_err_cs(cs,
+ "Unknown proto name \"%s\"", proto);
+ return -1;
+ }
+
+ /*
+ * TCP requires a destination IP for sockets.
+ * UDP doesn't, so it's allowed.
+ */
+#ifdef WITH_PROXY
+ if ((this->type == RAD_LISTEN_PROXY) &&
+ (sock->proto != IPPROTO_UDP)) {
+ cf_log_err_cs(cs,
+ "Proxy listeners can only listen on proto = udp");
+ return -1;
+ }
+#endif /* WITH_PROXY */
+
+#ifdef WITH_TLS
+ tls = cf_section_sub_find(cs, "tls");
+
+ if (tls) {
+ /*
+ * Don't allow TLS configurations for UDP sockets.
+ */
+ if (sock->proto != IPPROTO_TCP) {
+ cf_log_err_cs(cs,
+ "TLS transport is not available for UDP sockets");
+ return -1;
+ }
+
+ /*
+ * Add support for http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+ */
+ rcode = cf_item_parse(cs, "proxy_protocol", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &this->proxy_protocol), NULL);
+ if (rcode < 0) return -1;
+
+ /*
+ * Allow non-blocking for TLS sockets
+ */
+ rcode = cf_item_parse(cs, "nonblock", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &this->nonblock), NULL);
+ if (rcode < 0) return -1;
+
+ /*
+ * If unset, set to default.
+ */
+ if (listen_port == 0) listen_port = PW_RADIUS_TLS_PORT;
+
+ this->tls = tls_server_conf_parse(tls);
+ if (!this->tls) {
+ return -1;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&sock->mutex, NULL) < 0) {
+ rad_assert(0 == 1);
+ listen_free(&this);
+ return 0;
+ }
+#endif
+
+ rcode = cf_item_parse(cs, "check_client_connections", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &this->check_client_connections), "no");
+ if (rcode < 0) return -1;
+
+#ifdef WITH_RADIUSV11
+ if (this->tls->radiusv11_name) {
+ rcode = fr_str2int(radiusv11_types, this->tls->radiusv11_name, -1);
+ if (rcode < 0) {
+ cf_log_err_cs(cs, "Invalid value for 'radiusv11'");
+ return -1;
+ }
+
+ this->radiusv11 = this->tls->radiusv11 = rcode;
+ }
+#endif
+ }
+#else /* WITH_TLS */
+ /*
+ * Built without TLS. Disallow it.
+ */
+ if (cf_section_sub_find(cs, "tls")) {
+ cf_log_err_cs(cs,
+ "TLS transport is not available in this executable");
+ return -1;
+ }
+#endif /* WITH_TLS */
+
+#endif /* WITH_TCP */
+
+ /*
+ * No "proto" field. Disallow TLS.
+ */
+ } else if (cf_section_sub_find(cs, "tls")) {
+ cf_log_err_cs(cs,
+ "TLS transport is not available in this \"listen\" section");
+ return -1;
+ }
+
+ /*
+ * Magical tuning methods!
+ */
+ subcs = cf_section_sub_find(cs, "performance");
+ if (subcs) {
+ rcode = cf_section_parse(subcs, this,
+ performance_config);
+ if (rcode < 0) return -1;
+
+ if (this->synchronous && sock->max_rate) {
+ WARN("Setting 'max_pps' is incompatible with 'synchronous'. Disabling 'max_pps'");
+ sock->max_rate = 0;
+ }
+
+ if (!this->synchronous && this->workers) {
+ WARN("Setting 'workers' requires 'synchronous'. Disabling 'workers'");
+ this->workers = 0;
+ }
+ }
+
+ subcs = cf_section_sub_find(cs, "limit");
+ if (subcs) {
+ rcode = cf_section_parse(subcs, sock,
+ limit_config);
+ if (rcode < 0) return -1;
+
+ if (sock->max_rate && ((sock->max_rate < 10) || (sock->max_rate > 1000000))) {
+ cf_log_err_cs(cs,
+ "Invalid value for \"max_pps\"");
+ return -1;
+ }
+
+#ifdef WITH_TCP
+ if ((sock->limit.idle_timeout > 0) && (sock->limit.idle_timeout < 5)) {
+ WARN("Setting idle_timeout to 5");
+ sock->limit.idle_timeout = 5;
+ }
+
+ if ((sock->limit.lifetime > 0) && (sock->limit.lifetime < 5)) {
+ WARN("Setting lifetime to 5");
+ sock->limit.lifetime = 5;
+ }
+
+ if ((sock->limit.lifetime > 0) && (sock->limit.idle_timeout > sock->limit.lifetime)) {
+ WARN("Setting idle_timeout to 0");
+ sock->limit.idle_timeout = 0;
+ }
+
+ /*
+ * Force no duplicate detection for TCP sockets.
+ */
+ if (sock->proto == IPPROTO_TCP) {
+ this->nodup = true;
+ }
+
+ } else {
+ sock->limit.max_connections = 60;
+ sock->limit.idle_timeout = 30;
+ sock->limit.lifetime = 0;
+#endif
+ }
+
+ sock->my_ipaddr = ipaddr;
+ sock->my_port = listen_port;
+
+#ifdef WITH_PROXY
+ if (check_config) {
+ /*
+ * Until there is a side effects free way of forwarding a
+ * request to another virtual server, this check is invalid,
+ * and should be left disabled.
+ */
+#if 0
+ if (home_server_find(&sock->my_ipaddr, sock->my_port, sock->proto)) {
+ char buffer[128];
+
+ ERROR("We have been asked to listen on %s port %d, which is also listed as a "
+ "home server. This can create a proxy loop",
+ ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)), sock->my_port);
+ return -1;
+ }
+#endif
+ return 0; /* don't do anything */
+ }
+#endif
+
+ /*
+ * If we can bind to interfaces, do so,
+ * else don't.
+ */
+ cp = cf_pair_find(cs, "interface");
+ if (cp) {
+ char const *value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cs(cs,
+ "No interface name given");
+ return -1;
+ }
+ sock->interface = value;
+ }
+
+#ifdef WITH_DHCP
+ /*
+ * If we can do broadcasts..
+ */
+ cp = cf_pair_find(cs, "broadcast");
+ if (cp) {
+#ifndef SO_BROADCAST
+ cf_log_err_cs(cs,
+ "System does not support broadcast sockets. Delete this line from the configuration file");
+ return -1;
+#else
+ if (this->type != RAD_LISTEN_DHCP) {
+ cf_log_err_cp(cp,
+ "Broadcast can only be set for DHCP listeners. Delete this line from the configuration file");
+ return -1;
+ }
+
+ char const *value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cs(cs,
+ "No broadcast value given");
+ return -1;
+ }
+
+ /*
+ * Hack... whatever happened to cf_section_parse?
+ */
+ sock->broadcast = (strcmp(value, "yes") == 0);
+#endif
+ }
+#endif
+
+ /*
+ * And bind it to the port.
+ */
+ if (listen_bind(this) < 0) {
+ char buffer[128];
+ cf_log_err_cs(cs,
+ "Error binding to port for %s port %d",
+ ip_ntoh(&sock->my_ipaddr, buffer, sizeof(buffer)),
+ sock->my_port);
+ return -1;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * Proxy sockets don't have clients.
+ */
+ if (this->type == RAD_LISTEN_PROXY) return 0;
+#endif
+
+ /*
+ * The more specific configurations are preferred to more
+ * generic ones.
+ */
+ client_cs = NULL;
+ parentcs = cf_top_section(cs);
+ rcode = cf_item_parse(cs, "clients", FR_ITEM_POINTER(PW_TYPE_STRING, &section_name), NULL);
+ if (rcode < 0) return -1; /* bad string */
+ if (rcode == 0) {
+ /*
+ * Explicit list given: use it.
+ */
+ client_cs = cf_section_sub_find_name2(parentcs, "clients", section_name);
+ if (!client_cs) {
+ client_cs = cf_section_find(section_name);
+ }
+ if (!client_cs) {
+ cf_log_err_cs(cs,
+ "Failed to find clients %s {...}",
+ section_name);
+ return -1;
+ }
+ } /* else there was no "clients = " entry. */
+
+ /*
+ * The "listen" section wasn't given an explicit client list.
+ * Look for (a) clients in this virtual server, or
+ * (b) the global client list.
+ */
+ if (!client_cs) {
+ CONF_SECTION *server_cs;
+
+ server_cs = cf_section_sub_find_name2(parentcs,
+ "server",
+ this->server);
+ /*
+ * Found a "server foo" section. If there are clients
+ * in it, use them.
+ */
+ if (server_cs &&
+ (cf_section_sub_find(server_cs, "client") != NULL)) {
+ client_cs = server_cs;
+ }
+ }
+
+ /*
+ * Still nothing. Look for global clients.
+ */
+ if (!client_cs) client_cs = parentcs;
+
+#ifdef WITH_TLS
+ sock->clients = client_list_parse_section(client_cs, (this->tls != NULL));
+#else
+ sock->clients = client_list_parse_section(client_cs, false);
+#endif
+ if (!sock->clients) {
+ cf_log_err_cs(cs,
+ "Failed to load clients for this listen section");
+ return -1;
+ }
+
+#ifdef WITH_TCP
+ if (sock->proto == IPPROTO_TCP) {
+ /*
+ * Re-write the listener receive function to
+ * allow us to accept the socket.
+ */
+ this->recv = dual_tcp_accept;
+
+ /*
+ * @todo - add a free function? Though this only
+ * matters when we're tearing down the server, so
+ * perhaps it's less relevant.
+ */
+ this->children = rbtree_create(this, listener_cmp, NULL, 0);
+ if (!this->children) {
+ cf_log_err_cs(cs, "Failed to create child list for TCP socket.");
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * Send a response packet
+ */
+static int common_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == common_socket_send);
+
+ if (request->reply->code == 0) return 0;
+
+#ifdef WITH_UDPFROMTO
+ /*
+ * Overwrite the src ip address on the outbound packet
+ * with the one specified by the client.
+ * This is useful to work around broken DSR implementations
+ * and other routing issues.
+ */
+ if (request->client->src_ipaddr.af != AF_UNSPEC) {
+ request->reply->src_ipaddr = request->client->src_ipaddr;
+ }
+#endif
+
+ if (rad_send(request->reply, request->packet,
+ request->client->secret) < 0) {
+ RERROR("Failed sending reply: %s",
+ fr_strerror());
+ return -1;
+ }
+ return 0;
+}
+
+
+#ifdef WITH_PROXY
+/*
+ * Send a packet to a home server.
+ *
+ * FIXME: have different code for proxy auth & acct!
+ */
+static int proxy_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ rad_assert(request->proxy_listener == listener);
+ rad_assert(listener->proxy_send == proxy_socket_send);
+
+ if (rad_send(request->proxy, NULL,
+ request->home_server->secret) < 0) {
+ RERROR("Failed sending proxied request: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef WITH_STATS
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int stats_socket_recv(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ int code;
+ uint16_t src_port;
+ RADIUS_PACKET *packet;
+ RADCLIENT *client = NULL;
+ fr_ipaddr_t src_ipaddr;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ FR_STATS_INC(auth, total_requests);
+
+ if (rcode < 20) { /* RADIUS_HDR_LEN */
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ FR_STATS_INC(auth, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_invalid_requests);
+ return 0;
+ }
+
+ FR_STATS_TYPE_INC(client->auth.total_requests);
+
+ /*
+ * We only understand Status-Server on this socket.
+ */
+ if (code != PW_CODE_STATUS_SERVER) {
+ DEBUG("Ignoring packet code %d sent to Status-Server port",
+ code);
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_unknown_types);
+ return 0;
+ }
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(NULL, listener->fd, 1); /* require message authenticator */
+ if (!packet) {
+ FR_STATS_INC(auth, total_malformed_requests);
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ return 0;
+ }
+
+ if (!request_receive(NULL, listener, packet, client, rad_status_server)) {
+ FR_STATS_INC(auth, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int auth_socket_recv(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ int code;
+ uint16_t src_port;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client = NULL;
+ fr_ipaddr_t src_ipaddr;
+ TALLOC_CTX *ctx;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ FR_STATS_INC(auth, total_requests);
+
+ if (rcode < 20) { /* RADIUS_HDR_LEN */
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ FR_STATS_INC(auth, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch (code) {
+ case PW_CODE_ACCESS_REQUEST:
+ FR_STATS_TYPE_INC(client->auth.total_requests);
+ fun = rad_authenticate;
+ break;
+
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_unknown_types);
+ WARN("Ignoring Status-Server request due to security configuration");
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_unknown_types);
+
+ if (DEBUG_ENABLED) ERROR("Receive - Invalid packet code %d sent to authentication port from "
+ "client %s port %d", code, client->shortname, src_port);
+ return 0;
+ } /* switch over packet types */
+
+ ctx = talloc_pool(NULL, main_config.talloc_pool_size);
+ if (!ctx) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(auth, total_packets_dropped);
+ return 0;
+ }
+ talloc_set_name_const(ctx, "auth_listener_pool");
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(ctx, listener->fd, client->message_authenticator);
+ if (!packet) {
+ FR_STATS_INC(auth, total_malformed_requests);
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ talloc_free(ctx);
+ return 0;
+ }
+
+#ifdef __APPLE__
+#ifdef WITH_UDPFROMTO
+ /*
+ * This is a NICE Mac OSX bug. Create an interface with
+ * two IP address, and then configure one listener for
+ * each IP address. Send thousands of packets to one
+ * address, and some will show up on the OTHER socket.
+ *
+ * This hack works ONLY if the clients are global. If
+ * each listener has the same client IP, but with
+ * different secrets, then it will fail the rad_recv()
+ * check above, and there's nothing you can do.
+ */
+ {
+ listen_socket_t *sock = listener->data;
+ rad_listen_t *other;
+
+ other = listener_find_byipaddr(&packet->dst_ipaddr,
+ packet->dst_port, sock->proto);
+ if (other) listener = other;
+ }
+#endif
+#endif
+
+ if (!request_receive(ctx, listener, packet, client, fun)) {
+ FR_STATS_INC(auth, total_packets_dropped);
+ talloc_free(ctx);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Receive packets from an accounting socket
+ */
+static int acct_socket_recv(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ int code;
+ uint16_t src_port;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client = NULL;
+ fr_ipaddr_t src_ipaddr;
+ TALLOC_CTX *ctx;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ FR_STATS_INC(acct, total_requests);
+
+ if (rcode < 20) { /* RADIUS_HDR_LEN */
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ FR_STATS_INC(acct, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(acct, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch (code) {
+ case PW_CODE_ACCOUNTING_REQUEST:
+ FR_STATS_TYPE_INC(client->acct.total_requests);
+ fun = rad_accounting;
+ break;
+
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(acct, total_unknown_types);
+
+ WARN("Ignoring Status-Server request due to security configuration");
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(acct, total_unknown_types);
+
+ DEBUG("Invalid packet code %d sent to a accounting port from client %s port %d : IGNORED",
+ code, client->shortname, src_port);
+ return 0;
+ } /* switch over packet types */
+
+ ctx = talloc_pool(NULL, main_config.talloc_pool_size);
+ if (!ctx) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(acct, total_packets_dropped);
+ return 0;
+ }
+ talloc_set_name_const(ctx, "acct_listener_pool");
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(ctx, listener->fd, 0);
+ if (!packet) {
+ FR_STATS_INC(acct, total_malformed_requests);
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ talloc_free(ctx);
+ return 0;
+ }
+
+ /*
+ * There can be no duplicate accounting packets.
+ */
+ if (!request_receive(ctx, listener, packet, client, fun)) {
+ FR_STATS_INC(acct, total_packets_dropped);
+ rad_free(&packet);
+ talloc_free(ctx);
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+
+#ifdef WITH_COA
+static int do_proxy(REQUEST *request)
+{
+ VALUE_PAIR *vp;
+
+ if (request->in_proxy_hash ||
+ (request->proxy_reply && (request->proxy_reply->code != 0))) {
+ return 0;
+ }
+
+ vp = fr_pair_find_by_num(request->config, PW_HOME_SERVER_POOL, 0, TAG_ANY);
+
+ if (vp) {
+ if (!home_pool_byname(vp->vp_strvalue, HOME_TYPE_COA)) {
+ REDEBUG2("Cannot proxy to unknown pool %s",
+ vp->vp_strvalue);
+ return -1;
+ }
+
+ return 1;
+ }
+
+ /*
+ * We have a destination IP address. It will (later) proxied.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
+ if (!vp) vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY);
+
+#ifdef WITH_COA_TUNNEL
+ if (!vp) vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_ORIGINATING_REALM, 0, TAG_ANY);
+#endif
+
+ if (!vp) return 0;
+
+ return 1;
+}
+
+/*
+ * Receive a CoA packet.
+ */
+int rad_coa_recv(REQUEST *request)
+{
+ int rcode = RLM_MODULE_OK;
+ int ack, nak;
+ int proxy_status;
+ VALUE_PAIR *vp;
+
+ /*
+ * Get the correct response
+ */
+ switch (request->packet->code) {
+ case PW_CODE_COA_REQUEST:
+ ack = PW_CODE_COA_ACK;
+ nak = PW_CODE_COA_NAK;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ ack = PW_CODE_DISCONNECT_ACK;
+ nak = PW_CODE_DISCONNECT_NAK;
+ break;
+
+ default: /* shouldn't happen */
+ return RLM_MODULE_FAIL;
+ }
+
+#ifdef WITH_PROXY
+#define WAS_PROXIED (request->proxy)
+#else
+#define WAS_PROXIED (0)
+#endif
+
+ if (!WAS_PROXIED) {
+ /*
+ * RFC 5176 Section 3.3. If we have a CoA-Request
+ * with Service-Type = Authorize-Only, it MUST
+ * have a State attribute in it.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_SERVICE_TYPE, 0, TAG_ANY);
+ if (request->packet->code == PW_CODE_COA_REQUEST) {
+ if (vp && (vp->vp_integer == PW_AUTHORIZE_ONLY)) {
+ vp = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (!vp || (vp->vp_length == 0)) {
+ REDEBUG("CoA-Request with Service-Type = Authorize-Only MUST contain a State attribute");
+ request->reply->code = PW_CODE_COA_NAK;
+ return RLM_MODULE_FAIL;
+ }
+ }
+ } else if (vp) {
+ /*
+ * RFC 5176, Section 3.2.
+ */
+ REDEBUG("Disconnect-Request MUST NOT contain a Service-Type attribute");
+ request->reply->code = PW_CODE_DISCONNECT_NAK;
+ return RLM_MODULE_FAIL;
+ }
+
+ rcode = process_recv_coa(0, request);
+ switch (rcode) {
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ request->reply->code = nak;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ return rcode;
+
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ proxy_status = do_proxy(request);
+ if (proxy_status == 1) return RLM_MODULE_OK;
+
+ if (proxy_status < 0) {
+ request->reply->code = nak;
+ } else {
+ request->reply->code = ack;
+ }
+ break;
+ }
+
+ }
+
+#ifdef WITH_PROXY
+ else if (request->proxy_reply) {
+ /*
+ * Start the reply code with the proxy reply
+ * code.
+ */
+ request->reply->code = request->proxy_reply->code;
+ }
+#endif
+
+ /*
+ * Copy State from the request to the reply.
+ * See RFC 5176 Section 3.3.
+ */
+ vp = fr_pair_list_copy_by_num(request->reply, request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (vp) fr_pair_add(&request->reply->vps, vp);
+
+ /*
+ * We may want to over-ride the reply.
+ */
+ if (request->reply->code) {
+ rcode = process_send_coa(0, request);
+ switch (rcode) {
+ /*
+ * We need to send CoA-NAK back if Service-Type
+ * is Authorize-Only. Rely on the user's policy
+ * to do that. We're not a real NAS, so this
+ * restriction doesn't (ahem) apply to us.
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_USERLOCK:
+ default:
+ /*
+ * Over-ride an ACK with a NAK
+ */
+ request->reply->code = nak;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ return rcode;
+
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ /*
+ * Do NOT over-ride a previously set value.
+ * Otherwise an "ok" here will re-write a
+ * NAK to an ACK.
+ */
+ if (request->reply->code == 0) {
+ request->reply->code = ack;
+ }
+ break;
+ }
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int coa_socket_recv(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ int code;
+ uint16_t src_port;
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client = NULL;
+ fr_ipaddr_t src_ipaddr;
+ TALLOC_CTX *ctx;
+
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ if (rcode < 20) { /* RADIUS_HDR_LEN */
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ FR_STATS_INC(coa, total_malformed_requests);
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &src_ipaddr, src_port)) == NULL) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(coa, total_requests);
+ FR_STATS_INC(coa, total_invalid_requests);
+ return 0;
+ }
+
+ /*
+ * Some sanity checks, based on the packet code.
+ */
+ switch (code) {
+ case PW_CODE_COA_REQUEST:
+ FR_STATS_INC(coa, total_requests);
+ fun = rad_coa_recv;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, total_requests);
+ fun = rad_coa_recv;
+ break;
+
+ default:
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(coa, total_unknown_types);
+ DEBUG("Invalid packet code %d sent to coa port from client %s port %d : IGNORED",
+ code, client->shortname, src_port);
+ return 0;
+ } /* switch over packet types */
+
+ ctx = talloc_pool(NULL, main_config.talloc_pool_size);
+ if (!ctx) {
+ rad_recv_discard(listener->fd);
+ FR_STATS_INC(coa, total_packets_dropped);
+ return 0;
+ }
+ talloc_set_name_const(ctx, "coa_socket_recv_pool");
+
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(ctx, listener->fd, client->message_authenticator);
+ if (!packet) {
+ FR_STATS_INC(coa, total_malformed_requests);
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ talloc_free(ctx);
+ return 0;
+ }
+
+ if (!request_receive(ctx, listener, packet, client, fun)) {
+ FR_STATS_INC(coa, total_packets_dropped);
+ rad_free(&packet);
+ talloc_free(ctx);
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+#ifdef WITH_PROXY
+/*
+ * Recieve packets from a proxy socket.
+ */
+static int proxy_socket_recv(rad_listen_t *listener)
+{
+ RADIUS_PACKET *packet;
+#ifdef WITH_TCP
+ listen_socket_t *sock;
+#endif
+ char buffer[128];
+
+ packet = rad_recv(NULL, listener->fd, 0);
+ if (!packet) {
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ return 0;
+ }
+
+ switch (packet->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_REJECT:
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ break;
+#endif
+
+ default:
+ /*
+ * FIXME: Update MIB for packet types?
+ */
+ ERROR("Invalid packet code %d sent to a proxy port "
+ "from home server %s port %d - ID %d : IGNORED",
+ packet->code,
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port, packet->id);
+#ifdef WITH_STATS
+ listener->stats.total_unknown_types++;
+#endif
+ rad_free(&packet);
+ return 0;
+ }
+
+#ifdef WITH_TCP
+ sock = listener->data;
+ packet->proto = sock->proto;
+#endif
+
+ if (!request_proxy_reply(packet)) {
+#ifdef WITH_STATS
+ listener->stats.total_packets_dropped++;
+#endif
+ rad_free(&packet);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef WITH_TCP
+/*
+ * Recieve packets from a proxy socket.
+ */
+static int proxy_socket_tcp_recv(rad_listen_t *listener)
+{
+ int rcode;
+ RADIUS_PACKET *packet;
+ listen_socket_t *sock = listener->data;
+ char buffer[256];
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+ if (!sock->packet) {
+ sock->packet = rad_alloc(sock, false);
+ if (!sock->packet) return 0;
+
+ sock->packet->sockfd = listener->fd;
+ sock->packet->src_ipaddr = sock->other_ipaddr;
+ sock->packet->src_port = sock->other_port;
+ sock->packet->dst_ipaddr = sock->my_ipaddr;
+ sock->packet->dst_port = sock->my_port;
+ sock->packet->proto = sock->proto;
+ }
+
+ packet = sock->packet;
+
+ rcode = fr_tcp_read_packet(packet, 0);
+
+ /*
+ * Still only a partial packet. Put it back, and return,
+ * so that we'll read more data when it's ready.
+ */
+ if (rcode == 0) {
+ return 0;
+ }
+
+ if (rcode == -1) { /* error reading packet */
+ ERROR("Invalid packet from %s port %d, closing socket: %s",
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port, fr_strerror());
+ }
+
+ if (rcode < 0) { /* error or connection reset */
+ listener->status = RAD_LISTEN_STATUS_EOL;
+
+ /*
+ * Tell the event handler that an FD has disappeared.
+ */
+ DEBUG("Home server %s port %d has closed connection",
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port);
+
+ radius_update_listener(listener);
+
+ /*
+ * Do NOT free the listener here. It's in use by
+ * a request, and will need to hang around until
+ * all of the requests are done.
+ *
+ * It is instead free'd in remove_from_request_hash()
+ */
+ return 0;
+ }
+
+ sock->packet = NULL; /* we have no need for more partial reads */
+
+ /*
+ * FIXME: Client MIB updates?
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_REJECT:
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ break;
+#endif
+
+ default:
+ /*
+ * FIXME: Update MIB for packet types?
+ */
+ ERROR("Invalid packet code %d sent to a proxy port "
+ "from home server %s port %d - ID %d : IGNORED",
+ packet->code,
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port, packet->id);
+ rad_free(&packet);
+ return 0;
+ }
+
+
+ /*
+ * FIXME: Have it return an indication of packets that
+ * are OK to ignore (dups, too late), versus ones that
+ * aren't OK to ignore (unknown response, spoofed, etc.)
+ *
+ * Close the socket on bad packets...
+ */
+ if (!request_proxy_reply(packet)) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ sock->opened = sock->last_packet = time(NULL);
+
+ return 1;
+}
+#endif
+#endif
+
+#ifdef WITH_TLS
+#define TLS_UNUSED
+#else
+#define TLS_UNUSED UNUSED
+#endif
+
+static int client_socket_encode(TLS_UNUSED rad_listen_t *listener, REQUEST *request)
+{
+#ifdef WITH_TLS
+ /*
+ * Don't encode fake packets.
+ */
+ listen_socket_t *sock = listener->data;
+ if (sock->state == LISTEN_TLS_CHECKING) return 0;
+
+#ifdef WITH_RADIUSV11
+ request->reply->radiusv11 = sock->radiusv11;
+#endif
+
+#endif
+
+ if (!request->reply->code) return 0;
+
+ if (request->reply->data) return 0; /* already encoded */
+
+ if (rad_encode(request->reply, request->packet, request->client->secret) < 0) {
+ RERROR("Failed encoding packet: %s", fr_strerror());
+
+ return -1;
+ }
+
+ if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+ RWDEBUG("Packet is large, and possibly truncated - %zd vs max %d",
+ request->reply->data_len, MAX_PACKET_LEN);
+ }
+
+ if (rad_sign(request->reply, request->packet, request->client->secret) < 0) {
+ RERROR("Failed signing packet: %s", fr_strerror());
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int client_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+#ifdef WITH_TLS
+ listen_socket_t *sock = request->listener->data;
+
+#ifdef WITH_RADIUSV11
+ request->packet->radiusv11 = sock->radiusv11;
+#endif
+#endif
+
+ if (rad_verify(request->packet, NULL,
+ request->client->secret) < 0) {
+ return -1;
+ }
+
+#ifdef WITH_TLS
+ /*
+ * FIXME: Add the rest of the TLS parameters, too? But
+ * how do we separate EAP-TLS parameters from RADIUS/TLS
+ * parameters?
+ */
+ if (sock->ssn && sock->ssn->ssl) {
+#ifdef PSK_MAX_IDENTITY_LEN
+ const char *identity = SSL_get_psk_identity(sock->ssn->ssl);
+ if (identity) {
+ RDEBUG("Retrieved psk identity: %s", identity);
+ pair_make_request("TLS-PSK-Identity", identity, T_OP_SET);
+ }
+#endif
+ }
+#endif
+
+ return rad_decode(request->packet, NULL,
+ request->client->secret);
+}
+
+#ifdef WITH_PROXY
+#ifdef WITH_RADIUSV11
+#define RADIUSV11_UNUSED
+#else
+#define RADIUSV11_UNUSED UNUSED
+#endif
+
+static int proxy_socket_encode(RADIUSV11_UNUSED rad_listen_t *listener, REQUEST *request)
+{
+#ifdef WITH_RADIUSV11
+ listen_socket_t *sock = listener->data;
+
+ request->proxy->radiusv11 = sock->radiusv11;
+#endif
+
+ if (rad_encode(request->proxy, NULL, request->home_server->secret) < 0) {
+ RERROR("Failed encoding proxied packet: %s", fr_strerror());
+
+ return -1;
+ }
+
+ if (request->proxy->data_len > (MAX_PACKET_LEN - 100)) {
+ RWDEBUG("Packet is large, and possibly truncated - %zd vs max %d",
+ request->proxy->data_len, MAX_PACKET_LEN);
+ }
+
+ if (rad_sign(request->proxy, NULL, request->home_server->secret) < 0) {
+ RERROR("Failed signing proxied packet: %s", fr_strerror());
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int proxy_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+#ifdef WITH_RADIUSV11
+ listen_socket_t *sock = listener->data;
+
+ request->proxy_reply->radiusv11 = sock->radiusv11;
+#endif
+
+ /*
+ * rad_verify is run in event.c, received_proxy_response()
+ */
+
+ return rad_decode(request->proxy_reply, request->proxy,
+ request->home_server->secret);
+}
+#endif
+
+#include "command.c"
+
+/*
+ * Temporarily NOT const!
+ */
+static fr_protocol_t master_listen[RAD_LISTEN_MAX] = {
+#ifdef WITH_STATS
+ { RLM_MODULE_INIT, "status", sizeof(listen_socket_t), NULL,
+ common_socket_parse, NULL,
+ stats_socket_recv, common_socket_send,
+ common_socket_print, client_socket_encode, client_socket_decode },
+#else
+ /*
+ * This always gets defined.
+ */
+ { RLM_MODULE_INIT, "status", 0, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL}, /* RAD_LISTEN_NONE */
+#endif
+
+#ifdef WITH_PROXY
+ /* proxying */
+ { RLM_MODULE_INIT, "proxy", sizeof(listen_socket_t), NULL,
+ common_socket_parse, common_socket_free,
+ proxy_socket_recv, proxy_socket_send,
+ common_socket_print, proxy_socket_encode, proxy_socket_decode },
+#else
+ { 0, "proxy", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+#endif
+
+ /* authentication */
+ { RLM_MODULE_INIT, "auth", sizeof(listen_socket_t), NULL,
+ common_socket_parse, common_socket_free,
+ auth_socket_recv, common_socket_send,
+ common_socket_print, client_socket_encode, client_socket_decode },
+
+#ifdef WITH_ACCOUNTING
+ /* accounting */
+ { RLM_MODULE_INIT, "acct", sizeof(listen_socket_t), NULL,
+ common_socket_parse, common_socket_free,
+ acct_socket_recv, common_socket_send,
+ common_socket_print, client_socket_encode, client_socket_decode},
+#else
+ { 0, "acct", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+#endif
+
+#ifdef WITH_DETAIL
+ /* detail */
+ { RLM_MODULE_INIT, "detail", sizeof(listen_detail_t), NULL,
+ detail_parse, detail_free,
+ detail_recv, detail_send,
+ detail_print, detail_encode, detail_decode },
+#endif
+
+ /* vlan query protocol */
+ { 0, "vmps", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+
+ /* dhcp query protocol */
+ { 0, "dhcp", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+
+#ifdef WITH_COMMAND_SOCKET
+ /* TCP command socket */
+ { RLM_MODULE_INIT, "control", sizeof(fr_command_socket_t), NULL,
+ command_socket_parse, command_socket_free,
+ command_domain_accept, command_domain_send,
+ command_socket_print, command_socket_encode, command_socket_decode },
+#else
+ { 0, "command", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+#endif
+
+#ifdef WITH_COA
+ /* Change of Authorization */
+ { RLM_MODULE_INIT, "coa", sizeof(listen_socket_t), NULL,
+ common_socket_parse, NULL,
+ coa_socket_recv, common_socket_send,
+ common_socket_print, client_socket_encode, client_socket_decode },
+#else
+ { 0, "coa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+#endif
+
+};
+
+
+
+/*
+ * Binds a listener to a socket.
+ */
+static int listen_bind(rad_listen_t *this)
+{
+ int rcode;
+ struct sockaddr_storage salocal;
+ socklen_t salen;
+ listen_socket_t *sock = this->data;
+#ifndef WITH_TCP
+#define proto_for_port "udp"
+#define sock_type SOCK_DGRAM
+#else
+ char const *proto_for_port = "udp";
+ int sock_type = SOCK_DGRAM;
+
+ if (sock->proto == IPPROTO_TCP) {
+#ifdef WITH_VMPS
+ if (this->type == RAD_LISTEN_VQP) {
+ ERROR("VQP does not support TCP transport");
+ return -1;
+ }
+#endif
+
+ proto_for_port = "tcp";
+ sock_type = SOCK_STREAM;
+ }
+#endif
+
+ /*
+ * If the port is zero, then it means the appropriate
+ * thing from /etc/services.
+ */
+ if (sock->my_port == 0) {
+ struct servent *svp;
+
+ switch (this->type) {
+ case RAD_LISTEN_AUTH:
+ svp = getservbyname ("radius", proto_for_port);
+ if (svp != NULL) {
+ sock->my_port = ntohs(svp->s_port);
+ } else {
+ sock->my_port = PW_AUTH_UDP_PORT;
+ }
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case RAD_LISTEN_ACCT:
+ svp = getservbyname ("radacct", proto_for_port);
+ if (svp != NULL) {
+ sock->my_port = ntohs(svp->s_port);
+ } else {
+ sock->my_port = PW_ACCT_UDP_PORT;
+ }
+ break;
+#endif
+
+#ifdef WITH_PROXY
+ case RAD_LISTEN_PROXY:
+ /* leave it at zero */
+ break;
+#endif
+
+#ifdef WITH_VMPS
+ case RAD_LISTEN_VQP:
+ sock->my_port = 1589;
+ break;
+#endif
+
+#ifdef WITH_COMMAND_SOCKET
+ case RAD_LISTEN_COMMAND:
+ sock->my_port = PW_RADMIN_PORT;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case RAD_LISTEN_COA:
+ svp = getservbyname ("radius-dynauth", "udp");
+ if (svp != NULL) {
+ sock->my_port = ntohs(svp->s_port);
+ } else {
+ sock->my_port = PW_COA_UDP_PORT;
+ }
+ break;
+#endif
+
+#ifdef WITH_DHCP
+ case RAD_LISTEN_DHCP:
+ svp = getservbyname ("bootps", "udp");
+ if (svp != NULL) {
+ sock->my_port = ntohs(svp->s_port);
+ } else {
+ sock->my_port = 67;
+ }
+ break;
+#endif
+
+ default:
+ WARN("Internal sanity check failed in binding to socket. Ignoring problem");
+ return -1;
+ }
+ }
+
+ /*
+ * Don't open sockets if we're checking the config.
+ */
+ if (check_config) {
+ this->fd = -1;
+ return 0;
+ }
+
+ /*
+ * Copy fr_socket() here, as we may need to bind to a device.
+ */
+ this->fd = socket(sock->my_ipaddr.af, sock_type, 0);
+ if (this->fd < 0) {
+ char buffer[256];
+
+ this->print(this, buffer, sizeof(buffer));
+
+ ERROR("Failed opening %s: %s", buffer, fr_syserror(errno));
+ return -1;
+ }
+
+#ifdef FD_CLOEXEC
+ /*
+ * We don't want child processes inheriting these
+ * file descriptors.
+ */
+ rcode = fcntl(this->fd, F_GETFD);
+ if (rcode >= 0) {
+ if (fcntl(this->fd, F_SETFD, rcode | FD_CLOEXEC) < 0) {
+ close(this->fd);
+ ERROR("Failed setting close on exec: %s", fr_syserror(errno));
+ return -1;
+ }
+ }
+#endif
+
+ /*
+ * Bind to a device BEFORE touching IP addresses.
+ */
+ if (sock->interface) {
+#ifdef SO_BINDTODEVICE
+ struct ifreq ifreq;
+
+ memset(&ifreq, 0, sizeof(ifreq));
+ strlcpy(ifreq.ifr_name, sock->interface, sizeof(ifreq.ifr_name));
+
+ rad_suid_up();
+ rcode = setsockopt(this->fd, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *)&ifreq, sizeof(ifreq));
+ rad_suid_down();
+ if (rcode < 0) {
+ close(this->fd);
+ ERROR("Failed binding to interface %s: %s",
+ sock->interface, fr_syserror(errno));
+ return -1;
+ } /* else it worked. */
+#else
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+#ifdef HAVE_NET_IF_H
+ /*
+ * Odds are that any system supporting "bind to
+ * device" also supports IPv6, so this next bit
+ * isn't necessary. But it's here for
+ * completeness.
+ *
+ * If we're doing IPv6, and the scope hasn't yet
+ * been defined, set the scope to the scope of
+ * the interface.
+ */
+ if (sock->my_ipaddr.af == AF_INET6) {
+ if (sock->my_ipaddr.scope == 0) {
+ sock->my_ipaddr.scope = if_nametoindex(sock->interface);
+ if (sock->my_ipaddr.scope == 0) {
+ close(this->fd);
+ ERROR("Failed finding interface %s: %s",
+ sock->interface, fr_syserror(errno));
+ return -1;
+ }
+ } /* else scope was defined: we're OK. */
+ } else
+#endif
+#endif
+ /*
+ * IPv4: no link local addresses,
+ * and no bind to device.
+ */
+ {
+ close(this->fd);
+ ERROR("Failed binding to interface %s: \"bind to device\" is unsupported", sock->interface);
+ return -1;
+ }
+#endif
+ }
+
+#ifdef WITH_TCP
+ if (sock->proto == IPPROTO_TCP) {
+ int on = 1;
+
+ if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ close(this->fd);
+ ERROR("Failed to reuse address: %s", fr_syserror(errno));
+ return -1;
+ }
+ }
+#endif
+
+#if defined(WITH_TCP) && defined(WITH_UDPFROMTO)
+ else /* UDP sockets get UDPfromto */
+#endif
+
+#ifdef WITH_UDPFROMTO
+ /*
+ * Initialize udpfromto for all sockets.
+ */
+ if (udpfromto_init(this->fd) != 0) {
+ ERROR("Failed initializing udpfromto: %s",
+ fr_syserror(errno));
+ close(this->fd);
+ return -1;
+ }
+#endif
+
+ /*
+ * Set up sockaddr stuff.
+ */
+ if (!fr_ipaddr2sockaddr(&sock->my_ipaddr, sock->my_port, &salocal, &salen)) {
+ close(this->fd);
+ return -1;
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ if (sock->my_ipaddr.af == AF_INET6) {
+ /*
+ * Listening on '::' does NOT get you IPv4 to
+ * IPv6 mapping. You've got to listen on an IPv4
+ * address, too. This makes the rest of the server
+ * design a little simpler.
+ */
+#ifdef IPV6_V6ONLY
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&sock->my_ipaddr.ipaddr.ip6addr)) {
+ int on = 1;
+
+ if (setsockopt(this->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&on, sizeof(on)) < 0) {
+ ERROR("Failed setting socket to IPv6 "
+ "only: %s", fr_syserror(errno));
+
+ close(this->fd);
+ return -1;
+ }
+ }
+#endif /* IPV6_V6ONLY */
+ }
+#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
+
+ if (sock->my_ipaddr.af == AF_INET) {
+#if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
+ int flag;
+#endif
+
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+
+ /*
+ * Disable PMTU discovery. On Linux, this
+ * also makes sure that the "don't fragment"
+ * flag is zero.
+ */
+ flag = IP_PMTUDISC_DONT;
+ if (setsockopt(this->fd, IPPROTO_IP, IP_MTU_DISCOVER,
+ &flag, sizeof(flag)) < 0) {
+ ERROR("Failed disabling PMTU discovery: %s",
+ fr_syserror(errno));
+
+ close(this->fd);
+ return -1;
+ }
+#endif
+
+#if defined(IP_DONTFRAG)
+ /*
+ * Ensure that the "don't fragment" flag is zero.
+ */
+ flag = 0;
+ if (setsockopt(this->fd, IPPROTO_IP, IP_DONTFRAG,
+ &flag, sizeof(flag)) < 0) {
+ ERROR("Failed setting don't fragment flag: %s",
+ fr_syserror(errno));
+
+ close(this->fd);
+ return -1;
+ }
+#endif
+ }
+
+#ifdef WITH_DHCP
+#ifdef SO_BROADCAST
+ if (sock->broadcast) {
+ int on = 1;
+
+ if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+ ERROR("Can't set broadcast option: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+ }
+#endif
+#endif
+
+#ifdef SO_RCVBUF
+ if (sock->recv_buff > 0) {
+ int opt;
+
+ opt = sock->recv_buff;
+ if (setsockopt(this->fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(int)) < 0) {
+ WARN("Failed setting 'recv_buf': %s", fr_syserror(errno));
+ }
+ }
+#endif
+
+ /*
+ * May be binding to priviledged ports.
+ */
+ if (sock->my_port != 0) {
+ rad_suid_up();
+ rcode = bind(this->fd, (struct sockaddr *) &salocal, salen);
+ rad_suid_down();
+ if (rcode < 0) {
+ char buffer[256];
+ close(this->fd);
+
+ this->print(this, buffer, sizeof(buffer));
+ ERROR("Failed binding to %s: %s\n",
+ buffer, fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * FreeBSD jail issues. We bind to 0.0.0.0, but the
+ * kernel instead binds us to a 1.2.3.4. If this
+ * happens, notice, and remember our real IP.
+ */
+ {
+ struct sockaddr_storage src;
+ socklen_t sizeof_src = sizeof(src);
+
+ memset(&src, 0, sizeof_src);
+ if (getsockname(this->fd, (struct sockaddr *) &src,
+ &sizeof_src) < 0) {
+ ERROR("Failed getting socket name: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src,
+ &sock->my_ipaddr, &sock->my_port)) {
+ ERROR("Socket has unsupported address family");
+ return -1;
+ }
+ }
+ }
+
+#ifdef WITH_TCP
+ if (sock->proto == IPPROTO_TCP) {
+ /*
+ * Woker threads are blocking.
+ *
+ * Otherwise, they're non-blocking.
+ */
+ if (!this->workers) {
+ if (fr_nonblock(this->fd) < 0) {
+ close(this->fd);
+ ERROR("Failed setting non-blocking on socket: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+ }
+
+ /*
+ * Allow a backlog of 8 listeners, but only for incoming interfaces.
+ */
+#ifdef WITH_PROXY
+ if (this->type != RAD_LISTEN_PROXY)
+#endif
+ if (listen(this->fd, 8) < 0) {
+ close(this->fd);
+ ERROR("Failed in listen(): %s", fr_syserror(errno));
+ return -1;
+ }
+ }
+#endif
+
+ /*
+ * Mostly for proxy sockets.
+ */
+ sock->other_ipaddr.af = sock->my_ipaddr.af;
+
+/*
+ * Don't screw up other people.
+ */
+#undef proto_for_port
+#undef sock_type
+
+ return 0;
+}
+
+
+static int _listener_free(rad_listen_t *this)
+{
+ /*
+ * Other code may have eaten the FD.
+ */
+ if (this->fd >= 0) close(this->fd);
+
+ if (master_listen[this->type].free) {
+ master_listen[this->type].free(this);
+ }
+
+#ifdef WITH_TCP
+ if ((this->type == RAD_LISTEN_AUTH)
+#ifdef WITH_ACCT
+ || (this->type == RAD_LISTEN_ACCT)
+#endif
+#ifdef WITH_PROXY
+ || (this->type == RAD_LISTEN_PROXY)
+#endif
+#ifdef WITH_COMMAND_SOCKET
+ || ((this->type == RAD_LISTEN_COMMAND) &&
+ (((fr_command_socket_t *) this->data)->magic != COMMAND_SOCKET_MAGIC))
+#endif
+ ) {
+
+ /*
+ * Remove the child from the parent tree.
+ */
+ if (this->parent) {
+ rbtree_deletebydata(this->parent->children, this);
+ }
+
+ /*
+ * Delete / close all of the children, too!
+ */
+ if (this->children) {
+ rbtree_walk(this->children, RBTREE_DELETE_ORDER, listener_unlink, this);
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Note that we do NOT free this->tls, as the
+ * pointer is parented by its CONF_SECTION. It
+ * may be used by multiple listeners.
+ */
+ if (this->tls) {
+ listen_socket_t *sock = this->data;
+
+ rad_assert(talloc_parent(sock) == this);
+ rad_assert(sock->ev == NULL);
+
+ rad_assert(!sock->ssn || (talloc_parent(sock->ssn) == sock));
+ rad_assert(!sock->request || (talloc_parent(sock->request) == sock));
+
+ if (sock->home && sock->home->listeners) (void) rbtree_deletebydata(sock->home->listeners, this);
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&(sock->mutex));
+#endif
+
+ }
+#endif /* WITH_TLS */
+ }
+#endif /* WITH_TCP */
+
+ return 0;
+}
+
+
+/*
+ * Allocate & initialize a new listener.
+ */
+static rad_listen_t *listen_alloc(TALLOC_CTX *ctx, RAD_LISTEN_TYPE type)
+{
+ rad_listen_t *this;
+
+ this = talloc_zero(ctx, rad_listen_t);
+
+ this->type = type;
+ this->recv = master_listen[this->type].recv;
+ this->send = master_listen[this->type].send;
+ this->print = master_listen[this->type].print;
+
+ if (type != RAD_LISTEN_PROXY) {
+ this->encode = master_listen[this->type].encode;
+ this->decode = master_listen[this->type].decode;
+ } else {
+ this->send = NULL; /* proxy packets shouldn't call this! */
+ this->proxy_send = master_listen[this->type].send;
+ this->proxy_encode = master_listen[this->type].encode;
+ this->proxy_decode = master_listen[this->type].decode;
+ }
+
+ talloc_set_destructor(this, _listener_free);
+
+ this->data = talloc_zero_array(this, uint8_t, master_listen[this->type].inst_size);
+
+ return this;
+}
+
+#ifdef WITH_PROXY
+
+/*
+ * Externally visible function for creating a new proxy LISTENER.
+ *
+ * Not thread-safe, but all calls to it are protected by the
+ * proxy mutex in event.c
+ */
+rad_listen_t *proxy_new_listener(TALLOC_CTX *ctx, home_server_t *home, uint16_t src_port)
+{
+ time_t now;
+ rad_listen_t *this;
+ listen_socket_t *sock;
+ char buffer[256];
+
+ if (!home) return NULL;
+
+ rad_assert(home->virtual_server == NULL); /* we only open real sockets */
+
+ if ((home->limit.max_connections > 0) &&
+ (home->limit.num_connections >= home->limit.max_connections)) {
+ RATE_LIMIT(INFO("Home server %s has too many open connections (%d)",
+ home->log_name, home->limit.max_connections));
+ return NULL;
+ }
+
+ now = time(NULL);
+ if (home->last_failed_open == now) {
+ WARN("Suppressing attempt to open socket to 'down' home server");
+ return NULL;
+ }
+
+ this = listen_alloc(ctx, RAD_LISTEN_PROXY);
+
+ sock = this->data;
+ sock->other_ipaddr = home->ipaddr;
+ sock->other_port = home->port;
+ sock->home = home;
+
+ sock->my_ipaddr = home->src_ipaddr;
+ sock->my_port = src_port;
+ sock->proto = home->proto;
+
+ /*
+ * For error messages.
+ */
+ this->print(this, buffer, sizeof(buffer));
+
+#ifdef WITH_TCP
+ sock->opened = sock->last_packet = now;
+
+ if (home->proto == IPPROTO_TCP) {
+ this->recv = proxy_socket_tcp_recv;
+
+ /*
+ * FIXME: connect() is blocking!
+ * We do this with the proxy mutex locked, which may
+ * cause large delays!
+ *
+ * http://www.developerweb.net/forum/showthread.php?p=13486
+ */
+ this->fd = fr_socket_client_tcp(&home->src_ipaddr,
+ &home->ipaddr, home->port, false);
+
+ /*
+ * Set max_requests, lifetime, and idle_timeout from the home server.
+ */
+ sock->limit = home->limit;
+ } else
+#endif
+ this->fd = fr_socket(&home->src_ipaddr, src_port);
+
+ if (this->fd < 0) {
+ this->print(this, buffer,sizeof(buffer));
+ ERROR("Failed opening new proxy socket '%s' : %s",
+ buffer, fr_strerror());
+ home->last_failed_open = now;
+ listen_free(&this);
+ return NULL;
+ }
+
+
+#ifdef WITH_TCP
+#ifdef WITH_TLS
+ if ((home->proto == IPPROTO_TCP) && home->tls) {
+ DEBUG("(TLS) Trying new outgoing proxy connection to %s", buffer);
+
+ /*
+ * Set SNI, if configured.
+ *
+ * The OpenSSL API says the filename is "char
+ * const *", but some versions have it as "void
+ * *", without the "const". So we un-const it
+ * here through various C magic.
+ */
+ if (home->tls->client_hostname) {
+ (void) SSL_set_tlsext_host_name(sock->ssn->ssl, (void *) (uintptr_t) home->tls->client_hostname);
+ }
+
+#ifdef WITH_RADIUSV11
+ this->radiusv11 = home->tls->radiusv11;
+#endif
+
+ this->nonblock |= home->nonblock;
+
+ /*
+ * Set non-blocking if it's configured.
+ */
+ if (this->nonblock) {
+ if (fr_nonblock(this->fd) < 0) {
+ ERROR("(TLS) Failed setting nonblocking for proxy socket '%s' - %s", buffer, fr_strerror());
+ goto error;
+ }
+
+ rad_assert(home->listeners != NULL);
+
+ if (!rbtree_insert(home->listeners, this)) {
+ ERROR("(TLS) Failed adding tracking informtion for proxy socket '%s'", buffer);
+ goto error;
+ }
+
+#ifdef TCP_NODELAY
+ /*
+ * Also set TCP_NODELAY, to force the data to be written quickly.
+ */
+ if (sock->proto == IPPROTO_TCP) {
+ int on = 1;
+
+ if (setsockopt(this->fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) {
+ ERROR("(TLS) Failed to set TCP_NODELAY: %s", fr_syserror(errno));
+ goto error;
+ }
+ }
+#endif
+ }
+
+ /*
+ * This is blocking. :(
+ */
+ sock->ssn = tls_new_client_session(sock, home->tls, this->fd, &sock->certs);
+ if (!sock->ssn) {
+ ERROR("(TLS) Failed opening connection on proxy socket '%s'", buffer);
+ goto error;
+ }
+
+#ifdef WITH_RADIUSV11
+ /*
+ * Must not have alpn_checked yet. This code only runs for blocking sockets.
+ */
+ if (sock->ssn->connected && (fr_radiusv11_client_get_alpn(this) < 0)) {
+ goto error;
+ }
+#endif
+
+ sock->connect_timeout = home->connect_timeout;
+
+ this->recv = proxy_tls_recv;
+ this->proxy_send = proxy_tls_send;
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&sock->mutex, NULL) < 0) {
+ rad_assert(0 == 1);
+ listen_free(&this);
+ return 0;
+ }
+#endif
+
+ /*
+ * Make sure that this listener is associated with the home server.
+ *
+ * Since it's TCP+TLS, this socket can only be associated with one home server.
+ */
+
+#ifdef WITH_COA_TUNNEL
+ if (home->recv_coa) {
+ RADCLIENT *client;
+
+ this->send_coa = true;
+
+ /*
+ * Don't set this->send_coa, as we are
+ * not sending CoA-Request packets to
+ * this home server. Instead, we are
+ * receiving CoA packets from this home
+ * server.
+ */
+ this->send = proxy_tls_send_reply;
+ this->encode = master_listen[RAD_LISTEN_AUTH].encode;
+ this->decode = master_listen[RAD_LISTEN_AUTH].decode;
+
+ /*
+ * Automatically create a client for this
+ * home server. There MAY be one already
+ * one for that IP in the configuration
+ * files, but there's no guarantee that
+ * it exists.
+ *
+ * The only real reason to use an
+ * existing client is to track various
+ * statistics.
+ */
+ sock->client = client = talloc_zero(sock, RADCLIENT);
+ client->ipaddr = sock->other_ipaddr;
+ client->src_ipaddr = sock->my_ipaddr;
+ client->longname = client->shortname = talloc_typed_strdup(client, home->name);
+ client->secret = talloc_typed_strdup(client, home->secret);
+ client->nas_type = "none";
+ client->server = talloc_typed_strdup(client, home->recv_coa_server);
+ }
+#endif
+ }
+#endif
+#endif
+ /*
+ * Figure out which port we were bound to.
+ */
+ if (sock->my_port == 0) {
+ struct sockaddr_storage src;
+ socklen_t sizeof_src = sizeof(src);
+
+ memset(&src, 0, sizeof_src);
+ if (getsockname(this->fd, (struct sockaddr *) &src,
+ &sizeof_src) < 0) {
+ ERROR("Failed getting socket name for '%s': %s",
+ buffer, fr_syserror(errno));
+ error:
+ close(this->fd);
+ home->last_failed_open = now;
+ listen_free(&this);
+ return NULL;
+ }
+
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src,
+ &sock->my_ipaddr, &sock->my_port)) {
+ ERROR("Socket has unsupported address family for '%s'", buffer);
+ goto error;
+ }
+
+ this->print(this, buffer, sizeof(buffer));
+ }
+
+ if (rad_debug_lvl >= 3) {
+ DEBUG("Opened new proxy socket '%s'", buffer);
+ }
+
+ home->limit.num_connections++;
+
+ return this;
+}
+#endif
+
+static const FR_NAME_NUMBER listen_compare[] = {
+#ifdef WITH_STATS
+ { "status", RAD_LISTEN_NONE },
+#endif
+ { "auth", RAD_LISTEN_AUTH },
+#ifdef WITH_COA_TUNNEL
+ { "auth+coa", RAD_LISTEN_AUTH },
+#endif
+#ifdef WITH_ACCOUNTING
+ { "acct", RAD_LISTEN_ACCT },
+ { "auth+acct", RAD_LISTEN_AUTH },
+#ifdef WITH_COA_TUNNEL
+ { "auth+acct+coa", RAD_LISTEN_AUTH },
+#endif
+#endif
+#ifdef WITH_DETAIL
+ { "detail", RAD_LISTEN_DETAIL },
+#endif
+#ifdef WITH_PROXY
+ { "proxy", RAD_LISTEN_PROXY },
+#endif
+#ifdef WITH_VMPS
+ { "vmps", RAD_LISTEN_VQP },
+#endif
+#ifdef WITH_DHCP
+ { "dhcp", RAD_LISTEN_DHCP },
+#endif
+#ifdef WITH_COMMAND_SOCKET
+ { "control", RAD_LISTEN_COMMAND },
+#endif
+#ifdef WITH_COA
+ { "coa", RAD_LISTEN_COA },
+#endif
+ { NULL, 0 },
+};
+
+static int _free_proto_handle(fr_dlhandle *handle)
+{
+ dlclose(*handle);
+ return 0;
+}
+
+static rad_listen_t *listen_parse(CONF_SECTION *cs, char const *server)
+{
+ int type, rcode;
+ char const *listen_type;
+ rad_listen_t *this;
+ CONF_PAIR *cp;
+ char const *value;
+ fr_dlhandle handle;
+ CONF_SECTION *server_cs;
+ char const *p;
+ char buffer[32];
+
+ cp = cf_pair_find(cs, "type");
+ if (!cp) {
+ cf_log_err_cs(cs,
+ "No type specified in listen section");
+ return NULL;
+ }
+
+ value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cp(cp,
+ "Type cannot be empty");
+ return NULL;
+ }
+
+ snprintf(buffer, sizeof(buffer), "proto_%s", value);
+ handle = fr_dlopenext(buffer);
+ if (handle) {
+ fr_protocol_t *proto;
+ fr_dlhandle *marker;
+
+ proto = dlsym(handle, buffer);
+ if (!proto) {
+#if 0
+ cf_log_err_cs(cs,
+ "Failed linking to protocol %s : %s\n",
+ value, dlerror());
+#endif
+ dlclose(handle);
+ return NULL;
+ }
+
+ type = fr_str2int(listen_compare, value, -1);
+ rad_assert(type >= 0); /* shouldn't be able to compile an invalid type */
+
+ memcpy(&master_listen[type], proto, sizeof(*proto));
+
+ /*
+ * Ensure handle gets closed if config section gets freed
+ */
+ marker = talloc(cs, fr_dlhandle);
+ *marker = handle;
+ talloc_set_destructor(marker, _free_proto_handle);
+
+ if (master_listen[type].magic != RLM_MODULE_INIT) {
+ ERROR("Failed to load protocol '%s', it has the wrong version.",
+ master_listen[type].name);
+ return NULL;
+ }
+ }
+
+ cf_log_info(cs, "listen {");
+
+ listen_type = NULL;
+ rcode = cf_item_parse(cs, "type", FR_ITEM_POINTER(PW_TYPE_STRING, &listen_type), "");
+ if (rcode < 0) return NULL;
+ if (rcode == 1) {
+ cf_log_err_cs(cs,
+ "No type specified in listen section");
+ return NULL;
+ }
+
+ type = fr_str2int(listen_compare, listen_type, -1);
+ if (type < 0) {
+ cf_log_err_cs(cs,
+ "Invalid type \"%s\" in listen section.",
+ listen_type);
+ return NULL;
+ }
+
+ /*
+ * DHCP and VMPS *must* be loaded dynamically.
+ */
+ if (master_listen[type].magic != RLM_MODULE_INIT) {
+ ERROR("Cannot load protocol '%s', as the required library does not exist",
+ master_listen[type].name);
+ return NULL;
+ }
+
+ /*
+ * Allow listen sections in the default config to
+ * refer to a server.
+ */
+ if (!server) {
+ rcode = cf_item_parse(cs, "virtual_server", FR_ITEM_POINTER(PW_TYPE_STRING, &server), NULL);
+ if (rcode < 0) return NULL;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * We were passed a virtual server, so the caller is
+ * defining a proxy listener inside of a virtual server.
+ * This isn't allowed right now.
+ */
+ else if (type == RAD_LISTEN_PROXY) {
+ ERROR("Error: listen type \"proxy\" Cannot appear in a virtual server section");
+ return NULL;
+ }
+#endif
+
+ /*
+ * Set up cross-type data.
+ */
+ this = listen_alloc(cs, type);
+ this->server = server;
+ this->fd = -1;
+
+#ifdef WITH_TCP
+ /*
+ * Add special flags '+' for "auth+acct".
+ */
+ p = strchr(listen_type, '+');
+ if (p) {
+ if (strncmp(p + 1, "acct", 4) == 0) {
+ this->dual = true;
+#ifdef WITH_COA_TUNNEL
+ p += 5;
+ }
+
+ if (strcmp(p, "+coa") == 0) {
+ this->send_coa = true;
+#endif
+ }
+ }
+#endif
+
+ /*
+ * Call per-type parser.
+ */
+ if (master_listen[type].parse(cs, this) < 0) {
+ listen_free(&this);
+ return NULL;
+ }
+
+ server_cs = cf_section_sub_find_name2(main_config.config, "server",
+ this->server);
+ if (!server_cs && this->server) {
+ cf_log_err_cs(cs, "No such server \"%s\"", this->server);
+ listen_free(&this);
+ return NULL;
+ }
+
+#ifdef WITH_COA_TUNNEL
+ if (this->send_coa) {
+ CONF_SECTION *coa;
+
+ if (!this->tls) {
+ cf_log_err_cs(cs, "TLS is required in order to use \"+coa\"");
+ listen_free(&this);
+ return NULL;
+ }
+
+ /*
+ * Parse the configuration if it exists.
+ */
+ coa = cf_section_sub_find(cs, "coa");
+ if (coa) {
+ rcode = cf_section_parse(cs, this, coa_config);
+ if (rcode < 0) {
+ listen_free(&this);
+ return NULL;
+ }
+ }
+
+ /*
+ * Use the same boundary checks as for home
+ * server. See realm_home_server_sanitize().
+ */
+ FR_INTEGER_BOUND_CHECK("coa_irt", this->coa_irt, >=, 1);
+ FR_INTEGER_BOUND_CHECK("coa_irt", this->coa_irt, <=, 5);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrc", this->coa_mrc, <=, 20);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrt", this->coa_mrt, <=, 30);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrd", this->coa_mrd, >=, 5);
+ FR_INTEGER_BOUND_CHECK("coa_mrd", this->coa_mrd, <=, 60);
+ }
+#endif /* WITH_COA_TUNNEL */
+
+ cf_log_info(cs, "}");
+
+ return this;
+}
+
+#ifdef HAVE_PTHREAD_H
+/*
+ * A child thread which does NOTHING other than read and process
+ * packets.
+ */
+static void *recv_thread(void *arg)
+{
+ rad_listen_t *this = arg;
+
+ while (1) {
+ this->recv(this);
+ }
+
+ return NULL;
+}
+#endif
+
+
+/*
+ * Generate a list of listeners. Takes an input list of
+ * listeners, too, so we don't close sockets with waiting packets.
+ */
+int listen_init(CONF_SECTION *config, rad_listen_t **head, bool spawn_flag)
+{
+ bool override = false;
+ CONF_SECTION *cs = NULL;
+ rad_listen_t **last;
+ rad_listen_t *this;
+ fr_ipaddr_t server_ipaddr;
+ uint16_t auth_port = 0;
+
+ /*
+ * We shouldn't be called with a pre-existing list.
+ */
+ rad_assert(head && (*head == NULL));
+
+ memset(&server_ipaddr, 0, sizeof(server_ipaddr));
+
+ last = head;
+ server_ipaddr.af = AF_UNSPEC;
+
+ /*
+ * If the port is specified on the command-line,
+ * it over-rides the configuration file.
+ *
+ * FIXME: If argv[0] == "vmpsd", then don't listen on auth/acct!
+ */
+ if (main_config.port > 0) {
+ auth_port = main_config.port;
+
+ /*
+ * -p X but no -i Y on the command-line.
+ */
+ if (main_config.myip.af == AF_UNSPEC) {
+ ERROR("The command-line says \"-p %d\", but there is no associated IP address to use",
+ main_config.port);
+ return -1;
+ }
+ }
+
+ /*
+ * If the IP address was configured on the command-line,
+ * use that as the "bind_address"
+ */
+ if (main_config.myip.af != AF_UNSPEC) {
+ listen_socket_t *sock;
+
+ memcpy(&server_ipaddr, &main_config.myip,
+ sizeof(server_ipaddr));
+ override = true;
+
+#ifdef WITH_VMPS
+ if (strcmp(main_config.name, "vmpsd") == 0) {
+ this = listen_alloc(config, RAD_LISTEN_VQP);
+ if (!auth_port) auth_port = 1589;
+ } else
+#endif
+ this = listen_alloc(config, RAD_LISTEN_AUTH);
+
+ sock = this->data;
+
+ sock->my_ipaddr = server_ipaddr;
+ sock->my_port = auth_port;
+
+ sock->clients = client_list_parse_section(config, false);
+ if (!sock->clients) {
+ cf_log_err_cs(config,
+ "Failed to find any clients for this listen section");
+ listen_free(&this);
+ return -1;
+ }
+
+ if (listen_bind(this) < 0) {
+ listen_free(head);
+ ERROR("There appears to be another RADIUS server running on the authentication port %d", sock->my_port);
+ listen_free(&this);
+ return -1;
+ }
+ auth_port = sock->my_port; /* may have been updated in listen_bind */
+ if (override) {
+ cs = cf_section_sub_find_name2(config, "server",
+ main_config.name);
+ if (cs) this->server = main_config.name;
+ }
+
+ *last = this;
+ last = &(this->next);
+
+#ifdef WITH_VMPS
+ /*
+ * No acct for vmpsd
+ */
+ if (strcmp(main_config.name, "vmpsd") == 0) goto add_sockets;
+#endif
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Open Accounting Socket.
+ *
+ * If we haven't already gotten acct_port from
+ * /etc/services, then make it auth_port + 1.
+ */
+ this = listen_alloc(config, RAD_LISTEN_ACCT);
+ sock = this->data;
+
+ /*
+ * Create the accounting socket.
+ *
+ * The accounting port is always the
+ * authentication port + 1
+ */
+ sock->my_ipaddr = server_ipaddr;
+ sock->my_port = auth_port + 1;
+
+ sock->clients = client_list_parse_section(config, false);
+ if (!sock->clients) {
+ cf_log_err_cs(config,
+ "Failed to find any clients for this listen section");
+ return -1;
+ }
+
+ if (listen_bind(this) < 0) {
+ listen_free(&this);
+ listen_free(head);
+ ERROR("There appears to be another RADIUS server running on the accounting port %d", sock->my_port);
+ return -1;
+ }
+
+ if (override) {
+ cs = cf_section_sub_find_name2(config, "server",
+ main_config.name);
+ if (cs) this->server = main_config.name;
+ }
+
+ *last = this;
+ last = &(this->next);
+#endif
+ }
+
+ /*
+ * They specified an IP on the command-line, ignore
+ * all listen sections except the one in '-n'.
+ */
+ if (main_config.myip.af != AF_UNSPEC) {
+ CONF_SECTION *subcs;
+ char const *name2 = cf_section_name2(cs);
+
+ cs = cf_section_sub_find_name2(config, "server",
+ main_config.name);
+ if (!cs) goto add_sockets;
+
+ /*
+ * Should really abstract this code...
+ */
+ for (subcs = cf_subsection_find_next(cs, NULL, "listen");
+ subcs != NULL;
+ subcs = cf_subsection_find_next(cs, subcs, "listen")) {
+ this = listen_parse(subcs, name2);
+ if (!this) {
+ listen_free(head);
+ return -1;
+ }
+
+ *last = this;
+ last = &(this->next);
+ } /* loop over "listen" directives in server <foo> */
+
+ goto add_sockets;
+ }
+
+ /*
+ * Walk through the "listen" sections, if they exist.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "listen");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "listen")) {
+ this = listen_parse(cs, NULL);
+ if (!this) {
+ listen_free(head);
+ return -1;
+ }
+
+ *last = this;
+ last = &(this->next);
+ }
+
+ /*
+ * Check virtual servers for "listen" sections, too.
+ *
+ * FIXME: Move to virtual server init?
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "server")) {
+ CONF_SECTION *subcs;
+ char const *name2 = cf_section_name2(cs);
+
+ for (subcs = cf_subsection_find_next(cs, NULL, "listen");
+ subcs != NULL;
+ subcs = cf_subsection_find_next(cs, subcs, "listen")) {
+ this = listen_parse(subcs, name2);
+ if (!this) {
+ listen_free(head);
+ return -1;
+ }
+
+ *last = this;
+ last = &(this->next);
+ } /* loop over "listen" directives in virtual servers */
+ } /* loop over virtual servers */
+
+add_sockets:
+ /*
+ * No sockets to receive packets, this is an error.
+ * proxying is pointless.
+ */
+ if (!*head) {
+ ERROR("The server is not configured to listen on any ports. Cannot start");
+ return -1;
+ }
+
+ /*
+ * Print out which sockets we're listening on, and
+ * add them to the event list.
+ */
+ for (this = *head; this != NULL; this = this->next) {
+#ifdef WITH_TLS
+ if (!check_config && !spawn_flag && this->tls) {
+ cf_log_err_cs(this->cs, "Threading must be enabled for TLS sockets to function properly");
+ cf_log_err_cs(this->cs, "You probably need to do '%s -fxx -l stdout' for debugging",
+ main_config.name);
+ return -1;
+ }
+#endif
+ if (!check_config) {
+ if (this->workers && !spawn_flag) {
+ WARN("Setting 'workers' requires 'synchronous'. Disabling 'workers'");
+ this->workers = 0;
+ }
+
+ if (this->workers) {
+#ifdef HAVE_PTHREAD_H
+ int rcode;
+ uint32_t i;
+ char buffer[256];
+
+ this->print(this, buffer, sizeof(buffer));
+
+ for (i = 0; i < this->workers; i++) {
+ pthread_t id;
+
+ /*
+ * FIXME: create detached?
+ */
+ rcode = pthread_create(&id, 0, recv_thread, this);
+ if (rcode != 0) {
+ ERROR("Thread create failed: %s",
+ fr_syserror(rcode));
+ fr_exit(1);
+ }
+
+ DEBUG("Thread %d for %s\n", i, buffer);
+ }
+#else
+ WARN("Setting 'workers' requires 'synchronous'. Disabling 'workers'");
+ this->workers = 0;
+#endif
+
+ } else {
+ radius_update_listener(this);
+ }
+
+ }
+ }
+
+ /*
+ * Haven't defined any sockets. Die.
+ */
+ if (!*head) return -1;
+
+#ifdef WITH_COA_TUNNEL
+ if (listen_coa_init() < 0) return -1;
+#endif
+
+ return 0;
+}
+
+/*
+ * Free a linked list of listeners;
+ */
+void listen_free(rad_listen_t **head)
+{
+ rad_listen_t *this;
+
+ if (!head || !*head) return;
+
+ this = *head;
+ while (this) {
+ rad_listen_t *next = this->next;
+ talloc_free(this);
+ this = next;
+ }
+
+ *head = NULL;
+}
+
+#ifdef WITH_STATS
+RADCLIENT_LIST *listener_find_client_list(fr_ipaddr_t const *ipaddr, uint16_t port, int proto)
+{
+ rad_listen_t *this;
+
+ for (this = main_config.listen; this != NULL; this = this->next) {
+ listen_socket_t *sock;
+
+ if ((this->type != RAD_LISTEN_AUTH)
+#ifdef WITH_ACCOUNTING
+ && (this->type != RAD_LISTEN_ACCT)
+#endif
+#ifdef WITH_COA
+ && (this->type != RAD_LISTEN_COA)
+#endif
+ ) continue;
+
+ sock = this->data;
+
+ if (sock->my_port != port) continue;
+ if (sock->proto != proto) continue;
+ if (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) != 0) continue;
+
+ return sock->clients;
+ }
+
+ return NULL;
+}
+#endif
+
+rad_listen_t *listener_find_byipaddr(fr_ipaddr_t const *ipaddr, uint16_t port, int proto)
+{
+ rad_listen_t *this;
+
+ for (this = main_config.listen; this != NULL; this = this->next) {
+ listen_socket_t *sock;
+
+ sock = this->data;
+
+ if (sock->my_port != port) continue;
+ if (sock->proto != proto) continue;
+ if (fr_ipaddr_cmp(ipaddr, &sock->my_ipaddr) != 0) continue;
+
+ return this;
+ }
+
+ /*
+ * Failed to find a specific one. Find INADDR_ANY
+ */
+ for (this = main_config.listen; this != NULL; this = this->next) {
+ listen_socket_t *sock;
+
+ sock = this->data;
+
+ if (sock->my_port != port) continue;
+ if (sock->proto != proto) continue;
+ if (!fr_inaddr_any(&sock->my_ipaddr)) continue;
+
+ return this;
+ }
+
+ return NULL;
+}
+
+#ifdef WITH_COA_TUNNEL
+/*
+ * This is easier than putting ifdef's everywhere. And
+ * realistically, there aren't many systems which have OpenSSL,
+ * but not pthreads.
+ */
+#ifndef HAVE_PTHREAD_H
+#error CoA tunnels require pthreads
+#endif
+
+#include <pthread.h>
+
+static rbtree_t *coa_tree = NULL;
+
+/*
+ * We have an RB tree of keys, and within each key, a hash table
+ * of one or more listeners associated with that key.
+ */
+typedef struct {
+ char const *key;
+ fr_hash_table_t *ht;
+
+ pthread_mutex_t mutex; /* per key, to lower contention */
+} coa_key_t;
+
+typedef struct {
+ coa_key_t *coa_key;
+ rad_listen_t *listener;
+} coa_entry_t;
+
+static int coa_key_cmp(void const *one, void const *two)
+{
+ coa_key_t const *a = one;
+ coa_key_t const *b = two;
+
+ return strcmp(a->key, b->key);
+}
+
+static void coa_key_free(void *data)
+{
+ coa_key_t *coa_key = data;
+
+ pthread_mutex_destroy(&coa_key->mutex);
+ fr_hash_table_free(coa_key->ht);
+ talloc_free(coa_key);
+}
+
+static uint32_t coa_entry_hash(void const *data)
+{
+ coa_entry_t const *a = (coa_entry_t const *) data;
+
+ return fr_hash(&a->listener, sizeof(a->listener));
+}
+
+static int coa_entry_cmp(void const *one, void const *two)
+{
+ coa_entry_t const *a = one;
+ coa_entry_t const *b = two;
+
+ return memcmp(&a->listener, &b->listener, sizeof(a->listener));
+}
+
+/*
+ * Delete the entry, without holding the parents lock.
+ */
+static void coa_entry_free(void *data)
+{
+ talloc_free(data);
+}
+
+static int coa_entry_destructor(coa_entry_t *entry)
+{
+ pthread_mutex_lock(&entry->coa_key->mutex);
+ fr_hash_table_delete(entry->coa_key->ht, entry);
+ pthread_mutex_unlock(&entry->coa_key->mutex);
+
+ return 0;
+}
+
+static int listen_coa_init(void)
+{
+ /*
+ * We will be looking up listeners by key. Each key
+ * points us to a list of listeners. Each key has it's
+ * own mutex, so that it's thread-safe.
+ */
+ coa_tree = rbtree_create(NULL, coa_key_cmp, coa_key_free, RBTREE_FLAG_LOCK);
+ if (!coa_tree) {
+ ERROR("Failed creating internal tracking tree for Originating-Realm-Key");
+ return -1;
+ }
+
+ return 0;
+}
+
+void listen_coa_free(void)
+{
+ /*
+ * If we are freeing the tree, then all of the listeners
+ * must have been freed first.
+ */
+ rad_assert(rbtree_num_elements(coa_tree) == 0);
+ rbtree_free(coa_tree);
+ coa_tree = NULL;
+}
+
+/*
+ * Adds a listener to the hash of listeners, based on key.
+ */
+void listen_coa_add(rad_listen_t *this, char const *key)
+{
+ int tries = 0;
+ coa_key_t my_key, *coa_key;
+ coa_entry_t *entry;
+
+ rad_assert(this->send_coa);
+ rad_assert(this->parent);
+ rad_assert(!this->key);
+
+ /*
+ * Find the key. If we can't find it, then create it.
+ */
+ my_key.key = key;
+
+retry:
+ coa_key = rbtree_finddata(coa_tree, &my_key);
+ if (!coa_key) {
+ coa_key = talloc_zero(NULL, coa_key_t);
+ if (!coa_key) return;
+ coa_key->key = talloc_strdup(coa_key, key);
+ if (!coa_key->key) {
+ fail:
+ talloc_free(coa_key);
+ return;
+ }
+
+ /*
+ * Create the hash table of listeners.
+ */
+ coa_key->ht = fr_hash_table_create(coa_entry_hash, coa_entry_cmp, coa_entry_free);
+ if (!coa_key->ht) goto fail;
+
+ if (!rbtree_insert(coa_tree, coa_key)) {
+ talloc_free(coa_key);
+
+ /*
+ * The lookups are mutex protected, but
+ * if there's time between the lookup and
+ * the insert, another thread may have
+ * created the node. In which case we
+ * try again.
+ */
+ if (tries < 3) goto retry;
+ tries++;
+ return;
+ }
+
+ (void) pthread_mutex_init(&coa_key->mutex, NULL);
+ }
+
+ /*
+ * No need to strdup() this, coa_key will only be removed
+ * after the listener has been removed.
+ */
+ if (!this->key) this->key = coa_key->key;
+
+ entry = talloc_zero(this, coa_entry_t);
+ if (!entry) return;
+ talloc_set_destructor(entry, coa_entry_destructor);
+
+ entry->coa_key = coa_key;
+ entry->listener = this;
+
+ /*
+ * Insert the entry into the hash table.
+ */
+ pthread_mutex_lock(&coa_key->mutex);
+ fr_hash_table_insert(coa_key->ht, entry);
+ pthread_mutex_unlock(&coa_key->mutex);
+}
+
+/*
+ * Find an active listener by key.
+ *
+ * This function will update request->home_server, and
+ * request->proxy_listener.
+ */
+int listen_coa_find(REQUEST *request, char const *key)
+{
+ coa_key_t my_key, *coa_key;
+ rad_listen_t *this, *found;
+ listen_socket_t *sock;
+ fr_hash_iter_t iter;
+
+ /*
+ * Find the key. If we can't find it, then error out.
+ */
+ memcpy(&my_key.key, &key, sizeof(key)); /* const issues */
+ coa_key = rbtree_finddata(coa_tree, &my_key);
+ if (!coa_key) return -1;
+
+ /*
+ * We've found it. Now find a listener which has free
+ * IDs. i.e. where the number of used IDs is less tahn
+ * 256.
+ */
+ found = NULL;
+ pthread_mutex_lock(&coa_key->mutex);
+ for (this = fr_hash_table_iter_init(coa_key->ht, &iter);
+ this != NULL;
+ this = fr_hash_table_iter_next(coa_key->ht, &iter)) {
+ if (this->blocked) continue;
+
+ if (this->dead) continue;
+
+ if (!found) {
+ if (this->num_ids_used < 256) {
+ found = this;
+ }
+
+ /*
+ * Skip listeners which have all used IDs.
+ */
+ continue;
+ }
+
+ /*
+ * Try to spread the load across all available
+ * sockets.
+ */
+ if (found->num_ids_used > this->num_ids_used) {
+ found = this;
+ continue;
+ }
+
+ /*
+ * If they are equal, pick one at random.
+ *
+ * @todo - pick one with equal probability from
+ * among the ones with the same IDs used. This
+ * algorithm prefers the first one.
+ */
+ if (found->num_ids_used == this->num_ids_used) {
+ if ((fr_rand() & 0x01) == 0) {
+ found = this;
+ continue;
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&coa_key->mutex);
+ if (!found) return -1;
+
+ request->proxy_listener = found;
+
+ sock = found->data;
+ request->home_server = sock->home;
+ return 0;
+}
+
+/*
+ * Check for an active listener by key.
+ */
+static bool listen_coa_exists(rad_listen_t *this, char const *key)
+{
+ coa_key_t my_key, *coa_key;
+ coa_entry_t my_entry, *entry;
+
+ /*
+ * Find the key. If we can't find it, then error out.
+ */
+ memcpy(&my_key.key, &key, sizeof(key)); /* const issues */
+ coa_key = rbtree_finddata(coa_tree, &my_key);
+ if (!coa_key) return false;
+
+ my_entry.listener = this;
+ pthread_mutex_lock(&coa_key->mutex);
+ entry = fr_hash_table_finddata(coa_key->ht, &my_entry);
+ pthread_mutex_unlock(&coa_key->mutex);
+
+ return (entry != NULL);
+}
+
+/*
+ * Delete a listener entry.
+ */
+static void listen_coa_delete(rad_listen_t *this, char const *key)
+{
+ coa_key_t my_key, *coa_key;
+ coa_entry_t my_entry;
+
+ /*
+ * Find the key. If we can't find it, then error out.
+ */
+ memcpy(&my_key.key, &key, sizeof(key)); /* const issues */
+ coa_key = rbtree_finddata(coa_tree, &my_key);
+ if (!coa_key) return;
+
+ my_entry.listener = this;
+ pthread_mutex_lock(&coa_key->mutex);
+ (void) fr_hash_table_delete(coa_key->ht, &my_entry);
+ pthread_mutex_unlock(&coa_key->mutex);
+}
+
+
+static void listener_coa_update(rad_listen_t *this, VALUE_PAIR *vps)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ fr_cursor_init(&cursor, &vps);
+
+ /*
+ * Add or delete Operator-Name realms
+ */
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_OPERATOR_NAME, 0, TAG_ANY)) != NULL) {
+ if (vp->vp_length <= 1) continue;
+
+ if (vp->vp_strvalue[0] == '+') {
+ if (listen_coa_exists(this, vp->vp_strvalue)) continue;
+
+ listen_coa_add(this, vp->vp_strvalue);
+ continue;
+ }
+
+ if (vp->vp_strvalue[0] == '-') {
+ listen_coa_delete(this, vp->vp_strvalue);
+ continue;
+ }
+ }
+}
+#endif
diff --git a/src/main/log.c b/src/main/log.c
new file mode 100644
index 0000000..1ca2f91
--- /dev/null
+++ b/src/main/log.c
@@ -0,0 +1,923 @@
+/*
+ * 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 Logging functions used by the server core.
+ * @file main/log.c
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ * @copyright 2001 Chad Miller <cmiller@surfsouth.com>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#include <fcntl.h>
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include <sys/file.h>
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+log_lvl_t rad_debug_lvl = 0; //!< Global debugging level
+static bool rate_limit = true; //!< Whether repeated log entries should be rate limited
+
+/** Maps log categories to message prefixes
+ */
+static const FR_NAME_NUMBER levels[] = {
+ { ": Debug: ", L_DBG },
+ { ": Auth: ", L_AUTH },
+ { ": Proxy: ", L_PROXY },
+ { ": Info: ", L_INFO },
+ { ": Warning: ", L_WARN },
+ { ": Acct: ", L_ACCT },
+ { ": Error: ", L_ERR },
+ { ": WARNING: ", L_DBG_WARN },
+ { ": ERROR: ", L_DBG_ERR },
+ { ": WARNING: ", L_DBG_WARN_REQ },
+ { ": ERROR: ", L_DBG_ERR_REQ },
+ { NULL, 0 }
+};
+
+/** @name VT100 escape sequences
+ *
+ * These sequences may be written to VT100 terminals to change the
+ * colour and style of the text.
+ *
+ @code{.c}
+ fprintf(stdout, VTC_RED "This text will be coloured red" VTC_RESET);
+ @endcode
+ * @{
+ */
+#define VTC_RED "\x1b[31m" //!< Colour following text red.
+#define VTC_YELLOW "\x1b[33m" //!< Colour following text yellow.
+#define VTC_BOLD "\x1b[1m" //!< Embolden following text.
+#define VTC_RESET "\x1b[0m" //!< Reset terminal text to default style/colour.
+/** @} */
+
+/** Maps log categories to VT100 style/colour escape sequences
+ */
+static const FR_NAME_NUMBER colours[] = {
+ { "", L_DBG },
+ { VTC_BOLD, L_AUTH },
+ { VTC_BOLD, L_PROXY },
+ { VTC_BOLD, L_INFO },
+ { VTC_BOLD, L_ACCT },
+ { VTC_RED, L_ERR },
+ { VTC_BOLD VTC_YELLOW, L_WARN },
+ { VTC_BOLD VTC_RED, L_DBG_ERR },
+ { VTC_BOLD VTC_YELLOW, L_DBG_WARN },
+ { VTC_BOLD VTC_RED, L_DBG_ERR_REQ },
+ { VTC_BOLD VTC_YELLOW, L_DBG_WARN_REQ },
+ { NULL, 0 }
+};
+
+/** Syslog facility table
+ *
+ * Maps syslog facility keywords, to the syslog facility macros defined
+ * in the system's syslog.h.
+ *
+ * @note Not all facilities are supported by every operating system.
+ * If a facility is unavailable it will not appear in the table.
+ */
+const FR_NAME_NUMBER syslog_facility_table[] = {
+#ifdef LOG_KERN
+ { "kern", LOG_KERN },
+#endif
+#ifdef LOG_USER
+ { "user", LOG_USER },
+#endif
+#ifdef LOG_MAIL
+ { "mail", LOG_MAIL },
+#endif
+#ifdef LOG_DAEMON
+ { "daemon", LOG_DAEMON },
+#endif
+#ifdef LOG_AUTH
+ { "auth", LOG_AUTH },
+#endif
+#ifdef LOG_LPR
+ { "lpr", LOG_LPR },
+#endif
+#ifdef LOG_NEWS
+ { "news", LOG_NEWS },
+#endif
+#ifdef LOG_UUCP
+ { "uucp", LOG_UUCP },
+#endif
+#ifdef LOG_CRON
+ { "cron", LOG_CRON },
+#endif
+#ifdef LOG_AUTHPRIV
+ { "authpriv", LOG_AUTHPRIV },
+#endif
+#ifdef LOG_FTP
+ { "ftp", LOG_FTP },
+#endif
+#ifdef LOG_LOCAL0
+ { "local0", LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+ { "local1", LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+ { "local2", LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+ { "local3", LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+ { "local4", LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+ { "local5", LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+ { "local6", LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+ { "local7", LOG_LOCAL7 },
+#endif
+ { NULL, -1 }
+};
+
+/** Syslog severity table
+ *
+ * Maps syslog severity keywords, to the syslog severity macros defined
+ * in the system's syslog.h file.
+ *
+ */
+const FR_NAME_NUMBER syslog_severity_table[] = {
+#ifdef LOG_EMERG
+ { "emergency", LOG_EMERG },
+#endif
+#ifdef LOG_ALERT
+ { "alert", LOG_ALERT },
+#endif
+#ifdef LOG_CRIT
+ { "critical", LOG_CRIT },
+#endif
+#ifdef LOG_ERR
+ { "error", LOG_ERR },
+#endif
+#ifdef LOG_WARNING
+ { "warning", LOG_WARNING },
+#endif
+#ifdef LOG_NOTICE
+ { "notice", LOG_NOTICE },
+#endif
+#ifdef LOG_INFO
+ { "info", LOG_INFO },
+#endif
+#ifdef LOG_DEBUG
+ { "debug", LOG_DEBUG },
+#endif
+ { NULL, -1 }
+};
+
+const FR_NAME_NUMBER log_str2dst[] = {
+ { "null", L_DST_NULL },
+ { "files", L_DST_FILES },
+ { "syslog", L_DST_SYSLOG },
+ { "stdout", L_DST_STDOUT },
+ { "stderr", L_DST_STDERR },
+ { NULL, L_DST_NUM_DEST }
+};
+
+bool log_dates_utc = false;
+
+fr_log_t default_log = {
+ .colourise = false, //!< Will be set later. Should be off before we do terminal detection.
+ .fd = STDOUT_FILENO,
+ .dst = L_DST_STDOUT,
+ .file = NULL,
+ .debug_file = NULL,
+};
+
+static int stderr_fd = -1; //!< The original unmolested stderr file descriptor
+static int stdout_fd = -1; //!< The original unmolested stdout file descriptor
+
+static char const spaces[] = " ";
+
+/** On fault, reset STDOUT and STDERR to something useful
+ *
+ * @return 0
+ */
+static int _restore_std(UNUSED int sig)
+{
+ if ((stderr_fd > 0) && (stdout_fd > 0)) {
+ dup2(stderr_fd, STDOUT_FILENO);
+ dup2(stdout_fd, STDERR_FILENO);
+ return 0;
+ }
+
+ if (default_log.fd > 0) {
+ dup2(default_log.fd, STDOUT_FILENO);
+ dup2(default_log.fd, STDERR_FILENO);
+ return 0;
+ }
+
+ return 0;
+}
+
+/** Initialise file descriptors based on logging destination
+ *
+ * @param log Logger to manipulate.
+ * @param daemonize Whether the server is starting as a daemon.
+ * @return 0 on success -1 on failure.
+ */
+int radlog_init(fr_log_t *log, bool daemonize)
+{
+ int devnull;
+
+ rate_limit = daemonize;
+
+ /*
+ * If we're running in foreground mode, save STDIN /
+ * STDERR as higher FDs, which won't get used by anyone
+ * else. When we fork/exec a program, it's STD FDs will
+ * get set to pipes. We later set STDOUT / STDERR to
+ * /dev/null, so that any library trying to write to them
+ * doesn't screw anything up.
+ *
+ * Then, when something goes wrong, restore them so that
+ * any debugger called from the panic action has access
+ * to STDOUT / STDERR.
+ */
+ if (!daemonize) {
+ fr_fault_set_cb(_restore_std);
+
+ stdout_fd = dup(STDOUT_FILENO);
+ stderr_fd = dup(STDERR_FILENO);
+ }
+
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ fr_strerror_printf("Error opening /dev/null: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * STDOUT & STDERR go to /dev/null, unless we have "-x",
+ * then STDOUT & STDERR go to the "-l log" destination.
+ *
+ * The complexity here is because "-l log" can go to
+ * STDOUT or STDERR, too.
+ */
+ if (log->dst == L_DST_STDOUT) {
+ setlinebuf(stdout);
+ log->fd = STDOUT_FILENO;
+
+ /*
+ * If we're debugging, allow STDERR to go to
+ * STDOUT too, for executed programs,
+ */
+ if (rad_debug_lvl) {
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ } else {
+ dup2(devnull, STDERR_FILENO);
+ }
+
+ } else if (log->dst == L_DST_STDERR) {
+ setlinebuf(stderr);
+ log->fd = STDERR_FILENO;
+
+ /*
+ * If we're debugging, allow STDOUT to go to
+ * STDERR too, for executed programs,
+ */
+ if (rad_debug_lvl) {
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ } else {
+ dup2(devnull, STDOUT_FILENO);
+ }
+
+ } else if (log->dst == L_DST_SYSLOG) {
+ /*
+ * Discard STDOUT and STDERR no matter what the
+ * status of debugging. Syslog isn't a file
+ * descriptor, so we can't use it.
+ */
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+
+ } else if (rad_debug_lvl) {
+ /*
+ * If we're debugging, allow STDOUT and STDERR to
+ * go to the log file.
+ */
+ dup2(log->fd, STDOUT_FILENO);
+ dup2(log->fd, STDERR_FILENO);
+
+ } else {
+ /*
+ * Not debugging, and the log isn't STDOUT or
+ * STDERR. Ensure that we move both of them to
+ * /dev/null, so that the calling terminal can
+ * exit, and the output from executed programs
+ * doesn't pollute STDOUT / STDERR.
+ */
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+ }
+
+ close(devnull);
+
+ fr_fault_set_log_fd(log->fd);
+
+ return 0;
+}
+
+/** Send a server log message to its destination
+ *
+ * @param type of log message.
+ * @param msg with printf style substitution tokens.
+ * @param ap Substitution arguments.
+ */
+int vradlog(log_type_t type, char const *msg, va_list ap)
+{
+ unsigned char *p;
+ char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
+ char *unsan;
+ size_t len;
+ int colourise = default_log.colourise;
+
+ /*
+ * If we don't want any messages, then
+ * throw them away.
+ */
+ if (default_log.dst == L_DST_NULL) {
+ return 0;
+ }
+
+ buffer[0] = '\0';
+ len = 0;
+
+ if (colourise) {
+ len += strlcpy(buffer + len, fr_int2str(colours, type, ""), sizeof(buffer) - len) ;
+ if (len == 0) {
+ colourise = false;
+ }
+ }
+
+ /*
+ * Mark the point where we treat the buffer as unsanitized.
+ */
+ unsan = buffer + len;
+
+ /*
+ * Don't print timestamps to syslog, it does that for us.
+ * Don't print timestamps and error types for low levels
+ * of debugging.
+ *
+ * Print timestamps for non-debugging, and for high levels
+ * of debugging.
+ */
+ if (default_log.dst != L_DST_SYSLOG) {
+ if ((rad_debug_lvl != 1) && (rad_debug_lvl != 2)) {
+ time_t timeval;
+
+ timeval = time(NULL);
+ CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
+
+ len = strlen(buffer);
+ len += strlcpy(buffer + len, fr_int2str(levels, type, ": "), sizeof(buffer) - len);
+ } else goto add_prefix;
+ } else {
+ add_prefix:
+ if (len < sizeof(buffer)) switch (type) {
+ case L_DBG_WARN:
+ len += strlcpy(buffer + len, "WARNING: ", sizeof(buffer) - len);
+ break;
+
+ case L_DBG_ERR:
+ len += strlcpy(buffer + len, "ERROR: ", sizeof(buffer) - len);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (len < sizeof(buffer)) {
+ vsnprintf(buffer + len, sizeof(buffer) - len - 1, msg, ap);
+ len += strlen(buffer + len);
+ }
+
+ /*
+ * Filter out control chars and non UTF8 chars
+ */
+ for (p = (unsigned char *)unsan; *p != '\0'; p++) {
+ int clen;
+
+ switch (*p) {
+ case '\r':
+ case '\n':
+ *p = ' ';
+ break;
+
+ case '\t':
+ continue;
+
+ default:
+ clen = fr_utf8_char(p, -1);
+ if (!clen) {
+ *p = '?';
+ continue;
+ }
+ p += (clen - 1);
+ break;
+ }
+ }
+
+ if (colourise && (len < sizeof(buffer))) {
+ len += strlcpy(buffer + len, VTC_RESET, sizeof(buffer) - len);
+ }
+
+ if (len < (sizeof(buffer) - 2)) {
+ buffer[len] = '\n';
+ buffer[len + 1] = '\0';
+ } else {
+ buffer[sizeof(buffer) - 2] = '\n';
+ buffer[sizeof(buffer) - 1] = '\0';
+ }
+
+ switch (default_log.dst) {
+
+#ifdef HAVE_SYSLOG_H
+ case L_DST_SYSLOG:
+ switch (type) {
+ case L_DBG:
+ case L_DBG_WARN:
+ case L_DBG_ERR:
+ case L_DBG_ERR_REQ:
+ case L_DBG_WARN_REQ:
+ type = LOG_DEBUG;
+ break;
+
+ case L_AUTH:
+ case L_PROXY:
+ case L_ACCT:
+ type = LOG_NOTICE;
+ break;
+
+ case L_INFO:
+ type = LOG_INFO;
+ break;
+
+ case L_WARN:
+ type = LOG_WARNING;
+ break;
+
+ case L_ERR:
+ type = LOG_ERR;
+ break;
+ }
+ syslog(type, "%s", buffer);
+ break;
+#endif
+
+ case L_DST_FILES:
+ case L_DST_STDOUT:
+ case L_DST_STDERR:
+ return write(default_log.fd, buffer, strlen(buffer));
+
+ default:
+ case L_DST_NULL: /* should have been caught above */
+ break;
+ }
+
+ return 0;
+}
+
+/** Send a server log message to its destination
+ *
+ * @param type of log message.
+ * @param msg with printf style substitution tokens.
+ * @param ... Substitution arguments.
+ */
+int radlog(log_type_t type, char const *msg, ...)
+{
+ va_list ap;
+ int r = 0;
+
+ va_start(ap, msg);
+
+ /*
+ * Non-debug message, or debugging is enabled. Log it.
+ */
+ if (((type & L_DBG) == 0) || (rad_debug_lvl > 0)) {
+ r = vradlog(type, msg, ap);
+ }
+ va_end(ap);
+
+ return r;
+}
+
+/** Send a server log message to its destination without evaluating its debug level
+ *
+ * @param type of log message.
+ * @param msg with printf style substitution tokens.
+ * @param ... Substitution arguments.
+ */
+static int radlog_always(log_type_t type, char const *msg, ...) CC_HINT(format (printf, 2, 3));
+static int radlog_always(log_type_t type, char const *msg, ...)
+{
+ va_list ap;
+ int r;
+
+ va_start(ap, msg);
+ r = vradlog(type, msg, ap);
+ va_end(ap);
+
+ return r;
+}
+
+/** Whether a server debug message should be logged
+ *
+ * @param type of message.
+ * @param lvl of debugging this message should be logged at.
+ * @return true if message should be logged, else false.
+ */
+inline bool debug_enabled(log_type_t type, log_lvl_t lvl)
+{
+ if ((type & L_DBG) && (lvl <= rad_debug_lvl)) return true;
+
+ return false;
+}
+
+/** Whether rate limiting is enabled
+ */
+bool rate_limit_enabled(void)
+{
+ if (rate_limit || (rad_debug_lvl < 1)) return true;
+
+ return false;
+}
+
+/** Whether a request specific debug message should be logged
+ *
+ * @param type of message.
+ * @param lvl of debugging this message should be logged at.
+ * @param request The current request.
+ * @return true if message should be logged, else false.
+ */
+inline bool radlog_debug_enabled(log_type_t type, log_lvl_t lvl, REQUEST *request)
+{
+ /*
+ * It's a debug class message, note this doesn't mean it's a debug type message.
+ *
+ * For example it could be a RIDEBUG message, which would be an informational message,
+ * instead of an RDEBUG message which would be a debug debug message.
+ *
+ * There is log function, but the request debug level isn't high enough.
+ * OR, we're in debug mode, and the global debug level isn't high enough,
+ * then don't log the message.
+ */
+ if ((type & L_DBG) &&
+ ((request->log.func && (lvl <= request->log.lvl)) ||
+ ((rad_debug_lvl != 0) && (lvl <= rad_debug_lvl)))) {
+ return true;
+ }
+
+ return false;
+}
+
+/** Send a log message to its destination, possibly including fields from the request
+ *
+ * @param type of log message, #L_ERR, #L_WARN, #L_INFO, #L_DBG.
+ * @param lvl Minimum required server or request level to output this message.
+ * @param request The current request.
+ * @param msg with printf style substitution tokens.
+ * @param ap Substitution arguments.
+ */
+void vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap)
+{
+ size_t len = 0;
+ char const *filename = default_log.file;
+ FILE *fp = NULL;
+
+ char buffer[10240]; /* The largest config item size, then extra for prefixes and suffixes */
+
+ char *p;
+ char const *extra = "";
+ uint8_t indent;
+ va_list aq;
+
+ /*
+ * Debug messages get treated specially.
+ */
+ if ((type & L_DBG) != 0) {
+
+ if (!radlog_debug_enabled(type, lvl, request)) {
+ return;
+ }
+
+ /*
+ * Use the debug output file, if specified,
+ * otherwise leave it as the default log file.
+ */
+#ifdef WITH_COMMAND_SOCKET
+ filename = default_log.debug_file;
+ if (!filename)
+#endif
+ {
+ filename = default_log.file;
+ }
+ }
+
+ if (filename) {
+ radlog_func_t rl = request->log.func;
+
+ request->log.func = NULL;
+
+ /*
+ * This is SLOW! Doing it for every log message
+ * in every request is NOT recommended!
+ */
+ if (radius_xlat(buffer, sizeof(buffer), request, filename, rad_filename_escape, NULL) < 0) return;
+ request->log.func = rl;
+
+ /*
+ * Ensure the directory structure exists, for
+ * where we're going to write the log file.
+ */
+ p = strrchr(buffer, FR_DIR_SEP);
+ if (p) {
+ *p = '\0';
+ if (rad_mkdir(buffer, S_IRWXU, -1, -1) < 0) {
+ ERROR("Failed creating %s: %s", buffer, fr_syserror(errno));
+ return;
+ }
+ *p = FR_DIR_SEP;
+ }
+
+ fp = fopen(buffer, "a");
+ }
+
+ /*
+ * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
+ * due to ap sometimes being implemented with a stack offset which is invalidated if
+ * ap is passed into another function. See here:
+ * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
+ *
+ * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
+ * running unit tests which generate errors under CI.
+ */
+ va_copy(aq, ap);
+ vsnprintf(buffer + len, sizeof(buffer) - len, msg, aq);
+ va_end(aq);
+
+ /*
+ * Make sure the indent isn't set to something crazy
+ */
+ indent = request->log.indent > sizeof(spaces) ?
+ sizeof(spaces) :
+ request->log.indent;
+
+ /*
+ * Logging to a file descriptor
+ */
+ if (fp) {
+ char time_buff[64]; /* The current timestamp */
+
+ time_t timeval;
+ timeval = time(NULL);
+
+#ifdef HAVE_GMTIME_R
+ if (log_dates_utc) {
+ struct tm utc;
+ gmtime_r(&timeval, &utc);
+ ASCTIME_R(&utc, time_buff, sizeof(time_buff));
+ } else
+#endif
+ {
+ CTIME_R(&timeval, time_buff, sizeof(time_buff));
+ }
+
+ /*
+ * Strip trailing new lines
+ */
+ p = strrchr(time_buff, '\n');
+ if (p) p[0] = '\0';
+
+ if (request->module && (request->module[0] != '\0')) {
+ fprintf(fp, "(%u) %s%s%s: %.*s%s\n",
+ request->number, time_buff, fr_int2str(levels, type, ""),
+ request->module, indent, spaces, buffer);
+ } else {
+ fprintf(fp, "(%u) %s%s%.*s%s\n",
+ request->number, time_buff, fr_int2str(levels, type, ""),
+ indent, spaces, buffer);
+ }
+ fclose(fp);
+ return;
+ }
+
+ /*
+ * Logging everywhere else
+ */
+ if (!DEBUG_ENABLED3) switch (type) {
+ case L_DBG_WARN:
+ extra = "WARNING: ";
+ type = L_DBG_WARN_REQ;
+ break;
+
+ case L_DBG_ERR:
+ extra = "ERROR: ";
+ type = L_DBG_ERR_REQ;
+ break;
+ default:
+ break;
+ }
+
+ if (request->module && (request->module[0] != '\0')) {
+ radlog_always(type, "(%u) %s: %.*s%s%s", request->number,
+ request->module, indent, spaces, extra, buffer);
+ } else {
+ radlog_always(type, "(%u) %.*s%s%s", request->number,
+ indent, spaces, extra, buffer);
+ }
+}
+
+/** Martial variadic log arguments into a va_list and pass to normal logging functions
+ *
+ * @see radlog_request_error for more details.
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be logged at.
+ * @param request The current request.
+ * @param msg with printf style substitution tokens.
+ * @param ... Substitution arguments.
+ */
+void radlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
+{
+ va_list ap;
+
+ if (!request->log.func && !(type & L_DBG)) return;
+
+ va_start(ap, msg);
+ if (request->log.func) request->log.func(type, lvl, request, msg, ap);
+ else if (!(type & L_DBG)) vradlog_request(type, lvl, request, msg, ap);
+ va_end(ap);
+}
+
+/** Martial variadic log arguments into a va_list and pass to error logging functions
+ *
+ * This could all be done in a macro, but it turns out some implementations of the
+ * variadic macros do not work at all well if the va_list being written to is further
+ * up the stack (which is required as you still need a function to convert the elipses
+ * into a va_list).
+ *
+ * So, we use this small wrapper function instead, which will hopefully guarantee
+ * consistent behaviour.
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be logged at.
+ * @param request The current request.
+ * @param msg with printf style substitution tokens.
+ * @param ... Substitution arguments.
+ */
+void radlog_request_error(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ if (request->log.func) request->log.func(type, lvl, request, msg, ap);
+ else if (!(type & L_DBG)) vradlog_request(type, lvl, request, msg, ap);
+ vmodule_failure_msg(request, msg, ap);
+ va_end(ap);
+}
+
+/** Write the string being parsed, and a marker showing where the parse error occurred
+ *
+ * @param type the log category.
+ * @param lvl of debugging this message should be logged at.
+ * @param request The current request.
+ * @param msg string we were parsing.
+ * @param idx The position of the marker relative to the string.
+ * @param error What the parse error was.
+ */
+void radlog_request_marker(log_type_t type, log_lvl_t lvl, REQUEST *request,
+ char const *msg, size_t idx, char const *error)
+{
+ char const *prefix = "";
+ uint8_t indent;
+
+ if (idx >= sizeof(spaces)) {
+ size_t offset = (idx - (sizeof(spaces) - 1)) + (sizeof(spaces) * 0.75);
+ idx -= offset;
+ msg += offset;
+
+ prefix = "... ";
+ }
+
+ /*
+ * Don't want format markers being indented
+ */
+ indent = request->log.indent;
+ request->log.indent = 0;
+
+ radlog_request(type, lvl, request, "%s%s", prefix, msg);
+ radlog_request(type, lvl, request, "%s%.*s^ %s", prefix, (int) idx, spaces, error);
+
+ request->log.indent = indent;
+}
+
+
+/** Canonicalize error strings, removing tabs, and generate spaces for error marker
+ *
+ * @note talloc_free must be called on the buffer returned in spaces and text
+ *
+ * Used to produce error messages such as this:
+ @verbatim
+ I'm a string with a parser # error
+ ^ Unexpected character in string
+ @endverbatim
+ *
+ * With code resembling this:
+ @code{.c}
+ ERROR("%s", parsed_str);
+ ERROR("%s^ %s", space, text);
+ @endcode
+ *
+ * @todo merge with above function (radlog_request_marker)
+ *
+ * @param sp Where to write a dynamically allocated buffer of spaces used to indent the error text.
+ * @param text Where to write the canonicalized version of msg (the error text).
+ * @param ctx to allocate the spaces and text buffers in.
+ * @param slen of error marker. Expects negative integer value, as returned by parse functions.
+ * @param msg to canonicalize.
+ */
+void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *msg)
+{
+ size_t offset, skip = 0;
+ char *spbuf, *p;
+ char *value;
+
+ offset = -slen;
+
+ /*
+ * Ensure that the error isn't indented
+ * too far.
+ */
+ if (offset > 45) {
+ skip = offset - 40;
+ offset -= skip;
+ value = talloc_strdup(ctx, msg + skip);
+ memcpy(value, "...", 3);
+
+ } else {
+ value = talloc_strdup(ctx, msg);
+ }
+
+ spbuf = talloc_array(ctx, char, offset + 1);
+ memset(spbuf, ' ', offset);
+ spbuf[offset] = '\0';
+
+ /*
+ * Smash tabs to spaces for the input string.
+ */
+ for (p = value; *p != '\0'; p++) {
+ if (*p == '\t') *p = ' ';
+ }
+
+
+ /*
+ * Ensure that there isn't too much text after the error.
+ */
+ if (strlen(value) > 100) {
+ memcpy(value + 95, "... ", 5);
+ }
+
+ *sp = spbuf;
+ *text = value;
+}
+
diff --git a/src/main/mainconfig.c b/src/main/mainconfig.c
new file mode 100644
index 0000000..227ae4a
--- /dev/null
+++ b/src/main/mainconfig.c
@@ -0,0 +1,1420 @@
+/*
+ * mainconf.c Handle the server's configuration.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2002,2006-2007 The FreeRADIUS server project
+ * Copyright 2002 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+
+main_config_t main_config; //!< Main server configuration.
+extern fr_cond_t *debug_condition;
+fr_cond_t *debug_condition = NULL; //!< Condition used to mark packets up for checking.
+bool event_loop_started = false; //!< Whether the main event loop has been started yet.
+
+typedef struct cached_config_t {
+ struct cached_config_t *next;
+ time_t created;
+ CONF_SECTION *cs;
+} cached_config_t;
+
+static cached_config_t *cs_cache = NULL;
+
+/*
+ * Temporary local variables for parsing the configuration
+ * file.
+ */
+#ifdef HAVE_SETUID
+/*
+ * Systems that have set/getresuid also have setuid.
+ */
+static uid_t server_uid = 0;
+static gid_t server_gid = 0;
+static char const *uid_name = NULL;
+static char const *gid_name = NULL;
+#endif
+static char const *chroot_dir = NULL;
+static bool allow_core_dumps = false;
+static char const *radlog_dest = NULL;
+
+/*
+ * These are not used anywhere else..
+ */
+static char const *localstatedir = NULL;
+static char const *prefix = NULL;
+static char const *my_name = NULL;
+static char const *sbindir = NULL;
+static char const *run_dir = NULL;
+static char const *syslog_facility = NULL;
+static bool do_colourise = false;
+
+static char const *radius_dir = NULL; //!< Path to raddb directory
+
+/**********************************************************************
+ *
+ * We need to figure out where the logs go, before doing anything
+ * else. This is so that the log messages go to the correct
+ * place.
+ *
+ * BUT, we want the settings from the command line to over-ride
+ * the ones in the configuration file. So, these items are
+ * parsed ONLY if there is no "-l foo" on the command line.
+ *
+ **********************************************************************/
+
+/*
+ * Log destinations
+ */
+static const CONF_PARSER startup_log_config[] = {
+ { "destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), "files" },
+ { "syslog_facility", FR_CONF_POINTER(PW_TYPE_STRING, &syslog_facility), STRINGIFY(0) },
+
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
+ { "file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), "${logdir}/radius.log" },
+ { "requests", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &default_log.file), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Basic configuration for the server.
+ */
+static const CONF_PARSER startup_server_config[] = {
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) startup_log_config },
+
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+
+ { "log_file", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.log_file), NULL },
+ { "log_destination", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dest), NULL },
+ { "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/**********************************************************************
+ *
+ * Now that we've parsed the log destination, AND the security
+ * items, we can parse the rest of the configuration items.
+ *
+ **********************************************************************/
+static const CONF_PARSER log_config[] = {
+ { "stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_stripped_names),"no" },
+ { "auth", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth), "no" },
+ { "auth_accept", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_accept), NULL},
+ { "auth_reject", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_reject), NULL},
+ { "auth_badpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth_badpass), "no" },
+ { "auth_goodpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.log_auth_goodpass), "no" },
+ { "msg_badpass", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.auth_badpass_msg), NULL},
+ { "msg_goodpass", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.auth_goodpass_msg), NULL},
+ { "colourise",FR_CONF_POINTER(PW_TYPE_BOOLEAN, &do_colourise), NULL },
+ { "use_utc", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &log_dates_utc), NULL },
+ { "msg_denied", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.denied_msg), "You are already logged in - access denied" },
+ { "suppress_secrets", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.suppress_secrets), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Security configuration for the server.
+ */
+static const CONF_PARSER security_config[] = {
+ { "max_attributes", FR_CONF_POINTER(PW_TYPE_INTEGER, &fr_max_attributes), STRINGIFY(0) },
+ { "reject_delay", FR_CONF_POINTER(PW_TYPE_TIMEVAL, &main_config.reject_delay), STRINGIFY(0) },
+ { "status_server", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.status_server), "no"},
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+ { "allow_vulnerable_openssl", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.allow_vulnerable_openssl), "no"},
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER resources[] = {
+ /*
+ * Don't set a default here. It's set in the code, below. This means that
+ * the config item will *not* get printed out in debug mode, so that no one knows
+ * it exists.
+ */
+ { "talloc_pool_size", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.talloc_pool_size), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER server_config[] = {
+ /*
+ * FIXME: 'prefix' is the ONLY one which should be
+ * configured at compile time. Hard-coding it here is
+ * bad. It will be cleaned up once we clean up the
+ * hard-coded defines for the locations of the various
+ * files.
+ */
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+ { "sbindir", FR_CONF_POINTER(PW_TYPE_STRING, &sbindir), "${prefix}/sbin"},
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
+ { "run_dir", FR_CONF_POINTER(PW_TYPE_STRING, &run_dir), "${localstatedir}/run/${name}"},
+ { "libdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlib_dir), "${prefix}/lib"},
+ { "radacctdir", FR_CONF_POINTER(PW_TYPE_STRING, &radacct_dir), "${logdir}/radacct" },
+ { "panic_action", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.panic_action), NULL},
+ { "hostname_lookups", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &fr_dns_lookups), "no" },
+ { "max_request_time", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.max_request_time), STRINGIFY(MAX_REQUEST_TIME) },
+ { "cleanup_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.cleanup_delay), STRINGIFY(CLEANUP_DELAY) },
+ { "max_requests", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.max_requests), STRINGIFY(MAX_REQUESTS) },
+ { "postauth_client_lost", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.postauth_client_lost), "no" },
+ { "pidfile", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.pid_file), "${run_dir}/radiusd.pid"},
+ { "checkrad", FR_CONF_POINTER(PW_TYPE_STRING, &main_config.checkrad), "${sbindir}/checkrad" },
+
+ { "debug_level", FR_CONF_POINTER(PW_TYPE_INTEGER, &main_config.debug_level), "0"},
+
+#ifdef WITH_PROXY
+ { "proxy_requests", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &main_config.proxy_requests), "yes" },
+#endif
+ { "log", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) log_config },
+
+ { "resources", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) resources },
+
+ /*
+ * People with old configs will have these. They are listed
+ * AFTER the "log" section, so if they exist in radiusd.conf,
+ * it will prefer "log_foo = bar" to "log { foo = bar }".
+ * They're listed with default values of NULL, so that if they
+ * DON'T exist in radiusd.conf, then the previously parsed
+ * values for "log { foo = bar}" will be used.
+ */
+ { "log_auth", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth), NULL },
+ { "log_auth_badpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth_badpass), NULL },
+ { "log_auth_goodpass", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &main_config.log_auth_goodpass), NULL },
+ { "log_stripped_names", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &log_stripped_names), NULL },
+
+ { "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) security_config },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/**********************************************************************
+ *
+ * The next few items are here as a "bootstrap" for security.
+ * They allow the server to switch users, chroot, while still
+ * opening the various output files with the correct permission.
+ *
+ * It's rare (or impossible) to have parse errors here, so we
+ * don't worry too much about that. In contrast, when we parse
+ * the rest of the configuration, we CAN get parse errors. We
+ * want THOSE parse errors to go to the log file, and we want the
+ * log file to have the correct permissions.
+ *
+ **********************************************************************/
+static const CONF_PARSER bootstrap_security_config[] = {
+#ifdef HAVE_SETUID
+ { "user", FR_CONF_POINTER(PW_TYPE_STRING, &uid_name), NULL },
+ { "group", FR_CONF_POINTER(PW_TYPE_STRING, &gid_name), NULL },
+#endif
+ { "chroot", FR_CONF_POINTER(PW_TYPE_STRING, &chroot_dir), NULL },
+ { "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &allow_core_dumps), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER bootstrap_config[] = {
+ { "security", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) bootstrap_security_config },
+
+ { "name", FR_CONF_POINTER(PW_TYPE_STRING, &my_name), "radiusd"},
+ { "prefix", FR_CONF_POINTER(PW_TYPE_STRING, &prefix), "/usr/local"},
+ { "localstatedir", FR_CONF_POINTER(PW_TYPE_STRING, &localstatedir), "${prefix}/var"},
+
+ { "logdir", FR_CONF_POINTER(PW_TYPE_STRING, &radlog_dir), "${localstatedir}/log"},
+ { "run_dir", FR_CONF_POINTER(PW_TYPE_STRING, &run_dir), "${localstatedir}/run/${name}"},
+
+ /*
+ * For backwards compatibility.
+ */
+#ifdef HAVE_SETUID
+ { "user", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &uid_name), NULL },
+ { "group", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &gid_name), NULL },
+#endif
+ { "chroot", FR_CONF_POINTER(PW_TYPE_STRING | PW_TYPE_DEPRECATED, &chroot_dir), NULL },
+ { "allow_core_dumps", FR_CONF_POINTER(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, &allow_core_dumps), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static size_t config_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ size_t len = 0;
+ static char const disallowed[] = "%{}\\'\"`";
+
+ while (in[0]) {
+ /*
+ * Non-printable characters get replaced with their
+ * mime-encoded equivalents.
+ */
+ if ((in[0] < 32)) {
+ if (outlen <= 3) break;
+
+ snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
+ in++;
+ out += 3;
+ outlen -= 3;
+ len += 3;
+ continue;
+
+ } else if (strchr(disallowed, *in) != NULL) {
+ if (outlen <= 2) break;
+
+ out[0] = '\\';
+ out[1] = *in;
+ in++;
+ out += 2;
+ outlen -= 2;
+ len += 2;
+ continue;
+ }
+
+ /*
+ * Only one byte left.
+ */
+ if (outlen <= 1) {
+ break;
+ }
+
+ /*
+ * Allowed character.
+ */
+ *out = *in;
+ out++;
+ in++;
+ outlen--;
+ len++;
+ }
+ *out = '\0';
+ return len;
+}
+
+/*
+ * Xlat for %{config:section.subsection.attribute}
+ */
+static ssize_t xlat_config(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ char const *value;
+ CONF_PAIR *cp;
+ CONF_ITEM *ci;
+ char buffer[1024];
+
+ /*
+ * Expand it safely.
+ */
+ if (radius_xlat(buffer, sizeof(buffer), request, fmt, config_escape_func, NULL) < 0) {
+ return 0;
+ }
+
+ ci = cf_reference_item(request->root->config,
+ request->root->config, buffer);
+ if (!ci || !cf_item_is_pair(ci)) {
+ REDEBUG("Config item \"%s\" does not exist", fmt);
+ *out = '\0';
+ return -1;
+ }
+
+ cp = cf_item_to_pair(ci);
+
+ /*
+ * Ensure that we only copy what's necessary.
+ *
+ * If 'outlen' is too small, then the output is chopped to fit.
+ */
+ value = cf_pair_value(cp);
+ if (!value) {
+ out[0] = '\0';
+ return 0;
+ }
+
+ if (outlen > strlen(value)) {
+ outlen = strlen(value) + 1;
+ }
+
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
+}
+
+
+/*
+ * Xlat for %{client:foo}
+ */
+static ssize_t xlat_client(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ char const *value = NULL;
+ CONF_PAIR *cp;
+
+ if (!fmt || !out || (outlen < 1)) return 0;
+
+ if (!request->client) {
+ RWDEBUG("No client associated with this request");
+ *out = '\0';
+ return 0;
+ }
+
+ cp = cf_pair_find(request->client->cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ if (strcmp(fmt, "shortname") == 0 && request->client->shortname) {
+ value = request->client->shortname;
+ }
+ else if (strcmp(fmt, "nas_type") == 0 && request->client->nas_type) {
+ value = request->client->nas_type;
+ } else {
+ *out = '\0';
+ return 0;
+ }
+ }
+
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
+}
+
+/*
+ * Xlat for %{getclient:<ipaddr>.foo}
+ */
+static ssize_t xlat_getclient(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ char const *value = NULL;
+ char buffer[INET6_ADDRSTRLEN], *q;
+ char const *p = fmt;
+ fr_ipaddr_t ip;
+ CONF_PAIR *cp;
+ RADCLIENT *client = NULL;
+
+ if (!fmt || !out || (outlen < 1)) return 0;
+
+ q = strrchr(p, '.');
+ if (!q || (q == p) || (((size_t)(q - p)) > sizeof(buffer))) {
+ REDEBUG("Invalid client string");
+ goto error;
+ }
+
+ strlcpy(buffer, p, (q + 1) - p);
+ if (fr_pton(&ip, buffer, -1, AF_UNSPEC, false) < 0) {
+ REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", buffer);
+ goto error;
+ }
+
+ fmt = q + 1;
+
+ client = client_find(NULL, &ip, IPPROTO_IP);
+ if (!client) {
+ RDEBUG("No client found with IP \"%s\"", buffer);
+ *out = '\0';
+ return 0;
+ }
+
+ cp = cf_pair_find(client->cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ if (strcmp(fmt, "shortname") == 0) {
+ strlcpy(out, request->client->shortname, outlen);
+ return strlen(out);
+ }
+ *out = '\0';
+ return 0;
+ }
+
+ strlcpy(out, value, outlen);
+ return strlen(out);
+
+ error:
+ *out = '\0';
+ return -1;
+}
+
+/*
+ * Common xlat for listeners
+ */
+static ssize_t xlat_listen_common(REQUEST *request, rad_listen_t *listen,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *value = NULL;
+ CONF_PAIR *cp;
+
+ if (!fmt || !out || (outlen < 1)) return 0;
+
+ if (!listen) {
+ RWDEBUG("No listener associated with this request");
+ *out = '\0';
+ return 0;
+ }
+
+ /*
+ * When TLS is configured, we *require* the use of TLS.
+ */
+ if (strcmp(fmt, "tls") == 0) {
+#ifdef WITH_TLS
+ if (listen->tls) {
+ strlcpy(out, "yes", outlen);
+ return strlen(out);
+ }
+#endif
+
+ strlcpy(out, "no", outlen);
+ return strlen(out);
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Look for TLS certificate data.
+ */
+ if (strncmp(fmt, "TLS-", 4) == 0) {
+ VALUE_PAIR *vp;
+ listen_socket_t *sock = listen->data;
+
+ if (!listen->tls) {
+ RDEBUG("Listener is not using TLS. TLS attributes are not available");
+ *out = '\0';
+ return 0;
+ }
+
+ for (vp = sock->certs; vp != NULL; vp = vp->next) {
+ if (strcmp(fmt, vp->da->name) == 0) {
+ return vp_prints_value(out, outlen, vp, 0);
+ }
+ }
+
+ RDEBUG("Unknown TLS attribute \"%s\"", fmt);
+ *out = '\0';
+ return 0;
+ }
+#else
+ if (strncmp(fmt, "TLS-", 4) == 0) {
+ RDEBUG("Server is not built with TLS support");
+ *out = '\0';
+ return 0;
+ }
+#endif
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Look for RADSEC CoA tunnel key.
+ */
+ if (listen->key && (strcmp(fmt, "Originating-Realm-Key") == 0)) {
+ strlcpy(out, listen->key, outlen);
+ return strlen(out);
+ }
+#endif
+
+ cp = cf_pair_find(listen->cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ RDEBUG("Listener does not contain config item \"%s\"", fmt);
+ *out = '\0';
+ return 0;
+ }
+
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
+}
+
+
+/*
+ * Xlat for %{listen:foo}
+ */
+static ssize_t xlat_listen(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ return xlat_listen_common(request, request->listener, fmt, out, outlen);
+}
+
+/*
+ * Xlat for %{proxy_listen:foo}
+ */
+static ssize_t xlat_proxy_listen(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ if (!request->proxy_listener) {
+ *out = '\0';
+ return 0;
+ }
+
+ return xlat_listen_common(request, request->proxy_listener, fmt, out, outlen);
+}
+
+#ifdef HAVE_SETUID
+/*
+ * Do chroot, if requested.
+ *
+ * Switch UID and GID to what is specified in the config file
+ */
+static int switch_users(CONF_SECTION *cs)
+{
+ bool do_suid = false;
+ bool do_sgid = false;
+
+ /*
+ * Get the current maximum for core files. Do this
+ * before anything else so as to ensure it's properly
+ * initialized.
+ */
+ if (fr_set_dumpable_init() < 0) {
+ return 0;
+ }
+
+ /*
+ * Don't do chroot/setuid/setgid if we're in debugging
+ * as non-root.
+ */
+ if (rad_debug_lvl && (getuid() != 0)) return 1;
+
+ if (cf_section_parse(cs, NULL, bootstrap_config) < 0) {
+ fr_strerror_printf("Failed to parse user/group information.");
+ return 0;
+ }
+
+#ifdef HAVE_GRP_H
+ /*
+ * Get the correct GID for the server.
+ */
+ server_gid = getgid();
+
+ if (gid_name) {
+ struct group *gr;
+
+ gr = getgrnam(gid_name);
+ if (!gr) {
+ fr_strerror_printf("Cannot get ID for group %s: %s",
+ gid_name, fr_syserror(errno));
+ return 0;
+ }
+
+ if (server_gid != gr->gr_gid) {
+ server_gid = gr->gr_gid;
+ do_sgid = true;
+ }
+ }
+#endif
+
+ /*
+ * Get the correct UID for the server.
+ */
+ server_uid = getuid();
+
+ if (uid_name) {
+ struct passwd *user;
+
+ if (rad_getpwnam(cs, &user, uid_name) < 0) {
+ fr_strerror_printf("Cannot get passwd entry for user %s: %s",
+ uid_name, fr_strerror());
+ return 0;
+ }
+
+ /*
+ * We're not the correct user. Go set that.
+ */
+ if (server_uid != user->pw_uid) {
+ server_uid = user->pw_uid;
+ do_suid = true;
+#ifdef HAVE_INITGROUPS
+ if (initgroups(uid_name, server_gid) < 0) {
+ fr_strerror_printf("Cannot initialize supplementary group list for user %s: %s",
+ uid_name, fr_syserror(errno));
+ talloc_free(user);
+ return 0;
+ }
+#endif
+ }
+
+ talloc_free(user);
+ }
+
+ /*
+ * Do chroot BEFORE changing UIDs.
+ */
+ if (chroot_dir) {
+ if (chroot(chroot_dir) < 0) {
+ fr_strerror_printf("Failed to perform chroot to %s: %s",
+ chroot_dir, fr_syserror(errno));
+ return 0;
+ }
+
+ /*
+ * Note that we leave chdir alone. It may be
+ * OUTSIDE of the root. This allows us to read
+ * the configuration from "-d ./etc/raddb", with
+ * the chroot as "./chroot/" for example. After
+ * the server has been loaded, it does a "cd
+ * ${logdir}" below, so that core files (if any)
+ * go to a logging directory.
+ *
+ * This also allows the configuration of the
+ * server to be outside of the chroot. If the
+ * server is statically linked, then the only
+ * things needed inside of the chroot are the
+ * logging directories.
+ */
+ }
+
+#ifdef HAVE_GRP_H
+ /*
+ * Set the GID. Don't bother checking it.
+ */
+ if (do_sgid) {
+ if (setgid(server_gid) < 0){
+ fr_strerror_printf("Failed setting group to %s: %s",
+ gid_name, fr_syserror(errno));
+ return 0;
+ }
+ }
+#endif
+
+ /*
+ * The directories for PID files and logs must exist. We
+ * need to create them if we're told to write files to
+ * those directories.
+ *
+ * Because this creation is new in 3.0.9, it's a soft
+ * fail.
+ *
+ */
+ if (main_config.write_pid) {
+ char *my_dir;
+
+ my_dir = talloc_strdup(NULL, run_dir);
+ if (rad_mkdir(my_dir, 0750, server_uid, server_gid) < 0) {
+ DEBUG("Failed to create run_dir %s: %s",
+ my_dir, strerror(errno));
+ }
+ talloc_free(my_dir);
+ }
+
+ if (default_log.dst == L_DST_FILES) {
+ char *my_dir;
+
+ my_dir = talloc_strdup(NULL, radlog_dir);
+ if (rad_mkdir(my_dir, 0750, server_uid, server_gid) < 0) {
+ DEBUG("Failed to create logdir %s: %s",
+ my_dir, strerror(errno));
+ }
+ talloc_free(my_dir);
+ }
+
+ /*
+ * If we don't already have a log file open, open one
+ * now. We may not have been logging anything yet. The
+ * server normally starts up fairly quietly.
+ */
+ if ((default_log.dst == L_DST_FILES) &&
+ (default_log.fd < 0)) {
+ default_log.fd = open(main_config.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (default_log.fd < 0) {
+ fr_strerror_printf("Failed to open log file %s: %s\n",
+ main_config.log_file, fr_syserror(errno));
+ return 0;
+ }
+ }
+
+ /*
+ * If we need to change UID, ensure that the log files
+ * have the correct owner && group.
+ *
+ * We have to do this because some log files MAY already
+ * have been written as root. We need to change them to
+ * have the correct ownership before proceeding.
+ */
+ if ((do_suid || do_sgid) &&
+ (default_log.dst == L_DST_FILES)) {
+ if (fchown(default_log.fd, server_uid, server_gid) < 0) {
+ fr_strerror_printf("Cannot change ownership of log file %s: %s\n",
+ main_config.log_file, fr_syserror(errno));
+ return 0;
+ }
+ }
+
+ /*
+ * Once we're done with all of the privileged work,
+ * permanently change the UID.
+ */
+ if (do_suid) {
+ rad_suid_set_down_uid(server_uid);
+ rad_suid_down();
+ }
+
+ /*
+ * This also clears the dumpable flag if core dumps
+ * aren't allowed.
+ */
+ if (fr_set_dumpable(allow_core_dumps) < 0) {
+ WARN("Failed to allow core dumps - %s", fr_strerror());
+ }
+
+ if (allow_core_dumps) {
+ INFO("Core dumps are enabled");
+ }
+
+ return 1;
+}
+#endif /* HAVE_SETUID */
+
+/** Set the global radius config directory.
+ *
+ * @param ctx Where to allocate the memory for the path string.
+ * @param path to config dir root e.g. /usr/local/etc/raddb
+ */
+void set_radius_dir(TALLOC_CTX *ctx, char const *path)
+{
+ if (radius_dir) {
+ char *p;
+
+ memcpy(&p, &radius_dir, sizeof(p));
+ talloc_free(p);
+ radius_dir = NULL;
+ }
+ if (path) radius_dir = talloc_strdup(ctx, path);
+}
+
+/** Get the global radius config directory.
+ *
+ * @return the global radius config directory.
+ */
+char const *get_radius_dir(void)
+{
+ return radius_dir;
+}
+
+static int _dlhandle_free(void **dl_handle)
+{
+ dlclose(*dl_handle);
+ return 0;
+}
+
+/*
+ * Read config files.
+ *
+ * This function can ONLY be called from the main server process.
+ */
+int main_config_init(void)
+{
+ char const *p = NULL;
+ CONF_SECTION *cs, *subcs;
+ struct stat statbuf;
+ cached_config_t *cc;
+ char buffer[1024];
+
+ if (stat(radius_dir, &statbuf) < 0) {
+ ERROR("Errors reading %s: %s",
+ radius_dir, fr_syserror(errno));
+ return -1;
+ }
+
+#ifdef S_IWOTH
+ if ((statbuf.st_mode & S_IWOTH) != 0) {
+ ERROR("Configuration directory %s is globally writable. Refusing to start due to insecure configuration.",
+ radius_dir);
+ return -1;
+ }
+#endif
+
+#if 0 && defined(S_IROTH)
+ if (statbuf.st_mode & S_IROTH != 0) {
+ ERROR("Configuration directory %s is globally readable. Refusing to start due to insecure configuration.",
+ radius_dir);
+ return -1;
+ }
+#endif
+ INFO("Starting - reading configuration files ...");
+
+ /*
+ * We need to load the dictionaries before reading the
+ * configuration files. This is because of the
+ * pre-compilation in conffile.c. That should probably
+ * be fixed to be done as a second stage.
+ */
+ if (!main_config.dictionary_dir) {
+ main_config.dictionary_dir = DICTDIR;
+ }
+
+ /*
+ * About sizeof(REQUEST) + sizeof(RADIUS_PACKET) * 2 + sizeof(VALUE_PAIR) * 400
+ *
+ * Which should be enough for many configurations.
+ */
+ main_config.talloc_pool_size = 8 * 1024; /* default */
+
+ /*
+ * Read the distribution dictionaries first, then
+ * the ones in raddb.
+ */
+ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
+ if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
+ ERROR("Errors reading dictionary: %s",
+ fr_strerror());
+ return -1;
+ }
+
+#define DICT_READ_OPTIONAL(_d, _n) \
+do {\
+ switch (dict_read(_d, _n)) {\
+ case -1:\
+ ERROR("Errors reading %s/%s: %s", _d, _n, fr_strerror());\
+ return -1;\
+ case 0:\
+ DEBUG2("including dictionary file %s/%s", _d,_n);\
+ break;\
+ default:\
+ break;\
+ }\
+} while (0)
+
+ /*
+ * Try to load protocol-specific dictionaries. It's OK
+ * if they don't exist.
+ */
+#ifdef WITH_DHCP
+ DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.dhcp");
+#endif
+
+#ifdef WITH_VMPS
+ DICT_READ_OPTIONAL(main_config.dictionary_dir, "dictionary.vqp");
+#endif
+
+ /*
+ * It's OK if this one doesn't exist.
+ */
+ DICT_READ_OPTIONAL(radius_dir, RADIUS_DICTIONARY);
+
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) return -1;
+
+ /*
+ * Add a 'feature' subsection off the main config
+ * We check if it's defined first, as the user may
+ * have defined their own feature flags, or want
+ * to manually override the ones set by modules
+ * or the server.
+ */
+ subcs = cf_section_sub_find(cs, "feature");
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, "feature", NULL);
+ if (!subcs) return -1;
+
+ cf_section_add(cs, subcs);
+ }
+ version_init_features(subcs);
+
+ /*
+ * Add a 'version' subsection off the main config
+ * We check if it's defined first, this is for
+ * backwards compatibility.
+ */
+ subcs = cf_section_sub_find(cs, "version");
+ if (!subcs) {
+ subcs = cf_section_alloc(cs, "version", NULL);
+ if (!subcs) return -1;
+ cf_section_add(cs, subcs);
+ }
+ version_init_numbers(subcs);
+
+ /* Read the configuration file */
+ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name);
+ if (cf_file_read(cs, buffer) < 0) {
+ ERROR("Errors reading or parsing %s", buffer);
+ failure:
+ talloc_free(cs);
+ return -1;
+ }
+
+ /*
+ * Parse environment variables first.
+ */
+ subcs = cf_section_sub_find(cs, "ENV");
+ if (subcs) {
+ char const *attr, *value;
+ CONF_PAIR *cp;
+ CONF_ITEM *ci;
+
+ for (ci = cf_item_find_next(subcs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(subcs, ci)) {
+
+ if (cf_item_is_data(ci)) continue;
+
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "Unexpected item in ENV section");
+ goto failure;
+ }
+
+ cp = cf_item_to_pair(ci);
+ if (cf_pair_operator(cp) != T_OP_EQ) {
+ cf_log_err(ci, "Invalid operator for item in ENV section");
+ goto failure;
+ }
+
+ attr = cf_pair_attr(cp);
+ value = cf_pair_value(cp);
+ if (!value) {
+ if (unsetenv(attr) < 0) {
+ cf_log_err(ci, "Failed deleting environment variable %s: %s",
+ attr, fr_syserror(errno));
+ goto failure;
+ }
+ } else {
+ void *handle;
+ void **handle_p;
+
+ if (setenv(attr, value, 1) < 0) {
+ cf_log_err(ci, "Failed setting environment variable %s: %s",
+ attr, fr_syserror(errno));
+ goto failure;
+ }
+
+ /*
+ * Hacks for LD_PRELOAD.
+ */
+ if (strcmp(attr, "LD_PRELOAD") != 0) continue;
+
+ handle = dlopen(value, RTLD_NOW | RTLD_GLOBAL);
+ if (!handle) {
+ cf_log_err(ci, "Failed loading library %s: %s", value, dlerror());
+ goto failure;
+ }
+
+ /*
+ * Wrap the pointer, so we can set a destructor.
+ */
+ MEM(handle_p = talloc(NULL, void *));
+ *handle_p = handle;
+ talloc_set_destructor(handle_p, _dlhandle_free);
+
+ (void) cf_data_add(subcs, value, handle, NULL);
+ }
+ } /* loop over pairs in ENV */
+ } /* there's an ENV subsection */
+
+ /*
+ * If there was no log destination set on the command line,
+ * set it now.
+ */
+ if (default_log.dst == L_DST_NULL) {
+ default_log.dst = L_DST_STDERR;
+ default_log.fd = STDERR_FILENO;
+
+ if (cf_section_parse(cs, NULL, startup_server_config) == -1) {
+ fprintf(stderr, "%s: Error: Failed to parse log{} section.\n",
+ main_config.name);
+ cf_file_free(cs);
+ return -1;
+ }
+
+ if (!radlog_dest) {
+ fprintf(stderr, "%s: Error: No log destination specified.\n",
+ main_config.name);
+ cf_file_free(cs);
+ return -1;
+ }
+
+ default_log.fd = -1;
+ default_log.dst = fr_str2int(log_str2dst, radlog_dest,
+ L_DST_NUM_DEST);
+ if (default_log.dst == L_DST_NUM_DEST) {
+ fprintf(stderr, "%s: Error: Unknown log_destination %s\n",
+ main_config.name, radlog_dest);
+ cf_file_free(cs);
+ return -1;
+ }
+
+ if (default_log.dst == L_DST_SYSLOG) {
+ /*
+ * Make sure syslog_facility isn't NULL
+ * before using it
+ */
+ if (!syslog_facility) {
+ fprintf(stderr, "%s: Error: Syslog chosen but no facility was specified\n",
+ main_config.name);
+ cf_file_free(cs);
+ return -1;
+ }
+ main_config.syslog_facility = fr_str2int(syslog_facility_table, syslog_facility, -1);
+ if (main_config.syslog_facility < 0) {
+ fprintf(stderr, "%s: Error: Unknown syslog_facility %s\n",
+ main_config.name, syslog_facility);
+ cf_file_free(cs);
+ return -1;
+ }
+
+#ifdef HAVE_SYSLOG_H
+ /*
+ * Call openlog only once, when the
+ * program starts.
+ */
+ openlog(main_config.name, LOG_PID, main_config.syslog_facility);
+#endif
+
+ } else if (default_log.dst == L_DST_FILES) {
+ if (!main_config.log_file) {
+ fprintf(stderr, "%s: Error: Specified \"files\" as a log destination, but no log filename was given!\n",
+ main_config.name);
+ cf_file_free(cs);
+ return -1;
+ }
+ }
+ }
+
+#ifdef HAVE_SETUID
+ /*
+ * Switch users as early as possible.
+ */
+ if (!switch_users(cs)) {
+ fprintf(stderr, "%s: ERROR - %s\n", main_config.name, fr_strerror());
+ fr_exit(1);
+ }
+#endif
+
+ /*
+ * This allows us to figure out where, relative to
+ * radiusd.conf, the other configuration files exist.
+ */
+ if (cf_section_parse(cs, NULL, server_config) < 0) return -1;
+
+ /*
+ * Fix up log_auth, and log_accept and log_reject
+ */
+ if (main_config.log_auth) {
+ main_config.log_accept = main_config.log_reject = true;
+ }
+
+ /*
+ * We ignore colourization of output until after the
+ * configuration files have been parsed.
+ */
+ p = getenv("TERM");
+ if (do_colourise && p && isatty(default_log.fd) && strstr(p, "xterm")) {
+ default_log.colourise = true;
+ } else {
+ default_log.colourise = false;
+ }
+
+ /*
+ * Starting the server, WITHOUT "-x" on the
+ * command-line: use whatever is in the config
+ * file.
+ */
+ if (rad_debug_lvl == 0) {
+ rad_debug_lvl = main_config.debug_level;
+ }
+ fr_debug_lvl = rad_debug_lvl;
+
+ FR_INTEGER_COND_CHECK("max_request_time", main_config.max_request_time,
+ (main_config.max_request_time != 0), 100);
+
+ /*
+ * reject_delay can be zero. OR 1 though 10.
+ */
+ if ((main_config.reject_delay.tv_sec != 0) || (main_config.reject_delay.tv_usec != 0)) {
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, >=, 1, 0);
+ }
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, <=, 10, 0);
+
+ FR_INTEGER_BOUND_CHECK("cleanup_delay", main_config.cleanup_delay, <=, 30);
+
+ FR_INTEGER_BOUND_CHECK("resources.talloc_pool_size", main_config.talloc_pool_size, >=, 2 * 1024);
+ FR_INTEGER_BOUND_CHECK("resources.talloc_pool_size", main_config.talloc_pool_size, <=, 1024 * 1024);
+
+ /*
+ * Set default initial request processing delay to 1/3 of a second.
+ * Will be updated by the lowest response window across all home servers,
+ * if it is less than this.
+ */
+ main_config.init_delay.tv_sec = 0;
+ main_config.init_delay.tv_usec = 2* (1000000 / 3);
+
+ /*
+ * Free the old configuration items, and replace them
+ * with the new ones.
+ *
+ * Note that where possible, we do atomic switch-overs,
+ * to ensure that the pointers are always valid.
+ */
+ rad_assert(main_config.config == NULL);
+ root_config = main_config.config = cs;
+
+ DEBUG2("%s: #### Loading Realms and Home Servers ####", main_config.name);
+ if (!realms_init(cs)) {
+ return -1;
+ }
+
+ DEBUG2("%s: #### Loading Clients ####", main_config.name);
+ if (!client_list_parse_section(cs, false)) {
+ return -1;
+ }
+
+ /*
+ * Register the %{config:section.subsection} xlat function.
+ */
+ xlat_register("config", xlat_config, NULL, NULL);
+ xlat_register("client", xlat_client, NULL, NULL);
+ xlat_register("getclient", xlat_getclient, NULL, NULL);
+ xlat_register("listen", xlat_listen, NULL, NULL);
+ xlat_register("proxy_listen", xlat_proxy_listen, NULL, NULL);
+
+ /*
+ * Go update our behaviour, based on the configuration
+ * changes.
+ */
+
+ /*
+ * Sanity check the configuration for internal
+ * consistency.
+ */
+ FR_TIMEVAL_BOUND_CHECK("reject_delay", &main_config.reject_delay, <=, main_config.cleanup_delay, 0);
+
+ if (chroot_dir) {
+ if (chdir(radlog_dir) < 0) {
+ ERROR("Failed to 'chdir %s' after chroot: %s",
+ radlog_dir, fr_syserror(errno));
+ return -1;
+ }
+ }
+
+ cc = talloc_zero(NULL, cached_config_t);
+ if (!cc) return -1;
+
+ cc->cs = talloc_steal(cc ,cs);
+ rad_assert(cs_cache == NULL);
+ cs_cache = cc;
+
+ /* Clear any unprocessed configuration errors */
+ (void) fr_strerror();
+
+ return 0;
+}
+
+/*
+ * Free the configuration. Called only when the server is exiting.
+ */
+int main_config_free(void)
+{
+ virtual_servers_free(0);
+
+ /*
+ * Clean up the configuration data
+ * structures.
+ */
+ client_list_free(NULL);
+ realms_free();
+ listen_free(&main_config.listen);
+
+ /*
+ * Frees current config and any previous configs.
+ */
+ TALLOC_FREE(cs_cache);
+ dict_free();
+
+ return 0;
+}
+
+void hup_logfile(void)
+{
+ int fd, old_fd;
+
+ if (default_log.dst != L_DST_FILES) return;
+
+ fd = open(main_config.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (fd >= 0) {
+ /*
+ * Atomic swap. We'd like to keep the old
+ * FD around so that callers don't
+ * suddenly find the FD closed, and the
+ * writes go nowhere. But that's hard to
+ * do. So... we have the case where a
+ * log message *might* be lost on HUP.
+ */
+ old_fd = default_log.fd;
+ default_log.fd = fd;
+ close(old_fd);
+ }
+}
+
+static int hup_callback(void *ctx, void *data)
+{
+ CONF_SECTION *modules = ctx;
+ CONF_SECTION *cs = data;
+ CONF_SECTION *parent;
+ char const *name;
+ module_instance_t *mi;
+
+ /*
+ * Files may be defined in sub-sections of a module
+ * config. Walk up the tree until we find the module
+ * definition.
+ */
+ parent = cf_item_parent(cf_section_to_item(cs));
+ while (parent != modules) {
+ cs = parent;
+ parent = cf_item_parent(cf_section_to_item(cs));
+
+ /*
+ * Something went wrong. Oh well...
+ */
+ if (!parent) return 0;
+ }
+
+ name = cf_section_name2(cs);
+ if (!name) name = cf_section_name1(cs);
+
+ mi = module_find(modules, name);
+ if (!mi) return 0;
+
+ if ((mi->entry->module->type & RLM_TYPE_HUP_SAFE) == 0) return 0;
+
+ if (!module_hup_module(mi->cs, mi, time(NULL))) return 0;
+
+ return 1;
+}
+
+void main_config_hup(void)
+{
+ int rcode;
+ cached_config_t *cc;
+ CONF_SECTION *cs;
+ time_t when;
+ char buffer[1024];
+
+ static time_t last_hup = 0;
+
+ /*
+ * Re-open the log file. If we can't, then keep logging
+ * to the old log file.
+ *
+ * The "open log file" code is here rather than in log.c,
+ * because it makes that function MUCH simpler.
+ */
+ hup_logfile();
+
+ /*
+ * Only check the config files every few seconds.
+ */
+ when = time(NULL);
+ if ((last_hup + 2) >= when) {
+ INFO("HUP - Last HUP was too recent. Ignoring");
+ return;
+ }
+ last_hup = when;
+
+ rcode = cf_file_changed(cs_cache->cs, hup_callback);
+ if (rcode == CF_FILE_NONE) {
+ INFO("HUP - No files changed. Ignoring");
+ return;
+ }
+
+ if (rcode == CF_FILE_ERROR) {
+ INFO("HUP - Cannot read configuration files. Ignoring");
+ return;
+ }
+
+ /*
+ * No config files have changed.
+ */
+ if ((rcode & CF_FILE_CONFIG) == 0) {
+ if ((rcode & CF_FILE_MODULE) != 0) {
+ INFO("HUP - Files loaded by a module have changed.");
+
+ /*
+ * FIXME: reload the module.
+ */
+
+ }
+ return;
+ }
+
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) return;
+
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "RELOADING=1");
+#endif
+
+ /* Read the configuration file */
+ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name);
+
+ INFO("HUP - Re-reading configuration files");
+ if (cf_file_read(cs, buffer) < 0) {
+ ERROR("Failed to re-read or parse %s", buffer);
+ talloc_free(cs);
+ return;
+ }
+
+ cc = talloc_zero(cs_cache, cached_config_t);
+ if (!cc) {
+ ERROR("Out of memory");
+ return;
+ }
+
+ /*
+ * Save the current configuration. Note that we do NOT
+ * free older ones. We should probably do so at some
+ * point. Doing so will require us to mark which modules
+ * are still in use, and which aren't. Modules that
+ * can't be HUPed always use the original configuration.
+ * Modules that can be HUPed use one of the newer
+ * configurations.
+ */
+ cc->created = time(NULL);
+ cc->cs = talloc_steal(cc, cs);
+ cc->next = cs_cache;
+ cs_cache = cc;
+
+ INFO("HUP - loading modules");
+
+ /*
+ * Prefer the new module configuration.
+ */
+ modules_hup(cf_section_sub_find(cs, "modules"));
+
+ /*
+ * Load new servers BEFORE freeing old ones.
+ */
+ virtual_servers_load(cs);
+
+ virtual_servers_free(cc->created - (main_config.max_request_time * 4));
+
+#ifdef HAVE_SYSTEMD
+ /*
+ * If RELOADING=1 event is sent then it needed also a "READY=1" notification
+ * when it completed reloading its configuration.
+ */
+ sd_notify(0, "READY=1");
+#endif
+}
diff --git a/src/main/map.c b/src/main/map.c
new file mode 100644
index 0000000..e59fcec
--- /dev/null
+++ b/src/main/map.c
@@ -0,0 +1,1717 @@
+/*
+ * 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 map / template functions
+ * @file main/map.c
+ *
+ * @ingroup AVP
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#ifdef DEBUG_MAP
+static void map_dump(REQUEST *request, vp_map_t const *map)
+{
+ RDEBUG(">>> MAP TYPES LHS: %s, RHS: %s",
+ fr_int2str(tmpl_names, map->lhs->type, "???"),
+ fr_int2str(tmpl_names, map->rhs->type, "???"));
+
+ if (map->rhs) {
+ RDEBUG(">>> MAP NAMES %s %s", map->lhs->name, map->rhs->name);
+ }
+}
+#endif
+
+
+/** re-parse a map where the lhs is an unknown attribute.
+ *
+ *
+ * @param map to process.
+ * @param rhs_type quotation type around rhs.
+ * @param rhs string to re-parse.
+ */
+bool map_cast_from_hex(vp_map_t *map, FR_TOKEN rhs_type, char const *rhs)
+{
+ size_t len;
+ ssize_t rlen;
+ uint8_t *ptr;
+ char const *p;
+ pair_lists_t list;
+
+ DICT_ATTR const *da;
+ VALUE_PAIR *vp;
+ vp_tmpl_t *vpt;
+
+ rad_assert(map != NULL);
+
+ rad_assert(map->lhs != NULL);
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+
+ rad_assert(map->rhs == NULL);
+ rad_assert(rhs != NULL);
+
+ VERIFY_MAP(map);
+
+ /*
+ * If the attribute is still unknown, go parse the RHS.
+ */
+ da = dict_attrbyvalue(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor);
+ if (!da || da->flags.is_unknown) return false;
+
+ /*
+ * If the RHS is something OTHER than an octet
+ * string, go parse it as that.
+ */
+ if (rhs_type != T_BARE_WORD) return false;
+ if ((rhs[0] != '0') || (tolower((uint8_t)rhs[1]) != 'x')) return false;
+ if (!rhs[2]) return false;
+
+ len = strlen(rhs + 2);
+
+ ptr = talloc_array(map, uint8_t, len >> 1);
+ if (!ptr) return false;
+
+ len = fr_hex2bin(ptr, len >> 1, rhs + 2, len);
+
+ /*
+ * If we can't parse it, or if it's malformed,
+ * it's still unknown.
+ */
+ rlen = data2vp(NULL, NULL, NULL, NULL, da, ptr, len, len, &vp);
+ talloc_free(ptr);
+
+ if (rlen < 0) return false;
+
+ if ((size_t) rlen < len) {
+ free_vp:
+ fr_pair_list_free(&vp);
+ return false;
+ }
+
+ /*
+ * Was still parsed as an unknown attribute.
+ */
+ if (vp->da->flags.is_unknown) goto free_vp;
+
+ /*
+ * Set the RHS to the PARSED name, not the crap octet
+ * string which was input.
+ */
+ map->rhs = tmpl_alloc(map, TMPL_TYPE_DATA, NULL, 0);
+ if (!map->rhs) goto free_vp;
+
+ map->rhs->tmpl_data_type = da->type;
+ map->rhs->tmpl_data_length = vp->vp_length;
+ if (vp->da->flags.is_pointer) {
+ if (vp->da->type == PW_TYPE_STRING) {
+ map->rhs->tmpl_data_value.ptr = talloc_bstrndup(map->rhs, vp->data.ptr, vp->vp_length);
+ } else {
+ map->rhs->tmpl_data_value.ptr = talloc_memdup(map->rhs, vp->data.ptr, vp->vp_length);
+ }
+ } else {
+ memcpy(&map->rhs->tmpl_data_value, &vp->data, sizeof(map->rhs->tmpl_data_value));
+ }
+ map->rhs->name = vp_aprints_value(map->rhs, vp, '"');
+ map->rhs->len = talloc_array_length(map->rhs->name) - 1;
+
+ /*
+ * Set the LHS to the REAL attribute name.
+ */
+ vpt = tmpl_alloc(map, TMPL_TYPE_ATTR, map->lhs->tmpl_da->name, -1);
+ memcpy(&vpt->data.attribute, &map->lhs->data.attribute, sizeof(vpt->data.attribute));
+ vpt->tmpl_da = da;
+
+ /*
+ * Be sure to keep the "&control:" or "control:" prefix.
+ * If it's there, we re-generate it from whatever was in
+ * the original name, including the '&'.
+ */
+ p = map->lhs->name;
+ if (*p == '&') p++;
+ len = radius_list_name(&list, p, PAIR_LIST_UNKNOWN);
+
+ if (list != PAIR_LIST_UNKNOWN) {
+ rad_const_free(vpt->name);
+
+ vpt->name = talloc_asprintf(vpt, "%.*s:%s",
+ (int) len, map->lhs->name,
+ map->lhs->tmpl_da->name);
+ vpt->len = strlen(vpt->name);
+ }
+
+ talloc_free(map->lhs);
+ map->lhs = vpt;
+
+ fr_pair_list_free(&vp);
+
+ VERIFY_MAP(map);
+
+ return true;
+}
+
+/** Convert CONFIG_PAIR (which may contain refs) to vp_map_t.
+ *
+ * Treats the left operand as an attribute reference
+ * @verbatim<request>.<list>.<attribute>@endverbatim
+ *
+ * Treatment of left operand depends on quotation, barewords are treated as
+ * attribute references, double quoted values are treated as expandable strings,
+ * single quoted values are treated as literal strings.
+ *
+ * Return must be freed with talloc_free
+ *
+ * @param[in] ctx for talloc.
+ * @param[in] out Where to write the pointer to the new value_pair_map_struct.
+ * @param[in] cp to convert to map.
+ * @param[in] dst_request_def The default request to insert unqualified
+ * attributes into.
+ * @param[in] dst_list_def The default list to insert unqualified attributes
+ * into.
+ * @param[in] src_request_def The default request to resolve attribute
+ * references in.
+ * @param[in] src_list_def The default list to resolve unqualified attributes
+ * in.
+ * @return vp_map_t if successful or NULL on error.
+ */
+int map_afrom_cp(TALLOC_CTX *ctx, vp_map_t **out, CONF_PAIR *cp,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def)
+{
+ vp_map_t *map;
+ char const *attr, *value;
+ ssize_t slen;
+ FR_TOKEN type;
+
+ *out = NULL;
+
+ if (!cp) return -1;
+
+ map = talloc_zero(ctx, vp_map_t);
+ map->op = cf_pair_operator(cp);
+ map->ci = cf_pair_to_item(cp);
+
+ attr = cf_pair_attr(cp);
+ value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cp(cp, "Missing attribute value");
+ goto error;
+ }
+
+ /*
+ * LHS may be an expansion (that expands to an attribute reference)
+ * or an attribute reference. Quoting determines which it is.
+ */
+ type = cf_pair_attr_type(cp);
+ switch (type) {
+ case T_DOUBLE_QUOTED_STRING:
+ case T_BACK_QUOTED_STRING:
+ slen = tmpl_afrom_str(ctx, &map->lhs, attr, talloc_array_length(attr) - 1,
+ type, dst_request_def, dst_list_def, true);
+ if (slen <= 0) {
+ char *spaces, *text;
+
+ marker:
+ fr_canonicalize_error(ctx, &spaces, &text, slen, attr);
+ cf_log_err_cp(cp, "%s", text);
+ cf_log_err_cp(cp, "%s^ %s", spaces, fr_strerror());
+
+ talloc_free(spaces);
+ talloc_free(text);
+ goto error;
+ }
+ break;
+
+ case T_BARE_WORD:
+ /*
+ * Foo = %{...}
+ *
+ * Not allowed!
+ */
+ if ((attr[0] == '%') && (attr[1] == '{')) {
+ cf_log_err_cp(cp, "Bare expansions are not permitted. They must be in a double-quoted string.");
+ goto error;
+ }
+ /* FALL-THROUGH */
+
+ default:
+ slen = tmpl_afrom_attr_str(ctx, &map->lhs, attr, dst_request_def, dst_list_def, true, true);
+ if (slen <= 0) {
+ cf_log_err_cp(cp, "Failed parsing attribute reference");
+
+ goto marker;
+ }
+
+ if (tmpl_define_unknown_attr(map->lhs) < 0) {
+ cf_log_err_cp(cp, "Failed creating attribute %s: %s",
+ map->lhs->name, fr_strerror());
+ goto error;
+ }
+
+ break;
+ }
+
+ /*
+ * RHS might be an attribute reference.
+ */
+ type = cf_pair_value_type(cp);
+
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ map->lhs->tmpl_da->flags.is_unknown &&
+ !map_cast_from_hex(map, type, value)) {
+ goto error;
+
+ } else {
+ slen = tmpl_afrom_str(map, &map->rhs, value, strlen(value), type, src_request_def, src_list_def, true);
+ if (slen < 0) goto marker;
+ if (tmpl_define_unknown_attr(map->rhs) < 0) {
+ cf_log_err_cp(cp, "Failed creating attribute %s: %s", map->rhs->name, fr_strerror());
+ goto error;
+ }
+ }
+ if (!map->rhs) {
+ cf_log_err_cp(cp, "%s", fr_strerror());
+ goto error;
+ }
+
+ if (map->rhs->type == TMPL_TYPE_ATTR) {
+ /*
+ * We cannot assign a count to an attribute. That must
+ * be done in an xlat.
+ */
+ if (map->rhs->tmpl_num == NUM_COUNT) {
+ cf_log_err_cp(cp, "Cannot assign from a count");
+ goto error;
+ }
+
+ if (map->rhs->tmpl_da->flags.virtual) {
+ cf_log_err_cp(cp, "Virtual attributes must be in an expansion such as \"%%{%s}\".", map->rhs->tmpl_da->name);
+ goto error;
+ }
+ }
+
+ VERIFY_MAP(map);
+
+ *out = map;
+
+ return 0;
+
+error:
+ talloc_free(map);
+ return -1;
+}
+
+/** Convert an 'update' config section into an attribute map.
+ *
+ * Uses 'name2' of section to set default request and lists.
+ *
+ * @param[in] cs the update section
+ * @param[out] out Where to store the head of the map.
+ * @param[in] dst_list_def The default destination list, usually dictated by
+ * the section the module is being called in.
+ * @param[in] src_list_def The default source list, usually dictated by the
+ * section the module is being called in.
+ * @param[in] validate map using this callback (may be NULL).
+ * @param[in] ctx to pass to callback.
+ * @param[in] max number of mappings to process.
+ * @return -1 on error, else 0.
+ */
+int map_afrom_cs(vp_map_t **out, CONF_SECTION *cs,
+ pair_lists_t dst_list_def, pair_lists_t src_list_def,
+ map_validate_t validate, void *ctx,
+ unsigned int max)
+{
+ char const *cs_list, *p;
+
+ request_refs_t request_def = REQUEST_CURRENT;
+
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+
+ unsigned int total = 0;
+ vp_map_t **tail, *map;
+ TALLOC_CTX *parent;
+
+ *out = NULL;
+ tail = out;
+
+ /*
+ * The first map has cs as the parent.
+ * The rest have the previous map as the parent.
+ */
+ parent = cs;
+
+ ci = cf_section_to_item(cs);
+
+ cs_list = p = cf_section_name2(cs);
+ if (cs_list) {
+ p += radius_request_name(&request_def, p, REQUEST_CURRENT);
+ if (request_def == REQUEST_UNKNOWN) {
+ cf_log_err(ci, "Default request specified in mapping section is invalid");
+ return -1;
+ }
+
+ dst_list_def = fr_str2int(pair_lists, p, PAIR_LIST_UNKNOWN);
+ if (dst_list_def == PAIR_LIST_UNKNOWN) {
+ cf_log_err(ci, "Default list \"%s\" specified "
+ "in mapping section is invalid", p);
+ return -1;
+ }
+ }
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ if (total++ == max) {
+ cf_log_err(ci, "Map size exceeded");
+ error:
+ TALLOC_FREE(*out);
+ return -1;
+ }
+
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "Entry is not in \"attribute = value\" format");
+ goto error;
+ }
+
+ cp = cf_item_to_pair(ci);
+ if (map_afrom_cp(parent, &map, cp, request_def, dst_list_def, REQUEST_CURRENT, src_list_def) < 0) {
+ goto error;
+ }
+
+ VERIFY_MAP(map);
+
+ /*
+ * Check the types in the map are valid
+ */
+ if (validate && (validate(map, ctx) < 0)) goto error;
+
+ parent = *tail = map;
+ tail = &(map->next);
+ }
+
+ return 0;
+
+}
+
+
+/** Convert strings to vp_map_t
+ *
+ * Treatment of operands depends on quotation, barewords are treated
+ * as attribute references, double quoted values are treated as
+ * expandable strings, single quoted values are treated as literal
+ * strings.
+ *
+ * Return must be freed with talloc_free
+ *
+ * @param[in] ctx for talloc
+ * @param[out] out Where to store the head of the map.
+ * @param[in] lhs of the operation
+ * @param[in] lhs_type type of the LHS string
+ * @param[in] op the operation to perform
+ * @param[in] rhs of the operation
+ * @param[in] rhs_type type of the RHS string
+ * @param[in] dst_request_def The default request to insert unqualified
+ * attributes into.
+ * @param[in] dst_list_def The default list to insert unqualified attributes
+ * into.
+ * @param[in] src_request_def The default request to resolve attribute
+ * references in.
+ * @param[in] src_list_def The default list to resolve unqualified attributes
+ * in.
+ * @return vp_map_t if successful or NULL on error.
+ */
+int map_afrom_fields(TALLOC_CTX *ctx, vp_map_t **out, char const *lhs, FR_TOKEN lhs_type,
+ FR_TOKEN op, char const *rhs, FR_TOKEN rhs_type,
+ request_refs_t dst_request_def,
+ pair_lists_t dst_list_def,
+ request_refs_t src_request_def,
+ pair_lists_t src_list_def)
+{
+ ssize_t slen;
+ vp_map_t *map;
+
+ map = talloc_zero(ctx, vp_map_t);
+
+ slen = tmpl_afrom_str(map, &map->lhs, lhs, strlen(lhs), lhs_type, dst_request_def, dst_list_def, true);
+ if (slen < 0) {
+ error:
+ talloc_free(map);
+ return -1;
+ }
+
+ map->op = op;
+
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ map->lhs->tmpl_da->flags.is_unknown &&
+ map_cast_from_hex(map, rhs_type, rhs)) {
+ return 0;
+ }
+
+ slen = tmpl_afrom_str(map, &map->rhs, rhs, strlen(rhs), rhs_type, src_request_def, src_list_def, true);
+ if (slen < 0) goto error;
+
+ VERIFY_MAP(map);
+
+ *out = map;
+
+ return 0;
+}
+
+/** Convert a value pair string to valuepair map
+ *
+ * Takes a valuepair string with list and request qualifiers and converts it into a
+ * vp_map_t.
+ *
+ * @param ctx where to allocate the map.
+ * @param out Where to write the new map (must be freed with talloc_free()).
+ * @param vp_str string to parse.
+ * @param dst_request_def to use if attribute isn't qualified.
+ * @param dst_list_def to use if attribute isn't qualified.
+ * @param src_request_def to use if attribute isn't qualified.
+ * @param src_list_def to use if attribute isn't qualified.
+ * @return 0 on success, < 0 on error.
+ */
+int map_afrom_attr_str(TALLOC_CTX *ctx, vp_map_t **out, char const *vp_str,
+ request_refs_t dst_request_def, pair_lists_t dst_list_def,
+ request_refs_t src_request_def, pair_lists_t src_list_def)
+{
+ char const *p = vp_str;
+ FR_TOKEN quote;
+
+ VALUE_PAIR_RAW raw;
+ vp_map_t *map = NULL;
+
+ quote = gettoken(&p, raw.l_opand, sizeof(raw.l_opand), false);
+ switch (quote) {
+ case T_BARE_WORD:
+ break;
+
+ case T_INVALID:
+ error:
+ return -1;
+
+ default:
+ fr_strerror_printf("Left operand must be an attribute");
+ return -1;
+ }
+
+ raw.op = getop(&p);
+ if (raw.op == T_INVALID) goto error;
+
+ raw.quote = gettoken(&p, raw.r_opand, sizeof(raw.r_opand), false);
+ if (raw.quote == T_INVALID) goto error;
+ if (!fr_str_tok[raw.quote]) {
+ fr_strerror_printf("Right operand must be an attribute or string");
+ return -1;
+ }
+
+ if (map_afrom_fields(ctx, &map, raw.l_opand, T_BARE_WORD, raw.op, raw.r_opand, raw.quote,
+ dst_request_def, dst_list_def, src_request_def, src_list_def) < 0) {
+ return -1;
+ }
+
+ rad_assert(map != NULL);
+ *out = map;
+
+ VERIFY_MAP(map);
+
+ return 0;
+}
+
+/** Compare map where LHS is #TMPL_TYPE_ATTR
+ *
+ * Compares maps by lhs->tmpl_da, lhs->tmpl_tag, lhs->tmpl_num
+ *
+ * @note both map->lhs must be #TMPL_TYPE_ATTR.
+ *
+ * @param a first map.
+ * @param b second map.
+ */
+int8_t map_cmp_by_lhs_attr(void const *a, void const *b)
+{
+ vp_tmpl_t const *my_a = ((vp_map_t const *)a)->lhs;
+ vp_tmpl_t const *my_b = ((vp_map_t const *)b)->lhs;
+
+ VERIFY_TMPL(my_a);
+ VERIFY_TMPL(my_b);
+
+ uint8_t cmp;
+
+ rad_assert(my_a->type == TMPL_TYPE_ATTR);
+ rad_assert(my_b->type == TMPL_TYPE_ATTR);
+
+ cmp = fr_pointer_cmp(my_a->tmpl_da, my_b->tmpl_da);
+ if (cmp != 0) return cmp;
+
+ if (my_a->tmpl_tag < my_b->tmpl_tag) return -1;
+
+ if (my_a->tmpl_tag > my_b->tmpl_tag) return 1;
+
+ if (my_a->tmpl_num < my_b->tmpl_num) return -1;
+
+ if (my_a->tmpl_num > my_b->tmpl_num) return 1;
+
+ return 0;
+}
+
+static void map_sort_split(vp_map_t *source, vp_map_t **front, vp_map_t **back)
+{
+ vp_map_t *fast;
+ vp_map_t *slow;
+
+ /*
+ * Stopping condition - no more elements left to split
+ */
+ if (!source || !source->next) {
+ *front = source;
+ *back = NULL;
+
+ return;
+ }
+
+ /*
+ * Fast advances twice as fast as slow, so when it gets to the end,
+ * slow will point to the middle of the linked list.
+ */
+ slow = source;
+ fast = source->next;
+
+ while (fast) {
+ fast = fast->next;
+ if (fast) {
+ slow = slow->next;
+ fast = fast->next;
+ }
+ }
+
+ *front = source;
+ *back = slow->next;
+ slow->next = NULL;
+}
+
+static vp_map_t *map_sort_merge(vp_map_t *a, vp_map_t *b, fr_cmp_t cmp)
+{
+ vp_map_t *result = NULL;
+
+ if (!a) return b;
+ if (!b) return a;
+
+ /*
+ * Compare things in the maps
+ */
+ if (cmp(a, b) <= 0) {
+ result = a;
+ result->next = map_sort_merge(a->next, b, cmp);
+ } else {
+ result = b;
+ result->next = map_sort_merge(a, b->next, cmp);
+ }
+
+ return result;
+}
+
+/** Sort a linked list of #vp_map_t using merge sort
+ *
+ * @param[in,out] maps List of #vp_map_t to sort.
+ * @param[in] cmp to sort with
+ */
+void map_sort(vp_map_t **maps, fr_cmp_t cmp)
+{
+ vp_map_t *head = *maps;
+ vp_map_t *a;
+ vp_map_t *b;
+
+ /*
+ * If there's 0-1 elements it must already be sorted.
+ */
+ if (!head || !head->next) {
+ return;
+ }
+
+ map_sort_split(head, &a, &b); /* Split into sublists */
+ map_sort(&a, cmp); /* Traverse left */
+ map_sort(&b, cmp); /* Traverse right */
+
+ /*
+ * merge the two sorted lists together
+ */
+ *maps = map_sort_merge(a, b, cmp);
+}
+
+/** Process map which has exec as a src
+ *
+ * Evaluate maps which specify exec as a src. This may be used by various sorts of update sections,
+ * and so has been broken out into it's own function.
+ *
+ * @param[in,out] ctx to allocate new #VALUE_PAIR (s) in.
+ * @param[out] out Where to write the #VALUE_PAIR (s).
+ * @param[in] request structure (used only for talloc).
+ * @param[in] map the map. The LHS (dst) must be TMPL_TYPE_ATTR or TMPL_TYPE_LIST. The RHS (src)
+ * must be TMPL_TYPE_EXEC.
+ * @return -1 on failure, 0 on success.
+ */
+static int map_exec_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map)
+{
+ int result;
+ char *expanded = NULL;
+ char answer[1024];
+ VALUE_PAIR **input_pairs = NULL;
+ VALUE_PAIR *output_pairs = NULL;
+
+ *out = NULL;
+
+ VERIFY_MAP(map);
+
+ rad_assert(map->rhs->type == TMPL_TYPE_EXEC);
+ rad_assert((map->lhs->type == TMPL_TYPE_ATTR) || (map->lhs->type == TMPL_TYPE_LIST));
+
+ /*
+ * We always put the request pairs into the environment
+ */
+ input_pairs = radius_list(request, PAIR_LIST_REQUEST);
+
+ /*
+ * Automagically switch output type depending on our destination
+ * If dst is a list, then we create attributes from the output of the program
+ * if dst is an attribute, then we create an attribute of that type and then
+ * call fr_pair_value_from_str on the output of the script.
+ */
+ result = radius_exec_program(ctx, answer, sizeof(answer),
+ (map->lhs->type == TMPL_TYPE_LIST) ? &output_pairs : NULL,
+ request, map->rhs->name, input_pairs ? *input_pairs : NULL,
+ true, true, EXEC_TIMEOUT);
+ talloc_free(expanded);
+ if (result != 0) {
+ talloc_free(output_pairs);
+ return -1;
+ }
+
+ switch (map->lhs->type) {
+ case TMPL_TYPE_LIST:
+ if (!output_pairs) {
+ REDEBUG("No valid attributes received from program");
+ return -2;
+ }
+ *out = output_pairs;
+ return 0;
+
+ case TMPL_TYPE_ATTR:
+ {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!vp) return -1;
+ vp->op = map->op;
+ vp->tag = map->lhs->tmpl_tag;
+ if (fr_pair_value_from_str(vp, answer, -1) < 0) {
+ fr_pair_list_free(&vp);
+ return -2;
+ }
+ *out = vp;
+
+ return 0;
+ }
+
+ default:
+ rad_assert(0);
+ }
+
+ return -1;
+}
+
+/** Convert a map to a VALUE_PAIR.
+ *
+ * @param[in,out] ctx to allocate #VALUE_PAIR (s) in.
+ * @param[out] out Where to write the #VALUE_PAIR (s), which may be NULL if not found
+ * @param[in] request The current request.
+ * @param[in] map the map. The LHS (dst) has to be #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
+ * @param[in] uctx unused.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int map_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, UNUSED void *uctx)
+{
+ int rcode = 0;
+ ssize_t len;
+ VALUE_PAIR *vp = NULL, *new, *found = NULL;
+ REQUEST *context = request;
+ vp_cursor_t cursor;
+ ssize_t slen;
+ char *str;
+
+ *out = NULL;
+
+ VERIFY_MAP(map);
+ rad_assert(map->lhs != NULL);
+ rad_assert(map->rhs != NULL);
+
+ rad_assert((map->lhs->type == TMPL_TYPE_LIST) || (map->lhs->type == TMPL_TYPE_ATTR));
+
+ /*
+ * Special case for !*, we don't need to parse RHS as this is a unary operator.
+ */
+ if (map->op == T_OP_CMP_FALSE) return 0;
+
+ /*
+ * List to list found, this is a special case because we don't need
+ * to allocate any attributes, just finding the current list, and change
+ * the op.
+ */
+ if ((map->lhs->type == TMPL_TYPE_LIST) && (map->rhs->type == TMPL_TYPE_LIST)) {
+ VALUE_PAIR **from = NULL;
+
+ if (radius_request(&context, map->rhs->tmpl_request) == 0) {
+ from = radius_list(context, map->rhs->tmpl_list);
+ }
+ if (!from) return 0;
+
+ found = fr_pair_list_copy(ctx, *from);
+
+ /*
+ * List to list copy is empty if the src list has no attributes.
+ */
+ if (!found) return 0;
+
+ for (vp = fr_cursor_init(&cursor, &found);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vp->op = T_OP_ADD;
+ }
+
+ *out = found;
+
+ return 0;
+ }
+
+ /*
+ * And parse the RHS
+ */
+ switch (map->rhs->type) {
+ case TMPL_TYPE_XLAT_STRUCT:
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+ rad_assert(map->lhs->tmpl_da); /* We need to know which attribute to create */
+ rad_assert(map->rhs->tmpl_xlat != NULL);
+
+ new = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!new) return -1;
+
+ str = NULL;
+ slen = radius_axlat_struct(&str, request, map->rhs->tmpl_xlat, NULL, NULL);
+ if (slen < 0) {
+ rcode = slen;
+ goto error;
+ }
+
+ /*
+ * We do the debug printing because radius_axlat_struct
+ * doesn't have access to the original string. It's been
+ * mangled during the parsing to xlat_exp_t
+ */
+ RDEBUG2("EXPAND %s", map->rhs->name);
+ RDEBUG2(" --> %s", str);
+
+ rcode = fr_pair_value_from_str(new, str, -1);
+ talloc_free(str);
+ if (rcode < 0) {
+ fr_pair_list_free(&new);
+ goto error;
+ }
+ new->op = map->op;
+ new->tag = map->lhs->tmpl_tag;
+ *out = new;
+ break;
+
+ case TMPL_TYPE_XLAT:
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+ rad_assert(map->lhs->tmpl_da); /* We need to know which attribute to create */
+
+ new = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!new) return -1;
+
+ str = NULL;
+ slen = radius_axlat(&str, request, map->rhs->name, NULL, NULL);
+ if (slen < 0) {
+ rcode = slen;
+ goto error;
+ }
+
+ rcode = fr_pair_value_from_str(new, str, -1);
+ talloc_free(str);
+ if (rcode < 0) {
+ fr_pair_list_free(&new);
+ goto error;
+ }
+ new->op = map->op;
+ new->tag = map->lhs->tmpl_tag;
+ *out = new;
+ break;
+
+ case TMPL_TYPE_LITERAL:
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+ rad_assert(map->lhs->tmpl_da); /* We need to know which attribute to create */
+
+ new = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!new) return -1;
+
+ if (fr_pair_value_from_str(new, map->rhs->name, -1) < 0) {
+ rcode = 0;
+ goto error;
+ }
+ new->op = map->op;
+ new->tag = map->lhs->tmpl_tag;
+ *out = new;
+ break;
+
+ case TMPL_TYPE_ATTR:
+ {
+ vp_cursor_t from;
+
+ rad_assert(((map->lhs->type == TMPL_TYPE_ATTR) && map->lhs->tmpl_da) ||
+ ((map->lhs->type == TMPL_TYPE_LIST) && !map->lhs->tmpl_da));
+
+ /*
+ * @todo should log error, and return -1 for v3.1 (causes update to fail)
+ */
+ if (tmpl_copy_vps(ctx, &found, request, map->rhs) < 0) return 0;
+
+ vp = fr_cursor_init(&from, &found);
+
+ /*
+ * Src/Dst attributes don't match, convert src attributes
+ * to match dst.
+ */
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ (map->rhs->tmpl_da->type != map->lhs->tmpl_da->type)) {
+ vp_cursor_t to;
+
+ (void) fr_cursor_init(&to, out);
+ for (; vp; vp = fr_cursor_next(&from)) {
+ new = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!new) return -1;
+
+ len = value_data_cast(new, &new->data, new->da->type, new->da,
+ vp->da->type, vp->da, &vp->data, vp->vp_length);
+ if (len < 0) {
+ REDEBUG("Attribute conversion failed: %s", fr_strerror());
+ fr_pair_list_free(&found);
+ fr_pair_list_free(&new);
+ return -1;
+ }
+
+ new->vp_length = len;
+ vp = fr_cursor_remove(&from);
+ talloc_free(vp);
+
+ if (new->da->type == PW_TYPE_STRING) {
+ rad_assert(new->vp_strvalue != NULL);
+ }
+
+ new->op = map->op;
+ new->tag = map->lhs->tmpl_tag;
+ fr_cursor_insert(&to, new);
+ }
+ return 0;
+ }
+
+ /*
+ * Otherwise we just need to fixup the attribute types
+ * and operators
+ */
+ for (; vp; vp = fr_cursor_next(&from)) {
+ vp->da = map->lhs->tmpl_da;
+ vp->op = map->op;
+ vp->tag = map->lhs->tmpl_tag;
+ }
+ *out = found;
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ rad_assert(map->lhs->tmpl_da);
+ rad_assert(map->lhs->type == TMPL_TYPE_ATTR);
+ rad_assert(map->lhs->tmpl_da->type == map->rhs->tmpl_data_type);
+
+ new = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ if (!new) return -1;
+
+ len = value_data_copy(new, &new->data, new->da->type, &map->rhs->tmpl_data_value,
+ map->rhs->tmpl_data_length);
+ if (len < 0) goto error;
+
+ new->vp_length = len;
+ new->op = map->op;
+ new->tag = map->lhs->tmpl_tag;
+ *out = new;
+
+ VERIFY_MAP(map);
+ break;
+
+ /*
+ * This essentially does the same as rlm_exec xlat, except it's non-configurable.
+ * It's only really here as a convenience for people who expect the contents of
+ * backticks to be executed in a shell.
+ *
+ * exec string is xlat expanded and arguments are shell escaped.
+ */
+ case TMPL_TYPE_EXEC:
+ return map_exec_to_vp(ctx, out, request, map);
+
+ default:
+ rad_assert(0); /* Should have been caught at parse time */
+
+ error:
+ fr_pair_list_free(&vp);
+ return rcode;
+ }
+
+ return 0;
+}
+
+#define DEBUG_OVERWRITE(_old, _new) \
+do {\
+ if (RDEBUG_ENABLED3) {\
+ char *old = vp_aprints_value(request, _old, '"');\
+ char *new = vp_aprints_value(request, _new, '"');\
+ RDEBUG3("Overwriting value \"%s\" with \"%s\"", old, new);\
+ talloc_free(old);\
+ talloc_free(new);\
+ }\
+} while (0)
+
+/** Convert vp_map_t to VALUE_PAIR(s) and add them to a REQUEST.
+ *
+ * Takes a single vp_map_t, resolves request and list identifiers
+ * to pointers in the current request, then attempts to retrieve module
+ * specific value(s) using callback, and adds the resulting values to the
+ * correct request/list.
+ *
+ * @param request The current request.
+ * @param map specifying destination attribute and location and src identifier.
+ * @param func to retrieve module specific values and convert them to
+ * VALUE_PAIRS.
+ * @param ctx to be passed to func.
+ * @return -1 if the operation failed, -2 in the source attribute wasn't valid, 0 on success.
+ */
+int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t func, void *ctx)
+{
+ int rcode = 0;
+ int num;
+ VALUE_PAIR **list, *vp, *dst, *head = NULL;
+ bool found = false;
+ REQUEST *context;
+ TALLOC_CTX *parent;
+ vp_cursor_t dst_list, src_list;
+
+ vp_map_t exp_map;
+ vp_tmpl_t exp_lhs;
+
+ VERIFY_MAP(map);
+ rad_assert(map->lhs != NULL);
+ rad_assert(map->rhs != NULL);
+
+ /*
+ * Preprocessing of the LHS of the map.
+ */
+ switch (map->lhs->type) {
+ /*
+ * Already in the correct form.
+ */
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_ATTR:
+ break;
+
+ /*
+ * Everything else gets expanded, then re-parsed as an
+ * attribute reference.
+ */
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ case TMPL_TYPE_EXEC:
+ {
+ char *attr;
+ ssize_t slen;
+
+ slen = tmpl_aexpand(request, &attr, request, map->lhs, NULL, NULL);
+ if (slen <= 0) {
+ REDEBUG("Left side \"%.*s\" of map failed expansion", (int)map->lhs->len, map->lhs->name);
+ return -1;
+ }
+
+ slen = tmpl_from_attr_str(&exp_lhs, attr, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) ;
+ if (slen <= 0) {
+ REDEBUG("Left side \"%.*s\" expansion not an attribute reference: %s",
+ (int)map->lhs->len, map->lhs->name, fr_strerror());
+ talloc_free(attr);
+ return -1;
+ }
+ rad_assert((exp_lhs.type == TMPL_TYPE_ATTR) || (exp_lhs.type == TMPL_TYPE_LIST));
+
+ memcpy(&exp_map, map, sizeof(exp_map));
+ exp_map.lhs = &exp_lhs;
+ map = &exp_map;
+ }
+ break;
+
+ default:
+ rad_assert(0);
+ break;
+ }
+
+
+ /*
+ * Sanity check inputs. We can have a list or attribute
+ * as a destination.
+ */
+ if ((map->lhs->type != TMPL_TYPE_LIST) &&
+ (map->lhs->type != TMPL_TYPE_ATTR)) {
+ REDEBUG("Left side \"%.*s\" of map should be an attr or list but is an %s",
+ (int)map->lhs->len, map->lhs->name,
+ fr_int2str(tmpl_names, map->lhs->type, "<INVALID>"));
+ return -2;
+ }
+
+ context = request;
+ if (radius_request(&context, map->lhs->tmpl_request) < 0) {
+ REDEBUG("Mapping \"%.*s\" -> \"%.*s\" invalid in this context",
+ (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name);
+ return -2;
+ }
+
+ /*
+ * If there's no CoA packet and we're updating it,
+ * auto-allocate it.
+ */
+ if (((map->lhs->tmpl_list == PAIR_LIST_COA) ||
+ (map->lhs->tmpl_list == PAIR_LIST_DM)) && !request->coa) {
+ if (request->parent) {
+ REDEBUG("You can only do 'update coa' when processing a packet which was received from the network");
+ return -2;
+ }
+
+ if ((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST)) {
+ REDEBUG("You cannot do 'update coa' when processing a CoA / Disconnect request. Use 'update request' instead.");
+ return -2;
+ }
+
+ if (!request_alloc_coa(context)) {
+ REDEBUG("Failed to create a CoA/Disconnect Request message");
+ return -2;
+ }
+ context->coa->proxy->code = (map->lhs->tmpl_list == PAIR_LIST_COA) ?
+ PW_CODE_COA_REQUEST :
+ PW_CODE_DISCONNECT_REQUEST;
+ }
+
+ list = radius_list(context, map->lhs->tmpl_list);
+ if (!list) {
+ REDEBUG("Mapping \"%.*s\" -> \"%.*s\" invalid in this context",
+ (int)map->rhs->len, map->rhs->name, (int)map->lhs->len, map->lhs->name);
+
+ return -2;
+ }
+
+ parent = radius_list_ctx(context, map->lhs->tmpl_list);
+ if (!parent) {
+ REDEBUG("Unable to set parent list");
+ return -1;
+ }
+
+ /*
+ * The callback should either return -1 to signify operations error,
+ * -2 when it can't find the attribute or list being referenced, or
+ * 0 to signify success. It may return "success", but still have no
+ * VPs to work with.
+ */
+ if (map->rhs->type != TMPL_TYPE_NULL) {
+ rcode = func(parent, &head, request, map, ctx);
+ if (rcode < 0) {
+ rad_assert(!head);
+ return rcode;
+ }
+ if (!head) {
+ RDEBUG2("No attributes updated for RHS %s", map->rhs->name);
+ return rcode;
+ }
+ } else {
+ if (rad_debug_lvl) map_debug_log(request, map, NULL);
+ }
+
+ /*
+ * Print the VPs
+ */
+ for (vp = fr_cursor_init(&src_list, &head);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ VERIFY_VP(vp);
+
+ if (rad_debug_lvl) map_debug_log(request, map, vp);
+ }
+
+ /*
+ * The destination is a list (which is a completely different set of operations)
+ */
+ if (map->lhs->type == TMPL_TYPE_LIST) {
+ switch (map->op) {
+ case T_OP_CMP_FALSE:
+ /* We don't need the src VPs (should just be 'ANY') */
+ rad_assert(!head);
+
+ /* Clear the entire dst list */
+ fr_pair_list_free(list);
+
+ if (map->lhs->tmpl_list == PAIR_LIST_REQUEST) {
+ context->username = NULL;
+ context->password = NULL;
+ }
+ return 0;
+
+ case T_OP_SET:
+ if (map->rhs->type == TMPL_TYPE_LIST) {
+ fr_pair_list_free(list);
+ *list = head;
+ head = NULL;
+ } else { /* FALL-THROUGH */
+ case T_OP_EQ:
+ rad_assert(map->rhs->type == TMPL_TYPE_EXEC);
+ /* FALL-THROUGH */
+ case T_OP_ADD:
+ fr_pair_list_move(parent, list, &head, map->op);
+ fr_pair_list_free(&head);
+ }
+ goto finish;
+ case T_OP_PREPEND:
+ fr_pair_list_move(parent, list, &head, T_OP_PREPEND);
+ fr_pair_list_free(&head);
+ goto finish;
+
+ default:
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ }
+
+ /*
+ * Find the destination attribute. We leave with either
+ * the dst_list and vp pointing to the attribute or the VP
+ * being NULL (no attribute at that index).
+ */
+ num = map->lhs->tmpl_num;
+ (void) fr_cursor_init(&dst_list, list);
+ if ((num != NUM_ANY) && (num > 0)) {
+ while ((dst = fr_cursor_next_by_da(&dst_list, map->lhs->tmpl_da, map->lhs->tmpl_tag))) {
+ if (num <= 0) break;
+ num--;
+ }
+ } else {
+ dst = fr_cursor_next_by_da(&dst_list, map->lhs->tmpl_da, map->lhs->tmpl_tag);
+ }
+ rad_assert(!dst || (map->lhs->tmpl_da == dst->da));
+
+ /*
+ * The destination is an attribute
+ */
+ switch (map->op) {
+ default:
+ break;
+ /*
+ * !* - Remove all attributes which match dst in the specified list.
+ * This doesn't use attributes returned by the func(), and immediately frees them.
+ */
+ case T_OP_CMP_FALSE:
+ /* We don't need the src VPs (should just be 'ANY') */
+ rad_assert(!head);
+ if (!dst) return 0;
+
+ /*
+ * Wildcard: delete all of the matching ones, based on tag.
+ */
+ if (map->lhs->tmpl_num == NUM_ANY) {
+ fr_pair_delete_by_num(list, map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor, map->lhs->tmpl_tag);
+ dst = NULL;
+ /*
+ * We've found the Nth one. Delete it, and only it.
+ */
+ } else {
+ dst = fr_cursor_remove(&dst_list);
+ fr_pair_list_free(&dst);
+ }
+
+ /*
+ * Check that the User-Name and User-Password
+ * caches point to the correct attribute.
+ */
+ goto finish;
+
+ /*
+ * -= - Delete attributes in the dst list which match any of the
+ * src_list attributes.
+ *
+ * This operation has two modes:
+ * - If map->lhs->tmpl_num > 0, we check each of the src_list attributes against
+ * the dst attribute, to see if any of their values match.
+ * - If map->lhs->tmpl_num == NUM_ANY, we compare all instances of the dst attribute
+ * against each of the src_list attributes.
+ */
+ case T_OP_SUB:
+ /* We didn't find any attributes earlier */
+ if (!dst) {
+ fr_pair_list_free(&head);
+ return 0;
+ }
+
+ /*
+ * Instance specific[n] delete
+ */
+ if (map->lhs->tmpl_num != NUM_ANY) {
+ for (vp = fr_cursor_first(&src_list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ head->op = T_OP_CMP_EQ;
+ rcode = radius_compare_vps(request, vp, dst);
+ if (rcode == 0) {
+ dst = fr_cursor_remove(&dst_list);
+ fr_pair_list_free(&dst);
+ found = true;
+ }
+ }
+ fr_pair_list_free(&head);
+ if (!found) return 0;
+ goto finish;
+ }
+
+ /*
+ * All instances[*] delete
+ */
+ for (dst = fr_cursor_current(&dst_list);
+ dst;
+ dst = fr_cursor_next_by_da(&dst_list, map->lhs->tmpl_da, map->lhs->tmpl_tag)) {
+ for (vp = fr_cursor_first(&src_list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ head->op = T_OP_CMP_EQ;
+ rcode = radius_compare_vps(request, vp, dst);
+ if (rcode == 0) {
+ dst = fr_cursor_remove(&dst_list);
+ fr_pair_list_free(&dst);
+ found = true;
+ }
+ }
+ }
+ fr_pair_list_free(&head);
+ if (!found) return 0;
+ goto finish;
+ }
+
+ /*
+ * Another fixup pass to set tags on attributes were about to insert
+ */
+ if (map->lhs->tmpl_tag != TAG_ANY) {
+ for (vp = fr_cursor_init(&src_list, &head);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ vp->tag = map->lhs->tmpl_tag;
+ }
+ }
+
+ switch (map->op) {
+ /*
+ * = - Set only if not already set
+ */
+ case T_OP_EQ:
+ if (dst) {
+ RDEBUG3("Refusing to overwrite (use :=)");
+ fr_pair_list_free(&head);
+ return 0;
+ }
+
+ /* Insert first instance (if multiple) */
+ fr_cursor_first(&src_list);
+ fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
+ /* Free any we didn't insert */
+ fr_pair_list_free(&head);
+ break;
+
+ /*
+ * := - Overwrite existing attribute with last src_list attribute
+ */
+ case T_OP_SET:
+ /* Wind to last instance */
+ fr_cursor_last(&src_list);
+ if (dst) {
+ DEBUG_OVERWRITE(dst, fr_cursor_current(&src_list));
+ dst = fr_cursor_replace(&dst_list, fr_cursor_remove(&src_list));
+ fr_pair_list_free(&dst);
+ } else {
+ fr_cursor_insert(&dst_list, fr_cursor_remove(&src_list));
+ }
+ /* Free any we didn't insert */
+ fr_pair_list_free(&head);
+ break;
+
+ /*
+ * ^= - Prepend src_list attributes to the destination
+ */
+ case T_OP_PREPEND:
+ fr_pair_prepend(list, head);
+ head = NULL;
+ break;
+
+ /*
+ * += - Add all src_list attributes to the destination
+ */
+ case T_OP_ADD:
+ /* Insert all the instances! (if multiple) */
+ fr_pair_add(list, head);
+ head = NULL;
+ break;
+
+ /*
+ * Filter operators
+ */
+ case T_OP_REG_NE:
+ case T_OP_NE:
+ case T_OP_REG_EQ:
+ case T_OP_CMP_EQ:
+ case T_OP_GE:
+ case T_OP_GT:
+ case T_OP_LE:
+ case T_OP_LT:
+ {
+ VALUE_PAIR *a, *b;
+
+ fr_pair_list_sort(&head, fr_pair_cmp_by_da_tag);
+ fr_pair_list_sort(list, fr_pair_cmp_by_da_tag);
+
+ fr_cursor_first(&dst_list);
+
+ for (b = fr_cursor_first(&src_list);
+ b;
+ b = fr_cursor_next(&src_list)) {
+ found = false;
+
+ for (a = fr_cursor_current(&dst_list);
+ a;
+ a = fr_cursor_next(&dst_list)) {
+ int8_t cmp;
+
+ cmp = fr_pair_cmp_by_da_tag(a, b); /* attribute and tag match */
+ if (cmp > 0) break;
+ else if (cmp < 0) continue;
+
+ /*
+ * The LHS exists. We need to
+ * limit it's value based on the
+ * operator, and on the value of
+ * the RHS.
+ */
+ cmp = (value_data_cmp_op(map->op, a->da->type, &a->data, a->vp_length, b->da->type, &b->data, b->vp_length) == 0);
+ if (cmp == 1) switch (map->op) {
+
+ /*
+ * Keep only matching attributes.
+ */
+ default:
+ case T_OP_REG_NE:
+ case T_OP_NE:
+ case T_OP_REG_EQ:
+ case T_OP_CMP_EQ:
+ a = fr_cursor_remove(&dst_list);
+ talloc_free(a);
+ break;
+
+ /*
+ * Keep matching
+ * attribute, and enforce
+ * matching values.
+ */
+ case T_OP_GE:
+ case T_OP_GT:
+ case T_OP_LE:
+ case T_OP_LT:
+ DEBUG_OVERWRITE(a, b);
+ (void) value_data_copy(a, &a->data, a->da->type,
+ &b->data, b->vp_length);
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * End of the dst list.
+ */
+ if (!a) {
+ if (found) break;
+
+ switch (map->op) {
+ default:
+ break;
+
+ /*
+ * It wasn't found. Insert it with the given value.
+ */
+ case T_OP_GE:
+ case T_OP_GT:
+ case T_OP_LE:
+ case T_OP_LT:
+ (void) fr_cursor_insert(&dst_list, fr_pair_copy(parent, b));
+ break;
+ }
+ break;
+ }
+ }
+ fr_pair_list_free(&head);
+ }
+ break;
+
+ default:
+ rad_assert(0); /* Should have been caught be the caller */
+ return -1;
+ }
+
+finish:
+ rad_assert(!head);
+
+ /*
+ * Update the cached username && password. This is code
+ * we execute on EVERY update (sigh) so that SOME modules
+ * MIGHT NOT have to do the search themselves.
+ *
+ * TBH, we should probably make each module just do the
+ * search themselves.
+ */
+ if (map->lhs->tmpl_list == PAIR_LIST_REQUEST) {
+ context->username = NULL;
+ context->password = NULL;
+
+ for (vp = fr_cursor_init(&src_list, list);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+
+ if (vp->da->vendor != 0) continue;
+ if (vp->da->flags.has_tag) continue;
+
+ if (!context->username && (vp->da->attr == PW_USER_NAME)) {
+ context->username = vp;
+ continue;
+ }
+
+ if (vp->da->attr == PW_STRIPPED_USER_NAME) {
+ context->username = vp;
+ continue;
+ }
+
+ if (vp->da->attr == PW_USER_PASSWORD) {
+ context->password = vp;
+ continue;
+ }
+ }
+ }
+ return 0;
+}
+
+/** Check whether the destination of a map is currently valid
+ *
+ * @param request The current request.
+ * @param map to check.
+ * @return true if the map resolves to a request and list else false.
+ */
+bool map_dst_valid(REQUEST *request, vp_map_t const *map)
+{
+ REQUEST *context = request;
+
+ VERIFY_MAP(map);
+
+ if (radius_request(&context, map->lhs->tmpl_request) < 0) return false;
+ if (!radius_list(context, map->lhs->tmpl_list)) return false;
+
+ return true;
+}
+
+/** Print a map to a string
+ *
+ * @param[out] buffer for the output string
+ * @param[in] bufsize of the buffer
+ * @param[in] map to print
+ * @return the size of the string printed
+ */
+size_t map_prints(char *buffer, size_t bufsize, vp_map_t const *map)
+{
+ size_t len;
+ DICT_ATTR const *da = NULL;
+ char *p = buffer;
+ char *end = buffer + bufsize;
+
+ VERIFY_MAP(map);
+
+ if (map->lhs->type == TMPL_TYPE_ATTR) da = map->lhs->tmpl_da;
+
+ len = tmpl_prints(buffer, bufsize, map->lhs, da);
+ p += len;
+
+ *(p++) = ' ';
+ strlcpy(p, fr_token_name(map->op), end - p);
+ p += strlen(p);
+ *(p++) = ' ';
+
+ /*
+ * The RHS doesn't matter for many operators
+ */
+ if ((map->op == T_OP_CMP_TRUE) ||
+ (map->op == T_OP_CMP_FALSE)) {
+ strlcpy(p, "ANY", (end - p));
+ p += strlen(p);
+ return p - buffer;
+ }
+
+ rad_assert(map->rhs != NULL);
+
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
+ (map->rhs->type == TMPL_TYPE_LITERAL)) {
+ *(p++) = '\'';
+ len = tmpl_prints(p, end - p, map->rhs, da);
+ p += len;
+ *(p++) = '\'';
+ *p = '\0';
+ } else {
+ len = tmpl_prints(p, end - p, map->rhs, da);
+ p += len;
+ }
+
+ return p - buffer;
+}
+
+/*
+ * Debug print a map / VP
+ */
+void map_debug_log(REQUEST *request, vp_map_t const *map, VALUE_PAIR const *vp)
+{
+ char *value;
+ char buffer[1024];
+
+ VERIFY_MAP(map);
+ rad_assert(map->lhs != NULL);
+ rad_assert(map->rhs != NULL);
+
+ rad_assert(vp || (map->rhs->type == TMPL_TYPE_NULL));
+
+ switch (map->rhs->type) {
+ /*
+ * Just print the value being assigned
+ */
+ default:
+ case TMPL_TYPE_LITERAL:
+ vp_prints_value(buffer, sizeof(buffer), vp, map->rhs->quote);
+ value = buffer;
+ break;
+
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ vp_prints_value(buffer, sizeof(buffer), vp, map->rhs->quote);
+ value = buffer;
+ break;
+
+ case TMPL_TYPE_DATA:
+ vp_prints_value(buffer, sizeof(buffer), vp, map->rhs->quote);
+ value = buffer;
+ break;
+
+ /*
+ * For the lists, we can't use the original name, and have to
+ * rebuild it using tmpl_prints, for each attribute we're
+ * copying.
+ */
+ case TMPL_TYPE_LIST:
+ {
+ char attr[256];
+ char quote = '\0';
+ vp_tmpl_t vpt;
+ /*
+ * Fudge a temporary tmpl that describes the attribute we're copying
+ * this is a combination of the original list tmpl, and values from
+ * the VALUE_PAIR. This way, we get tag info included.
+ */
+ memcpy(&vpt, map->rhs, sizeof(vpt));
+ vpt.tmpl_da = vp->da;
+ vpt.tmpl_tag = vp->tag;
+ vpt.type = TMPL_TYPE_ATTR;
+
+ /*
+ * Not appropriate to use map->rhs->quote here, as that's the quoting
+ * around the list ref. The attribute value has no quoting, so we choose
+ * the quoting based on the data type, and whether it's printable.
+ */
+ if (vp->da->type == PW_TYPE_STRING) quote = is_printable(vp->vp_strvalue,
+ vp->vp_length) ? '\'' : '"';
+ vp_prints_value(buffer, sizeof(buffer), vp, quote);
+ tmpl_prints(attr, sizeof(attr), &vpt, vp->da);
+ value = talloc_typed_asprintf(request, "%s -> %s", attr, buffer);
+ }
+ break;
+
+ case TMPL_TYPE_ATTR:
+ {
+ char quote = '\0';
+
+ /*
+ * Not appropriate to use map->rhs->quote here, as that's the quoting
+ * around the attr ref. The attribute value has no quoting, so we choose
+ * the quoting based on the data type, and whether it's printable.
+ */
+ if (vp->da->type == PW_TYPE_STRING) quote = is_printable(vp->vp_strvalue,
+ vp->vp_length) ? '\'' : '"';
+ vp_prints_value(buffer, sizeof(buffer), vp, quote);
+ value = talloc_typed_asprintf(request, "%.*s -> %s", (int)map->rhs->len, map->rhs->name, buffer);
+ }
+ break;
+
+ case TMPL_TYPE_NULL:
+ strcpy(buffer, "ANY");
+ value = buffer;
+ break;
+ }
+
+ switch (map->lhs->type) {
+ case TMPL_TYPE_LIST:
+ RDEBUG("%.*s:%s %s %s", (int)map->lhs->len, map->lhs->name, vp ? vp->da->name : "",
+ fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
+ break;
+
+ case TMPL_TYPE_ATTR:
+ RDEBUG("%s %s %s", map->lhs->name,
+ fr_int2str(fr_tokens, vp ? vp->op : map->op, "<INVALID>"), value);
+ break;
+
+ default:
+ RDEBUG("map %s = %s", fr_int2str(tmpl_names, map->lhs->type, "???"), value);
+ break;
+ }
+
+ if (value != buffer) talloc_free(value);
+}
diff --git a/src/main/modcall.c b/src/main/modcall.c
new file mode 100644
index 0000000..aa6abf8
--- /dev/null
+++ b/src/main/modcall.c
@@ -0,0 +1,4041 @@
+/*
+ * @name modcall.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+
+
+/* mutually-recursive static functions need a prototype up front */
+static modcallable *do_compile_modgroup(modcallable *,
+ rlm_components_t, CONF_SECTION *,
+ int, int, int);
+
+/* Actions may be a positive integer (the highest one returned in the group
+ * will be returned), or the keyword "return", represented here by
+ * MOD_ACTION_RETURN, to cause an immediate return.
+ * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
+ * to cause an immediate reject. */
+#define MOD_ACTION_RETURN (-1)
+#define MOD_ACTION_REJECT (-2)
+
+/* Here are our basic types: modcallable, modgroup, and modsingle. For an
+ * explanation of what they are all about, see doc/configurable_failover.rst */
+struct modcallable {
+ modcallable *parent;
+ struct modcallable *next;
+ char const *name;
+ char const *debug_name;
+ enum { MOD_SINGLE = 1, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE,
+#ifdef WITH_UNLANG
+ MOD_IF, MOD_ELSE, MOD_ELSIF, MOD_UPDATE, MOD_SWITCH, MOD_CASE,
+ MOD_FOREACH, MOD_BREAK, MOD_RETURN,
+#endif
+ MOD_POLICY, MOD_REFERENCE, MOD_XLAT } type;
+ rlm_components_t method;
+ int actions[RLM_MODULE_NUMCODES];
+};
+
+#define MOD_LOG_OPEN_BRACE RDEBUG2("%s {", c->debug_name)
+
+#define MOD_LOG_CLOSE_BRACE RDEBUG2("} # %s = %s", c->debug_name, fr_int2str(mod_rcode_table, result, "<invalid>"))
+
+typedef struct {
+ modcallable mc; /* self */
+ enum {
+ GROUPTYPE_SIMPLE = 0,
+ GROUPTYPE_REDUNDANT,
+ GROUPTYPE_COUNT
+ } grouptype; /* after mc */
+ modcallable *children;
+ modcallable *tail; /* of the children list */
+ CONF_SECTION *cs;
+ vp_map_t *map; /* update */
+ vp_tmpl_t *vpt; /* switch */
+ fr_cond_t *cond; /* if/elsif */
+ bool done_pass2;
+} modgroup;
+
+typedef struct {
+ modcallable mc;
+ module_instance_t *modinst;
+} modsingle;
+
+typedef struct {
+ modcallable mc;
+ char const *ref_name;
+ CONF_SECTION *ref_cs;
+} modref;
+
+typedef struct {
+ modcallable mc;
+ int exec;
+ char *xlat_name;
+} modxlat;
+
+/* Simple conversions: modsingle and modgroup are subclasses of modcallable,
+ * so we often want to go back and forth between them. */
+static modsingle *mod_callabletosingle(modcallable *p)
+{
+ rad_assert(p->type==MOD_SINGLE);
+ return (modsingle *)p;
+}
+static modgroup *mod_callabletogroup(modcallable *p)
+{
+ rad_assert((p->type > MOD_SINGLE) && (p->type <= MOD_POLICY));
+
+ return (modgroup *)p;
+}
+static modcallable *mod_singletocallable(modsingle *p)
+{
+ return (modcallable *)p;
+}
+static modcallable *mod_grouptocallable(modgroup *p)
+{
+ return (modcallable *)p;
+}
+
+static modref *mod_callabletoref(modcallable *p)
+{
+ rad_assert(p->type==MOD_REFERENCE);
+ return (modref *)p;
+}
+static modcallable *mod_reftocallable(modref *p)
+{
+ return (modcallable *)p;
+}
+
+static modxlat *mod_callabletoxlat(modcallable *p)
+{
+ rad_assert(p->type==MOD_XLAT);
+ return (modxlat *)p;
+}
+static modcallable *mod_xlattocallable(modxlat *p)
+{
+ return (modcallable *)p;
+}
+
+/* modgroups are grown by adding a modcallable to the end */
+static void add_child(modgroup *g, modcallable *c)
+{
+ if (!c) return;
+
+ (void) talloc_steal(g, c);
+
+ if (!g->children) {
+ g->children = g->tail = c;
+ } else {
+ rad_assert(g->tail->next == NULL);
+ g->tail->next = c;
+ g->tail = c;
+ }
+
+ c->parent = mod_grouptocallable(g);
+}
+
+/* Here's where we recognize all of our keywords: first the rcodes, then the
+ * actions */
+const FR_NAME_NUMBER mod_rcode_table[] = {
+ { "reject", RLM_MODULE_REJECT },
+ { "fail", RLM_MODULE_FAIL },
+ { "ok", RLM_MODULE_OK },
+ { "handled", RLM_MODULE_HANDLED },
+ { "invalid", RLM_MODULE_INVALID },
+ { "userlock", RLM_MODULE_USERLOCK },
+ { "notfound", RLM_MODULE_NOTFOUND },
+ { "noop", RLM_MODULE_NOOP },
+ { "updated", RLM_MODULE_UPDATED },
+ { NULL, 0 }
+};
+
+
+/*
+ * Compile action && rcode for later use.
+ */
+static int compile_action(modcallable *c, CONF_PAIR *cp)
+{
+ int action;
+ char const *attr, *value;
+
+ attr = cf_pair_attr(cp);
+ value = cf_pair_value(cp);
+ if (!value) return 0;
+
+ if (!strcasecmp(value, "return"))
+ action = MOD_ACTION_RETURN;
+
+ else if (!strcasecmp(value, "break"))
+ action = MOD_ACTION_RETURN;
+
+ else if (!strcasecmp(value, "reject"))
+ action = MOD_ACTION_REJECT;
+
+ else if (strspn(value, "0123456789")==strlen(value)) {
+ action = atoi(value);
+
+ /*
+ * Don't allow priority zero, for future use.
+ */
+ if (action == 0) return 0;
+ } else {
+ cf_log_err_cp(cp, "Unknown action '%s'.\n",
+ value);
+ return 0;
+ }
+
+ if (strcasecmp(attr, "default") != 0) {
+ int rcode;
+
+ rcode = fr_str2int(mod_rcode_table, attr, -1);
+ if (rcode < 0) {
+ cf_log_err_cp(cp,
+ "Unknown module rcode '%s'.\n",
+ attr);
+ return 0;
+ }
+ c->actions[rcode] = action;
+
+ } else { /* set all unset values to the default */
+ int i;
+
+ for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
+ if (!c->actions[i]) c->actions[i] = action;
+ }
+ }
+
+ return 1;
+}
+
+/* Some short names for debugging output */
+static char const * const comp2str[] = {
+ "authenticate",
+ "authorize",
+ "preacct",
+ "accounting",
+ "session",
+ "pre-proxy",
+ "post-proxy",
+ "post-auth"
+#ifdef WITH_COA
+ ,
+ "recv-coa",
+ "send-coa"
+#endif
+};
+
+#ifdef HAVE_PTHREAD_H
+/*
+ * Lock the mutex for the module
+ */
+static void safe_lock(module_instance_t *instance)
+{
+ if (instance->mutex)
+ pthread_mutex_lock(instance->mutex);
+}
+
+/*
+ * Unlock the mutex for the module
+ */
+static void safe_unlock(module_instance_t *instance)
+{
+ if (instance->mutex)
+ pthread_mutex_unlock(instance->mutex);
+}
+#else
+/*
+ * No threads: these functions become NULL's.
+ */
+#define safe_lock(foo)
+#define safe_unlock(foo)
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) call_modsingle(rlm_components_t component, modsingle *sp, REQUEST *request)
+{
+ int blocked;
+ int indent = request->log.indent;
+ char const *old;
+
+ /*
+ * If the request should stop, refuse to do anything.
+ */
+ blocked = (request->master_state == REQUEST_STOP_PROCESSING);
+ if (blocked) return RLM_MODULE_NOOP;
+
+ RDEBUG3("modsingle[%s]: calling %s (%s)",
+ comp2str[component], sp->modinst->name,
+ sp->modinst->entry->name);
+ request->log.indent = 0;
+
+ if (sp->modinst->force) {
+ request->rcode = sp->modinst->code;
+ goto fail;
+ }
+
+ /*
+ * For logging unresponsive children.
+ */
+ old = request->module;
+ request->module = sp->modinst->name;
+
+ safe_lock(sp->modinst);
+ request->rcode = sp->modinst->entry->module->methods[component](sp->modinst->insthandle, request);
+ safe_unlock(sp->modinst);
+
+ request->module = old;
+
+ /*
+ * Wasn't blocked, and now is. Complain!
+ */
+ blocked = (request->master_state == REQUEST_STOP_PROCESSING);
+ if (blocked) {
+ RWARN("Module %s became unblocked", sp->modinst->entry->name);
+ }
+
+ fail:
+ request->log.indent = indent;
+ RDEBUG3("modsingle[%s]: returned from %s (%s)",
+ comp2str[component], sp->modinst->name,
+ sp->modinst->entry->name);
+
+ return request->rcode;
+}
+
+static int default_component_results[MOD_COUNT] = {
+ RLM_MODULE_REJECT, /* AUTH */
+ RLM_MODULE_NOTFOUND, /* AUTZ */
+ RLM_MODULE_NOOP, /* PREACCT */
+ RLM_MODULE_NOOP, /* ACCT */
+ RLM_MODULE_FAIL, /* SESS */
+ RLM_MODULE_NOOP, /* PRE_PROXY */
+ RLM_MODULE_NOOP, /* POST_PROXY */
+ RLM_MODULE_NOOP /* POST_AUTH */
+#ifdef WITH_COA
+ ,
+ RLM_MODULE_NOOP, /* RECV_COA_TYPE */
+ RLM_MODULE_NOOP /* SEND_COA_TYPE */
+#endif
+};
+
+
+extern char const *unlang_keyword[];
+
+char const *unlang_keyword[] = {
+ "",
+ "single",
+ "group",
+ "load-balance group",
+ "redundant-load-balance group",
+#ifdef WITH_UNLANG
+ "if",
+ "else",
+ "elsif",
+ "update",
+ "switch",
+ "case",
+ "foreach",
+ "break",
+ "return",
+#endif
+ "policy",
+ "reference",
+ "xlat",
+ NULL
+};
+
+static char const modcall_spaces[] = " ";
+
+#define MODCALL_STACK_MAX (32)
+
+/*
+ * Don't call the modules recursively. Instead, do them
+ * iteratively, and manage the call stack ourselves.
+ */
+typedef struct modcall_stack_entry_t {
+ rlm_rcode_t result;
+ int priority;
+ int unwind; /* unwind to this one if it exists */
+ modcallable *c;
+} modcall_stack_entry_t;
+
+
+static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
+ modcall_stack_entry_t *entry, bool do_next_sibling);
+
+/*
+ * Call a child of a block.
+ */
+static void modcall_child(REQUEST *request, rlm_components_t component, int depth,
+ modcall_stack_entry_t *entry, modcallable *c,
+ rlm_rcode_t *result, bool do_next_sibling)
+{
+ modcall_stack_entry_t *next;
+
+ if (depth >= MODCALL_STACK_MAX) {
+ ERROR("Internal sanity check failed: module stack is too deep");
+ fr_exit(1);
+ }
+
+ /*
+ * Initialize the childs stack frame.
+ */
+ next = entry + 1;
+ next->c = c;
+ next->result = entry->result;
+ next->priority = 0;
+ next->unwind = 0;
+
+ if (!modcall_recurse(request, component,
+ depth, next, do_next_sibling)) {
+ *result = RLM_MODULE_FAIL;
+ return;
+ }
+
+ /*
+ * Unwind back up the stack
+ */
+ if (next->unwind != 0) {
+ entry->unwind = next->unwind;
+ }
+
+ *result = next->result;
+
+ return;
+}
+
+
+/*
+ * Interpret the various types of blocks.
+ */
+static bool modcall_recurse(REQUEST *request, rlm_components_t component, int depth,
+ modcall_stack_entry_t *entry, bool do_next_sibling)
+{
+ bool if_taken, was_if;
+ modcallable *c;
+ int priority;
+ rlm_rcode_t result;
+
+ was_if = if_taken = false;
+ result = RLM_MODULE_UNKNOWN;
+ RINDENT();
+
+redo:
+ priority = -1;
+ c = entry->c;
+
+ /*
+ * Nothing more to do. Return the code and priority
+ * which was set by the caller.
+ */
+ if (!c) goto finish;
+
+ if (fr_debug_lvl >= 3) {
+ VERIFY_REQUEST(request);
+ }
+
+ rad_assert(c->debug_name != NULL); /* if this happens, all bets are off. */
+
+ /*
+ * We've been asked to stop. Do so.
+ */
+ if ((request->master_state == REQUEST_STOP_PROCESSING) ||
+ (request->parent &&
+ (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
+ entry->result = RLM_MODULE_FAIL;
+ entry->priority = 9999;
+ goto finish;
+ }
+
+#ifdef WITH_UNLANG
+ /*
+ * Handle "if" conditions.
+ */
+ if (c->type == MOD_IF) {
+ int condition;
+ modgroup *g;
+
+ mod_if:
+ g = mod_callabletogroup(c);
+ rad_assert(g->cond != NULL);
+
+ RDEBUG2("%s %s{", unlang_keyword[c->type], c->name);
+
+ /*
+ * Use "result" UNLESS it wasn't set, in which
+ * case we use the previous result on the stack.
+ */
+ condition = radius_evaluate_cond(request, result != RLM_MODULE_UNKNOWN ? result : entry->result, 0, g->cond);
+ if (condition < 0) {
+ condition = false;
+ REDEBUG("Failed retrieving values required to evaluate condition");
+ } else {
+ RDEBUG2("%s %s -> %s",
+ unlang_keyword[c->type],
+ c->name, condition ? "TRUE" : "FALSE");
+ }
+
+ /*
+ * Didn't pass. Remember that.
+ */
+ if (!condition) {
+ was_if = true;
+ if_taken = false;
+ goto next_sibling;
+ }
+
+ /*
+ * We took the "if". Go recurse into its' children.
+ */
+ was_if = true;
+ if_taken = true;
+ goto do_children;
+ } /* MOD_IF */
+
+ /*
+ * "else" if the previous "if" was taken.
+ * "if" if the previous if wasn't taken.
+ */
+ if (c->type == MOD_ELSIF) {
+ if (!was_if) goto elsif_error;
+
+ /*
+ * Like MOD_ELSE, but allow for a later "else"
+ */
+ if (if_taken) {
+ RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+ unlang_keyword[c->type]);
+ was_if = true;
+ if_taken = true;
+ goto next_sibling;
+ }
+
+ /*
+ * Check the "if" condition.
+ */
+ goto mod_if;
+ } /* MOD_ELSIF */
+
+ /*
+ * "else" for a preceding "if".
+ */
+ if (c->type == MOD_ELSE) {
+ if (!was_if) { /* error */
+ elsif_error:
+ RDEBUG2("... skipping %s: No preceding \"if\"",
+ unlang_keyword[c->type]);
+ goto next_sibling;
+ }
+
+ if (if_taken) {
+ RDEBUG2("... skipping %s: Preceding \"if\" was taken",
+ unlang_keyword[c->type]);
+ was_if = false;
+ if_taken = false;
+ goto next_sibling;
+ }
+
+ /*
+ * We need to process it. Go do that.
+ */
+ was_if = false;
+ if_taken = false;
+ goto do_children;
+ } /* MOD_ELSE */
+
+ /*
+ * We're no longer processing if/else/elsif. Reset the
+ * trackers for those conditions.
+ */
+ was_if = false;
+ if_taken = false;
+#endif /* WITH_UNLANG */
+
+ if (c->type == MOD_SINGLE) {
+ modsingle *sp;
+
+ /*
+ * Process a stand-alone child, and fall through
+ * to dealing with it's parent.
+ */
+ sp = mod_callabletosingle(c);
+
+ result = call_modsingle(c->method, sp, request);
+ RDEBUG2("[%s] = %s", c->name ? c->name : "",
+ fr_int2str(mod_rcode_table, result, "<invalid>"));
+ goto calculate_result;
+ } /* MOD_SINGLE */
+
+#ifdef WITH_UNLANG
+ /*
+ * Update attribute(s)
+ */
+ if (c->type == MOD_UPDATE) {
+ int rcode;
+ modgroup *g = mod_callabletogroup(c);
+ vp_map_t *map;
+
+ MOD_LOG_OPEN_BRACE;
+ RINDENT();
+ for (map = g->map; map != NULL; map = map->next) {
+ rcode = map_to_request(request, map, map_to_vp, NULL);
+ if (rcode < 0) {
+ result = (rcode == -2) ? RLM_MODULE_INVALID : RLM_MODULE_FAIL;
+ REXDENT();
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ }
+ }
+ REXDENT();
+ result = RLM_MODULE_NOOP;
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ } /* MOD_IF */
+
+ /*
+ * Loop over a set of attributes.
+ */
+ if (c->type == MOD_FOREACH) {
+ int i, foreach_depth = -1;
+ VALUE_PAIR *vps, *vp;
+ modcall_stack_entry_t *next = NULL;
+ vp_cursor_t copy;
+ modgroup *g = mod_callabletogroup(c);
+
+ if (depth >= MODCALL_STACK_MAX) {
+ ERROR("Internal sanity check failed: module stack is too deep");
+ fr_exit(1);
+ }
+
+ /*
+ * Figure out how deep we are in nesting by looking at request_data
+ * stored previously.
+ */
+ for (i = 0; i < 8; i++) {
+ if (!request_data_reference(request, (void *)radius_get_vp, i)) {
+ foreach_depth = i;
+ break;
+ }
+ }
+
+ if (foreach_depth < 0) {
+ REDEBUG("foreach Nesting too deep!");
+ result = RLM_MODULE_FAIL;
+ goto calculate_result;
+ }
+
+ /*
+ * Copy the VPs from the original request, this ensures deterministic
+ * behaviour if someone decides to add or remove VPs in the set were
+ * iterating over.
+ */
+ if (tmpl_copy_vps(request, &vps, request, g->vpt) < 0) { /* nothing to loop over */
+ MOD_LOG_OPEN_BRACE;
+ result = RLM_MODULE_NOOP;
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ }
+
+ rad_assert(vps != NULL);
+ fr_cursor_init(&copy, &vps);
+
+ RDEBUG2("foreach %s ", c->name);
+
+ /*
+ * This is the actual body of the foreach loop
+ */
+ for (vp = fr_cursor_first(&copy);
+ vp != NULL;
+ vp = fr_cursor_next(&copy)) {
+#ifndef NDEBUG
+ if (fr_debug_lvl >= 2) {
+ char buffer[1024];
+
+ vp_prints_value(buffer, sizeof(buffer), vp, '"');
+ RDEBUG2("# Foreach-Variable-%d = %s", foreach_depth, buffer);
+ }
+#endif
+
+ /*
+ * Add the vp to the request, so that
+ * xlat.c, xlat_foreach() can find it.
+ */
+ request_data_add(request, (void *)radius_get_vp, foreach_depth, &vp, false);
+
+ /*
+ * Initialize the childs stack frame.
+ */
+ next = entry + 1;
+ next->c = g->children;
+ next->result = entry->result;
+ next->priority = 0;
+ next->unwind = 0;
+
+ if (!modcall_recurse(request, component, depth + 1, next, true)) {
+ break;
+ }
+
+ /*
+ * We've been asked to unwind to the
+ * enclosing "foreach". We're here, so
+ * we can stop unwinding.
+ */
+ if (next->unwind == MOD_BREAK) {
+ entry->unwind = 0;
+ break;
+ }
+
+ /*
+ * Unwind all the way.
+ */
+ if (next->unwind == MOD_RETURN) {
+ entry->unwind = MOD_RETURN;
+ break;
+ }
+ } /* loop over VPs */
+
+ /*
+ * Free the copied vps and the request data
+ * If we don't remove the request data, something could call
+ * the xlat outside of a foreach loop and trigger a segv.
+ */
+ fr_pair_list_free(&vps);
+ request_data_get(request, (void *)radius_get_vp, foreach_depth);
+
+ rad_assert(next != NULL);
+ result = next->result;
+ priority = next->priority;
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ } /* MOD_FOREACH */
+
+ /*
+ * Break out of a "foreach" loop, or return from a nested
+ * group.
+ */
+ if ((c->type == MOD_BREAK) || (c->type == MOD_RETURN)) {
+ int i;
+ VALUE_PAIR **copy_p;
+
+ RDEBUG2("%s", unlang_keyword[c->type]);
+
+ for (i = 8; i >= 0; i--) {
+ copy_p = request_data_get(request, (void *)radius_get_vp, i);
+ if (copy_p) {
+ if (c->type == MOD_BREAK) {
+ RDEBUG2("# break Foreach-Variable-%d", i);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Leave result / priority on the stack, and stop processing the section.
+ */
+ entry->unwind = c->type;
+ goto finish;
+ } /* MOD_BREAK */
+
+#endif /* WITH_UNLANG */
+
+ /*
+ * Child is a group that has children of it's own.
+ */
+ if ((c->type == MOD_GROUP) || (c->type == MOD_POLICY)
+#ifdef WITH_UNLANG
+ || (c->type == MOD_CASE)
+#endif
+ ) {
+ modgroup *g;
+
+#ifdef WITH_UNLANG
+ do_children:
+#endif
+ g = mod_callabletogroup(c);
+
+ /*
+ * This should really have been caught in the
+ * compiler, and the node never generated. But
+ * doing that requires changing it's API so that
+ * it returns a flag instead of the compiled
+ * MOD_GROUP.
+ */
+ if (!g->children) {
+ if (c->type == MOD_CASE) {
+ result = RLM_MODULE_NOOP;
+ goto calculate_result;
+ }
+
+ RDEBUG2("%s { ... } # empty sub-section is ignored", c->name);
+ goto next_sibling;
+ }
+
+ MOD_LOG_OPEN_BRACE;
+ modcall_child(request, component,
+ depth + 1, entry, g->children,
+ &result, true);
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ } /* MOD_GROUP */
+
+#ifdef WITH_UNLANG
+ if (c->type == MOD_SWITCH) {
+ modcallable *this, *found, *null_case;
+ modgroup *g, *h;
+ fr_cond_t cond;
+ value_data_t data;
+ vp_map_t map;
+ vp_tmpl_t vpt;
+
+ MOD_LOG_OPEN_BRACE;
+
+ g = mod_callabletogroup(c);
+
+ memset(&cond, 0, sizeof(cond));
+ memset(&map, 0, sizeof(map));
+
+ cond.type = COND_TYPE_MAP;
+ cond.data.map = &map;
+
+ map.op = T_OP_CMP_EQ;
+ map.ci = cf_section_to_item(g->cs);
+
+ rad_assert(g->vpt != NULL);
+
+ null_case = found = NULL;
+ data.ptr = NULL;
+
+ /*
+ * The attribute doesn't exist. We can skip
+ * directly to the default 'case' statement.
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) && (tmpl_find_vp(NULL, request, g->vpt) < 0)) {
+ find_null_case:
+ for (this = g->children; this; this = this->next) {
+ rad_assert(this->type == MOD_CASE);
+
+ h = mod_callabletogroup(this);
+ if (h->vpt) continue;
+
+ found = this;
+ break;
+ }
+
+ goto do_null_case;
+ }
+
+ /*
+ * Expand the template if necessary, so that it
+ * is evaluated once instead of for each 'case'
+ * statement.
+ */
+ if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
+ (g->vpt->type == TMPL_TYPE_XLAT) ||
+ (g->vpt->type == TMPL_TYPE_EXEC)) {
+ char *p;
+ ssize_t len;
+
+ len = tmpl_aexpand(request, &p, request, g->vpt, NULL, NULL);
+ if (len < 0) goto find_null_case;
+ data.strvalue = p;
+ tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, len);
+ }
+
+ /*
+ * Find either the exact matching name, or the
+ * "case {...}" statement.
+ */
+ for (this = g->children; this; this = this->next) {
+ rad_assert(this->type == MOD_CASE);
+
+ h = mod_callabletogroup(this);
+
+ /*
+ * Remember the default case
+ */
+ if (!h->vpt) {
+ if (!null_case) null_case = this;
+ continue;
+ }
+
+ /*
+ * If we're switching over an attribute
+ * AND we haven't pre-parsed the data for
+ * the case statement, then cast the data
+ * to the type of the attribute.
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) &&
+ (h->vpt->type != TMPL_TYPE_DATA)) {
+ map.rhs = g->vpt;
+ map.lhs = h->vpt;
+ cond.cast = g->vpt->tmpl_da;
+
+ /*
+ * Remove unnecessary casting.
+ */
+ if ((h->vpt->type == TMPL_TYPE_ATTR) &&
+ (g->vpt->tmpl_da->type == h->vpt->tmpl_da->type)) {
+ cond.cast = NULL;
+ }
+
+ /*
+ * Use the pre-expanded string.
+ */
+ } else if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
+ (g->vpt->type == TMPL_TYPE_XLAT) ||
+ (g->vpt->type == TMPL_TYPE_EXEC)) {
+ map.rhs = h->vpt;
+ map.lhs = &vpt;
+ cond.cast = NULL;
+
+ /*
+ * Else evaluate the 'switch' statement.
+ */
+ } else {
+ map.rhs = h->vpt;
+ map.lhs = g->vpt;
+ cond.cast = NULL;
+ }
+
+ if (radius_evaluate_map(request, RLM_MODULE_UNKNOWN, 0,
+ &cond) == 1) {
+ found = this;
+ break;
+ }
+ }
+
+ if (!found) found = null_case;
+
+ do_null_case:
+ talloc_free(data.ptr);
+ modcall_child(request, component, depth + 1, entry, found, &result, true);
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ } /* MOD_SWITCH */
+#endif
+
+ if ((c->type == MOD_LOAD_BALANCE) ||
+ (c->type == MOD_REDUNDANT_LOAD_BALANCE)) {
+ uint32_t count = 0;
+ modcallable *this, *found;
+ modgroup *g;
+
+ MOD_LOG_OPEN_BRACE;
+
+ g = mod_callabletogroup(c);
+ found = g->children;
+ rad_assert(g->children != NULL);
+
+ /*
+ * Choose a child at random.
+ */
+ for (this = g->children; this; this = this->next) {
+ count++;
+
+ if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
+ found = this;
+ }
+ }
+
+ if (c->type == MOD_LOAD_BALANCE) {
+ modcall_child(request, component,
+ depth + 1, entry, found,
+ &result, false);
+
+ } else {
+ this = found;
+
+ do {
+ modcall_child(request, component,
+ depth + 1, entry, this,
+ &result, false);
+ if (this->actions[result] == MOD_ACTION_RETURN) {
+ priority = -1;
+ break;
+ }
+
+ this = this->next;
+ if (!this) this = g->children;
+ } while (this != found);
+ }
+ MOD_LOG_CLOSE_BRACE;
+ goto calculate_result;
+ } /* MOD_LOAD_BALANCE */
+
+ /*
+ * Reference another virtual server.
+ *
+ * This should really be deleted, and replaced with a
+ * more abstracted / functional version.
+ */
+ if (c->type == MOD_REFERENCE) {
+ modref *mr = mod_callabletoref(c);
+ char const *server = request->server;
+
+ if (server == mr->ref_name) {
+ RWDEBUG("Suppressing recursive call to server %s", server);
+ goto next_sibling;
+ }
+
+ request->server = mr->ref_name;
+ RDEBUG("server %s { # nested call", mr->ref_name);
+ result = indexed_modcall(component, 0, request);
+ RDEBUG("} # server %s with nested call", mr->ref_name);
+ request->server = server;
+ goto calculate_result;
+ } /* MOD_REFERENCE */
+
+ /*
+ * xlat a string without doing anything else
+ *
+ * This should really be deleted, and replaced with a
+ * more abstracted / functional version.
+ */
+ if (c->type == MOD_XLAT) {
+ modxlat *mx = mod_callabletoxlat(c);
+ char buffer[128];
+
+ if (!mx->exec) {
+ radius_xlat(buffer, sizeof(buffer), request, mx->xlat_name, NULL, NULL);
+ } else {
+ RDEBUG("`%s`", mx->xlat_name);
+ radius_exec_program(request, NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
+ false, true, EXEC_TIMEOUT);
+ }
+
+ goto next_sibling;
+ } /* MOD_XLAT */
+
+ /*
+ * Add new module types here.
+ */
+
+calculate_result:
+#if 0
+ RDEBUG("(%s, %d) ? (%s, %d)",
+ fr_int2str(mod_rcode_table, result, "<invalid>"),
+ priority,
+ fr_int2str(mod_rcode_table, entry->result, "<invalid>"),
+ entry->priority);
+#endif
+
+
+ rad_assert(result != RLM_MODULE_UNKNOWN);
+
+ /*
+ * The child's action says return. Do so.
+ */
+ if ((c->actions[result] == MOD_ACTION_RETURN) &&
+ (priority <= 0)) {
+ entry->result = result;
+ goto finish;
+ }
+
+ /*
+ * If "reject", break out of the loop and return
+ * reject.
+ */
+ if (c->actions[result] == MOD_ACTION_REJECT) {
+ entry->result = RLM_MODULE_REJECT;
+ goto finish;
+ }
+
+ /*
+ * The array holds a default priority for this return
+ * code. Grab it in preference to any unset priority.
+ */
+ if (priority < 0) {
+ priority = c->actions[result];
+ }
+
+ /*
+ * We're higher than any previous priority, remember this
+ * return code and priority.
+ */
+ if (priority > entry->priority) {
+ entry->result = result;
+ entry->priority = priority;
+ }
+
+#ifdef WITH_UNLANG
+ /*
+ * If we're processing a "case" statement, we return once
+ * it's done, rather than going to the next "case" statement.
+ */
+ if (c->type == MOD_CASE) goto finish;
+#endif
+
+ /*
+ * If we've been told to stop processing
+ * it, do so.
+ */
+ if (entry->unwind == MOD_BREAK) {
+ RDEBUG2("# unwind to enclosing foreach");
+ goto finish;
+ }
+
+ if (entry->unwind == MOD_RETURN) {
+ goto finish;
+ }
+
+next_sibling:
+ if (do_next_sibling) {
+ entry->c = entry->c->next;
+
+ if (entry->c) goto redo;
+ }
+
+finish:
+ /*
+ * And we're done!
+ */
+ REXDENT();
+ return true;
+}
+
+
+/** Call a module, iteratively, with a local stack, rather than recursively
+ *
+ * What did Paul Graham say about Lisp...?
+ */
+int modcall(rlm_components_t component, modcallable *c, REQUEST *request)
+{
+ modcall_stack_entry_t stack[MODCALL_STACK_MAX];
+
+#ifndef NDEBUG
+ memset(stack, 0, sizeof(stack));
+#endif
+ /*
+ * Set up the initial stack frame.
+ */
+ stack[0].c = c;
+ stack[0].result = default_component_results[component];
+ stack[0].priority = 0;
+ stack[0].unwind = 0;
+
+ /*
+ * Call the main handler.
+ */
+ if (!modcall_recurse(request, component, 0, &stack[0], true)) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Return the result.
+ */
+ return stack[0].result;
+}
+
+
+#if 0
+static char const *action2str(int action)
+{
+ static char buf[32];
+ if(action==MOD_ACTION_RETURN)
+ return "return";
+ if(action==MOD_ACTION_REJECT)
+ return "reject";
+ snprintf(buf, sizeof buf, "%d", action);
+ return buf;
+}
+
+/* If you suspect a bug in the parser, you'll want to use these dump
+ * functions. dump_tree should reproduce a whole tree exactly as it was found
+ * in radiusd.conf, but in long form (all actions explicitly defined) */
+static void dump_mc(modcallable *c, int indent)
+{
+ int i;
+
+ if(c->type==MOD_SINGLE) {
+ modsingle *single = mod_callabletosingle(c);
+ DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
+ single->modinst->name);
+ } else if ((c->type > MOD_SINGLE) && (c->type <= MOD_POLICY)) {
+ modgroup *g = mod_callabletogroup(c);
+ modcallable *p;
+ DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
+ unlang_keyword[c->type]);
+ for(p = g->children;p;p = p->next)
+ dump_mc(p, indent+1);
+ } /* else ignore it for now */
+
+ for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
+ DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
+ fr_int2str(mod_rcode_table, i, "<invalid>"),
+ action2str(c->actions[i]));
+ }
+
+ DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
+}
+
+static void dump_tree(rlm_components_t comp, modcallable *c)
+{
+ DEBUG("[%s]", comp2str[comp]);
+ dump_mc(c, 0);
+}
+#else
+#define dump_tree(a, b)
+#endif
+
+/* These are the default actions. For each component, the group{} block
+ * behaves like the code from the old module_*() function. redundant{}
+ * are based on my guesses of what they will be used for. --Pac. */
+static const int
+defaultactions[MOD_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
+{
+ /* authenticate */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ 1, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ 1, /* noop */
+ 1 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* authorize */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* preacct */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 2, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ 1, /* noop */
+ 3 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* accounting */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 2, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ 1, /* noop */
+ 3 /* updated */
+ },
+ /* redundant */
+ {
+ 1, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ 1, /* invalid */
+ 1, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ }
+ },
+ /* checksimul */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* pre-proxy */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* post-proxy */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* post-auth */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ }
+#ifdef WITH_COA
+ ,
+ /* recv-coa */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ },
+ /* send-coa */
+ {
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 3, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 4 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+ }
+#endif
+};
+
+static const int authtype_actions[GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
+{
+ /* group */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ MOD_ACTION_RETURN, /* fail */
+ 4, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ 1, /* notfound */
+ 2, /* noop */
+ 3 /* updated */
+ },
+ /* redundant */
+ {
+ MOD_ACTION_RETURN, /* reject */
+ 1, /* fail */
+ MOD_ACTION_RETURN, /* ok */
+ MOD_ACTION_RETURN, /* handled */
+ MOD_ACTION_RETURN, /* invalid */
+ MOD_ACTION_RETURN, /* userlock */
+ MOD_ACTION_RETURN, /* notfound */
+ MOD_ACTION_RETURN, /* noop */
+ MOD_ACTION_RETURN /* updated */
+ }
+};
+
+/** Validate and fixup a map that's part of an update section.
+ *
+ * @param map to validate.
+ * @param ctx data to pass to fixup function (currently unused).
+ * @return 0 if valid else -1.
+ */
+int modcall_fixup_update(vp_map_t *map, UNUSED void *ctx)
+{
+ CONF_PAIR *cp = cf_item_to_pair(map->ci);
+ /*
+ * Anal-retentive checks.
+ */
+ if (DEBUG_ENABLED3) {
+ if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->lhs->name[0] != '&')) {
+ WARN("%s[%d]: Please change attribute reference to '&%s %s ...'",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ map->lhs->name, fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ }
+
+ if ((map->rhs->type == TMPL_TYPE_ATTR) && (map->rhs->name[0] != '&')) {
+ WARN("%s[%d]: Please change attribute reference to '... %s &%s'",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ fr_int2str(fr_tokens, map->op, "<INVALID>"), map->rhs->name);
+ }
+ }
+
+ /*
+ * Values used by unary operators should be literal ANY
+ *
+ * We then free the template and alloc a NULL one instead.
+ */
+ if (map->op == T_OP_CMP_FALSE) {
+ if ((map->rhs->type != TMPL_TYPE_LITERAL) || (strcmp(map->rhs->name, "ANY") != 0)) {
+ WARN("%s[%d] Wildcard deletion MUST use '!* ANY'",
+ cf_pair_filename(cp), cf_pair_lineno(cp));
+ }
+
+ TALLOC_FREE(map->rhs);
+
+ map->rhs = tmpl_alloc(map, TMPL_TYPE_NULL, NULL, 0);
+ }
+
+ /*
+ * Lots of sanity checks for insane people...
+ */
+
+ /*
+ * What exactly where you expecting to happen here?
+ */
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ (map->rhs->type == TMPL_TYPE_LIST)) {
+ cf_log_err(map->ci, "Can't copy list into an attribute");
+ return -1;
+ }
+
+ /*
+ * Depending on the attribute type, some operators are disallowed.
+ */
+ if ((map->lhs->type == TMPL_TYPE_ATTR) && (!fr_assignment_op[map->op] && !fr_equality_op[map->op])) {
+ cf_log_err(map->ci, "Invalid operator \"%s\" in update section. "
+ "Only assignment or filter operators are allowed",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ return -1;
+ }
+
+ if (map->lhs->type == TMPL_TYPE_LIST) {
+ /*
+ * Can't copy an xlat expansion or literal into a list,
+ * we don't know what type of attribute we'd need
+ * to create.
+ *
+ * The only exception is where were using a unary
+ * operator like !*.
+ */
+ if (map->op != T_OP_CMP_FALSE) switch (map->rhs->type) {
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_LITERAL:
+ cf_log_err(map->ci, "Can't copy value into list (we don't know which attribute to create)");
+ return -1;
+
+ default:
+ break;
+ }
+
+ /*
+ * Only += and :=, and !*, and ^= operators are supported
+ * for lists.
+ */
+ switch (map->op) {
+ case T_OP_CMP_FALSE:
+ break;
+
+ case T_OP_ADD:
+ if ((map->rhs->type != TMPL_TYPE_LIST) &&
+ (map->rhs->type != TMPL_TYPE_EXEC)) {
+ cf_log_err(map->ci, "Invalid source for list assignment '%s += ...'", map->lhs->name);
+ return -1;
+ }
+ break;
+
+ case T_OP_SET:
+ if (map->rhs->type == TMPL_TYPE_EXEC) {
+ WARN("%s[%d]: Please change ':=' to '=' for list assignment",
+ cf_pair_filename(cp), cf_pair_lineno(cp));
+ }
+
+ if (map->rhs->type != TMPL_TYPE_LIST) {
+ cf_log_err(map->ci, "Invalid source for list assignment '%s := ...'", map->lhs->name);
+ return -1;
+ }
+ break;
+
+ case T_OP_EQ:
+ if (map->rhs->type != TMPL_TYPE_EXEC) {
+ cf_log_err(map->ci, "Invalid source for list assignment '%s = ...'", map->lhs->name);
+ return -1;
+ }
+ break;
+
+ case T_OP_PREPEND:
+ if ((map->rhs->type != TMPL_TYPE_LIST) &&
+ (map->rhs->type != TMPL_TYPE_EXEC)) {
+ cf_log_err(map->ci, "Invalid source for list assignment '%s ^= ...'", map->lhs->name);
+ return -1;
+ }
+ break;
+
+ default:
+ cf_log_err(map->ci, "Operator \"%s\" not allowed for list assignment",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ return -1;
+ }
+ }
+
+ /*
+ * If the map has a unary operator there's no further
+ * processing we need to, as RHS is unused.
+ */
+ if (map->op == T_OP_CMP_FALSE) return 0;
+
+ /*
+ * If LHS is an attribute, and RHS is a literal, we can
+ * preparse the information into a TMPL_TYPE_DATA.
+ *
+ * Unless it's a unary operator in which case we
+ * ignore map->rhs.
+ */
+ if ((map->lhs->type == TMPL_TYPE_ATTR) && (map->rhs->type == TMPL_TYPE_LITERAL)) {
+ /*
+ * It's a literal string, just copy it.
+ * Don't escape anything.
+ */
+ if (!cf_new_escape &&
+ (map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
+ (cf_pair_value_type(cp) == T_SINGLE_QUOTED_STRING)) {
+ tmpl_cast_in_place_str(map->rhs);
+
+ } else {
+ /*
+ * RHS is hex, try to parse it as
+ * type-specific data.
+ */
+ if (map->lhs->auto_converted &&
+ (map->rhs->name[0] == '0') && (map->rhs->name[1] == 'x') &&
+ (map->rhs->len > 2) && ((map->rhs->len & 0x01) == 0)) {
+ vp_tmpl_t *vpt = map->rhs;
+ map->rhs = NULL;
+
+ if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
+ map->rhs = vpt;
+ cf_log_err(map->ci, "Cannot parse RHS hex as the data type of the attribute %s", map->lhs->tmpl_da->name);
+ return -1;
+ }
+ talloc_free(vpt);
+
+ } else if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) {
+ cf_log_err(map->ci, "%s", fr_strerror());
+ return -1;
+ }
+
+ /*
+ * Fixup LHS da if it doesn't match the type
+ * of the RHS.
+ */
+ if (map->lhs->tmpl_da->type != map->rhs->tmpl_data_type) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbytype(map->lhs->tmpl_da->attr, map->lhs->tmpl_da->vendor,
+ map->rhs->tmpl_data_type);
+ if (!da) {
+ cf_log_err(map->ci, "Cannot find %s variant of attribute \"%s\"",
+ fr_int2str(dict_attr_types, map->rhs->tmpl_data_type,
+ "<INVALID>"), map->lhs->tmpl_da->name);
+ return -1;
+ }
+ map->lhs->tmpl_da = da;
+ }
+ }
+ } /* else we can't precompile the data */
+
+ return 0;
+}
+
+
+#ifdef WITH_UNLANG
+static modcallable *do_compile_modupdate(modcallable *parent, rlm_components_t component,
+ CONF_SECTION *cs, char const *name2)
+{
+ int rcode;
+ modgroup *g;
+ modcallable *csingle;
+
+ vp_map_t *head;
+
+ /*
+ * This looks at cs->name2 to determine which list to update
+ */
+ rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
+ if (rcode < 0) return NULL; /* message already printed */
+ if (!head) {
+ cf_log_err_cs(cs, "'update' sections cannot be empty");
+ return NULL;
+ }
+
+ g = talloc_zero(parent, modgroup);
+ csingle = mod_grouptocallable(g);
+
+ csingle->parent = parent;
+ csingle->next = NULL;
+
+ if (name2) {
+ csingle->name = name2;
+ } else {
+ csingle->name = "";
+ }
+ csingle->type = MOD_UPDATE;
+ csingle->method = component;
+
+ memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
+ sizeof(csingle->actions));
+
+ g->grouptype = GROUPTYPE_SIMPLE;
+ g->children = NULL;
+ g->cs = cs;
+ g->map = talloc_steal(g, head);
+
+ return csingle;
+}
+
+
+static modcallable *do_compile_modswitch (modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
+{
+ CONF_ITEM *ci;
+ FR_TOKEN type;
+ char const *name2;
+ bool had_seen_default = false;
+ modcallable *csingle;
+ modgroup *g;
+ ssize_t slen;
+ vp_tmpl_t *vpt;
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err_cs(cs, "You must specify a variable to switch over for 'switch'");
+ return NULL;
+ }
+
+ if (!cf_item_find_next(cs, NULL)) {
+ cf_log_err_cs(cs, "'switch' statements cannot be empty");
+ return NULL;
+ }
+
+ /*
+ * Create the template. If we fail, AND it's a bare word
+ * with &Foo-Bar, it MAY be an attribute defined by a
+ * module. Allow it for now. The pass2 checks below
+ * will fix it up.
+ */
+ type = cf_section_name2_type(cs);
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err_cs(cs, "Syntax error");
+ cf_log_err_cs(cs, "%s", name2);
+ cf_log_err_cs(cs, "%s^ %s", spaces, text);
+
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return NULL;
+ }
+
+ /*
+ * Otherwise a NULL vpt may refer to an attribute defined
+ * by a module. That is checked in pass 2.
+ */
+
+ if (vpt->type == TMPL_TYPE_LIST) {
+ cf_log_err_cs(cs, "Syntax error: Cannot switch over list '%s'", name2);
+ return NULL;
+ }
+
+ /*
+ * Warn about confusing things.
+ */
+ if ((vpt->type == TMPL_TYPE_ATTR) && (*name2 != '&')) {
+ WARN("%s[%d]: Please change \"switch %s\" to \"switch &%s\"",
+ cf_section_filename(cs), cf_section_lineno(cs),
+ name2, name2);
+ }
+
+ /*
+ * Walk through the children of the switch section,
+ * ensuring that they're all 'case' statements
+ */
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ CONF_SECTION *subcs;
+ char const *name1;
+
+ if (!cf_item_is_section(ci)) {
+ if (!cf_item_is_pair(ci)) continue;
+
+ cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ subcs = cf_item_to_section(ci); /* can't return NULL */
+ name1 = cf_section_name1(subcs);
+
+ if (strcmp(name1, "case") != 0) {
+ cf_log_err(ci, "\"switch\" sections can only have \"case\" subsections");
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ name2 = cf_section_name2(subcs);
+ if (!name2) {
+ if (!had_seen_default) {
+ had_seen_default = true;
+ continue;
+ }
+
+ cf_log_err(ci, "Cannot have two 'default' case statements");
+ talloc_free(vpt);
+ return NULL;
+ }
+ }
+
+ csingle = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ GROUPTYPE_SIMPLE,
+ MOD_SWITCH);
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = talloc_steal(g, vpt);
+
+ return csingle;
+}
+
+static modcallable *do_compile_modcase(modcallable *parent, rlm_components_t component, CONF_SECTION *cs)
+{
+ int i;
+ char const *name2;
+ modcallable *csingle;
+ modgroup *g;
+ vp_tmpl_t *vpt;
+
+ if (!parent || (parent->type != MOD_SWITCH)) {
+ cf_log_err_cs(cs, "\"case\" statements may only appear within a \"switch\" section");
+ return NULL;
+ }
+
+ /*
+ * case THING means "match THING"
+ * case means "match anything"
+ */
+ name2 = cf_section_name2(cs);
+ if (name2) {
+ ssize_t slen;
+ FR_TOKEN type;
+
+ type = cf_section_name2_type(cs);
+
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err_cs(cs, "Syntax error");
+ cf_log_err_cs(cs, "%s", name2);
+ cf_log_err_cs(cs, "%s^ %s", spaces, text);
+
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return NULL;
+ }
+
+ if (vpt->type == TMPL_TYPE_LIST) {
+ cf_log_err_cs(cs, "Syntax error: Cannot match list '%s'", name2);
+ return NULL;
+ }
+
+ /*
+ * Otherwise a NULL vpt may refer to an attribute defined
+ * by a module. That is checked in pass 2.
+ */
+
+ } else {
+ vpt = NULL;
+ }
+
+ csingle = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ GROUPTYPE_SIMPLE,
+ MOD_CASE);
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ /*
+ * The interpretor expects this to be NULL for the
+ * default case. do_compile_modgroup sets it to name2,
+ * unless name2 is NULL, in which case it sets it to name1.
+ */
+ csingle->name = name2;
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = talloc_steal(g, vpt);
+
+ /*
+ * Set all of it's codes to return, so that
+ * when we pick a 'case' statement, we don't
+ * fall through to processing the next one.
+ */
+ for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
+ csingle->actions[i] = MOD_ACTION_RETURN;
+ }
+
+ return csingle;
+}
+
+static modcallable *do_compile_modforeach(modcallable *parent,
+ rlm_components_t component, CONF_SECTION *cs)
+{
+ FR_TOKEN type;
+ char const *name2;
+ modcallable *csingle;
+ modgroup *g;
+ ssize_t slen;
+ vp_tmpl_t *vpt;
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err_cs(cs,
+ "You must specify an attribute to loop over in 'foreach'");
+ return NULL;
+ }
+
+ if (!cf_item_find_next(cs, NULL)) {
+ cf_log_err_cs(cs, "'foreach' blocks cannot be empty");
+ return NULL;
+ }
+
+ /*
+ * Create the template. If we fail, AND it's a bare word
+ * with &Foo-Bar, it MAY be an attribute defined by a
+ * module. Allow it for now. The pass2 checks below
+ * will fix it up.
+ */
+ type = cf_section_name2_type(cs);
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(cs, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err_cs(cs, "Syntax error");
+ cf_log_err_cs(cs, "%s", name2);
+ cf_log_err_cs(cs, "%s^ %s", spaces, text);
+
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return NULL;
+ }
+
+ /*
+ * If we don't have a negative return code, we must have a vpt
+ * (mostly to quiet coverity).
+ */
+ rad_assert(vpt);
+
+ if ((vpt->type != TMPL_TYPE_ATTR) && (vpt->type != TMPL_TYPE_LIST)) {
+ cf_log_err_cs(cs, "MUST use attribute or list reference in 'foreach'");
+ return NULL;
+ }
+
+ /*
+ * Fix up the template to iterate over all instances of
+ * the attribute. In a perfect consistent world, users would do
+ * foreach &attr[*], but that's taking the consistency thing a bit far.
+ */
+ vpt->tmpl_num = NUM_ALL;
+
+ csingle = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+ MOD_FOREACH);
+
+ if (!csingle) {
+ talloc_free(vpt);
+ return NULL;
+ }
+
+ g = mod_callabletogroup(csingle);
+ g->vpt = vpt;
+
+ return csingle;
+}
+
+static modcallable *do_compile_modbreak(modcallable *parent,
+ rlm_components_t component, CONF_ITEM const *ci)
+{
+ CONF_SECTION const *cs = NULL;
+
+ for (cs = cf_item_parent(ci);
+ cs != NULL;
+ cs = cf_item_parent(cf_section_to_item(cs))) {
+ if (strcmp(cf_section_name1(cs), "foreach") == 0) {
+ break;
+ }
+ }
+
+ if (!cs) {
+ cf_log_err(ci, "'break' can only be used in a 'foreach' section");
+ return NULL;
+ }
+
+ return do_compile_modgroup(parent, component, NULL,
+ GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+ MOD_BREAK);
+}
+#endif
+
+static modcallable *do_compile_modserver(modcallable *parent,
+ rlm_components_t component, CONF_ITEM *ci,
+ char const *name,
+ CONF_SECTION *cs,
+ char const *server)
+{
+ modcallable *csingle;
+ CONF_SECTION *subcs;
+ modref *mr;
+
+ subcs = cf_section_sub_find_name2(cs, comp2str[component], NULL);
+ if (!subcs) {
+ cf_log_err(ci, "Server %s has no %s section",
+ server, comp2str[component]);
+ return NULL;
+ }
+
+ mr = talloc_zero(parent, modref);
+
+ csingle = mod_reftocallable(mr);
+ csingle->parent = parent;
+ csingle->next = NULL;
+ csingle->name = name;
+ csingle->type = MOD_REFERENCE;
+ csingle->method = component;
+
+ memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
+ sizeof(csingle->actions));
+
+ mr->ref_name = strdup(server);
+ mr->ref_cs = cs;
+
+ return csingle;
+}
+
+static modcallable *do_compile_modxlat(modcallable *parent,
+ rlm_components_t component, char const *fmt)
+{
+ modcallable *csingle;
+ modxlat *mx;
+
+ mx = talloc_zero(parent, modxlat);
+
+ csingle = mod_xlattocallable(mx);
+ csingle->parent = parent;
+ csingle->next = NULL;
+ csingle->name = "expand";
+ csingle->type = MOD_XLAT;
+ csingle->method = component;
+
+ memcpy(csingle->actions, defaultactions[component][GROUPTYPE_SIMPLE],
+ sizeof(csingle->actions));
+
+ mx->xlat_name = talloc_strdup(mx, fmt);
+ if (!mx->xlat_name) {
+ talloc_free(mx);
+ return NULL;
+ }
+
+ if (fmt[0] != '%') {
+ char *p;
+ mx->exec = true;
+
+ strcpy(mx->xlat_name, fmt + 1);
+ p = strrchr(mx->xlat_name, '`');
+ if (p) *p = '\0';
+ }
+
+ return csingle;
+}
+
+/*
+ * redundant, etc. can refer to modules or groups, but not much else.
+ */
+static int all_children_are_modules(CONF_SECTION *cs, char const *name)
+{
+ CONF_ITEM *ci;
+
+ for (ci=cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(cs, ci)) {
+ /*
+ * If we're a redundant, etc. group, then the
+ * intention is to call modules, rather than
+ * processing logic. These checks aren't
+ * *strictly* necessary, but they keep the users
+ * from doing crazy things.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *subcs = cf_item_to_section(ci);
+ char const *name1 = cf_section_name1(subcs);
+
+ if ((strcmp(name1, "if") == 0) ||
+ (strcmp(name1, "else") == 0) ||
+ (strcmp(name1, "elsif") == 0) ||
+ (strcmp(name1, "update") == 0) ||
+ (strcmp(name1, "switch") == 0) ||
+ (strcmp(name1, "case") == 0)) {
+ cf_log_err(ci, "%s sections cannot contain a \"%s\" statement",
+ name, name1);
+ return 0;
+ }
+ continue;
+ }
+
+ if (cf_item_is_pair(ci)) {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+ if (cf_pair_value(cp) != NULL) {
+ cf_log_err(ci,
+ "Entry with no value is invalid");
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/** Load a named module from "instantiate" or "policy".
+ *
+ * If it's "foo.method", look for "foo", and return "method" as the method
+ * we wish to use, instead of the input component.
+ *
+ * @param[out] pcomponent Where to write the method we found, if any. If no method is specified
+ * will be set to MOD_COUNT.
+ * @param[in] real_name Complete name string e.g. foo.authorize.
+ * @param[in] virtual_name Virtual module name e.g. foo.
+ * @param[in] method_name Method override (may be NULL) or the method name e.g. authorize.
+ * @return the CONF_SECTION specifying the virtual module.
+ */
+static CONF_SECTION *virtual_module_find_cs(rlm_components_t *pcomponent,
+ char const *real_name, char const *virtual_name, char const *method_name)
+{
+ CONF_SECTION *cs, *subcs;
+ rlm_components_t method = *pcomponent;
+ char buffer[256];
+
+ /*
+ * Turn the method name into a method enum.
+ */
+ if (method_name) {
+ rlm_components_t i;
+
+ for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+ if (strcmp(comp2str[i], method_name) == 0) break;
+ }
+
+ if (i != MOD_COUNT) {
+ method = i;
+ } else {
+ method_name = NULL;
+ virtual_name = real_name;
+ }
+ }
+
+ /*
+ * Look for "foo" in the "instantiate" section. If we
+ * find it, AND there's no method name, we've found the
+ * right thing.
+ *
+ * Return it to the caller, with the updated method.
+ */
+ cs = cf_section_find("instantiate");
+ if (cs) {
+ /*
+ * Found "foo". Load it as "foo", or "foo.method".
+ */
+ subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
+ if (subcs) {
+ *pcomponent = method;
+ return subcs;
+ }
+ }
+
+ /*
+ * Look for it in "policy".
+ *
+ * If there's no policy section, we can't do anything else.
+ */
+ cs = cf_section_find("policy");
+ if (!cs) return NULL;
+
+ /*
+ * "foo.authorize" means "load policy "foo" as method "authorize".
+ *
+ * And bail out if there's no policy "foo".
+ */
+ if (method_name) {
+ subcs = cf_section_sub_find_name2(cs, NULL, virtual_name);
+ if (subcs) *pcomponent = method;
+
+ return subcs;
+ }
+
+ /*
+ * "foo" means "look for foo.component" first, to allow
+ * method overrides. If that's not found, just look for
+ * a policy "foo".
+ *
+ */
+ snprintf(buffer, sizeof(buffer), "%s.%s",
+ virtual_name, comp2str[method]);
+ subcs = cf_section_sub_find_name2(cs, NULL, buffer);
+ if (subcs) return subcs;
+
+ return cf_section_sub_find_name2(cs, NULL, virtual_name);
+}
+
+
+/*
+ * Compile one entry of a module call.
+ */
+static modcallable *do_compile_modsingle(modcallable *parent,
+ rlm_components_t component, CONF_ITEM *ci,
+ int grouptype,
+ char const **modname)
+{
+ char const *modrefname, *p;
+ modsingle *single;
+ modcallable *csingle;
+ module_instance_t *this;
+ CONF_SECTION *cs, *subcs, *modules;
+ CONF_SECTION *loop;
+ char const *realname;
+ rlm_components_t method = component;
+
+ if (cf_item_is_section(ci)) {
+ char const *name2;
+
+ cs = cf_item_to_section(ci);
+ modrefname = cf_section_name1(cs);
+ name2 = cf_section_name2(cs);
+ if (!name2) name2 = "";
+
+ /*
+ * group{}, redundant{}, or append{} may appear
+ * where a single module instance was expected.
+ * In that case, we hand it off to
+ * compile_modgroup
+ */
+ if (strcmp(modrefname, "group") == 0) {
+ *modname = name2;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_GROUP);
+
+ } else if (strcmp(modrefname, "redundant") == 0) {
+ *modname = name2;
+
+ if (!all_children_are_modules(cs, modrefname)) {
+ return NULL;
+ }
+
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_REDUNDANT,
+ grouptype, MOD_GROUP);
+
+ } else if (strcmp(modrefname, "load-balance") == 0) {
+ *modname = name2;
+
+ if (!all_children_are_modules(cs, modrefname)) {
+ return NULL;
+ }
+
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_LOAD_BALANCE);
+
+ } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
+ *modname = name2;
+
+ if (!all_children_are_modules(cs, modrefname)) {
+ return NULL;
+ }
+
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_REDUNDANT,
+ grouptype, MOD_REDUNDANT_LOAD_BALANCE);
+
+#ifdef WITH_UNLANG
+ } else if (strcmp(modrefname, "if") == 0) {
+ if (!cf_section_name2(cs)) {
+ cf_log_err(ci, "'if' without condition");
+ return NULL;
+ }
+
+ *modname = name2;
+ csingle= do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_IF);
+ if (!csingle) return NULL;
+ *modname = name2;
+
+ return csingle;
+
+ } else if (strcmp(modrefname, "elsif") == 0) {
+ if (parent &&
+ ((parent->type == MOD_LOAD_BALANCE) ||
+ (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
+ cf_log_err(ci, "'elsif' cannot be used in this section");
+ return NULL;
+ }
+
+ if (!cf_section_name2(cs)) {
+ cf_log_err(ci, "'elsif' without condition");
+ return NULL;
+ }
+
+ *modname = name2;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_ELSIF);
+
+ } else if (strcmp(modrefname, "else") == 0) {
+ if (parent &&
+ ((parent->type == MOD_LOAD_BALANCE) ||
+ (parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
+ cf_log_err(ci, "'else' cannot be used in this section section");
+ return NULL;
+ }
+
+ if (cf_section_name2(cs)) {
+ cf_log_err(ci, "Cannot have conditions on 'else'");
+ return NULL;
+ }
+
+ *modname = name2;
+ return do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_ELSE);
+
+ } else if (strcmp(modrefname, "update") == 0) {
+ *modname = name2;
+
+ return do_compile_modupdate(parent, component, cs,
+ name2);
+
+ } else if (strcmp(modrefname, "switch") == 0) {
+ *modname = name2;
+
+ return do_compile_modswitch (parent, component, cs);
+
+ } else if (strcmp(modrefname, "case") == 0) {
+ *modname = name2;
+
+ return do_compile_modcase(parent, component, cs);
+
+ } else if (strcmp(modrefname, "foreach") == 0) {
+ *modname = name2;
+
+ return do_compile_modforeach(parent, component, cs);
+
+#endif
+ } /* else it's something like sql { fail = 1 ...} */
+
+ } else if (!cf_item_is_pair(ci)) { /* CONF_DATA or some such */
+ return NULL;
+
+ /*
+ * Else it's a module reference, with updated return
+ * codes.
+ */
+ } else {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+ modrefname = cf_pair_attr(cp);
+
+ /*
+ * Actions (ok = 1), etc. are orthogonal to just
+ * about everything else.
+ */
+ if (cf_pair_value(cp) != NULL) {
+ cf_log_err(ci, "Entry is not a reference to a module");
+ return NULL;
+ }
+
+ /*
+ * In-place xlat's via %{...}.
+ *
+ * This should really be removed from the server.
+ */
+ if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
+ (modrefname[0] == '`')) {
+ return do_compile_modxlat(parent, component,
+ modrefname);
+ }
+ }
+
+#ifdef WITH_UNLANG
+ /*
+ * These can't be over-ridden.
+ */
+ if (strcmp(modrefname, "break") == 0) {
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "Invalid use of 'break' as section name.");
+ return NULL;
+ }
+
+ return do_compile_modbreak(parent, component, ci);
+ }
+
+ if (strcmp(modrefname, "return") == 0) {
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "Invalid use of 'return' as section name.");
+ return NULL;
+ }
+
+ return do_compile_modgroup(parent, component, NULL,
+ GROUPTYPE_SIMPLE, GROUPTYPE_SIMPLE,
+ MOD_RETURN);
+ }
+#endif
+
+ /*
+ * Run a virtual server. This is really terrible and
+ * should be deleted.
+ */
+ if (strncmp(modrefname, "server[", 7) == 0) {
+ char buffer[256];
+
+ if (!cf_item_is_pair(ci)) {
+ cf_log_err(ci, "Invalid syntax");
+ return NULL;
+ }
+
+ strlcpy(buffer, modrefname + 7, sizeof(buffer));
+ p = strrchr(buffer, ']');
+ if (!p || p[1] != '\0' || (p == buffer)) {
+ cf_log_err(ci, "Invalid server reference in \"%s\".", modrefname);
+ return NULL;
+ }
+
+ buffer[p - buffer] = '\0';
+
+ cs = cf_section_sub_find_name2(NULL, "server", buffer);
+ if (!cs) {
+ cf_log_err(ci, "No such server \"%s\".", buffer);
+ return NULL;
+ }
+
+ /*
+ * Ignore stupid attempts to over-ride the return
+ * code.
+ */
+ return do_compile_modserver(parent, component, ci,
+ modrefname, cs, buffer);
+ }
+
+ /*
+ * We now have a name. It can be one of two forms. A
+ * bare module name, or a section named for the module,
+ * with over-rides for the return codes.
+ *
+ * The name can refer to a real module, in the "modules"
+ * section. In that case, the name will be either the
+ * first or second name of the sub-section of "modules".
+ *
+ * Or, the name can refer to a policy, in the "policy"
+ * section. In that case, the name will be first name of
+ * the sub-section of "policy". Unless it's a "redudant"
+ * block...
+ *
+ * Or, the name can refer to a "module.method", in which
+ * case we're calling a different method than normal for
+ * this section.
+ *
+ * Or, the name can refer to a virtual module, in the
+ * "instantiate" section. In that case, the name will be
+ * the first of the sub-section of "instantiate". Unless
+ * it's a "redudant" block...
+ *
+ * We try these in sequence, from the bottom up. This is
+ * so that things in "instantiate" and "policy" can
+ * over-ride calls to real modules.
+ */
+
+
+ /*
+ * Try:
+ *
+ * instantiate { ... name { ...} ... }
+ * instantiate { ... name.method { ...} ... }
+ * policy { ... name { .. } .. }
+ * policy { ... name.method { .. } .. }
+ *
+ * The only difference between things in "instantiate"
+ * and "policy" is that "instantiate" will cause modules
+ * to be instantiated in a particular order.
+ */
+ subcs = NULL;
+ p = strrchr(modrefname, '.');
+ if (!p) {
+ subcs = virtual_module_find_cs(&method, modrefname, modrefname, NULL);
+ } else {
+ char buffer[256];
+
+ strlcpy(buffer, modrefname, sizeof(buffer));
+ buffer[p - modrefname] = '\0';
+
+ subcs = virtual_module_find_cs(&method, modrefname, buffer, buffer + (p - modrefname) + 1);
+ }
+
+ /*
+ * Check that we're not creating a loop. We may
+ * be compiling an "sql" module reference inside
+ * of an "sql" policy. If so, we allow the
+ * second "sql" to refer to the module.
+ */
+ for (loop = cf_item_parent(ci);
+ loop && subcs;
+ loop = cf_item_parent(cf_section_to_item(loop))) {
+ if (loop == subcs) {
+ subcs = NULL;
+ }
+ }
+
+ /*
+ * We've found the relevant entry. It MUST be a
+ * sub-section.
+ *
+ * However, it can be a "redundant" block, or just a
+ * section name.
+ */
+ if (subcs) {
+ /*
+ * modules.c takes care of ensuring that this is:
+ *
+ * group foo { ...
+ * load-balance foo { ...
+ * redundant foo { ...
+ * redundant-load-balance foo { ...
+ *
+ * We can just recurs to compile the section as
+ * if it was found here.
+ */
+ if (cf_section_name2(subcs)) {
+ csingle = do_compile_modsingle(parent,
+ method,
+ cf_section_to_item(subcs),
+ grouptype,
+ modname);
+ } else {
+ /*
+ * We have:
+ *
+ * foo { ...
+ *
+ * So we compile it like it was:
+ *
+ * group foo { ...
+ */
+ csingle = do_compile_modgroup(parent,
+ method,
+ subcs,
+ GROUPTYPE_SIMPLE,
+ grouptype, MOD_GROUP);
+ }
+
+ /*
+ * Return the compiled thing if we can.
+ */
+ if (!csingle) return NULL;
+ if (cf_item_is_pair(ci)) return csingle;
+
+ /*
+ * Else we have a reference to a policy, and that reference
+ * over-rides the return codes for the policy!
+ */
+ goto action_override;
+ }
+
+ /*
+ * Not a virtual module. It must be a real module.
+ */
+ modules = cf_section_find("modules");
+ this = NULL;
+ realname = modrefname;
+
+ if (modules) {
+ /*
+ * Try to load the optional module.
+ */
+ if (realname[0] == '-') realname++;
+
+ /*
+ * As of v3, the "modules" section contains
+ * modules we use. Configuration for other
+ * modules belongs in raddb/mods-available/,
+ * which isn't loaded into the "modules" section.
+ */
+ this = module_instantiate_method(modules, realname, &method);
+ if (this) goto allocate_csingle;
+
+ /*
+ * We were asked to MAYBE load it and it
+ * doesn't exist. Return a soft error.
+ */
+ if (realname != modrefname) {
+ *modname = modrefname;
+ return NULL;
+ }
+ }
+
+ /*
+ * Can't de-reference it to anything. Ugh.
+ */
+ *modname = NULL;
+ cf_log_err(ci, "Failed to find \"%s\" as a module or policy.", modrefname);
+ cf_log_err(ci, "Please verify that the configuration exists in %s/mods-enabled/%s.", get_radius_dir(), modrefname);
+ return NULL;
+
+ /*
+ * We know it's all OK, allocate the structures, and fill
+ * them in.
+ */
+allocate_csingle:
+ /*
+ * Check if the module in question has the necessary
+ * component.
+ */
+ if (!this->entry->module->methods[method]) {
+ cf_log_err(ci, "\"%s\" modules aren't allowed in '%s' sections -- they have no such method.", this->entry->module->name,
+ comp2str[method]);
+ return NULL;
+ }
+
+ single = talloc_zero(parent, modsingle);
+ single->modinst = this;
+ *modname = this->entry->module->name;
+
+ csingle = mod_singletocallable(single);
+ csingle->parent = parent;
+ csingle->next = NULL;
+ if (!parent || (component != MOD_AUTHENTICATE)) {
+ memcpy(csingle->actions, defaultactions[component][grouptype],
+ sizeof csingle->actions);
+ } else { /* inside Auth-Type has different rules */
+ memcpy(csingle->actions, authtype_actions[grouptype],
+ sizeof csingle->actions);
+ }
+ rad_assert(modrefname != NULL);
+ csingle->name = realname;
+ csingle->type = MOD_SINGLE;
+ csingle->method = method;
+
+action_override:
+ /*
+ * Over-ride the default return codes of the module.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_ITEM *csi;
+
+ cs = cf_item_to_section(ci);
+ for (csi=cf_item_find_next(cs, NULL);
+ csi != NULL;
+ csi=cf_item_find_next(cs, csi)) {
+
+ if (cf_item_is_section(csi)) {
+ cf_log_err(csi, "Subsection of module instance call not allowed");
+ talloc_free(csingle);
+ return NULL;
+ }
+
+ if (!cf_item_is_pair(csi)) continue;
+
+ if (!compile_action(csingle, cf_item_to_pair(csi))) {
+ talloc_free(csingle);
+ return NULL;
+ }
+ }
+ }
+
+ return csingle;
+}
+
+modcallable *compile_modsingle(TALLOC_CTX *ctx,
+ modcallable **parent,
+ rlm_components_t component, CONF_ITEM *ci,
+ char const **modname)
+{
+ modcallable *ret;
+
+ if (!*parent) {
+ modcallable *c;
+ modgroup *g;
+ CONF_SECTION *parentcs;
+
+ g = talloc_zero(ctx, modgroup);
+ memset(g, 0, sizeof(*g));
+ g->grouptype = GROUPTYPE_SIMPLE;
+ c = mod_grouptocallable(g);
+ c->next = NULL;
+ memcpy(c->actions,
+ defaultactions[component][GROUPTYPE_SIMPLE],
+ sizeof(c->actions));
+
+ parentcs = cf_item_parent(ci);
+ c->name = cf_section_name2(parentcs);
+ if (!c->name) {
+ c->name = cf_section_name1(parentcs);
+ }
+
+ c->type = MOD_GROUP;
+ c->method = component;
+ g->children = NULL;
+
+ *parent = mod_grouptocallable(g);
+ }
+
+ ret = do_compile_modsingle(*parent, component, ci,
+ GROUPTYPE_SIMPLE,
+ modname);
+ dump_tree(component, ret);
+ return ret;
+}
+
+
+/*
+ * Internal compile group code.
+ */
+static modcallable *do_compile_modgroup(modcallable *parent,
+ rlm_components_t component, CONF_SECTION *cs,
+ int grouptype, int parentgrouptype, int mod_type)
+{
+ int i;
+ modgroup *g;
+ modcallable *c;
+ CONF_ITEM *ci;
+
+ g = talloc_zero(parent, modgroup);
+ g->grouptype = grouptype;
+ g->children = NULL;
+ g->cs = cs;
+
+ c = mod_grouptocallable(g);
+ c->parent = parent;
+ c->type = mod_type;
+ c->next = NULL;
+ memset(c->actions, 0, sizeof(c->actions));
+
+ if (!cs) { /* only for "break" and "return" */
+ c->name = "";
+ goto set_codes;
+ }
+
+ /*
+ * Remember the name for printing, etc.
+ *
+ * FIXME: We may also want to put the names into a
+ * rbtree, so that groups can reference each other...
+ */
+ c->name = cf_section_name2(cs);
+ if (!c->name) {
+ c->name = cf_section_name1(cs);
+ if ((strcmp(c->name, "group") == 0) ||
+ (strcmp(c->name, "redundant") == 0)) {
+ c->name = "";
+ } else if (c->type == MOD_GROUP) {
+ c->type = MOD_POLICY;
+ }
+ }
+
+#ifdef WITH_UNLANG
+ /*
+ * Do load-time optimizations
+ */
+ if ((c->type == MOD_IF) || (c->type == MOD_ELSIF) || (c->type == MOD_ELSE)) {
+ modgroup *f, *p;
+
+ rad_assert(parent != NULL);
+
+ if (c->type == MOD_IF) {
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
+ check_if:
+ if (g->cond->type == COND_TYPE_FALSE) {
+ INFO(" # Skipping contents of '%s' as it is always 'false' -- %s:%d",
+ unlang_keyword[g->mc.type],
+ cf_section_filename(g->cs), cf_section_lineno(g->cs));
+ goto set_codes;
+ }
+
+ } else if (c->type == MOD_ELSIF) {
+
+ g->cond = cf_data_find(g->cs, "if");
+ rad_assert(g->cond != NULL);
+
+ rad_assert(parent != NULL);
+ p = mod_callabletogroup(parent);
+
+ if (!p->tail) goto elsif_fail;
+
+ /*
+ * We're in the process of compiling the
+ * section, so the parent's tail is the
+ * previous "if" statement.
+ */
+ f = mod_callabletogroup(p->tail);
+ if ((f->mc.type != MOD_IF) &&
+ (f->mc.type != MOD_ELSIF)) {
+ elsif_fail:
+ cf_log_err_cs(g->cs, "Invalid location for 'elsif'. There is no preceding 'if' statement");
+ talloc_free(g);
+ return NULL;
+ }
+
+ /*
+ * If we took the previous condition, we
+ * don't need to take this one.
+ *
+ * We reset our condition to 'true', so
+ * that subsequent sections can check
+ * that they don't need to be executed.
+ */
+ if (f->cond->type == COND_TYPE_TRUE) {
+ skip_true:
+ INFO(" # Skipping contents of '%s' as previous '%s' is always 'true' -- %s:%d",
+ unlang_keyword[g->mc.type],
+ unlang_keyword[f->mc.type],
+ cf_section_filename(g->cs), cf_section_lineno(g->cs));
+ g->cond = f->cond;
+ goto set_codes;
+ }
+ goto check_if;
+
+ } else {
+ rad_assert(c->type == MOD_ELSE);
+
+ rad_assert(parent != NULL);
+ p = mod_callabletogroup(parent);
+
+ if (!p->tail) goto else_fail;
+
+ f = mod_callabletogroup(p->tail);
+ if ((f->mc.type != MOD_IF) &&
+ (f->mc.type != MOD_ELSIF)) {
+ else_fail:
+ cf_log_err_cs(g->cs, "Invalid location for 'else'. There is no preceding 'if' statement");
+ talloc_free(g);
+ return NULL;
+ }
+
+ /*
+ * If we took the previous condition, we
+ * don't need to take this one.
+ */
+ if (f->cond->type == COND_TYPE_TRUE) goto skip_true;
+ }
+
+ /*
+ * Else we need to compile this section
+ */
+ }
+#endif
+
+ /*
+ * Loop over the children of this group.
+ */
+ for (ci=cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(cs, ci)) {
+
+ /*
+ * Sections are references to other groups, or
+ * to modules with updated return codes.
+ */
+ if (cf_item_is_section(ci)) {
+ char const *junk = NULL;
+ modcallable *single;
+ CONF_SECTION *subcs = cf_item_to_section(ci);
+
+ single = do_compile_modsingle(c, component, ci,
+ grouptype, &junk);
+ if (!single) {
+ cf_log_err(ci, "Failed to parse \"%s\" subsection.",
+ cf_section_name1(subcs));
+ talloc_free(c);
+ return NULL;
+ }
+ add_child(g, single);
+
+ } else if (!cf_item_is_pair(ci)) { /* CONF_DATA */
+ continue;
+
+ } else {
+ char const *attr, *value;
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+
+ attr = cf_pair_attr(cp);
+ value = cf_pair_value(cp);
+
+ /*
+ * A CONF_PAIR is either a module
+ * instance with no actions
+ * specified ...
+ */
+ if (!value) {
+ modcallable *single;
+ char const *junk = NULL;
+
+ single = do_compile_modsingle(c,
+ component,
+ ci,
+ grouptype,
+ &junk);
+ if (!single) {
+ if (cf_item_is_pair(ci) &&
+ cf_pair_attr(cf_item_to_pair(ci))[0] == '-') {
+ continue;
+ }
+
+ cf_log_err(ci,
+ "Failed to parse \"%s\" entry.",
+ attr);
+ talloc_free(c);
+ return NULL;
+ }
+ add_child(g, single);
+
+ /*
+ * Or a module instance with action.
+ */
+ } else if (!compile_action(c, cp)) {
+ talloc_free(c);
+ return NULL;
+ } /* else it worked */
+ }
+ }
+
+set_codes:
+ /*
+ * Set the default actions, if they haven't already been
+ * set.
+ */
+ for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
+ if (!c->actions[i]) {
+ if (!parent || (component != MOD_AUTHENTICATE)) {
+ c->actions[i] = defaultactions[component][parentgrouptype][i];
+ } else { /* inside Auth-Type has different rules */
+ c->actions[i] = authtype_actions[parentgrouptype][i];
+ }
+ }
+ }
+
+ switch (c->type) {
+ default:
+ break;
+
+ case MOD_GROUP:
+ if (grouptype != GROUPTYPE_REDUNDANT) break;
+ /* FALL-THROUGH */
+
+ case MOD_LOAD_BALANCE:
+ case MOD_REDUNDANT_LOAD_BALANCE:
+ if (!g->children) {
+ cf_log_err_cs(g->cs, "%s sections cannot be empty",
+ cf_section_name1(g->cs));
+ talloc_free(c);
+ return NULL;
+ }
+ }
+
+ /*
+ * FIXME: If there are no children, return NULL?
+ */
+ return mod_grouptocallable(g);
+}
+
+modcallable *compile_modgroup(modcallable *parent,
+ rlm_components_t component, CONF_SECTION *cs)
+{
+ modcallable *ret = do_compile_modgroup(parent, component, cs,
+ GROUPTYPE_SIMPLE,
+ GROUPTYPE_SIMPLE, MOD_GROUP);
+
+ if (rad_debug_lvl > 3) {
+ modcall_debug(ret, 2);
+ }
+
+ return ret;
+}
+
+void add_to_modcallable(modcallable *parent, modcallable *this)
+{
+ modgroup *g;
+
+ rad_assert(this != NULL);
+ rad_assert(parent != NULL);
+
+ g = mod_callabletogroup(parent);
+
+ add_child(g, this);
+}
+
+
+#ifdef WITH_UNLANG
+static bool pass2_xlat_compile(CONF_ITEM const *ci, vp_tmpl_t **pvpt, bool convert,
+ DICT_ATTR const *da)
+{
+ ssize_t slen;
+ char *fmt;
+ char const *error;
+ xlat_exp_t *head;
+ vp_tmpl_t *vpt;
+
+ vpt = *pvpt;
+
+ rad_assert(vpt->type == TMPL_TYPE_XLAT);
+
+ fmt = talloc_typed_strdup(vpt, vpt->name);
+ slen = xlat_tokenize(vpt, fmt, &head, &error);
+
+ if (slen < 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
+
+ cf_log_err(ci, "Failed parsing expanded string:");
+ cf_log_err(ci, "%s", text);
+ cf_log_err(ci, "%s^ %s", spaces, error);
+
+ talloc_free(spaces);
+ talloc_free(text);
+ return false;
+ }
+
+ /*
+ * Convert %{Attribute-Name} to &Attribute-Name
+ */
+ if (convert) {
+ vp_tmpl_t *attr;
+
+ attr = xlat_to_tmpl_attr(talloc_parent(vpt), head);
+ if (attr) {
+ /*
+ * If it's a virtual attribute, leave it
+ * alone.
+ */
+ if (attr->tmpl_da->flags.virtual) {
+ talloc_free(attr);
+ return true;
+ }
+
+ /*
+ * If the attribute is of incompatible
+ * type, leave it alone.
+ */
+ if (da && (da->type != attr->tmpl_da->type)) {
+ talloc_free(attr);
+ return true;
+ }
+
+ if (cf_item_is_pair(ci)) {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+
+ WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
+ cf_pair_filename(cp), cf_pair_lineno(cp),
+ attr->name, attr->name);
+ } else {
+ CONF_SECTION *cs = cf_item_to_section(ci);
+
+ WARN("%s[%d]: Please change \"%%{%s}\" to &%s",
+ cf_section_filename(cs), cf_section_lineno(cs),
+ attr->name, attr->name);
+ }
+ TALLOC_FREE(*pvpt);
+ *pvpt = attr;
+ return true;
+ }
+ }
+
+ /*
+ * Re-write it to be a pre-parsed XLAT structure.
+ */
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ vpt->tmpl_xlat = head;
+
+ return true;
+}
+
+
+#ifdef HAVE_REGEX
+static bool pass2_regex_compile(CONF_ITEM const *ci, vp_tmpl_t *vpt)
+{
+ ssize_t slen;
+ regex_t *preg;
+
+ rad_assert(vpt->type == TMPL_TYPE_REGEX);
+
+ /*
+ * It's a dynamic expansion. We can't expand the string,
+ * but we can pre-parse it as an xlat struct. In that
+ * case, we convert it to a pre-compiled XLAT.
+ *
+ * This is a little more complicated than it needs to be
+ * because radius_evaluate_map() keys off of the src
+ * template type, instead of the operators. And, the
+ * pass2_xlat_compile() function expects to get passed an
+ * XLAT instead of a REGEX.
+ */
+ if (strchr(vpt->name, '%')) {
+ vpt->type = TMPL_TYPE_XLAT;
+ return pass2_xlat_compile(ci, &vpt, false, NULL);
+ }
+
+ slen = regex_compile(vpt, &preg, vpt->name, vpt->len,
+ vpt->tmpl_iflag, vpt->tmpl_mflag, true, false);
+ if (slen <= 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(vpt, &spaces, &text, slen, vpt->name);
+
+ cf_log_err(ci, "Invalid regular expression:");
+ cf_log_err(ci, "%s", text);
+ cf_log_err(ci, "%s^ %s", spaces, fr_strerror());
+
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return false;
+ }
+
+ vpt->type = TMPL_TYPE_REGEX_STRUCT;
+ vpt->tmpl_preg = preg;
+
+ return true;
+}
+#endif
+
+static bool pass2_fixup_undefined(CONF_ITEM const *ci, vp_tmpl_t *vpt)
+{
+ DICT_ATTR const *da;
+
+ rad_assert(vpt->type == TMPL_TYPE_ATTR_UNDEFINED);
+
+ da = dict_attrbyname(vpt->tmpl_unknown_name);
+ if (!da) {
+ cf_log_err(ci, "Unknown attribute '%s'", vpt->tmpl_unknown_name);
+ return false;
+ }
+
+ vpt->tmpl_da = da;
+ vpt->type = TMPL_TYPE_ATTR;
+ return true;
+}
+
+static bool pass2_callback(void *ctx, fr_cond_t *c)
+{
+ vp_map_t *map;
+ vp_tmpl_t *vpt;
+
+ /*
+ * These don't get optimized.
+ */
+ if ((c->type == COND_TYPE_TRUE) ||
+ (c->type == COND_TYPE_FALSE)) {
+ return true;
+ }
+
+ /*
+ * Call children.
+ */
+ if (c->type == COND_TYPE_CHILD) return pass2_callback(ctx, c->data.child);
+
+ /*
+ * A few simple checks here.
+ */
+ if (c->type == COND_TYPE_EXISTS) {
+ if (c->data.vpt->type == TMPL_TYPE_XLAT) {
+ return pass2_xlat_compile(c->ci, &c->data.vpt, true, NULL);
+ }
+
+ rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
+
+ /*
+ * The existence check might have been &Foo-Bar,
+ * where Foo-Bar is defined by a module.
+ */
+ if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
+ if (!pass2_fixup_undefined(c->ci, c->data.vpt)) return false;
+ c->pass2_fixup = PASS2_FIXUP_NONE;
+ }
+
+ /*
+ * Convert virtual &Attr-Foo to "%{Attr-Foo}"
+ */
+ vpt = c->data.vpt;
+ if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
+ vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ return true;
+ }
+
+ /*
+ * And tons of complicated checks.
+ */
+ rad_assert(c->type == COND_TYPE_MAP);
+
+ map = c->data.map; /* shorter */
+
+ /*
+ * Auth-Type := foo
+ *
+ * Where "foo" is dynamically defined.
+ */
+ if (c->pass2_fixup == PASS2_FIXUP_TYPE) {
+ if (!dict_valbyname(map->lhs->tmpl_da->attr,
+ map->lhs->tmpl_da->vendor,
+ map->rhs->name)) {
+ cf_log_err(map->ci, "Invalid reference to non-existent %s %s { ... }",
+ map->lhs->tmpl_da->name,
+ map->rhs->name);
+ return false;
+ }
+
+ /*
+ * These guys can't have a paircompare fixup applied.
+ */
+ c->pass2_fixup = PASS2_FIXUP_NONE;
+ return true;
+ }
+
+ if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
+ if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
+ }
+
+ if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
+ }
+
+ c->pass2_fixup = PASS2_FIXUP_NONE;
+ }
+
+ /*
+ * Just in case someone adds a new fixup later.
+ */
+ rad_assert((c->pass2_fixup == PASS2_FIXUP_NONE) ||
+ (c->pass2_fixup == PASS2_PAIRCOMPARE));
+
+ /*
+ * Precompile xlat's
+ */
+ if (map->lhs->type == TMPL_TYPE_XLAT) {
+ /*
+ * Compile the LHS to an attribute reference only
+ * if the RHS is a literal.
+ *
+ * @todo v3.1: allow anything anywhere.
+ */
+ if (map->rhs->type != TMPL_TYPE_LITERAL) {
+ if (!pass2_xlat_compile(map->ci, &map->lhs, false, NULL)) {
+ return false;
+ }
+ } else {
+ if (!pass2_xlat_compile(map->ci, &map->lhs, true, NULL)) {
+ return false;
+ }
+
+ /*
+ * Attribute compared to a literal gets
+ * the literal cast to the data type of
+ * the attribute.
+ *
+ * The code in parser.c did this for
+ *
+ * &Attr == data
+ *
+ * But now we've just converted "%{Attr}"
+ * to &Attr, so we've got to do it again.
+ */
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ (map->rhs->type == TMPL_TYPE_LITERAL)) {
+ /*
+ * RHS is hex, try to parse it as
+ * type-specific data.
+ */
+ if (map->lhs->auto_converted &&
+ (map->rhs->name[0] == '0') && (map->rhs->name[1] == 'x') &&
+ (map->rhs->len > 2) && ((map->rhs->len & 0x01) == 0)) {
+ vpt = map->rhs;
+ map->rhs = NULL;
+
+ if (!map_cast_from_hex(map, T_BARE_WORD, vpt->name)) {
+ map->rhs = vpt;
+ cf_log_err(map->ci, "Cannot parse RHS hex as the data type of the attribute %s", map->lhs->tmpl_da->name);
+ return -1;
+ }
+ talloc_free(vpt);
+
+ } else if ((map->rhs->len > 0) ||
+ (map->op != T_OP_CMP_EQ) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_STRING) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_OCTETS)) {
+
+ if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) {
+ cf_log_err(map->ci, "Failed to parse data type %s from string: %s",
+ fr_int2str(dict_attr_types, map->lhs->tmpl_da->type, "<UNKNOWN>"),
+ map->rhs->name);
+ return false;
+ } /* else the cast was successful */
+
+ } else { /* RHS is empty, it's just a check for empty / non-empty string */
+ vpt = talloc_steal(c, map->lhs);
+ map->lhs = NULL;
+ talloc_free(c->data.map);
+
+ /*
+ * "%{Foo}" == '' ---> !Foo
+ * "%{Foo}" != '' ---> Foo
+ */
+ c->type = COND_TYPE_EXISTS;
+ c->data.vpt = vpt;
+ c->negate = !c->negate;
+
+ WARN("%s[%d]: Please change (\"%%{%s}\" %s '') to %c&%s",
+ cf_section_filename(cf_item_to_section(c->ci)),
+ cf_section_lineno(cf_item_to_section(c->ci)),
+ vpt->name, c->negate ? "==" : "!=",
+ c->negate ? '!' : ' ', vpt->name);
+
+ /*
+ * No more RHS, so we can't do more optimizations
+ */
+ return true;
+ }
+ }
+ }
+ }
+
+ if (map->rhs->type == TMPL_TYPE_XLAT) {
+ /*
+ * Convert the RHS to an attribute reference only
+ * if the LHS is an attribute reference, AND is
+ * of the same type as the RHS.
+ *
+ * We can fix this when the code in evaluate.c
+ * can handle strings on the LHS, and attributes
+ * on the RHS. For now, the code in parser.c
+ * forbids this.
+ */
+ if (map->lhs->type == TMPL_TYPE_ATTR) {
+ DICT_ATTR const *da = c->cast;
+
+ if (!c->cast) da = map->lhs->tmpl_da;
+
+ if (!pass2_xlat_compile(map->ci, &map->rhs, true, da)) {
+ return false;
+ }
+
+ } else {
+ if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
+ return false;
+ }
+ }
+ }
+
+ /*
+ * Convert bare refs to %{Foreach-Variable-N}
+ */
+ if ((map->lhs->type == TMPL_TYPE_LITERAL) &&
+ (strncmp(map->lhs->name, "Foreach-Variable-", 17) == 0)) {
+ char *fmt;
+ ssize_t slen;
+
+ fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
+ slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
+ T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(map->ci, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err(map->ci, "Failed converting %s to xlat", map->lhs->name);
+ cf_log_err(map->ci, "%s", fmt);
+ cf_log_err(map->ci, "%s^ %s", spaces, text);
+
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(fmt);
+
+ return false;
+ }
+ talloc_free(map->lhs);
+ map->lhs = vpt;
+ }
+
+#ifdef HAVE_REGEX
+ if (map->rhs->type == TMPL_TYPE_REGEX) {
+ if (!pass2_regex_compile(map->ci, map->rhs)) {
+ return false;
+ }
+ }
+ rad_assert(map->lhs->type != TMPL_TYPE_REGEX);
+#endif
+
+ /*
+ * Convert &Packet-Type to "%{Packet-Type}", because
+ * these attributes don't really exist. The code to
+ * find an attribute reference doesn't work, but the
+ * xlat code does.
+ */
+ vpt = c->data.map->lhs;
+ if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
+ if (!c->cast) c->cast = vpt->tmpl_da;
+ vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ /*
+ * Convert RHS to expansions, too.
+ */
+ vpt = c->data.map->rhs;
+ if ((vpt->type == TMPL_TYPE_ATTR) && vpt->tmpl_da->flags.virtual) {
+ vpt->tmpl_xlat = xlat_from_tmpl_attr(vpt, vpt);
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ /*
+ * @todo v3.1: do the same thing for the RHS...
+ */
+
+ /*
+ * Only attributes can have a paircompare registered, and
+ * they can only be with the current REQUEST, and only
+ * with the request pairs.
+ */
+ if ((map->lhs->type != TMPL_TYPE_ATTR) ||
+ (map->lhs->tmpl_request != REQUEST_CURRENT) ||
+ (map->lhs->tmpl_list != PAIR_LIST_REQUEST)) {
+ return true;
+ }
+
+ if (!radius_find_compare(map->lhs->tmpl_da)) return true;
+
+ if (map->rhs->type == TMPL_TYPE_REGEX) {
+ cf_log_err(map->ci, "Cannot compare virtual attribute %s via a regex",
+ map->lhs->name);
+ return false;
+ }
+
+ if (c->cast) {
+ cf_log_err(map->ci, "Cannot cast virtual attribute %s",
+ map->lhs->name);
+ return false;
+ }
+
+ if (map->op != T_OP_CMP_EQ) {
+ cf_log_err(map->ci, "Must use '==' for comparisons with virtual attribute %s",
+ map->lhs->name);
+ return false;
+ }
+
+ /*
+ * Mark it as requiring a paircompare() call, instead of
+ * fr_pair_cmp().
+ */
+ c->pass2_fixup = PASS2_PAIRCOMPARE;
+
+ return true;
+}
+
+
+/*
+ * Compile the RHS of update sections to xlat_exp_t
+ */
+static bool modcall_pass2_update(modgroup *g)
+{
+ vp_map_t *map;
+
+ for (map = g->map; map != NULL; map = map->next) {
+ if (map->rhs->type == TMPL_TYPE_XLAT) {
+ rad_assert(map->rhs->tmpl_xlat == NULL);
+
+ /*
+ * FIXME: compile to attribute && handle
+ * the conversion in map_to_vp().
+ */
+ if (!pass2_xlat_compile(map->ci, &map->rhs, false, NULL)) {
+ return false;
+ }
+ }
+
+ rad_assert(map->rhs->type != TMPL_TYPE_REGEX);
+
+ /*
+ * Deal with undefined attributes now.
+ */
+ if (map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(map->ci, map->lhs)) return false;
+ }
+
+ if (map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(map->ci, map->rhs)) return false;
+ }
+ }
+
+ return true;
+}
+#endif
+
+/*
+ * Do a second-stage pass on compiling the modules.
+ */
+bool modcall_pass2(modcallable *mc)
+{
+ ssize_t slen;
+ char const *name2;
+ modcallable *c;
+ modgroup *g;
+
+ for (c = mc; c != NULL; c = c->next) {
+ switch (c->type) {
+ default:
+ rad_assert(0 == 1);
+ break;
+
+#ifdef WITH_UNLANG
+ case MOD_UPDATE:
+ g = mod_callabletogroup(c);
+ if (g->done_pass2) goto do_next;
+
+ name2 = cf_section_name2(g->cs);
+ if (!name2) {
+ c->debug_name = unlang_keyword[c->type];
+ } else {
+ c->debug_name = talloc_asprintf(c, "update %s", name2);
+ }
+
+ if (!modcall_pass2_update(g)) {
+ return false;
+ }
+ g->done_pass2 = true;
+ break;
+
+ case MOD_XLAT: /* @todo: pre-parse xlat's */
+ case MOD_REFERENCE:
+ case MOD_BREAK:
+ case MOD_RETURN:
+#endif
+
+ case MOD_SINGLE:
+ c->debug_name = c->name;
+ break; /* do nothing */
+
+#ifdef WITH_UNLANG
+ case MOD_IF:
+ case MOD_ELSIF:
+ g = mod_callabletogroup(c);
+ if (g->done_pass2) goto do_next;
+
+ name2 = cf_section_name2(g->cs);
+ c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
+
+ /*
+ * The compilation code takes care of
+ * simplifying 'true' and 'false'
+ * conditions. For others, we have to do
+ * a second pass to parse && compile
+ * xlats.
+ */
+ if (!((g->cond->type == COND_TYPE_TRUE) ||
+ (g->cond->type == COND_TYPE_FALSE))) {
+ if (!fr_condition_walk(g->cond, pass2_callback, NULL)) {
+ return false;
+ }
+ }
+
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+#endif
+
+#ifdef WITH_UNLANG
+ case MOD_SWITCH:
+ g = mod_callabletogroup(c);
+ if (g->done_pass2) goto do_next;
+
+ name2 = cf_section_name2(g->cs);
+ c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
+
+ /*
+ * We had &Foo-Bar, where Foo-Bar is
+ * defined by a module.
+ */
+ if (!g->vpt) {
+ rad_assert(c->name != NULL);
+ rad_assert(c->name[0] == '&');
+ rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
+
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
+ cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) {
+ char *spaces, *text;
+
+ parse_error:
+ fr_canonicalize_error(g->cs, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err_cs(g->cs, "Syntax error");
+ cf_log_err_cs(g->cs, "%s", c->name);
+ cf_log_err_cs(g->cs, "%s^ %s", spaces, text);
+
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return false;
+ }
+
+ goto do_children;
+ }
+
+ /*
+ * Statically compile xlats
+ */
+ if (g->vpt->type == TMPL_TYPE_XLAT) {
+ if (!pass2_xlat_compile(cf_section_to_item(g->cs),
+ &g->vpt, true, NULL)) {
+ return false;
+ }
+
+ goto do_children;
+ }
+
+ /*
+ * Convert virtual &Attr-Foo to "%{Attr-Foo}"
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
+ g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
+ g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ /*
+ * We may have: switch Foo-Bar {
+ *
+ * where Foo-Bar is an attribute defined
+ * by a module. Since there's no leading
+ * &, it's parsed as a literal. But if
+ * we can parse it as an attribute,
+ * switch to using that.
+ */
+ if (g->vpt->type == TMPL_TYPE_LITERAL) {
+ vp_tmpl_t *vpt;
+
+ slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) goto parse_error;
+ if (vpt->type == TMPL_TYPE_ATTR) {
+ talloc_free(g->vpt);
+ g->vpt = vpt;
+ }
+
+ goto do_children;
+ }
+
+ /*
+ * Warn about old-style configuration.
+ *
+ * DEPRECATED: switch User-Name { ...
+ * ALLOWED : switch &User-Name { ...
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) &&
+ (c->name[0] != '&')) {
+ WARN("%s[%d]: Please change %s to &%s",
+ cf_section_filename(g->cs),
+ cf_section_lineno(g->cs),
+ c->name, c->name);
+ }
+
+ do_children:
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_CASE:
+ g = mod_callabletogroup(c);
+ if (g->done_pass2) goto do_next;
+
+ name2 = cf_section_name2(g->cs);
+ if (!name2) {
+ c->debug_name = unlang_keyword[c->type];
+ } else {
+ c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
+ }
+
+ rad_assert(c->parent != NULL);
+ rad_assert(c->parent->type == MOD_SWITCH);
+
+ /*
+ * The statement may refer to an
+ * attribute which doesn't exist until
+ * all of the modules have been loaded.
+ * Check for that now.
+ */
+ if (!g->vpt && c->name &&
+ (c->name[0] == '&') &&
+ (cf_section_name2_type(g->cs) == T_BARE_WORD)) {
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
+ cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) goto parse_error;
+ }
+
+ /*
+ * We have "case {...}". There's no
+ * argument, so we don't need to check
+ * it.
+ */
+ if (!g->vpt) goto do_children;
+
+ /*
+ * Do type-specific checks on the case statement
+ */
+ if (g->vpt->type == TMPL_TYPE_LITERAL) {
+ modgroup *f;
+
+ f = mod_callabletogroup(mc->parent);
+ rad_assert(f->vpt != NULL);
+
+ /*
+ * We're switching over an
+ * attribute. Check that the
+ * values match.
+ */
+ if (f->vpt->type == TMPL_TYPE_ATTR) {
+ rad_assert(f->vpt->tmpl_da != NULL);
+
+ if (tmpl_cast_in_place(g->vpt, f->vpt->tmpl_da->type, f->vpt->tmpl_da) < 0) {
+ cf_log_err_cs(g->cs, "Invalid argument for case statement: %s",
+ fr_strerror());
+ return false;
+ }
+ }
+
+ goto do_children;
+ }
+
+ if (g->vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ if (!pass2_fixup_undefined(cf_section_to_item(g->cs), g->vpt)) {
+ return false;
+ }
+ }
+
+ /*
+ * Compile and sanity check xlat
+ * expansions.
+ */
+ if (g->vpt->type == TMPL_TYPE_XLAT) {
+ modgroup *f;
+
+ f = mod_callabletogroup(mc->parent);
+ rad_assert(f->vpt != NULL);
+
+ /*
+ * Don't expand xlat's into an
+ * attribute of a different type.
+ */
+ if (f->vpt->type == TMPL_TYPE_ATTR) {
+ if (!pass2_xlat_compile(cf_section_to_item(g->cs),
+ &g->vpt, true, f->vpt->tmpl_da)) {
+ return false;
+ }
+ } else {
+ if (!pass2_xlat_compile(cf_section_to_item(g->cs),
+ &g->vpt, true, NULL)) {
+ return false;
+ }
+ }
+ }
+
+ /*
+ * Virtual attribute fixes for "case" statements, too.
+ */
+ if ((g->vpt->type == TMPL_TYPE_ATTR) && g->vpt->tmpl_da->flags.virtual) {
+ g->vpt->tmpl_xlat = xlat_from_tmpl_attr(g->vpt, g->vpt);
+ g->vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ }
+
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_FOREACH:
+ g = mod_callabletogroup(c);
+ if (g->done_pass2) goto do_next;
+
+ name2 = cf_section_name2(g->cs);
+ c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], name2);
+
+ /*
+ * Already parsed, handle the children.
+ */
+ if (g->vpt) goto check_children;
+
+ /*
+ * We had &Foo-Bar, where Foo-Bar is
+ * defined by a module.
+ */
+ rad_assert(c->name != NULL);
+ rad_assert(c->name[0] == '&');
+ rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
+
+ /*
+ * The statement may refer to an
+ * attribute which doesn't exist until
+ * all of the modules have been loaded.
+ * Check for that now.
+ */
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ if (slen < 0) goto parse_error;
+
+ check_children:
+ rad_assert((g->vpt->type == TMPL_TYPE_ATTR) || (g->vpt->type == TMPL_TYPE_LIST));
+ if (g->vpt->tmpl_num != NUM_ALL) {
+ cf_log_err_cs(g->cs, "MUST NOT use instance selectors in 'foreach'");
+ return false;
+ }
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+
+ case MOD_ELSE:
+ c->debug_name = unlang_keyword[c->type];
+ goto do_recurse;
+
+ case MOD_POLICY:
+ g = mod_callabletogroup(c);
+ c->debug_name = talloc_asprintf(c, "%s %s", unlang_keyword[c->type], cf_section_name1(g->cs));
+ goto do_recurse;
+#endif
+
+ case MOD_GROUP:
+ case MOD_LOAD_BALANCE:
+ case MOD_REDUNDANT_LOAD_BALANCE:
+ c->debug_name = unlang_keyword[c->type];
+
+#ifdef WITH_UNLANG
+ do_recurse:
+#endif
+ g = mod_callabletogroup(c);
+ if (!g->cs) {
+ c->debug_name = mc->name; /* for authorize, etc. */
+
+ } else if (c->type == MOD_GROUP) { /* for Auth-Type, etc. */
+ char const *name1 = cf_section_name1(g->cs);
+
+ if (strcmp(name1, unlang_keyword[c->type]) != 0) {
+ name2 = cf_section_name2(g->cs);
+
+ if (!name2) {
+ c->debug_name = name1;
+ } else {
+ c->debug_name = talloc_asprintf(c, "%s %s", name1, name2);
+ }
+ }
+ }
+
+ if (g->done_pass2) goto do_next;
+ if (!modcall_pass2(g->children)) return false;
+ g->done_pass2 = true;
+ break;
+ }
+
+ do_next:
+ rad_assert(c->debug_name != NULL);
+ }
+
+ return true;
+}
+
+void modcall_debug(modcallable *mc, int depth)
+{
+ modcallable *this;
+ modgroup *g;
+ vp_map_t *map;
+ char buffer[1024];
+
+ for (this = mc; this != NULL; this = this->next) {
+ switch (this->type) {
+ default:
+ break;
+
+ case MOD_SINGLE: {
+ modsingle *single = mod_callabletosingle(this);
+
+ DEBUG("%.*s%s", depth, modcall_spaces,
+ single->modinst->name);
+ }
+ break;
+
+#ifdef WITH_UNLANG
+ case MOD_UPDATE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ unlang_keyword[this->type]);
+
+ for (map = g->map; map != NULL; map = map->next) {
+ map_prints(buffer, sizeof(buffer), map);
+ DEBUG("%.*s%s", depth + 1, modcall_spaces, buffer);
+ }
+
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_ELSE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ unlang_keyword[this->type]);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_IF:
+ case MOD_ELSIF:
+ g = mod_callabletogroup(this);
+ fr_cond_sprint(buffer, sizeof(buffer), g->cond);
+ DEBUG("%.*s%s (%s) {", depth, modcall_spaces,
+ unlang_keyword[this->type], buffer);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_SWITCH:
+ case MOD_CASE:
+ g = mod_callabletogroup(this);
+ tmpl_prints(buffer, sizeof(buffer), g->vpt, NULL);
+ DEBUG("%.*s%s %s {", depth, modcall_spaces,
+ unlang_keyword[this->type], buffer);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_POLICY:
+ case MOD_FOREACH:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s %s {", depth, modcall_spaces,
+ unlang_keyword[this->type], this->name);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+ case MOD_BREAK:
+ DEBUG("%.*sbreak", depth, modcall_spaces);
+ break;
+
+#endif
+ case MOD_GROUP:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ unlang_keyword[this->type]);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+
+
+ case MOD_LOAD_BALANCE:
+ case MOD_REDUNDANT_LOAD_BALANCE:
+ g = mod_callabletogroup(this);
+ DEBUG("%.*s%s {", depth, modcall_spaces,
+ unlang_keyword[this->type]);
+ modcall_debug(g->children, depth + 1);
+ DEBUG("%.*s}", depth, modcall_spaces);
+ break;
+ }
+ }
+}
+
+int modcall_pass2_condition(fr_cond_t *c)
+{
+ if (!fr_condition_walk(c, pass2_callback, NULL)) return -1;
+
+ return 0;
+}
diff --git a/src/main/modules.c b/src/main/modules.c
new file mode 100644
index 0000000..fd4334d
--- /dev/null
+++ b/src/main/modules.c
@@ -0,0 +1,2302 @@
+/*
+ * modules.c Radius module support.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ * Copyright 2000 Alan Curry <pacman@world.std.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+
+/** Path to search for modules in
+ *
+ */
+char const *radlib_dir = NULL;
+
+typedef struct indexed_modcallable {
+ rlm_components_t comp;
+ int idx;
+ modcallable *modulelist;
+} indexed_modcallable;
+
+typedef struct virtual_server_t {
+ char const *name;
+ time_t created;
+ int can_free;
+ CONF_SECTION *cs;
+ rbtree_t *components;
+ modcallable *mc[MOD_COUNT];
+ CONF_SECTION *subcs[MOD_COUNT];
+ struct virtual_server_t *next;
+} virtual_server_t;
+
+/*
+ * Keep a hash of virtual servers, so that we can reload them.
+ */
+#define VIRTUAL_SERVER_HASH_SIZE (256)
+static virtual_server_t *virtual_servers[VIRTUAL_SERVER_HASH_SIZE];
+
+static rbtree_t *module_tree = NULL;
+
+static rbtree_t *instance_tree = NULL;
+
+struct fr_module_hup_t {
+ module_instance_t *mi;
+ time_t when;
+ void *insthandle;
+ fr_module_hup_t *next;
+};
+
+/*
+ * Ordered by component
+ */
+const section_type_value_t section_type_value[MOD_COUNT] = {
+ { "authenticate", "Auth-Type", PW_AUTH_TYPE },
+ { "authorize", "Autz-Type", PW_AUTZ_TYPE },
+ { "preacct", "Pre-Acct-Type", PW_PRE_ACCT_TYPE },
+ { "accounting", "Acct-Type", PW_ACCT_TYPE },
+ { "session", "Session-Type", PW_SESSION_TYPE },
+ { "pre-proxy", "Pre-Proxy-Type", PW_PRE_PROXY_TYPE },
+ { "post-proxy", "Post-Proxy-Type", PW_POST_PROXY_TYPE },
+ { "post-auth", "Post-Auth-Type", PW_POST_AUTH_TYPE }
+#ifdef WITH_COA
+ ,
+ { "recv-coa", "Recv-CoA-Type", PW_RECV_COA_TYPE },
+ { "send-coa", "Send-CoA-Type", PW_SEND_COA_TYPE }
+#endif
+};
+
+#ifndef RTLD_NOW
+#define RTLD_NOW (0)
+#endif
+#ifndef RTLD_LOCAL
+#define RTLD_LOCAL (0)
+#endif
+
+/** Check if the magic number in the module matches the one in the library
+ *
+ * This is used to detect potential ABI issues caused by running with modules which
+ * were built for a different version of the server.
+ *
+ * @param cs being parsed.
+ * @param module being loaded.
+ * @returns 0 on success, -1 if prefix mismatch, -2 if version mismatch, -3 if commit mismatch.
+ */
+static int check_module_magic(CONF_SECTION *cs, module_t const *module)
+{
+#ifdef HAVE_DLADDR
+ Dl_info dl_info;
+ dladdr(module, &dl_info);
+#endif
+
+ if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) {
+#ifdef HAVE_DLADDR
+ cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+#endif
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (prefix) mismatch."
+ " application: %x module: %x", module->name,
+ MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER),
+ MAGIC_PREFIX(module->magic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) {
+#ifdef HAVE_DLADDR
+ cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+#endif
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (version) mismatch."
+ " application: %lx module: %lx", module->name,
+ (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER),
+ (unsigned long) MAGIC_VERSION(module->magic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) {
+#ifdef HAVE_DLADDR
+ cf_log_err_cs(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname);
+#endif
+ cf_log_err_cs(cs, "Application and rlm_%s magic number (commit) mismatch."
+ " application: %lx module: %lx", module->name,
+ (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER),
+ (unsigned long) MAGIC_COMMIT(module->magic));
+ return -3;
+ }
+
+ return 0;
+}
+
+fr_dlhandle fr_dlopenext(char const *name)
+{
+ int flags = RTLD_NOW;
+ void *handle;
+ char buffer[2048];
+ char *env;
+ char const *search_path;
+#ifdef RTLD_GLOBAL
+ if (strcmp(name, "rlm_perl") == 0) {
+ flags |= RTLD_GLOBAL;
+ } else
+#endif
+ flags |= RTLD_LOCAL;
+#if defined(RTLD_DEEPBIND) && !defined(__SANITIZE_ADDRESS__)
+ flags |= RTLD_DEEPBIND;
+#endif
+
+#ifndef NDEBUG
+ /*
+ * Bind all the symbols *NOW* so we don't hit errors later
+ */
+ flags |= RTLD_NOW;
+#endif
+
+ /*
+ * Apple removed support for DYLD_LIBRARY_PATH in rootless mode.
+ */
+ env = getenv("FR_LIBRARY_PATH");
+ if (env) {
+ DEBUG3("Ignoring libdir as FR_LIBRARY_PATH set. Module search path will be: %s", env);
+ search_path = env;
+ } else {
+ search_path = radlib_dir;
+ }
+
+ /*
+ * Prefer loading our libraries by absolute path.
+ */
+ if (search_path) {
+ char *error;
+ char *ctx, *paths, *path;
+ char *p;
+
+ fr_strerror();
+
+ ctx = paths = talloc_strdup(NULL, search_path);
+ while ((path = strsep(&paths, ":")) != NULL) {
+ /*
+ * Trim the trailing slash
+ */
+ p = strrchr(path, '/');
+ if (p && ((p[1] == '\0') || (p[1] == ':'))) *p = '\0';
+
+ path = talloc_asprintf(ctx, "%s/%s%s", path, name, LT_SHREXT);
+
+ DEBUG4("Loading %s with path: %s", name, path);
+
+ handle = dlopen(path, flags);
+ if (handle) {
+ talloc_free(ctx);
+ return handle;
+ }
+ error = dlerror();
+
+ fr_strerror_printf("%s%s\n", fr_strerror(), error);
+ DEBUG4("Loading %s failed: %s - %s", name, error,
+ (access(path, R_OK) < 0) ? fr_syserror(errno) : "No access errors");
+ talloc_free(path);
+ }
+ talloc_free(ctx);
+ }
+
+ DEBUG4("Loading library using linker search path(s)");
+ if (DEBUG_ENABLED4) {
+#ifdef __APPLE__
+ env = getenv("LD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("LD_LIBRARY_PATH : %s", env);
+ }
+ env = getenv("DYLD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("DYLB_LIBRARY_PATH : %s", env);
+ }
+ env = getenv("DYLD_FALLBACK_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("DYLD_FALLBACK_LIBRARY_PATH : %s", env);
+ }
+ env = getcwd(buffer, sizeof(buffer));
+ if (env) {
+ DEBUG4("Current directory : %s", env);
+ }
+#else
+ env = getenv("LD_LIBRARY_PATH");
+ if (env) {
+ DEBUG4("LD_LIBRARY_PATH : %s", env);
+ }
+ DEBUG4("Defaults : /lib:/usr/lib");
+#endif
+ }
+
+ strlcpy(buffer, name, sizeof(buffer));
+ /*
+ * FIXME: Make this configurable...
+ */
+ strlcat(buffer, LT_SHREXT, sizeof(buffer));
+
+ handle = dlopen(buffer, flags);
+ if (!handle) {
+ char *error = dlerror();
+
+ DEBUG4("Failed with error: %s", error);
+ /*
+ * Don't overwrite the previous message
+ * It's likely to contain a better error.
+ */
+ if (!radlib_dir) fr_strerror_printf("%s", dlerror());
+ return NULL;
+ }
+ return handle;
+}
+
+void *fr_dlsym(fr_dlhandle handle, char const *symbol)
+{
+ return dlsym(handle, symbol);
+}
+
+int fr_dlclose(fr_dlhandle handle)
+{
+ if (!handle) return 0;
+
+ return dlclose(handle);
+}
+
+char const *fr_dlerror(void)
+{
+ return dlerror();
+}
+
+static int virtual_server_idx(char const *name)
+{
+ uint32_t hash;
+
+ if (!name) return 0;
+
+ hash = fr_hash_string(name);
+
+ return hash & (VIRTUAL_SERVER_HASH_SIZE - 1);
+}
+
+static virtual_server_t *virtual_server_find(char const *name)
+{
+ rlm_rcode_t rcode;
+ virtual_server_t *server;
+
+ rcode = virtual_server_idx(name);
+ for (server = virtual_servers[rcode];
+ server != NULL;
+ server = server->next) {
+ if (!name && !server->name) break;
+
+ if ((name && server->name) &&
+ (strcmp(name, server->name) == 0)) break;
+ }
+
+ return server;
+}
+
+static int _virtual_server_free(virtual_server_t *server)
+{
+ if (server->components) rbtree_free(server->components);
+ return 0;
+}
+
+void virtual_servers_free(time_t when)
+{
+ int i;
+ virtual_server_t **last;
+
+ for (i = 0; i < VIRTUAL_SERVER_HASH_SIZE; i++) {
+ virtual_server_t *server, *next;
+
+ last = &virtual_servers[i];
+ for (server = virtual_servers[i];
+ server != NULL;
+ server = next) {
+ next = server->next;
+
+ /*
+ * If we delete it, fix the links so that
+ * we don't orphan anything. Also,
+ * delete it if it's old, AND a newer one
+ * was defined.
+ *
+ * Otherwise, the last pointer gets set to
+ * the one we didn't delete.
+ */
+ if ((when == 0) ||
+ ((server->created < when) && server->can_free)) {
+ *last = server->next;
+ talloc_free(server);
+ } else {
+ last = &(server->next);
+ }
+ }
+ }
+}
+
+static int indexed_modcallable_cmp(void const *one, void const *two)
+{
+ indexed_modcallable const *a = one;
+ indexed_modcallable const *b = two;
+
+ if (a->comp < b->comp) return -1;
+ if (a->comp > b->comp) return +1;
+
+ return a->idx - b->idx;
+}
+
+
+/*
+ * Compare two module entries
+ */
+static int module_instance_cmp(void const *one, void const *two)
+{
+ module_instance_t const *a = one;
+ module_instance_t const *b = two;
+
+ return strcmp(a->name, b->name);
+}
+
+
+static void module_instance_free_old(UNUSED CONF_SECTION *cs, module_instance_t *node, time_t when)
+{
+ fr_module_hup_t *mh, **last;
+
+ /*
+ * Walk the list, freeing up old instances.
+ */
+ last = &(node->mh);
+ while (*last) {
+ mh = *last;
+
+ /*
+ * Free only every 60 seconds.
+ */
+ if ((when - mh->when) < 60) {
+ last = &(mh->next);
+ continue;
+ }
+
+ talloc_free(mh->insthandle);
+
+ *last = mh->next;
+ talloc_free(mh);
+ }
+}
+
+
+/*
+ * Free a module instance.
+ */
+static void module_instance_free(void *data)
+{
+ module_instance_t *module = talloc_get_type_abort(data, module_instance_t);
+
+ module_instance_free_old(module->cs, module, time(NULL) + 100);
+
+#ifdef HAVE_PTHREAD_H
+ if (module->mutex) {
+ /*
+ * FIXME
+ * The mutex MIGHT be locked...
+ * we'll check for that later, I guess.
+ */
+ pthread_mutex_destroy(module->mutex);
+ talloc_free(module->mutex);
+ }
+#endif
+
+ xlat_unregister(module->name, NULL, module->insthandle);
+
+ /*
+ * Remove all xlat's registered to module instance.
+ */
+ if (module->insthandle) {
+ /*
+ * Remove any registered paircompares.
+ */
+ paircompare_unregister_instance(module->insthandle);
+
+ xlat_unregister_module(module->insthandle);
+ }
+ talloc_free(module);
+}
+
+
+/*
+ * Compare two module entries
+ */
+static int module_entry_cmp(void const *one, void const *two)
+{
+ module_entry_t const *a = one;
+ module_entry_t const *b = two;
+
+ return strcmp(a->name, b->name);
+}
+
+/*
+ * Free a module entry.
+ */
+static int _module_entry_free(module_entry_t *this)
+{
+#ifndef NDEBUG
+ /*
+ * Don't dlclose() modules if we're doing memory
+ * debugging. This removes the symbols needed by
+ * valgrind.
+ */
+ if (!main_config.debug_memory)
+#endif
+ dlclose(this->handle); /* ignore any errors */
+ return 0;
+}
+
+
+/*
+ * Remove the module lists.
+ */
+int modules_free(void)
+{
+ rbtree_free(instance_tree);
+ rbtree_free(module_tree);
+
+ return 0;
+}
+
+
+/*
+ * dlopen() a module.
+ */
+static module_entry_t *module_dlopen(CONF_SECTION *cs, char const *module_name)
+{
+ module_entry_t myentry;
+ module_entry_t *node;
+ void *handle = NULL;
+ module_t const *module;
+
+ strlcpy(myentry.name, module_name, sizeof(myentry.name));
+ node = rbtree_finddata(module_tree, &myentry);
+ if (node) return node;
+
+ /*
+ * Link to the module's rlm_FOO{} structure, the same as
+ * the module name.
+ */
+
+#if !defined(WITH_LIBLTDL) && defined(HAVE_DLFCN_H) && defined(RTLD_SELF)
+ module = dlsym(RTLD_SELF, module_name);
+ if (module) goto open_self;
+#endif
+
+ /*
+ * Keep the handle around so we can dlclose() it.
+ */
+ handle = fr_dlopenext(module_name);
+ if (!handle) {
+ cf_log_err_cs(cs, "Failed to link to module '%s': %s", module_name, fr_strerror());
+ return NULL;
+ }
+
+ DEBUG3("Loaded %s, checking if it's valid", module_name);
+
+ module = dlsym(handle, module_name);
+ if (!module) {
+ cf_log_err_cs(cs, "Failed linking to %s structure: %s", module_name, dlerror());
+ dlclose(handle);
+ return NULL;
+ }
+
+#if !defined(WITH_LIBLTDL) && defined (HAVE_DLFCN_H) && defined(RTLD_SELF)
+ open_self:
+#endif
+ /*
+ * Before doing anything else, check if it's sane.
+ */
+ if (check_module_magic(cs, module) < 0) {
+ dlclose(handle);
+ return NULL;
+ }
+
+ /* make room for the module type */
+ node = talloc_zero(cs, module_entry_t);
+ talloc_set_destructor(node, _module_entry_free);
+ strlcpy(node->name, module_name, sizeof(node->name));
+ node->module = module;
+ node->handle = handle;
+
+ cf_log_module(cs, "Loaded module %s", module_name);
+
+ /*
+ * Add the module as "rlm_foo-version" to the configuration
+ * section.
+ */
+ if (!rbtree_insert(module_tree, node)) {
+ ERROR("Failed to cache module %s", module_name);
+ dlclose(handle);
+ talloc_free(node);
+ return NULL;
+ }
+
+ return node;
+}
+
+/** Parse module's configuration section and setup destructors
+ *
+ */
+static int module_conf_parse(module_instance_t *node, void **handle)
+{
+ *handle = NULL;
+
+ /*
+ * If there is supposed to be instance data, allocate it now.
+ * Also parse the configuration data, if required.
+ */
+ if (node->entry->module->inst_size) {
+ *handle = talloc_zero_array(node, uint8_t, node->entry->module->inst_size);
+ rad_assert(*handle);
+
+ talloc_set_name(*handle, "rlm_%s_t",
+ node->entry->module->name ? node->entry->module->name : "config");
+
+ if (node->entry->module->config &&
+ (cf_section_parse(node->cs, *handle, node->entry->module->config) < 0)) {
+ cf_log_err_cs(node->cs,"Invalid configuration for module \"%s\"", node->name);
+ talloc_free(*handle);
+
+ return -1;
+ }
+
+ /*
+ * Set the destructor.
+ */
+ if (node->entry->module->detach) {
+ talloc_set_destructor(*handle, node->entry->module->detach);
+ }
+ }
+
+ return 0;
+}
+
+/** Bootstrap a module.
+ *
+ * Load the module shared library, allocate instance memory for it,
+ * parse the module configuration, and call the modules "bootstrap" method.
+ */
+static module_instance_t *module_bootstrap(CONF_SECTION *cs)
+{
+ char const *name1, *name2, *askedname;
+ module_instance_t *node, myNode;
+ char module_name[256];
+
+ /*
+ * Figure out which module we want to load.
+ */
+ name1 = cf_section_name1(cs);
+ askedname = name2 = cf_section_name2(cs);
+ if (!askedname) {
+ askedname = name1;
+ name2 = "";
+ }
+
+ strlcpy(myNode.name, askedname, sizeof(myNode.name));
+
+ /*
+ * See if the module already exists.
+ */
+ node = rbtree_finddata(instance_tree, &myNode);
+ if (node) {
+ ERROR("Duplicate module \"%s %s { ... }\", in file %s:%d and file %s:%d",
+ name1, name2,
+ cf_section_filename(cs),
+ cf_section_lineno(cs),
+ cf_section_filename(node->cs),
+ cf_section_lineno(node->cs));
+ return NULL;
+ }
+
+ /*
+ * Hang the node struct off of the configuration
+ * section. If the CS is free'd the instance will be
+ * free'd, too.
+ */
+ node = talloc_zero(instance_tree, module_instance_t);
+ node->cs = cs;
+ strlcpy(node->name, askedname, sizeof(node->name));
+
+ /*
+ * Names in the "modules" section aren't prefixed
+ * with "rlm_", so we add it here.
+ */
+ snprintf(module_name, sizeof(module_name), "rlm_%s", name1);
+
+ /*
+ * Load the module shared library.
+ */
+ node->entry = module_dlopen(cs, module_name);
+ if (!node->entry) {
+ talloc_free(node);
+ return NULL;
+ }
+
+ cf_log_module(cs, "Loading module \"%s\" from file %s", node->name,
+ cf_section_filename(cs));
+
+ /*
+ * Parse the modules configuration.
+ */
+ if (module_conf_parse(node, &node->insthandle) < 0) {
+ talloc_free(node);
+ return NULL;
+ }
+
+ /*
+ * Bootstrap the module.
+ */
+ if (node->entry->module->bootstrap &&
+ ((node->entry->module->bootstrap)(cs, node->insthandle) < 0)) {
+ cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", node->name);
+ talloc_free(node);
+ return NULL;
+ }
+
+ /*
+ * Remember the module for later.
+ */
+ rbtree_insert(instance_tree, node);
+
+ return node;
+}
+
+
+/** Find an existing module instance.
+ *
+ */
+module_instance_t *module_find(CONF_SECTION *modules, char const *askedname)
+{
+ char const *instname;
+ module_instance_t myNode;
+
+ if (!modules) return NULL;
+
+ /*
+ * Look for the real name. Ignore the first character,
+ * which tells the server "it's OK for this module to not
+ * exist."
+ */
+ instname = askedname;
+ if (instname[0] == '-') instname++;
+
+ strlcpy(myNode.name, instname, sizeof(myNode.name));
+
+ return rbtree_finddata(instance_tree, &myNode);
+}
+
+
+/** Load a module, and instantiate it.
+ *
+ */
+module_instance_t *module_instantiate(CONF_SECTION *modules, char const *askedname)
+{
+ module_instance_t *node;
+
+ /*
+ * Find the module. If it's not there, do nothing.
+ */
+ node = module_find(modules, askedname);
+ if (!node) {
+ ERROR("Cannot find module \"%s\"", askedname);
+ return NULL;
+ }
+
+ /*
+ * The module is already instantiated. Return it.
+ */
+ if (node->instantiated) return node;
+
+ /*
+ * Now that ALL modules are instantiated, and ALL xlats
+ * are defined, go compile the config items marked as XLAT.
+ */
+ if (node->entry->module->config &&
+ (cf_section_parse_pass2(node->cs, node->insthandle,
+ node->entry->module->config) < 0)) {
+ return NULL;
+ }
+
+ /*
+ * Call the instantiate method, if any.
+ */
+ if (node->entry->module->instantiate) {
+ cf_log_module(node->cs, "Instantiating module \"%s\" from file %s", node->name,
+ cf_section_filename(node->cs));
+
+ /*
+ * Call the module's instantiation routine.
+ */
+ if ((node->entry->module->instantiate)(node->cs, node->insthandle) < 0) {
+ cf_log_err_cs(node->cs, "Instantiation failed for module \"%s\"", node->name);
+
+ return NULL;
+ }
+ }
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If we're threaded, check if the module is thread-safe.
+ *
+ * If it isn't, we create a mutex.
+ */
+ if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) {
+ node->mutex = talloc_zero(node, pthread_mutex_t);
+
+ /*
+ * Initialize the mutex.
+ */
+ pthread_mutex_init(node->mutex, NULL);
+ }
+#endif
+
+ node->instantiated = true;
+ node->last_hup = time(NULL); /* don't let us load it, then immediately hup it */
+
+ return node;
+}
+
+
+module_instance_t *module_instantiate_method(CONF_SECTION *modules, char const *name, rlm_components_t *method)
+{
+ char *p;
+ rlm_components_t i;
+ module_instance_t *mi;
+
+ /*
+ * If the module exists, ensure it's instantiated.
+ *
+ * Doing it this way avoids complaints from
+ * module_instantiate()
+ */
+ mi = module_find(modules, name);
+ if (mi) return module_instantiate(modules, name);
+
+ /*
+ * Find out which method is being used.
+ */
+ p = strrchr(name, '.');
+ if (!p) return NULL;
+
+ p++;
+
+ /*
+ * Find the component.
+ */
+ for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+ if (strcmp(p, section_type_value[i].section) == 0) {
+ char buffer[256];
+
+ strlcpy(buffer, name, sizeof(buffer));
+ buffer[p - name - 1] = '\0';
+
+ mi = module_find(modules, buffer);
+ if (mi) {
+ if (method) *method = i;
+ return module_instantiate(modules, buffer);
+ }
+ }
+ }
+
+ /*
+ * Not found.
+ */
+ return NULL;
+}
+
+
+/** Resolve polymorphic item's from a module's CONF_SECTION to a subsection in another module
+ *
+ * This allows certain module sections to reference module sections in other instances
+ * of the same module and share CONF_DATA associated with them.
+ *
+ * @verbatim
+example {
+ data {
+ ...
+ }
+}
+
+example inst {
+ data = example
+}
+ * @endverbatim
+ *
+ * @param out where to write the pointer to a module's config section. May be NULL on success, indicating the config
+ * item was not found within the module CONF_SECTION, or the chain of module references was followed and the
+ * module at the end of the chain did not a subsection.
+ * @param module CONF_SECTION.
+ * @param name of the polymorphic sub-section.
+ * @return 0 on success with referenced section, 1 on success with local section, or -1 on failure.
+ */
+int find_module_sibling_section(CONF_SECTION **out, CONF_SECTION *module, char const *name)
+{
+ static bool loop = true; /* not used, we just need a valid pointer to quiet static analysis */
+
+ CONF_PAIR *cp;
+ CONF_SECTION *cs;
+
+ module_instance_t *inst;
+ char const *inst_name;
+
+#define FIND_SIBLING_CF_KEY "find_sibling"
+
+ *out = NULL;
+
+ /*
+ * Is a real section (not referencing sibling module).
+ */
+ cs = cf_section_sub_find(module, name);
+ if (cs) {
+ *out = cs;
+
+ return 0;
+ }
+
+ /*
+ * Item omitted completely from module config.
+ */
+ cp = cf_pair_find(module, name);
+ if (!cp) return 0;
+
+ if (cf_data_find(module, FIND_SIBLING_CF_KEY)) {
+ cf_log_err_cp(cp, "Module reference loop found");
+
+ return -1;
+ }
+ cf_data_add(module, FIND_SIBLING_CF_KEY, &loop, NULL);
+
+ /*
+ * Item found, resolve it to a module instance.
+ * This triggers module loading, so we don't have
+ * instantiation order issues.
+ */
+ inst_name = cf_pair_value(cp);
+ inst = module_instantiate(cf_item_parent(cf_section_to_item(module)), inst_name);
+
+ /*
+ * Remove the config data we added for loop
+ * detection.
+ */
+ cf_data_remove(module, FIND_SIBLING_CF_KEY);
+ if (!inst) {
+ cf_log_err_cp(cp, "Unknown module instance \"%s\"", inst_name);
+
+ return -1;
+ }
+
+ /*
+ * Check the module instances are of the same type.
+ */
+ if (strcmp(cf_section_name1(inst->cs), cf_section_name1(module)) != 0) {
+ cf_log_err_cp(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
+ cf_section_name1(inst->cs), cf_section_name1(module));
+
+ return -1;
+ }
+
+ *out = cf_section_sub_find(inst->cs, name);
+
+ return 1;
+}
+
+static indexed_modcallable *lookup_by_index(rbtree_t *components,
+ rlm_components_t comp, int idx)
+{
+ indexed_modcallable myc;
+
+ myc.comp = comp;
+ myc.idx = idx;
+
+ return rbtree_finddata(components, &myc);
+}
+
+/*
+ * Create a new sublist.
+ */
+static indexed_modcallable *new_sublist(CONF_SECTION *cs,
+ rbtree_t *components, rlm_components_t comp, int idx)
+{
+ indexed_modcallable *c;
+
+ c = lookup_by_index(components, comp, idx);
+
+ /* It is an error to try to create a sublist that already
+ * exists. It would almost certainly be caused by accidental
+ * duplication in the config file.
+ *
+ * index 0 is the exception, because it is used when we want
+ * to collect _all_ listed modules under a single index by
+ * default, which is currently the case in all components
+ * except authenticate. */
+ if (c) {
+ if (idx == 0) {
+ return c;
+ }
+ return NULL;
+ }
+
+ c = talloc_zero(cs, indexed_modcallable);
+ c->modulelist = NULL;
+ c->comp = comp;
+ c->idx = idx;
+
+ if (!rbtree_insert(components, c)) {
+ talloc_free(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+rlm_rcode_t indexed_modcall(rlm_components_t comp, int idx, REQUEST *request)
+{
+ rlm_rcode_t rcode;
+ modcallable *list = NULL;
+ virtual_server_t *server;
+
+ /*
+ * Hack to find the correct virtual server.
+ */
+ server = virtual_server_find(request->server);
+ if (!server) {
+ RDEBUG("No such virtual server \"%s\"", request->server);
+ return RLM_MODULE_FAIL;
+ }
+
+ if (idx == 0) {
+ list = server->mc[comp];
+ if (!list) {
+ if (server->name) {
+ RDEBUG3("Empty %s section in virtual server \"%s\". Using default return values.",
+ section_type_value[comp].section, server->name);
+ } else {
+ RDEBUG3("Empty %s section. Using default return values.", section_type_value[comp].section);
+ }
+ }
+ } else {
+ indexed_modcallable *this;
+
+ this = lookup_by_index(server->components, comp, idx);
+ if (this) {
+ list = this->modulelist;
+ } else {
+ RDEBUG2("%s sub-section not found. Ignoring.", section_type_value[comp].typename);
+ }
+ }
+
+ if (server->subcs[comp]) {
+ if (idx == 0) {
+ RDEBUG("# Executing section %s from file %s",
+ section_type_value[comp].section,
+ cf_section_filename(server->subcs[comp]));
+ } else {
+ RDEBUG("# Executing group from file %s",
+ cf_section_filename(server->subcs[comp]));
+ }
+ }
+ request->component = section_type_value[comp].section;
+ rcode = modcall(comp, list, request);
+ request->component = "<core>";
+
+ return rcode;
+}
+
+/*
+ * Load a sub-module list, as found inside an Auth-Type foo {}
+ * block
+ */
+static int load_subcomponent_section(CONF_SECTION *cs,
+ rbtree_t *components,
+ DICT_ATTR const *da, rlm_components_t comp)
+{
+ indexed_modcallable *subcomp;
+ modcallable *ml;
+ DICT_VALUE *dval;
+ char const *name2 = cf_section_name2(cs);
+
+ /*
+ * Sanity check.
+ */
+ if (!name2) {
+ return 1;
+ }
+
+ DEBUG("Compiling %s %s for attr %s", cf_section_name1(cs), name2, da->name);
+
+ /*
+ * Compile the group.
+ */
+ ml = compile_modgroup(NULL, comp, cs);
+ if (!ml) {
+ return 0;
+ }
+
+ /*
+ * We must assign a numeric index to this subcomponent.
+ * It is generated and placed in the dictionary
+ * automatically. If it isn't found, it's a serious
+ * error.
+ */
+ dval = dict_valbyname(da->attr, da->vendor, name2);
+ if (!dval) {
+ talloc_free(ml);
+ cf_log_err_cs(cs,
+ "The %s attribute has no VALUE defined for %s",
+ section_type_value[comp].typename, name2);
+ return 0;
+ }
+
+ subcomp = new_sublist(cs, components, comp, dval->value);
+ if (!subcomp) {
+ talloc_free(ml);
+ return 1;
+ }
+
+ /*
+ * Link it into the talloc hierarchy.
+ */
+ subcomp->modulelist = talloc_steal(subcomp, ml);
+ return 1; /* OK */
+}
+
+/*
+ * Don't complain too often.
+ */
+#define MAX_IGNORED (32)
+static int last_ignored = -1;
+static char const *ignored[MAX_IGNORED];
+
+static int load_component_section(CONF_SECTION *cs,
+ rbtree_t *components, rlm_components_t comp)
+{
+ modcallable *this;
+ CONF_ITEM *modref;
+ int idx;
+ indexed_modcallable *subcomp;
+ char const *modname;
+ DICT_ATTR const *da;
+
+ /*
+ * Find the attribute used to store VALUEs for this section.
+ */
+ da = dict_attrbyvalue(section_type_value[comp].attr, 0);
+ if (!da) {
+ cf_log_err_cs(cs,
+ "No such attribute %s",
+ section_type_value[comp].typename);
+ return -1;
+ }
+
+ /*
+ * Loop over the entries in the named section, loading
+ * the sections this time.
+ */
+ for (modref = cf_item_find_next(cs, NULL);
+ modref != NULL;
+ modref = cf_item_find_next(cs, modref)) {
+ char const *name1;
+ CONF_PAIR *cp = NULL;
+ CONF_SECTION *scs = NULL;
+
+ if (cf_item_is_section(modref)) {
+ scs = cf_item_to_section(modref);
+
+ name1 = cf_section_name1(scs);
+
+ if (strcmp(name1,
+ section_type_value[comp].typename) == 0) {
+ if (!load_subcomponent_section(scs,
+ components,
+ da,
+ comp)) {
+
+ return -1; /* FIXME: memleak? */
+ }
+ continue;
+ }
+
+ cp = NULL;
+
+ } else if (cf_item_is_pair(modref)) {
+ cp = cf_item_to_pair(modref);
+
+ } else {
+ continue; /* ignore it */
+ }
+
+ /*
+ * Look for Auth-Type foo {}, which are special
+ * cases of named sections, and allowable ONLY
+ * at the top-level.
+ *
+ * i.e. They're not allowed in a "group" or "redundant"
+ * subsection.
+ */
+ if (comp == MOD_AUTHENTICATE) {
+ DICT_VALUE *dval;
+ char const *modrefname = NULL;
+
+ if (cp) {
+ modrefname = cf_pair_attr(cp);
+ } else {
+ modrefname = cf_section_name2(scs);
+ if (!modrefname) {
+ cf_log_err_cs(cs,
+ "Errors parsing %s sub-section.\n",
+ cf_section_name1(scs));
+ return -1;
+ }
+ }
+ if (*modrefname == '-') modrefname++;
+
+ dval = dict_valbyname(PW_AUTH_TYPE, 0, modrefname);
+ if (!dval) {
+ /*
+ * It's a section, but nothing we
+ * recognize. Die!
+ */
+ cf_log_err_cs(cs,
+ "Unknown Auth-Type \"%s\" in %s sub-section.",
+ modrefname, section_type_value[comp].section);
+ return -1;
+ }
+ idx = dval->value;
+ } else {
+ /* See the comment in new_sublist() for explanation
+ * of the special index 0 */
+ idx = 0;
+ }
+
+ subcomp = new_sublist(cs, components, comp, idx);
+ if (!subcomp) continue;
+
+ /*
+ * Try to compile one entry.
+ */
+ this = compile_modsingle(subcomp, &subcomp->modulelist, comp, modref, &modname);
+
+ /*
+ * It's OK for the module to not exist.
+ */
+ if (!this && modname && (modname[0] == '-')) {
+ int i;
+
+ if (last_ignored < 0) {
+ save_complain:
+ last_ignored++;
+ ignored[last_ignored] = modname;
+
+ complain:
+ WARN("Ignoring \"%s\" (see raddb/mods-available/README.rst)", modname + 1);
+ continue;
+ }
+
+ if (last_ignored >= MAX_IGNORED) goto complain;
+
+ for (i = 0; i <= last_ignored; i++) {
+ if (strcmp(ignored[i], modname) == 0) {
+ break;
+ }
+ }
+
+ if (i > last_ignored) goto save_complain;
+ continue;
+ }
+
+ if (!this) {
+ cf_log_err_cs(cs,
+ "Errors parsing %s section.\n",
+ cf_section_name1(cs));
+ return -1;
+ }
+
+ if (rad_debug_lvl > 2) modcall_debug(this, 2);
+
+ add_to_modcallable(subcomp->modulelist, this);
+ }
+
+
+ return 0;
+}
+
+static int load_byserver(CONF_SECTION *cs)
+{
+ rlm_components_t comp;
+ bool found;
+ char const *name = cf_section_name2(cs);
+ rbtree_t *components;
+ virtual_server_t *server = NULL;
+ indexed_modcallable *c;
+ bool is_bare;
+
+ if (name) {
+ cf_log_info(cs, "server %s { # from file %s",
+ name, cf_section_filename(cs));
+ } else {
+ cf_log_info(cs, "server { # from file %s",
+ cf_section_filename(cs));
+ }
+
+ is_bare = (cf_item_parent(cf_section_to_item(cs)) == NULL);
+
+ server = talloc_zero(cs, virtual_server_t);
+ server->name = name;
+ server->created = time(NULL);
+ server->cs = cs;
+ server->components = components = rbtree_create(server, indexed_modcallable_cmp, NULL, 0);
+ if (!components) {
+ ERROR("Failed to initialize components");
+
+ error:
+ if (rad_debug_lvl == 0) {
+ ERROR("Failed to load virtual server %s",
+ (name != NULL) ? name : "<default>");
+ }
+ return -1;
+ }
+ talloc_set_destructor(server, _virtual_server_free);
+
+ /*
+ * Loop over all of the known components, finding their
+ * configuration section, and loading it.
+ */
+ found = false;
+ for (comp = 0; comp < MOD_COUNT; ++comp) {
+ CONF_SECTION *subcs;
+
+ subcs = cf_section_sub_find(cs,
+ section_type_value[comp].section);
+ if (!subcs) continue;
+
+ if (is_bare) {
+ cf_log_err_cs(subcs, "The %s section should be inside of a 'server { ... }' block!",
+ section_type_value[comp].section);
+ }
+
+ if (cf_item_find_next(subcs, NULL) == NULL) continue;
+
+ /*
+ * Skip pre/post-proxy sections if we're not
+ * proxying.
+ */
+ if (
+#ifdef WITH_PROXY
+ !main_config.proxy_requests &&
+#endif
+ ((comp == MOD_PRE_PROXY) ||
+ (comp == MOD_POST_PROXY))) {
+ continue;
+ }
+
+#ifndef WITH_ACCOUNTING
+ if (comp == MOD_ACCOUNTING) continue;
+#endif
+
+#ifndef WITH_SESSION_MGMT
+ if (comp == MOD_SESSION) continue;
+#endif
+
+ if (rad_debug_lvl <= 3) {
+ cf_log_module(cs, "Loading %s {...}",
+ section_type_value[comp].section);
+ } else {
+ DEBUG(" %s {", section_type_value[comp].section);
+ }
+
+ if (load_component_section(subcs, components, comp) < 0) {
+ goto error;
+ }
+
+ if (rad_debug_lvl > 3) {
+ DEBUG(" } # %s", section_type_value[comp].section);
+ }
+
+ /*
+ * Cache a default, if it exists. Some people
+ * put empty sections for some reason...
+ */
+ c = lookup_by_index(components, comp, 0);
+ if (c) server->mc[comp] = c->modulelist;
+
+ server->subcs[comp] = subcs;
+
+ found = true;
+ } /* loop over components */
+
+ /*
+ * We haven't loaded any of the normal sections. Maybe we're
+ * supposed to load the vmps section.
+ *
+ * This is a bit of a hack...
+ */
+ if (!found) do {
+#if defined(WITH_VMPS) || defined(WITH_DHCP) || defined(WITH_TLS)
+ CONF_SECTION *subcs;
+#endif
+#if defined(WITH_DHCP) || defined(WITH_TLS)
+ DICT_ATTR const *da;
+#endif
+
+#ifdef WITH_VMPS
+ subcs = cf_section_sub_find(cs, "vmps");
+ if (subcs) {
+ cf_log_module(cs, "Loading vmps {...}");
+ if (load_component_section(subcs, components,
+ MOD_POST_AUTH) < 0) {
+ goto error;
+ }
+ c = lookup_by_index(components,
+ MOD_POST_AUTH, 0);
+ if (c) server->mc[MOD_POST_AUTH] = c->modulelist;
+ break;
+ }
+#endif
+
+#ifdef WITH_TLS
+ /*
+ * It's OK to not have TLS cache sections.
+ */
+ da = dict_attrbyname("TLS-Cache-Method");
+ subcs = cf_section_sub_find_name2(cs, "cache", "load");
+ if (subcs && !load_subcomponent_section(subcs,
+ components,
+ da,
+ MOD_POST_AUTH)) {
+ goto error; /* FIXME: memleak? */
+ }
+
+ subcs = cf_section_sub_find_name2(cs, "cache", "save");
+ if (subcs && !load_subcomponent_section(subcs,
+ components,
+ da,
+ MOD_POST_AUTH)) {
+ goto error; /* FIXME: memleak? */
+ }
+
+ subcs = cf_section_sub_find_name2(cs, "cache", "clear");
+ if (subcs && !load_subcomponent_section(subcs,
+ components,
+ da,
+ MOD_POST_AUTH)) {
+ goto error; /* FIXME: memleak? */
+ }
+
+ subcs = cf_section_sub_find_name2(cs, "cache", "refresh");
+ if (subcs && !load_subcomponent_section(subcs,
+ components,
+ da,
+ MOD_POST_AUTH)) {
+ goto error; /* FIXME: memleak? */
+ }
+#endif
+
+#ifdef WITH_DHCP
+ /*
+ * It's OK to not have DHCP.
+ */
+ subcs = cf_subsection_find_next(cs, NULL, "dhcp");
+ if (!subcs) break;
+
+ da = dict_attrbyname("DHCP-Message-Type");
+
+ /*
+ * Handle each DHCP Message type separately.
+ */
+ while (subcs) {
+ char const *name2 = cf_section_name2(subcs);
+
+ if (name2) {
+ cf_log_module(cs, "Loading dhcp %s {...}", name2);
+ } else {
+ cf_log_module(cs, "Loading dhcp {...}");
+ }
+ if (!load_subcomponent_section(subcs,
+ components,
+ da,
+ MOD_POST_AUTH)) {
+ goto error; /* FIXME: memleak? */
+ }
+ c = lookup_by_index(components,
+ MOD_POST_AUTH, 0);
+ if (c) server->mc[MOD_POST_AUTH] = c->modulelist;
+
+ subcs = cf_subsection_find_next(cs, subcs, "dhcp");
+ }
+#endif
+
+
+ } while (0);
+
+ if (name) {
+ cf_log_info(cs, "} # server %s", name);
+ } else {
+ cf_log_info(cs, "} # server");
+ }
+
+ if (rad_debug_lvl == 0) {
+ INFO("Loaded virtual server %s",
+ (name != NULL) ? name : "<default>");
+ }
+
+ /*
+ * Now that it is OK, insert it into the list.
+ *
+ * This is thread-safe...
+ */
+ comp = virtual_server_idx(name);
+ server->next = virtual_servers[comp];
+ virtual_servers[comp] = server;
+
+ /*
+ * Mark OLDER ones of the same name as being unused.
+ */
+ server = server->next;
+ while (server) {
+ if ((!name && !server->name) ||
+ (name && server->name &&
+ (strcmp(server->name, name) == 0))) {
+ server->can_free = true;
+ break;
+ }
+ server = server->next;
+ }
+
+ return 0;
+}
+
+
+static int pass2_cb(UNUSED void *ctx, void *data)
+{
+ indexed_modcallable *this = data;
+
+ if (!modcall_pass2(this->modulelist)) return -1;
+
+ return 0;
+}
+
+
+/*
+ * Load all of the virtual servers.
+ */
+int virtual_servers_load(CONF_SECTION *config)
+{
+ CONF_SECTION *cs;
+ virtual_server_t *server;
+ static bool first_time = true;
+
+ DEBUG2("%s: #### Loading Virtual Servers ####", main_config.name);
+
+ /*
+ * If we have "server { ...}", then there SHOULD NOT be
+ * bare "authorize", etc. sections. if there is no such
+ * server, then try to load the old-style sections first.
+ *
+ * In either case, load the "default" virtual server first.
+ * this matches better with users expectations.
+ */
+ cs = cf_section_find_name2(cf_subsection_find_next(config, NULL,
+ "server"),
+ "server", NULL);
+ if (cs) {
+ if (load_byserver(cs) < 0) {
+ return -1;
+ }
+ } else {
+ if (load_byserver(config) < 0) {
+ return -1;
+ }
+ }
+
+ /*
+ * Load all of the virtual servers.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "server")) {
+ char const *name2;
+
+ name2 = cf_section_name2(cs);
+ if (!name2) continue; /* handled above */
+
+ server = virtual_server_find(name2);
+ if (server &&
+ (cf_top_section(server->cs) == config)) {
+ ERROR("Duplicate virtual server \"%s\" in file %s:%d and file %s:%d",
+ server->name,
+ cf_section_filename(server->cs),
+ cf_section_lineno(server->cs),
+ cf_section_filename(cs),
+ cf_section_lineno(cs));
+ return -1;
+ }
+
+ if (load_byserver(cs) < 0) {
+ /*
+ * Once we successfully started once,
+ * continue loading the OTHER servers,
+ * even if one fails.
+ */
+ if (!first_time) continue;
+ return -1;
+ }
+ }
+
+ /*
+ * Try to compile the "authorize", etc. sections which
+ * aren't in a virtual server.
+ */
+ server = virtual_server_find(NULL);
+ if (server) {
+ int i;
+
+ for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+ if (!modcall_pass2(server->mc[i])) return -1;
+ }
+
+ if (server->components &&
+ (rbtree_walk(server->components, RBTREE_IN_ORDER,
+ pass2_cb, NULL) != 0)) {
+ return -1;
+ }
+ }
+
+ /*
+ * Now that we've loaded everything, run pass 2 over the
+ * conditions and xlats.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "server")) {
+ int i;
+ char const *name2;
+
+ name2 = cf_section_name2(cs);
+
+ server = virtual_server_find(name2);
+ if (!server) continue;
+
+ for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+ if (!modcall_pass2(server->mc[i])) return -1;
+ }
+
+ if (server->components &&
+ (rbtree_walk(server->components, RBTREE_IN_ORDER,
+ pass2_cb, NULL) != 0)) {
+ return -1;
+ }
+ }
+
+ /*
+ * If we succeed the first time around, remember that.
+ */
+ first_time = false;
+
+ return 0;
+}
+
+int module_hup_module(CONF_SECTION *cs, module_instance_t *node, time_t when)
+{
+ void *insthandle;
+ fr_module_hup_t *mh;
+
+ if (!node ||
+ node->entry->module->bootstrap ||
+ !node->entry->module->instantiate ||
+ ((node->entry->module->type & RLM_TYPE_HUP_SAFE) == 0)) {
+ return 1;
+ }
+
+ /*
+ * Silently ignore multiple HUPs within a short time period.
+ */
+ if ((node->last_hup + 2) >= when) return 1;
+ node->last_hup = when;
+
+ /*
+ * Clear any old instances before attempting to reload
+ */
+ module_instance_free_old(cs, node, when);
+
+ cf_log_module(cs, "Trying to reload module \"%s\"", node->name);
+
+ /*
+ * Parse the module configuration, and setup destructors so the
+ * module's detach method is called when it's instance data is
+ * about to be freed.
+ */
+ if (module_conf_parse(node, &insthandle) < 0) {
+ cf_log_err_cs(cs, "HUP failed for module \"%s\" (parsing config failed). "
+ "Using old configuration", node->name);
+
+ return 0;
+ }
+
+ if ((node->entry->module->instantiate)(cs, insthandle) < 0) {
+ cf_log_err_cs(cs, "HUP failed for module \"%s\". Using old configuration.", node->name);
+ talloc_free(insthandle);
+
+ return 0;
+ }
+
+ INFO(" Module: Reloaded module \"%s\"", node->name);
+
+ /*
+ * Save the old instance handle for later deletion.
+ */
+ mh = talloc_zero(cs, fr_module_hup_t);
+ mh->mi = node;
+ mh->when = when;
+ mh->insthandle = node->insthandle;
+ mh->next = node->mh;
+ node->mh = mh;
+
+ /*
+ * Replace the instance handle while the module is running.
+ */
+ node->insthandle = insthandle;
+
+ /*
+ * FIXME: Set a timeout to come back in 60s, so that
+ * we can pro-actively clean up the old instances.
+ */
+
+ return 1;
+}
+
+
+int modules_hup(CONF_SECTION *modules)
+{
+ time_t when;
+ CONF_ITEM *ci;
+ CONF_SECTION *cs;
+ module_instance_t *node;
+
+ if (!modules) return 0;
+
+ when = time(NULL);
+
+ /*
+ * Loop over the modules
+ */
+ for (ci=cf_item_find_next(modules, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(modules, ci)) {
+ char const *instname;
+ module_instance_t myNode;
+
+ /*
+ * If it's not a section, ignore it.
+ */
+ if (!cf_item_is_section(ci)) continue;
+
+ cs = cf_item_to_section(ci);
+ instname = cf_section_name2(cs);
+ if (!instname) instname = cf_section_name1(cs);
+
+ strlcpy(myNode.name, instname, sizeof(myNode.name));
+ node = rbtree_finddata(instance_tree, &myNode);
+
+ module_hup_module(cs, node, when);
+ }
+
+ return 1;
+}
+
+
+static int define_type(CONF_SECTION *cs, DICT_ATTR const *da, char const *name)
+{
+ uint32_t value;
+ DICT_VALUE *dval;
+
+ /*
+ * Allow for conditionally loaded types
+ */
+ if (*name == '-') name++;
+
+ /*
+ * If the value already exists, don't
+ * create it again.
+ */
+ dval = dict_valbyname(da->attr, da->vendor, name);
+ if (dval) {
+ if (dval->value == 0) {
+ ERROR("The dictionaries must not define VALUE %s %s 0",
+ da->name, name);
+ return 0;
+ }
+ return 1;
+ }
+
+ /*
+ * Create a new unique value with a
+ * meaningless number. You can't look at
+ * it from outside of this code, so it
+ * doesn't matter. The only requirement
+ * is that it's unique.
+ */
+ do {
+ value = (fr_rand() & 0x00ffffff) + 1;
+ } while (dict_valbyattr(da->attr, da->vendor, value));
+
+ cf_log_module(cs, "Creating %s = %s", da->name, name);
+ if (dict_addvalue(name, da->name, value) < 0) {
+ ERROR("%s", fr_strerror());
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Define Auth-Type, etc. in a server.
+ */
+static bool server_define_types(CONF_SECTION *cs)
+{
+ rlm_components_t comp;
+
+ /*
+ * Loop over all of the components
+ */
+ for (comp = 0; comp < MOD_COUNT; ++comp) {
+ CONF_SECTION *subcs, *type_cs;
+ DICT_ATTR const *da;
+
+ subcs = cf_section_sub_find(cs,
+ section_type_value[comp].section);
+ if (!subcs) continue;
+
+ if (cf_item_find_next(subcs, NULL) == NULL) continue;
+
+ /*
+ * Find the attribute used to store VALUEs for this section.
+ */
+ da = dict_attrbyvalue(section_type_value[comp].attr, 0);
+ if (!da) {
+ cf_log_err_cs(subcs,
+ "No such attribute %s",
+ section_type_value[comp].typename);
+ return false;
+ }
+
+ /*
+ * Define dynamic types, so that others can reference
+ * them.
+ *
+ * First, bare modules for 'authenticate'.
+ * Second, Auth-Type, etc.
+ */
+ if (section_type_value[comp].attr == PW_AUTH_TYPE) {
+ CONF_ITEM *modref;
+
+ for (modref = cf_item_find_next(subcs, NULL);
+ modref != NULL;
+ modref = cf_item_find_next(subcs, modref)) {
+ CONF_PAIR *cp;
+
+ if (!cf_item_is_pair(modref)) continue;
+
+ cp = cf_item_to_pair(modref);
+ if (!define_type(cs, da, cf_pair_attr(cp))) {
+ return false;
+ }
+
+ /*
+ * Check for duplicates
+ */
+ if (rad_debug_lvl) {
+ CONF_PAIR *cp2;
+ CONF_SECTION *cs2;
+
+ cp2 = cf_pair_find(subcs, cf_pair_attr(cp));
+ rad_assert(cp2 != NULL);
+ if (cp2 != cp) {
+ WARN("%s[%d]: Duplicate module '%s'",
+ cf_pair_filename(cp2),
+ cf_pair_lineno(cp2),
+ cf_pair_attr(cp));
+ }
+
+ cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_pair_attr(cp));
+ if (cs2) {
+ WARN("%s[%d]: Duplicate Auth-Type '%s'",
+ cf_section_filename(cs2),
+ cf_section_lineno(cs2),
+ cf_pair_attr(cp));
+ }
+ }
+
+ }
+ }
+
+ /*
+ * And loop over the type names
+ */
+ for (type_cs = cf_subsection_find_next(subcs, NULL, section_type_value[comp].typename);
+ type_cs != NULL;
+ type_cs = cf_subsection_find_next(subcs, type_cs, section_type_value[comp].typename)) {
+ if (!define_type(cs, da, cf_section_name2(type_cs))) {
+ return false;
+ }
+
+ if (rad_debug_lvl) {
+ CONF_SECTION *cs2;
+
+ cs2 = cf_section_sub_find_name2(subcs, section_type_value[comp].typename, cf_section_name2(type_cs));
+ rad_assert(cs2 != NULL);
+ if (cs2 != type_cs) {
+ WARN("%s[%d]: Duplicate Auth-Type '%s'",
+ cf_section_filename(cs2),
+ cf_section_lineno(cs2),
+ cf_section_name2(cs2));
+ }
+ }
+ }
+ } /* loop over components */
+
+ return true;
+}
+
+extern char const *unlang_keyword[];
+
+static bool is_reserved_word(const char *name)
+{
+ int i;
+
+ if (!name || !*name) return false;
+
+ for (i = 1; unlang_keyword[i] != NULL; i++) {
+ if (strcmp(name, unlang_keyword[i]) == 0) return true;
+ }
+
+ return false;
+}
+
+
+/*
+ * Parse the module config sections, and load
+ * and call each module's init() function.
+ */
+int modules_init(CONF_SECTION *config)
+{
+ CONF_ITEM *ci, *next;
+ CONF_SECTION *cs, *modules;
+
+ /*
+ * Set up the internal module struct.
+ */
+ module_tree = rbtree_create(NULL, module_entry_cmp, NULL, 0);
+ if (!module_tree) {
+ ERROR("Failed to initialize modules\n");
+ return -1;
+ }
+
+ instance_tree = rbtree_create(NULL, module_instance_cmp,
+ module_instance_free, 0);
+ if (!instance_tree) {
+ ERROR("Failed to initialize modules\n");
+ return -1;
+ }
+
+ memset(virtual_servers, 0, sizeof(virtual_servers));
+
+ /*
+ * Remember where the modules were stored.
+ */
+ modules = cf_section_sub_find(config, "modules");
+ if (!modules) {
+ WARN("Cannot find a \"modules\" section in the configuration file!");
+ }
+
+ /*
+ * Load dictionaries.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "server")) {
+#if defined(WITH_DHCP) || defined(WITH_VMPS)
+ CONF_SECTION *subcs;
+ DICT_ATTR const *da;
+#endif
+
+#ifdef WITH_VMPS
+ /*
+ * Auto-load the VMPS/VQP dictionary.
+ */
+ subcs = cf_section_sub_find(cs, "vmps");
+ if (subcs) {
+ da = dict_attrbyname("VQP-Packet-Type");
+ if (!da) {
+ if (dict_read(main_config.dictionary_dir, "dictionary.vqp") < 0) {
+ ERROR("Failed reading dictionary.vqp: %s",
+ fr_strerror());
+ return -1;
+ }
+ cf_log_module(cs, "Loading dictionary.vqp");
+
+ da = dict_attrbyname("VQP-Packet-Type");
+ if (!da) {
+ ERROR("No VQP-Packet-Type in dictionary.vqp");
+ return -1;
+ }
+ }
+ }
+#endif
+
+#ifdef WITH_DHCP
+ /*
+ * Auto-load the DHCP dictionary.
+ */
+ subcs = cf_subsection_find_next(cs, NULL, "dhcp");
+ if (subcs) {
+ da = dict_attrbyname("DHCP-Message-Type");
+ if (!da) {
+ cf_log_module(cs, "Loading dictionary.dhcp");
+ if (dict_read(main_config.dictionary_dir, "dictionary.dhcp") < 0) {
+ ERROR("Failed reading dictionary.dhcp: %s",
+ fr_strerror());
+ return -1;
+ }
+
+ da = dict_attrbyname("DHCP-Message-Type");
+ if (!da) {
+ ERROR("No DHCP-Message-Type in dictionary.dhcp");
+ return -1;
+ }
+ }
+ }
+#endif
+ /*
+ * Else it's a RADIUS virtual server, and the
+ * dictionaries are already loaded.
+ */
+
+ /*
+ * Root through each virtual server, defining
+ * Autz-Type and Auth-Type. This is so that the
+ * modules can reference a particular type.
+ */
+ if (!server_define_types(cs)) return -1;
+ }
+
+ DEBUG2("%s: #### Instantiating modules ####", main_config.name);
+
+ cf_log_info(config, " modules {");
+
+ /*
+ * Loop over module definitions, looking for duplicates.
+ *
+ * This is O(N^2) in the number of modules, but most
+ * systems should have less than 100 modules.
+ */
+ for (ci = cf_item_find_next(modules, NULL);
+ ci != NULL;
+ ci = next) {
+ char const *name1;
+ CONF_SECTION *subcs;
+ module_instance_t *node;
+
+ next = cf_item_find_next(modules, ci);
+
+ if (!cf_item_is_section(ci)) continue;
+
+ subcs = cf_item_to_section(ci);
+
+ node = module_bootstrap(subcs);
+ if (!node) return -1;
+
+ if (!next || !cf_item_is_section(next)) continue;
+
+ name1 = cf_section_name1(subcs);
+
+ if (is_reserved_word(name1)) {
+ cf_log_err_cs(subcs, "Module cannot be named for an 'unlang' keyword");
+ return -1;
+ }
+ }
+
+ /*
+ * Look for the 'instantiate' section, which tells us
+ * the instantiation order of the modules, and also allows
+ * us to load modules with no authorize/authenticate/etc.
+ * sections.
+ */
+ cs = cf_section_sub_find(config, "instantiate");
+ if (cs) {
+ CONF_PAIR *cp;
+ module_instance_t *module;
+ char const *name;
+
+ cf_log_info(cs, " instantiate {");
+
+ /*
+ * Loop over the items in the 'instantiate' section.
+ */
+ for (ci=cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(cs, ci)) {
+ /*
+ * Skip sections and "other" stuff.
+ * Sections will be handled later, if
+ * they're referenced at all...
+ */
+ if (cf_item_is_pair(ci)) {
+ cp = cf_item_to_pair(ci);
+ name = cf_pair_attr(cp);
+
+ module = module_instantiate(modules, name);
+ if (!module && (name[0] != '-')) {
+ return -1;
+ }
+ }
+
+ /*
+ * Can only be "redundant" or
+ * "load-balance" or
+ * "redundant-load-balance"
+ */
+ if (cf_item_is_section(ci)) {
+ bool all_same = true;
+ module_t const *last = NULL;
+ CONF_SECTION *subcs;
+ CONF_ITEM *subci;
+
+ subcs = cf_item_to_section(ci);
+ name = cf_section_name1(subcs);
+
+ /*
+ * Groups, etc. must have a name.
+ */
+ if (((strcmp(name, "group") == 0) ||
+ (strcmp(name, "redundant") == 0) ||
+ (strcmp(name, "redundant-load-balance") == 0) ||
+ strcmp(name, "load-balance") == 0)) {
+ name = cf_section_name2(subcs);
+ if (!name) {
+ cf_log_err_cs(subcs, "Subsection must have a name");
+ return -1;
+ }
+
+ if (is_reserved_word(name)) {
+ cf_log_err_cs(subcs, "Instantiate sections cannot be named for an 'unlang' keyword");
+ return -1;
+ }
+ } else {
+ if (is_reserved_word(name)) {
+ cf_log_err_cs(subcs, "Instantiate sections cannot be named for an 'unlang' keyword");
+ return -1;
+ }
+ }
+
+ /*
+ * Ensure that the modules we reference here exist.
+ */
+ for (subci=cf_item_find_next(subcs, NULL);
+ subci != NULL;
+ subci=cf_item_find_next(subcs, subci)) {
+ if (cf_item_is_pair(subci)) {
+ cp = cf_item_to_pair(subci);
+ if (cf_pair_value(cp)) {
+ cf_log_err(subci, "Cannot set return codes in a %s block",
+ cf_section_name1(subcs));
+ return -1;
+ }
+
+ /*
+ * Allow "foo.authorize" in subsections.
+ */
+ module = module_instantiate_method(modules, cf_pair_attr(cp), NULL);
+ if (!module) {
+ return -1;
+ }
+
+ if (all_same) {
+ if (!last) {
+ last = module->entry->module;
+ } else if (last != module->entry->module) {
+ last = NULL;
+ all_same = false;
+ }
+ }
+ } else {
+ all_same = false;
+ }
+
+ /*
+ * Don't check subsections for now.
+ */
+ } /* loop over modules in a "redundant foo" section */
+
+ /*
+ * Register a redundant xlat
+ */
+ if (all_same) {
+ if (!xlat_register_redundant(cf_item_to_section(ci))) {
+ WARN("%s[%d] Not registering expansions for %s",
+ cf_section_filename(subcs), cf_section_lineno(subcs),
+ cf_section_name2(subcs));
+ }
+ }
+ } /* handle subsections */
+ } /* loop over the "instantiate" section */
+
+ cf_log_info(cs, " }");
+ } /* if there's an 'instantiate' section. */
+
+ /*
+ * Now that we've loaded the explicitly ordered modules,
+ * load everything in the "modules" section. This is
+ * because we've now split up the modules into
+ * mods-enabled.
+ */
+ for (ci=cf_item_find_next(modules, NULL);
+ ci != NULL;
+ ci=next) {
+ char const *name;
+ module_instance_t *module;
+ CONF_SECTION *subcs;
+
+ next = cf_item_find_next(modules, ci);
+
+ if (!cf_item_is_section(ci)) continue;
+
+ subcs = cf_item_to_section(ci);
+ name = cf_section_name2(subcs);
+ if (!name) name = cf_section_name1(subcs);
+
+ module = module_instantiate(modules, name);
+ if (!module) return -1;
+ }
+ cf_log_info(config, " } # modules");
+
+ if (virtual_servers_load(config) < 0) return -1;
+
+ return 0;
+}
+
+/*
+ * Call all authorization modules until one returns
+ * somethings else than RLM_MODULE_OK
+ */
+rlm_rcode_t process_authorize(int autz_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_AUTHORIZE, autz_type, request);
+}
+
+/*
+ * Authenticate a user/password with various methods.
+ */
+rlm_rcode_t process_authenticate(int auth_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_AUTHENTICATE, auth_type, request);
+}
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Do pre-accounting for ALL configured sessions
+ */
+rlm_rcode_t module_preacct(REQUEST *request)
+{
+ return indexed_modcall(MOD_PREACCT, 0, request);
+}
+
+/*
+ * Do accounting for ALL configured sessions
+ */
+rlm_rcode_t process_accounting(int acct_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_ACCOUNTING, acct_type, request);
+}
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * See if a user is already logged in.
+ *
+ * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt
+ */
+int process_checksimul(int sess_type, REQUEST *request, int maxsimul)
+{
+ rlm_rcode_t rcode;
+
+ if(!request->username)
+ return 0;
+
+ request->simul_count = 0;
+ request->simul_max = maxsimul;
+ request->simul_mpp = 1;
+
+ rcode = indexed_modcall(MOD_SESSION, sess_type, request);
+
+ if (rcode != RLM_MODULE_OK) {
+ /* FIXME: Good spot for a *rate-limited* warning to the log */
+ return 0;
+ }
+
+ return (request->simul_count < maxsimul) ? 0 : request->simul_mpp;
+}
+#endif
+
+#ifdef WITH_PROXY
+/*
+ * Do pre-proxying for ALL configured sessions
+ */
+rlm_rcode_t process_pre_proxy(int type, REQUEST *request)
+{
+ return indexed_modcall(MOD_PRE_PROXY, type, request);
+}
+
+/*
+ * Do post-proxying for ALL configured sessions
+ */
+rlm_rcode_t process_post_proxy(int type, REQUEST *request)
+{
+ return indexed_modcall(MOD_POST_PROXY, type, request);
+}
+#endif
+
+/*
+ * Do post-authentication for ALL configured sessions
+ */
+rlm_rcode_t process_post_auth(int postauth_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_POST_AUTH, postauth_type, request);
+}
+
+#ifdef WITH_COA
+rlm_rcode_t process_recv_coa(int recv_coa_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_RECV_COA, recv_coa_type, request);
+}
+
+rlm_rcode_t process_send_coa(int send_coa_type, REQUEST *request)
+{
+ return indexed_modcall(MOD_SEND_COA, send_coa_type, request);
+}
+#endif
diff --git a/src/main/pair.c b/src/main/pair.c
new file mode 100644
index 0000000..3725ba1
--- /dev/null
+++ b/src/main/pair.c
@@ -0,0 +1,911 @@
+/*
+ * 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 Valuepair functions that are radiusd-specific and as such do not
+ * belong in the library.
+ * @file main/pair.c
+ *
+ * @ingroup AVP
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <ctype.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+struct cmp {
+ DICT_ATTR const *attribute;
+ DICT_ATTR const *from;
+ bool first_only;
+ void *instance; /* module instance */
+ RAD_COMPARE_FUNC compare;
+ struct cmp *next;
+};
+static struct cmp *cmp;
+
+/** Compares check and vp by value.
+ *
+ * Does not call any per-attribute comparison function, but does honour
+ * check.operator. Basically does "vp.value check.op check.value".
+ *
+ * @param request Current request.
+ * @param check rvalue, and operator.
+ * @param vp lvalue.
+ * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
+ * value, -2 on error.
+ */
+#ifdef HAVE_REGEX
+int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
+#else
+int radius_compare_vps(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
+#endif
+{
+ int ret = 0;
+
+ /*
+ * Check for =* and !* and return appropriately
+ */
+ if (check->op == T_OP_CMP_TRUE) return 0;
+ if (check->op == T_OP_CMP_FALSE) return 1;
+
+#ifdef HAVE_REGEX
+ if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) {
+ ssize_t slen;
+ regex_t *preg = NULL;
+ regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* +1 for %{0} (whole match) capture group */
+ size_t nmatch = sizeof(rxmatch) / sizeof(regmatch_t);
+
+ char *expr = NULL, *value = NULL;
+ char const *expr_p, *value_p;
+
+ if (!vp) return -2;
+
+ if (check->da->type == PW_TYPE_STRING) {
+ expr_p = check->vp_strvalue;
+ } else {
+ expr_p = expr = vp_aprints_value(request, check, '\0');
+ }
+
+ if (vp->da->type == PW_TYPE_STRING) {
+ value_p = vp->vp_strvalue;
+ } else {
+ value_p = value = vp_aprints_value(request, vp, '\0');
+ }
+
+ if (!expr_p || !value_p) {
+ REDEBUG("Error stringifying operand for regular expression");
+
+ regex_error:
+ talloc_free(preg);
+ talloc_free(expr);
+ talloc_free(value);
+ return -2;
+ }
+
+ /*
+ * Include substring matches.
+ */
+ slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1, false, false, true, true);
+ if (slen <= 0) {
+ REMARKER(expr_p, -slen, fr_strerror());
+
+ goto regex_error;
+ }
+
+ slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, rxmatch, &nmatch);
+ if (slen < 0) {
+ RERROR("%s", fr_strerror());
+
+ goto regex_error;
+ }
+
+ if (check->op == T_OP_REG_EQ) {
+ /*
+ * Add in %{0}. %{1}, etc.
+ */
+ regex_sub_to_request(request, &preg, value_p, talloc_array_length(value_p) - 1,
+ rxmatch, nmatch);
+ ret = (slen == 1) ? 0 : -1;
+ } else {
+ ret = (slen != 1) ? 0 : -1;
+ }
+
+ talloc_free(preg);
+ talloc_free(expr);
+ talloc_free(value);
+ goto finish;
+ }
+#endif
+
+ /*
+ * Attributes must be of the same type.
+ *
+ * FIXME: deal with type mismatch properly if one side contain
+ * ABINARY, OCTETS or STRING by converting the other side to
+ * a string
+ *
+ */
+ if (vp->da->type != check->da->type) return -1;
+
+ /*
+ * Tagged attributes are equal if and only if both the
+ * tag AND value match.
+ */
+ if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
+ ret = ((int) vp->tag) - ((int) check->tag);
+ if (ret != 0) goto finish;
+ }
+
+ /*
+ * Not a regular expression, compare the types.
+ */
+ switch (check->da->type) {
+#ifdef WITH_ASCEND_BINARY
+ /*
+ * Ascend binary attributes can be treated
+ * as opaque objects, I guess...
+ */
+ case PW_TYPE_ABINARY:
+#endif
+ case PW_TYPE_OCTETS:
+ if (vp->vp_length != check->vp_length) {
+ ret = 1; /* NOT equal */
+ break;
+ }
+ ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
+ vp->vp_length);
+ break;
+
+ case PW_TYPE_STRING:
+ ret = strcmp(vp->vp_strvalue,
+ check->vp_strvalue);
+ break;
+
+ case PW_TYPE_BYTE:
+ ret = vp->vp_byte - check->vp_byte;
+ break;
+ case PW_TYPE_SHORT:
+ ret = vp->vp_short - check->vp_short;
+ break;
+ case PW_TYPE_INTEGER:
+ ret = vp->vp_integer - check->vp_integer;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ /*
+ * Don't want integer overflow!
+ */
+ if (vp->vp_integer64 < check->vp_integer64) {
+ ret = -1;
+ } else if (vp->vp_integer64 > check->vp_integer64) {
+ ret = +1;
+ } else {
+ ret = 0;
+ }
+ break;
+
+ case PW_TYPE_SIGNED:
+ if (vp->vp_signed < check->vp_signed) {
+ ret = -1;
+ } else if (vp->vp_signed > check->vp_signed) {
+ ret = +1;
+ } else {
+ ret = 0;
+ }
+ break;
+
+ case PW_TYPE_DATE:
+ ret = vp->vp_date - check->vp_date;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
+ ret = fr_pair_cmp_op(check->op, vp, check);
+ if (ret == -1) return -2; // error
+ if (check->op == T_OP_LT || check->op == T_OP_LE)
+ ret = (ret == 1) ? -1 : 1;
+ else if (check->op == T_OP_GT || check->op == T_OP_GE)
+ ret = (ret == 1) ? 1 : -1;
+ else if (check->op == T_OP_CMP_EQ)
+ ret = (ret == 1) ? 0 : -1;
+ break;
+
+ case PW_TYPE_IFID:
+ ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid));
+ break;
+
+ default:
+ break;
+ }
+
+finish:
+ if (ret > 0) return 1;
+ if (ret < 0) return -1;
+ return 0;
+}
+
+
+/** Compare check and vp. May call the attribute comparison function.
+ *
+ * Unlike radius_compare_vps() this function will call any attribute-specific
+ * comparison functions registered.
+ *
+ * @param request Current request.
+ * @param req list pairs.
+ * @param check item to compare.
+ * @param check_pairs list.
+ * @param reply_pairs list.
+ * @return 0 if check and vp are equal, -1 if vp value is less than check value, 1 is vp value is more than check
+ * value.
+ */
+int radius_callback_compare(REQUEST *request, VALUE_PAIR *req,
+ VALUE_PAIR *check, VALUE_PAIR *check_pairs,
+ VALUE_PAIR **reply_pairs)
+{
+ struct cmp *c;
+
+ /*
+ * Check for =* and !* and return appropriately
+ */
+ if (check->op == T_OP_CMP_TRUE) return 0;
+ if (check->op == T_OP_CMP_FALSE) return 1;
+
+ /*
+ * See if there is a special compare function.
+ *
+ * FIXME: use new RB-Tree code.
+ */
+ for (c = cmp; c; c = c->next) {
+ if (c->attribute == check->da) {
+ return (c->compare)(c->instance, request, req, check,
+ check_pairs, reply_pairs);
+ }
+ }
+
+ if (!req) return -1; /* doesn't exist, don't compare it */
+
+ return radius_compare_vps(request, check, req);
+}
+
+
+/** Find a comparison function for two attributes.
+ *
+ * @todo this should probably take DA's.
+ * @param attribute to find comparison function for.
+ * @return true if a comparison function was found, else false.
+ */
+int radius_find_compare(DICT_ATTR const *attribute)
+{
+ struct cmp *c;
+
+ for (c = cmp; c; c = c->next) {
+ if (c->attribute == attribute) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/** See what attribute we want to compare with.
+ *
+ * @param attribute to find comparison function for.
+ * @param from reference to compare with
+ * @return true if the comparison callback require a matching attribue in the request, else false.
+ */
+static bool otherattr(DICT_ATTR const *attribute, DICT_ATTR const **from)
+{
+ struct cmp *c;
+
+ for (c = cmp; c; c = c->next) {
+ if (c->attribute == attribute) {
+ *from = c->from;
+ return c->first_only;
+ }
+ }
+
+ *from = attribute;
+ return false;
+}
+
+/** Register a function as compare function.
+ *
+ * @param name the attribute comparison to register
+ * @param from the attribute we want to compare with. Normally this is the same as attribute.
+ * If null call the comparison function on every attributes in the request if first_only is false
+ * @param first_only will decide if we loop over the request attributes or stop on the first one
+ * @param func comparison function
+ * @param instance argument to comparison function
+ * @return 0
+ */
+int paircompare_register_byname(char const *name, DICT_ATTR const *from,
+ bool first_only, RAD_COMPARE_FUNC func, void *instance)
+{
+ ATTR_FLAGS flags;
+ DICT_ATTR const *da;
+
+ memset(&flags, 0, sizeof(flags));
+ flags.compare = 1;
+
+ da = dict_attrbyname(name);
+ if (da) {
+ if (!da->flags.compare) {
+ fr_strerror_printf("Attribute '%s' already exists.", name);
+ return -1;
+ }
+ } else if (from) {
+ if (dict_addattr(name, -1, 0, from->type, flags) < 0) {
+ fr_strerror_printf("Failed creating attribute '%s'", name);
+ return -1;
+ }
+
+ da = dict_attrbyname(name);
+ if (!da) {
+ fr_strerror_printf("Failed finding attribute '%s'", name);
+ return -1;
+ }
+
+ DEBUG("Creating attribute %s", name);
+ }
+
+ return paircompare_register(da, from, first_only, func, instance);
+}
+
+/** Register a function as compare function.
+ *
+ * @param attribute to register comparison function for.
+ * @param from the attribute we want to compare with. Normally this is the same as attribute.
+ * If null call the comparison function on every attributes in the request if first_only is false
+ * @param first_only will decide if we loop over the request attributes or stop on the first one
+ * @param func comparison function
+ * @param instance argument to comparison function
+ * @return 0
+ */
+int paircompare_register(DICT_ATTR const *attribute, DICT_ATTR const *from,
+ bool first_only, RAD_COMPARE_FUNC func, void *instance)
+{
+ struct cmp *c;
+
+ rad_assert(attribute != NULL);
+
+ paircompare_unregister(attribute, func);
+
+ c = rad_malloc(sizeof(struct cmp));
+
+ c->compare = func;
+ c->attribute = attribute;
+ c->from = from;
+ c->first_only = first_only;
+ c->instance = instance;
+ c->next = cmp;
+ cmp = c;
+
+ return 0;
+}
+
+/** Unregister comparison function for an attribute
+ *
+ * @param attribute dict reference to unregister for.
+ * @param func comparison function to remove.
+ */
+void paircompare_unregister(DICT_ATTR const *attribute, RAD_COMPARE_FUNC func)
+{
+ struct cmp *c, *last;
+
+ last = NULL;
+ for (c = cmp; c; c = c->next) {
+ if (c->attribute == attribute && c->compare == func) {
+ break;
+ }
+ last = c;
+ }
+
+ if (c == NULL) return;
+
+ if (last != NULL) {
+ last->next = c->next;
+ } else {
+ cmp = c->next;
+ }
+
+ free(c);
+}
+
+/** Unregister comparison function for a module
+ *
+ * All paircompare() functions for this module will be unregistered.
+ *
+ * @param instance the module instance
+ */
+void paircompare_unregister_instance(void *instance)
+{
+ struct cmp *c, **tail;
+
+ tail = &cmp;
+ while ((c = *tail) != NULL) {
+ if (c->instance == instance) {
+ *tail = c->next;
+ free(c);
+ continue;
+ }
+
+ tail = &(c->next);
+ }
+}
+
+/** Compare two pair lists except for the password information.
+ *
+ * For every element in "check" at least one matching copy must be present
+ * in "reply".
+ *
+ * @param[in] request Current request.
+ * @param[in] req_list request valuepairs.
+ * @param[in] check Check/control valuepairs.
+ * @param[in,out] rep_list Reply value pairs.
+ *
+ * @return 0 on match.
+ */
+int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
+ VALUE_PAIR **rep_list)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *check_item;
+ VALUE_PAIR *auth_item = NULL;
+ DICT_ATTR const *from;
+
+ int result = 0;
+ int compare;
+ bool first_only;
+
+ for (check_item = fr_cursor_init(&cursor, &check);
+ check_item;
+ check_item = fr_cursor_next(&cursor)) {
+ /*
+ * If the user is setting a configuration value,
+ * then don't bother comparing it to any attributes
+ * sent to us by the user. It ALWAYS matches.
+ */
+ if ((check_item->op == T_OP_SET) ||
+ (check_item->op == T_OP_ADD)) {
+ continue;
+ }
+
+ if (!check_item->da->vendor) switch (check_item->da->attr) {
+ /*
+ * Attributes we skip during comparison.
+ * These are "server" check items.
+ */
+ case PW_CRYPT_PASSWORD:
+ case PW_AUTH_TYPE:
+ case PW_AUTZ_TYPE:
+ case PW_ACCT_TYPE:
+ case PW_SESSION_TYPE:
+ case PW_STRIP_USER_NAME:
+ continue;
+
+ /*
+ * IF the password attribute exists, THEN
+ * we can do comparisons against it. If not,
+ * then the request did NOT contain a
+ * User-Password attribute, so we CANNOT do
+ * comparisons against it.
+ *
+ * This hack makes CHAP-Password work..
+ */
+ case PW_USER_PASSWORD:
+ if (check_item->op == T_OP_CMP_EQ) {
+ WARN("Found User-Password == \"...\"");
+ WARN("Are you sure you don't mean Cleartext-Password?");
+ WARN("See \"man rlm_pap\" for more information");
+ }
+ if (fr_pair_find_by_num(req_list, PW_USER_PASSWORD, 0, TAG_ANY) == NULL) {
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * See if this item is present in the request.
+ */
+ first_only = otherattr(check_item->da, &from);
+
+ auth_item = req_list;
+ try_again:
+ if (!first_only) {
+ while (auth_item != NULL) {
+ VERIFY_VP(auth_item);
+ if ((auth_item->da == from) || (!from)) {
+ break;
+ }
+ auth_item = auth_item->next;
+ }
+ }
+
+ /*
+ * Not found, it's not a match.
+ */
+ if (auth_item == NULL) {
+ /*
+ * Didn't find it. If we were *trying*
+ * to not find it, then we succeeded.
+ */
+ if (check_item->op == T_OP_CMP_FALSE) {
+ continue;
+ } else {
+ return -1;
+ }
+ }
+
+ /*
+ * Else we found it, but we were trying to not
+ * find it, so we failed.
+ */
+ if (check_item->op == T_OP_CMP_FALSE) {
+ return -1;
+ }
+
+ /*
+ * We've got to xlat the string before doing
+ * the comparison.
+ */
+ radius_xlat_do(request, check_item);
+
+ /*
+ * OK it is present now compare them.
+ */
+ compare = radius_callback_compare(request, auth_item,
+ check_item, check, rep_list);
+
+ switch (check_item->op) {
+ case T_OP_EQ:
+ default:
+ RWDEBUG("Invalid operator '%s' for item %s: reverting to '=='",
+ fr_int2str(fr_tokens, check_item->op, "<INVALID>"), check_item->da->name);
+ /* FALL-THROUGH */
+ case T_OP_CMP_TRUE:
+ case T_OP_CMP_FALSE:
+ case T_OP_CMP_EQ:
+ if (compare != 0) result = -1;
+ break;
+
+ case T_OP_NE:
+ if (compare == 0) result = -1;
+ break;
+
+ case T_OP_LT:
+ if (compare >= 0) result = -1;
+ break;
+
+ case T_OP_GT:
+ if (compare <= 0) result = -1;
+ break;
+
+ case T_OP_LE:
+ if (compare > 0) result = -1;
+ break;
+
+ case T_OP_GE:
+ if (compare < 0) result = -1;
+ break;
+
+#ifdef HAVE_REGEX
+ case T_OP_REG_EQ:
+ case T_OP_REG_NE:
+ if (compare != 0) result = -1;
+ break;
+#endif
+ } /* switch over the operator of the check item */
+
+ /*
+ * This attribute didn't match, but maybe there's
+ * another of the same attribute, which DOES match.
+ */
+ if ((result != 0) && (!first_only)) {
+ fr_assert(auth_item != NULL);
+ auth_item = auth_item->next;
+ result = 0;
+ goto try_again;
+ }
+
+ } /* for every entry in the check item list */
+
+ return result;
+}
+
+/** Expands an attribute marked with fr_pair_mark_xlat
+ *
+ * Writes the new value to the vp.
+ *
+ * @param request Current request.
+ * @param vp to expand.
+ * @return 0 if successful else -1 (on xlat failure) or -2 (on parse failure).
+ * On failure pair will still no longer be marked for xlat expansion.
+ */
+int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
+{
+ ssize_t slen;
+
+ char *expanded = NULL;
+ if (vp->type != VT_XLAT) return 0;
+
+ vp->type = VT_DATA;
+
+ slen = radius_axlat(&expanded, request, vp->value.xlat, NULL, NULL);
+ rad_const_free(vp->value.xlat);
+ vp->value.xlat = NULL;
+ if (slen < 0) {
+ return -1;
+ }
+
+ /*
+ * Parse the string into a new value.
+ *
+ * If the VALUE_PAIR is being used in a regular expression
+ * then we just want to copy the new value in unmolested.
+ */
+ if ((vp->op == T_OP_REG_EQ) || (vp->op == T_OP_REG_NE)) {
+ fr_pair_value_strsteal(vp, expanded);
+ return 0;
+ }
+
+ if (fr_pair_value_from_str(vp, expanded, -1) < 0){
+ talloc_free(expanded);
+ return -2;
+ }
+
+ talloc_free(expanded);
+
+ return 0;
+}
+
+/** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s
+ *
+ * @note This function ALWAYS returns. If we're OOM, then it causes the
+ * @note server to exit, so you don't need to check the return value.
+ *
+ * @param[in] ctx for talloc
+ * @param[out] vps List to add new VALUE_PAIR to, if NULL will just
+ * return VALUE_PAIR.
+ * @param[in] attribute number.
+ * @param[in] vendor number.
+ * @return a new VLAUE_PAIR or causes server to exit on error.
+ */
+VALUE_PAIR *radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps,
+ unsigned int attribute, unsigned int vendor)
+{
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_afrom_num(ctx, attribute, vendor);
+ if (!vp) {
+ ERROR("No memory!");
+ rad_assert("No memory" == NULL);
+ fr_exit_now(1);
+ }
+
+ if (vps) fr_pair_add(vps, vp);
+
+ return vp;
+}
+
+/** Print a single valuepair to stderr or error log.
+ *
+ * @param[in] vp list to print.
+ */
+void debug_pair(VALUE_PAIR *vp)
+{
+ if (!vp || !rad_debug_lvl || !fr_log_fp) return;
+
+ vp_print(fr_log_fp, vp);
+}
+
+/** Print a single valuepair to stderr or error log.
+ *
+ * @param[in] level Debug level (1-4).
+ * @param[in] request to read logging params from.
+ * @param[in] vp to print.
+ * @param[in] prefix (optional).
+ */
+void rdebug_pair(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
+{
+ char buffer[768];
+ if (!vp || !request || !request->log.func) return;
+
+ if (!radlog_debug_enabled(L_DBG, level, request)) return;
+
+ if (vp->da->flags.secret && request->root && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUGX(level, "%s%s = <<< secret >>>", prefix ? prefix : "", vp->da->name);
+ return;
+ }
+
+ vp_prints(buffer, sizeof(buffer), vp);
+ RDEBUGX(level, "%s%s", prefix ? prefix : "", buffer);
+}
+
+/** Print a list of VALUE_PAIRs.
+ *
+ * @param[in] level Debug level (1-4).
+ * @param[in] request to read logging params from.
+ * @param[in] vp to print.
+ * @param[in] prefix (optional).
+ */
+void rdebug_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
+{
+ vp_cursor_t cursor;
+ char buffer[768];
+ if (!vp || !request || !request->log.func) return;
+
+ if (!radlog_debug_enabled(L_DBG, level, request)) return;
+
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &vp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VERIFY_VP(vp);
+
+ if (vp->da->flags.secret && request->root && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUGX(level, "%s%s = <<< secret >>>", prefix ? prefix : "", vp->da->name);
+ continue;
+ }
+
+ vp_prints(buffer, sizeof(buffer), vp);
+ RDEBUGX(level, "%s%s", prefix ? prefix : "", buffer);
+ }
+ REXDENT();
+}
+
+/** Print a list of protocol VALUE_PAIRs.
+ *
+ * @param[in] level Debug level (1-4).
+ * @param[in] request to read logging params from.
+ * @param[in] vp to print.
+ */
+void rdebug_proto_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp)
+{
+ vp_cursor_t cursor;
+ char buffer[768];
+ if (!vp || !request || !request->log.func) return;
+
+ if (!radlog_debug_enabled(L_DBG, level, request)) return;
+
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &vp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VERIFY_VP(vp);
+ if ((vp->da->vendor == 0) &&
+ ((vp->da->attr & 0xFFFF) > 0xff)) continue;
+
+ if (vp->da->flags.secret && request->root && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUGX(level, "%s = <<< secret >>>", vp->da->name);
+ continue;
+ }
+
+ vp_prints(buffer, sizeof(buffer), vp);
+ RDEBUGX(level, "%s", buffer);
+ }
+ REXDENT();
+}
+
+/** Return a VP from the specified request.
+ *
+ * @param out where to write the pointer to the resolved VP.
+ * Will be NULL if the attribute couldn't be resolved.
+ * @param request current request.
+ * @param name attribute name including qualifiers.
+ * @return -4 if either the attribute or qualifier were invalid, and the same error codes as tmpl_find_vp for other
+ * error conditions.
+ */
+int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
+{
+ int rcode;
+ vp_tmpl_t vpt;
+
+ *out = NULL;
+
+ if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
+ return -4;
+ }
+
+ rcode = tmpl_find_vp(out, request, &vpt);
+
+ return rcode;
+}
+
+/** Copy VP(s) from the specified request.
+ *
+ * @param ctx to alloc new VALUE_PAIRs in.
+ * @param out where to write the pointer to the copied VP.
+ * Will be NULL if the attribute couldn't be resolved.
+ * @param request current request.
+ * @param name attribute name including qualifiers.
+ * @return -4 if either the attribute or qualifier were invalid, and the same error codes as tmpl_find_vp for other
+ * error conditions.
+ */
+int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
+{
+ int rcode;
+ vp_tmpl_t vpt;
+
+ *out = NULL;
+
+ if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
+ return -4;
+ }
+
+ rcode = tmpl_copy_vps(ctx, out, request, &vpt);
+
+ return rcode;
+}
+
+void module_failure_msg(REQUEST *request, char const *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmodule_failure_msg(request, fmt, ap);
+ va_end(ap);
+}
+
+/** Add a module failure message VALUE_PAIR to the request
+ */
+void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
+{
+ char *p;
+ VALUE_PAIR *vp;
+ va_list aq;
+
+ if (!fmt || !request || !request->packet) {
+ return;
+ }
+
+ /*
+ * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
+ * due to ap sometimes being implemented with a stack offset which is invalidated if
+ * ap is passed into another function. See here:
+ * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
+ *
+ * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
+ * running unit tests which generate errors under CI.
+ */
+ va_copy(aq, ap);
+ p = talloc_vasprintf(request, fmt, aq);
+ va_end(aq);
+
+ MEM(vp = pair_make_request("Module-Failure-Message", NULL, T_OP_ADD));
+ if (request->module && (request->module[0] != '\0')) {
+ fr_pair_value_sprintf(vp, "%s: %s", request->module, p);
+ } else {
+ fr_pair_value_sprintf(vp, "%s", p);
+ }
+ talloc_free(p);
+}
diff --git a/src/main/parser.c b/src/main/parser.c
new file mode 100644
index 0000000..e337b94
--- /dev/null
+++ b/src/main/parser.c
@@ -0,0 +1,1809 @@
+/*
+ * parser.c Parse various things
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2013 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#define PW_CAST_BASE (1850)
+
+static const FR_NAME_NUMBER allowed_return_codes[] = {
+ { "reject", 1 },
+ { "fail", 1 },
+ { "ok", 1 },
+ { "handled", 1 },
+ { "invalid", 1 },
+ { "userlock", 1 },
+ { "notfound", 1 },
+ { "noop", 1 },
+ { "updated", 1 },
+ { NULL, 0 }
+};
+
+/*
+ * This file shouldn't use any functions from the server core.
+ */
+
+size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *in)
+{
+ size_t len;
+ char *p = buffer;
+ char *end = buffer + bufsize - 1;
+ fr_cond_t const *c = in;
+
+ rad_assert(bufsize > 0);
+
+next:
+ rad_assert(p < end);
+
+ if (!c) {
+ p[0] = '\0';
+ return 0;
+ }
+
+ /*
+ * Don't overflow the output buffer.
+ */
+ if ((end - p) < 2) {
+ p[0] = '\0';
+ return 0;
+ }
+
+ if (c->negate) {
+ *(p++) = '!'; /* FIXME: only allow for child? */
+ }
+
+ switch (c->type) {
+ case COND_TYPE_EXISTS:
+ rad_assert(c->data.vpt != NULL);
+ if (c->cast) {
+ snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
+ c->cast->type, "??"));
+ p += strlen(p);
+ }
+
+ len = tmpl_prints(p, end - p, c->data.vpt, NULL);
+ p += len;
+ break;
+
+ case COND_TYPE_MAP:
+ rad_assert(c->data.map != NULL);
+#if 0
+ *(p++) = '['; /* for extra-clear debugging */
+#endif
+ if (c->cast) {
+ snprintf(p, end - p, "<%s>", fr_int2str(dict_attr_types,
+ c->cast->type, "??"));
+ p += strlen(p);
+ }
+
+ len = map_prints(p, end - p, c->data.map);
+ p += len;
+#if 0
+ *(p++) = ']';
+#endif
+ break;
+
+ case COND_TYPE_CHILD:
+ rad_assert(c->data.child != NULL);
+ *(p++) = '(';
+ len = fr_cond_sprint(p, end - p, c->data.child);
+ p += len;
+ *(p++) = ')';
+ break;
+
+ case COND_TYPE_TRUE:
+ strlcpy(buffer, "true", bufsize);
+ return strlen(buffer);
+
+ case COND_TYPE_FALSE:
+ strlcpy(buffer, "false", bufsize);
+ return strlen(buffer);
+
+ default:
+ *buffer = '\0';
+ return 0;
+ }
+
+ if (c->next_op == COND_NONE) {
+ rad_assert(c->next == NULL);
+ *p = '\0';
+ return p - buffer;
+ }
+
+ if (c->next_op == COND_AND) {
+ strlcpy(p, " && ", end - p);
+ p += strlen(p);
+
+ } else if (c->next_op == COND_OR) {
+ strlcpy(p, " || ", end - p);
+ p += strlen(p);
+
+ } else {
+ rad_assert(0 == 1);
+ }
+
+ c = c->next;
+ goto next;
+}
+
+
+static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start,
+ FR_TOKEN *op)
+{
+ char const *p = start;
+ char *q;
+
+ switch (*p++) {
+ default:
+ return -1;
+
+ case '"':
+ *op = T_DOUBLE_QUOTED_STRING;
+ break;
+
+ case '\'':
+ *op = T_SINGLE_QUOTED_STRING;
+ break;
+
+ case '`':
+ *op = T_BACK_QUOTED_STRING;
+ break;
+
+ case '/':
+ *op = T_OP_REG_EQ; /* a bit of a hack. */
+ break;
+
+ }
+
+ *out = talloc_array(ctx, char, strlen(start) - 1); /* + 2 - 1 */
+ if (!*out) return -1;
+
+ q = *out;
+
+ while (*p) {
+ if (*p == *start) {
+ /*
+ * Call the STANDARD parse function to figure out what the string is.
+ */
+ if (cf_new_escape) {
+ ssize_t slen;
+ value_data_t data;
+ char quote = *start;
+ PW_TYPE src_type = PW_TYPE_STRING;
+
+ /*
+ * Regex compilers can handle escapes. So we don't do it.
+ */
+ if (quote == '/') quote = '\0';
+
+ slen = value_data_from_str(ctx, &data, &src_type, NULL, start + 1, p - (start + 1), quote);
+ if (slen < 0) {
+ *error = "error parsing string";
+ return slen - 1;
+ }
+
+ talloc_free(*out);
+ *out = talloc_steal(ctx, data.ptr);
+ data.strvalue = NULL;
+ } else {
+ char *out2;
+
+ *(q++) = '\0'; /* terminate the output string */
+
+ out2 = talloc_realloc(ctx, *out, char, (q - *out));
+ if (!out2) {
+ *error = "Out of memory";
+ return -1;
+ }
+ *out = out2;
+ }
+
+ p++;
+ return (p - start);
+ }
+
+ if (*p == '\\') {
+ if (!p[1]) {
+ p++;
+ *error = "End of string after escape";
+ return -(p - start);
+ }
+
+ /*
+ * Hacks for backwards compatibility
+ */
+ if (cf_new_escape) {
+ if (p[1] == start[0]) { /* Convert '\'' --> ' */
+ p++;
+ } else {
+ *(q++) = *(p++);
+ }
+
+ } else {
+ switch (p[1]) {
+ case 'r':
+ *q++ = '\r';
+ break;
+ case 'n':
+ *q++ = '\n';
+ break;
+ case 't':
+ *q++ = '\t';
+ break;
+ default:
+ *q++ = p[1];
+ break;
+ }
+ p += 2;
+ continue;
+ }
+
+ }
+ *(q++) = *(p++);
+ }
+
+ *error = "Unterminated string";
+ return -1;
+}
+
+static ssize_t condition_tokenize_word(TALLOC_CTX *ctx, char const *start, char **out,
+ FR_TOKEN *op, char const **error)
+{
+ size_t len;
+ char const *p = start;
+
+ if ((*p == '"') || (*p == '\'') || (*p == '`') || (*p == '/')) {
+ return condition_tokenize_string(ctx, out, error, start, op);
+ }
+
+ *op = T_BARE_WORD;
+ if (*p == '&') p++; /* special-case &User-Name */
+
+ while (*p) {
+ /*
+ * The LHS should really be limited to only a few
+ * things. For now, we allow pretty much anything.
+ */
+ if (*p == '\\') {
+ *error = "Unexpected escape";
+ return -(p - start);
+ }
+
+ /*
+ * ("foo") is valid.
+ */
+ if (*p == ')') {
+ break;
+ }
+
+ /*
+ * Spaces or special characters delineate the word
+ */
+ if (isspace((uint8_t) *p) || (*p == '&') || (*p == '|') ||
+ (*p == '!') || (*p == '=') || (*p == '<') || (*p == '>')) {
+ break;
+ }
+
+ if ((*p == '"') || (*p == '\'') || (*p == '`')) {
+ *error = "Unexpected start of string";
+ return -(p - start);
+ }
+
+ p++;
+ }
+
+ len = p - start;
+ if (!len) {
+ *error = "Empty string is invalid";
+ return 0;
+ }
+
+ *out = talloc_array(ctx, char, len + 1);
+ memcpy(*out, start, len);
+ (*out)[len] = '\0';
+ return len;
+}
+
+
+static ssize_t condition_tokenize_cast(char const *start, DICT_ATTR const **pda, char const **error)
+{
+ char const *p = start;
+ char const *q;
+ PW_TYPE cast;
+
+ while (isspace((uint8_t) *p)) p++; /* skip spaces before condition */
+
+ if (*p != '<') return 0;
+ p++;
+
+ q = p;
+ while (*q && *q != '>') q++;
+
+ cast = fr_substr2int(dict_attr_types, p, PW_TYPE_INVALID, q - p);
+ if (cast == PW_TYPE_INVALID) {
+ *error = "Invalid data type in cast";
+ return -(p - start);
+ }
+
+ /*
+ * We can only cast to basic data types. Complex ones
+ * are forbidden.
+ */
+ switch (cast) {
+#ifdef WITH_ASCEND_BINARY
+ case PW_TYPE_ABINARY:
+#endif
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_TLV:
+ case PW_TYPE_EXTENDED:
+ case PW_TYPE_LONG_EXTENDED:
+ case PW_TYPE_EVS:
+ case PW_TYPE_VSA:
+ *error = "Forbidden data type in cast";
+ return -(p - start);
+
+ default:
+ break;
+ }
+
+ *pda = dict_attrbyvalue(PW_CAST_BASE + cast, 0);
+ if (!*pda) {
+ *error = "Cannot cast to this data type";
+ return -(p - start);
+ }
+
+ q++;
+
+ while (isspace((uint8_t) *q)) q++; /* skip spaces after cast */
+
+ return q - start;
+}
+
+static bool condition_check_types(fr_cond_t *c, PW_TYPE lhs_type)
+{
+ /*
+ * SOME integer mismatch is OK. If the LHS has a large type,
+ * and the RHS has a small type, it's OK.
+ *
+ * If the LHS has a small type, and the RHS has a large type,
+ * then add a cast to the LHS.
+ */
+ if (lhs_type == PW_TYPE_INTEGER64) {
+ if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
+ c->cast = NULL;
+ return true;
+ }
+ }
+
+ if (lhs_type == PW_TYPE_INTEGER) {
+ if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE)) {
+ c->cast = NULL;
+ return true;
+ }
+
+ if (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) {
+ c->cast = c->data.map->rhs->tmpl_da;
+ return true;
+ }
+ }
+
+ if (lhs_type == PW_TYPE_SHORT) {
+ if (c->data.map->rhs->tmpl_da->type == PW_TYPE_BYTE) {
+ c->cast = NULL;
+ return true;
+ }
+
+ if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER)) {
+ c->cast = c->data.map->rhs->tmpl_da;
+ return true;
+ }
+ }
+
+ if (lhs_type == PW_TYPE_BYTE) {
+ if ((c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER64) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_INTEGER) ||
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_SHORT)) {
+ c->cast = c->data.map->rhs->tmpl_da;
+ return true;
+ }
+ }
+
+ if ((lhs_type == PW_TYPE_IPV4_PREFIX) &&
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_ADDR)) {
+ return true;
+ }
+
+ if ((lhs_type == PW_TYPE_IPV6_PREFIX) &&
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_ADDR)) {
+ return true;
+ }
+
+ /*
+ * Same checks as above, but with the types swapped, and
+ * with explicit cast for the interpretor.
+ */
+ if ((lhs_type == PW_TYPE_IPV4_ADDR) &&
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV4_PREFIX)) {
+ c->cast = c->data.map->rhs->tmpl_da;
+ return true;
+ }
+
+ if ((lhs_type == PW_TYPE_IPV6_ADDR) &&
+ (c->data.map->rhs->tmpl_da->type == PW_TYPE_IPV6_PREFIX)) {
+ c->cast = c->data.map->rhs->tmpl_da;
+ return true;
+ }
+
+ return false;
+}
+
+
+/*
+ * Less code means less bugs
+ */
+#define return_P(_x) *error = _x;goto return_p
+#define return_0(_x) *error = _x;goto return_0
+#define return_lhs(_x) *error = _x;goto return_lhs
+#define return_rhs(_x) *error = _x;goto return_rhs
+#define return_SLEN goto return_slen
+
+
+/** Tokenize a conditional check
+ *
+ * @param[in] ctx for talloc
+ * @param[in] ci for CONF_ITEM
+ * @param[in] start the start of the string to process. Should be "(..."
+ * @param[in] brace look for a closing brace
+ * @param[out] pcond pointer to the returned condition structure
+ * @param[out] error the parse error (if any)
+ * @param[in] flags do one/two pass
+ * @return length of the string skipped, or when negative, the offset to the offending error
+ */
+static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, bool brace,
+ fr_cond_t **pcond, char const **error, int flags)
+{
+ ssize_t slen, tlen;
+ char const *p = start;
+ char const *lhs_p, *rhs_p;
+ fr_cond_t *c;
+ char *lhs, *rhs;
+ FR_TOKEN op, lhs_type, rhs_type;
+
+ c = talloc_zero(ctx, fr_cond_t);
+
+ rad_assert(c != NULL);
+ lhs = rhs = NULL;
+ lhs_type = rhs_type = T_INVALID;
+
+ while (isspace((uint8_t) *p)) p++; /* skip spaces before condition */
+
+ if (!*p) {
+ return_P("Empty condition is invalid");
+ }
+
+ /*
+ * !COND
+ */
+ if (*p == '!') {
+ p++;
+ c->negate = true;
+ while (isspace((uint8_t) *p)) p++; /* skip spaces after negation */
+
+ /*
+ * Just for stupidity
+ */
+ if (*p == '!') {
+ return_P("Double negation is invalid");
+ }
+ }
+
+ /*
+ * (COND)
+ */
+ if (*p == '(') {
+ p++;
+
+ /*
+ * We've already eaten one layer of
+ * brackets. Go recurse to get more.
+ */
+ c->type = COND_TYPE_CHILD;
+ c->ci = ci;
+ slen = condition_tokenize(c, ci, p, true, &c->data.child, error, flags);
+ if (slen <= 0) {
+ return_SLEN;
+ }
+
+ if (!c->data.child) {
+ return_P("Empty condition is invalid");
+ }
+
+ p += slen;
+ while (isspace((uint8_t) *p)) p++; /* skip spaces after (COND)*/
+
+ } else { /* it's a bare FOO==BAR */
+ /*
+ * We didn't see anything special. The condition must be one of
+ *
+ * FOO
+ * FOO OP BAR
+ */
+
+ /*
+ * Grab the LHS
+ */
+ if (*p == '/') {
+ return_P("Conditional check cannot begin with a regular expression");
+ }
+
+ slen = condition_tokenize_cast(p, &c->cast, error);
+ if (slen < 0) {
+ return_SLEN;
+ }
+ p += slen;
+
+#ifndef __clang_analyzer__
+ lhs_p = p;
+#endif
+ slen = condition_tokenize_word(c, p, &lhs, &lhs_type, error);
+ if (slen <= 0) {
+ return_SLEN;
+ }
+ p += slen;
+
+
+#ifdef __clang_analyzer__
+ if (!lhs) return_P("Internal error");
+#endif
+
+ /*
+ * If the LHS is 0xabcdef... automatically cast it to octets
+ */
+ if (!c->cast && (lhs_type == T_BARE_WORD) &&
+ (lhs[0] == '0') && (lhs[1] == 'x') &&
+ ((slen & 0x01) == 0)) {
+ if (slen == 2) {
+ return_P("Empty octet string is invalid");
+ }
+
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_OCTETS, 0);
+ }
+
+ while (isspace((uint8_t)*p)) p++; /* skip spaces after LHS */
+
+ /*
+ * We may (or not) have an operator
+ */
+
+
+ /*
+ * (FOO)
+ */
+ if (*p == ')') {
+ /*
+ * don't skip the brace. We'll look for it later.
+ */
+ goto exists;
+
+ /*
+ * FOO
+ */
+ } else if (!*p) {
+ if (brace) {
+ return_P("No closing brace at end of string");
+ }
+
+ goto exists;
+
+ /*
+ * FOO && ...
+ */
+ } else if (((p[0] == '&') && (p[1] == '&')) ||
+ ((p[0] == '|') && (p[1] == '|'))) {
+
+ exists:
+ if (c->cast) {
+ return_0("Cannot do cast for existence check");
+ }
+
+ c->type = COND_TYPE_EXISTS;
+ c->ci = ci;
+
+ tlen = tmpl_afrom_str(c, &c->data.vpt, lhs, talloc_array_length(lhs) - 1,
+ lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
+ if (tlen < 0) {
+ p = lhs_p - tlen;
+ return_P(fr_strerror());
+ }
+
+ rad_assert(c->data.vpt->type != TMPL_TYPE_REGEX);
+
+ if (c->data.vpt->type == TMPL_TYPE_ATTR_UNDEFINED) {
+ c->pass2_fixup = PASS2_FIXUP_ATTR;
+ }
+
+ } else { /* it's an operator */
+#ifdef HAVE_REGEX
+ bool regex = false;
+ bool iflag = false;
+ bool mflag = false;
+#endif
+ vp_map_t *map;
+
+ /*
+ * The next thing should now be a comparison operator.
+ */
+ c->type = COND_TYPE_MAP;
+ c->ci = ci;
+
+ switch (*p) {
+ default:
+ return_P("Invalid text. Expected comparison operator");
+
+ case '!':
+ if (p[1] == '=') {
+ op = T_OP_NE;
+ p += 2;
+
+#ifdef HAVE_REGEX
+ } else if (p[1] == '~') {
+ regex = true;
+
+ op = T_OP_REG_NE;
+ p += 2;
+#endif
+
+ } else if (p[1] == '*') {
+ if (lhs_type != T_BARE_WORD) {
+ return_P("Cannot use !* on a string");
+ }
+
+ op = T_OP_CMP_FALSE;
+ p += 2;
+
+ } else {
+ goto invalid_operator;
+ }
+ break;
+
+ case '=':
+ if (p[1] == '=') {
+ op = T_OP_CMP_EQ;
+ p += 2;
+
+#ifdef HAVE_REGEX
+ } else if (p[1] == '~') {
+ regex = true;
+
+ op = T_OP_REG_EQ;
+ p += 2;
+#endif
+
+ } else if (p[1] == '*') {
+ if (lhs_type != T_BARE_WORD) {
+ return_P("Cannot use =* on a string");
+ }
+
+ op = T_OP_CMP_TRUE;
+ p += 2;
+
+ } else {
+ invalid_operator:
+ return_P("Invalid operator");
+ }
+
+ break;
+
+ case '<':
+ if (p[1] == '=') {
+ op = T_OP_LE;
+ p += 2;
+
+ } else {
+ op = T_OP_LT;
+ p++;
+ }
+ break;
+
+ case '>':
+ if (p[1] == '=') {
+ op = T_OP_GE;
+ p += 2;
+
+ } else {
+ op = T_OP_GT;
+ p++;
+ }
+ break;
+ }
+
+ while (isspace((uint8_t) *p)) p++; /* skip spaces after operator */
+
+ if (!*p) {
+ return_P("Expected text after operator");
+ }
+
+ /*
+ * Cannot have a cast on the RHS.
+ * But produce good errors, too.
+ */
+ if (*p == '<') {
+ DICT_ATTR const *cast_da;
+
+ slen = condition_tokenize_cast(p, &cast_da, error);
+ if (slen < 0) {
+ return_SLEN;
+ }
+
+#ifdef __clang_analyzer__
+ if (!cast_da) return_P("Internal error");
+#endif
+
+ if (!c->cast) {
+ return_P("Unexpected cast");
+ }
+
+ if (c->cast != cast_da) {
+ return_P("Cannot cast to a different data type");
+ }
+
+ return_P("Unnecessary cast");
+ }
+
+ /*
+ * Grab the RHS
+ */
+ rhs_p = p;
+ slen = condition_tokenize_word(c, p, &rhs, &rhs_type, error);
+ if (slen <= 0) {
+ return_SLEN;
+ }
+
+#ifdef HAVE_REGEX
+ /*
+ * Sanity checks for regexes.
+ */
+ if (regex) {
+ if (*p != '/') {
+ return_P("Expected regular expression");
+ }
+ for (;;) {
+ switch (p[slen]) {
+ /*
+ * /foo/i
+ */
+ case 'i':
+ iflag = true;
+ slen++;
+ continue;
+
+ /*
+ * /foo/m
+ */
+ case 'm':
+ mflag = true;
+ slen++;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ } else if (!regex && (*p == '/')) {
+ return_P("Unexpected regular expression");
+ }
+
+#endif
+ /*
+ * Duplicate map_from_fields here, as we
+ * want to separate parse errors in the
+ * LHS from ones in the RHS.
+ */
+ c->data.map = map = talloc_zero(c, vp_map_t);
+
+ tlen = tmpl_afrom_str(map, &map->lhs, lhs, talloc_array_length(lhs) - 1,
+ lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
+ if (tlen < 0) {
+ p = lhs_p - tlen;
+ return_P(fr_strerror());
+ }
+
+ if (tmpl_define_unknown_attr(map->lhs) < 0) {
+ return_lhs("Failed defining attribute");
+ return_lhs:
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return -(lhs_p - start);
+ }
+
+ map->op = op;
+
+ /*
+ * If the RHS is 0xabcdef... automatically cast it to octets
+ * unless the LHS is an attribute of type octets, or an
+ * integer type.
+ */
+ if (!c->cast && (rhs_type == T_BARE_WORD) &&
+ (rhs[0] == '0') && (rhs[1] == 'x') &&
+ ((slen & 0x01) == 0)) {
+ if (slen == 2) {
+ return_P("Empty octet string is invalid");
+ }
+
+ if ((map->lhs->type != TMPL_TYPE_ATTR) ||
+ !((map->lhs->tmpl_da->type == PW_TYPE_OCTETS) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_BYTE) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_SHORT) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_INTEGER) ||
+ (map->lhs->tmpl_da->type == PW_TYPE_INTEGER64))) {
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_OCTETS, 0);
+ }
+ }
+
+ if ((map->lhs->type == TMPL_TYPE_ATTR) &&
+ map->lhs->tmpl_da->flags.is_unknown &&
+ map_cast_from_hex(map, rhs_type, rhs)) {
+ /* do nothing */
+
+ } else {
+ tlen = tmpl_afrom_str(map, &map->rhs, rhs, talloc_array_length(rhs) - 1, rhs_type,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST, false);
+ if (tlen < 0) {
+ p = rhs_p - tlen;
+ return_P(fr_strerror());
+ }
+
+ if (tmpl_define_unknown_attr(map->rhs) < 0) {
+ return_rhs("Failed defining attribute");
+ }
+ }
+
+ /*
+ * Unknown attributes get marked up for pass2.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR_UNDEFINED) ||
+ (c->data.map->rhs->type == TMPL_TYPE_ATTR_UNDEFINED)) {
+ c->pass2_fixup = PASS2_FIXUP_ATTR;
+ }
+
+#ifdef HAVE_REGEX
+ if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
+ c->data.map->rhs->tmpl_iflag = iflag;
+ c->data.map->rhs->tmpl_mflag = mflag;
+ }
+#endif
+
+ /*
+ * Save the CONF_ITEM for later.
+ */
+ c->data.map->ci = ci;
+
+ /*
+ * @todo: check LHS and RHS separately, to
+ * get better errors
+ */
+ if ((c->data.map->rhs->type == TMPL_TYPE_LIST) ||
+ (c->data.map->lhs->type == TMPL_TYPE_LIST)) {
+ return_0("Cannot use list references in condition");
+ }
+
+ /*
+ * Check cast type. We can have the RHS
+ * a string if the LHS has a cast. But
+ * if the RHS is an attr, it MUST be the
+ * same type as the LHS.
+ */
+ if (c->cast) {
+ if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
+ (c->cast->type != c->data.map->rhs->tmpl_da->type)) {
+ if (condition_check_types(c, c->cast->type)) {
+ goto keep_going;
+ }
+
+ goto same_type;
+ }
+
+#ifdef HAVE_REGEX
+ if (c->data.map->rhs->type == TMPL_TYPE_REGEX) {
+ return_0("Cannot use cast with regex comparison");
+ }
+#endif
+
+ /*
+ * The LHS is a literal which has been cast to a data type.
+ * Cast it to the appropriate data type.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
+ (tmpl_cast_in_place(c->data.map->lhs, c->cast->type, c->cast) < 0)) {
+ *error = "Failed to parse field";
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return -(lhs_p - start);
+ }
+
+ /*
+ * The RHS is a literal, and the LHS has been cast to a data
+ * type.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
+ (c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
+ (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
+ return_rhs("Failed to parse field");
+ }
+
+ /*
+ * We may be casting incompatible
+ * types. We check this based on
+ * their size.
+ */
+ if (c->data.map->lhs->type == TMPL_TYPE_ATTR) {
+ /*
+ * dst.min == src.min
+ * dst.max == src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) &&
+ (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
+ goto cast_ok;
+ }
+
+ /*
+ * Run-time parsing of strings.
+ * Run-time copying of octets.
+ */
+ if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) ||
+ (c->data.map->lhs->tmpl_da->type == PW_TYPE_OCTETS)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ifid to integer64 is OK
+ */
+ if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IFID) &&
+ (c->cast->type == PW_TYPE_INTEGER64)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipaddr to ipv4prefix is OK
+ */
+ if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipv6addr to ipv6prefix is OK
+ */
+ if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * integer64 to ethernet is OK.
+ */
+ if ((c->data.map->lhs->tmpl_da->type == PW_TYPE_INTEGER64) &&
+ (c->cast->type == PW_TYPE_ETHERNET)) {
+ goto cast_ok;
+ }
+
+ /*
+ * dst.max < src.min
+ * dst.min > src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->lhs->tmpl_da->type][0]) ||
+ (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->lhs->tmpl_da->type][1])) {
+ return_0("Cannot cast to attribute of incompatible size");
+ }
+ }
+
+ cast_ok:
+ /*
+ * Casting to a redundant type means we don't need the cast.
+ *
+ * Do this LAST, as the rest of the code above assumes c->cast
+ * is not NULL.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ (c->cast->type == c->data.map->lhs->tmpl_da->type)) {
+ c->cast = NULL;
+ }
+
+ } else {
+ vp_tmpl_t *vpt;
+
+ /*
+ * Two attributes? They must be of the same type
+ */
+ if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->lhs->tmpl_da->type != c->data.map->rhs->tmpl_da->type)) {
+ if (condition_check_types(c, c->data.map->lhs->tmpl_da->type)) {
+ goto keep_going;
+ }
+
+ same_type:
+ return_0("Attribute comparisons must be of the same data type");
+ }
+
+ /*
+ * Without a cast, we can't compare "foo" to User-Name,
+ * it has to be done the other way around.
+ */
+ if ((c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
+ *error = "Cannot use attribute reference on right side of condition";
+ return_0:
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return 0;
+ }
+
+ /*
+ * Invalid: User-Name == bob
+ * Valid: User-Name == "bob"
+ *
+ * There's no real reason for
+ * this, other than consistency.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
+ (c->data.map->lhs->tmpl_da->type == PW_TYPE_STRING) &&
+ (c->data.map->op != T_OP_CMP_TRUE) &&
+ (c->data.map->op != T_OP_CMP_FALSE) &&
+ (rhs_type == T_BARE_WORD)) {
+ return_rhs("Must have string as value for attribute");
+ }
+
+ /*
+ * Quotes around non-string
+ * attributes mean that it's
+ * either xlat, or an exec.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->rhs->type != TMPL_TYPE_ATTR) &&
+ (c->data.map->lhs->tmpl_da->type != PW_TYPE_STRING) &&
+ (c->data.map->lhs->tmpl_da->type != PW_TYPE_OCTETS) &&
+ (c->data.map->lhs->tmpl_da->type != PW_TYPE_DATE) &&
+ (rhs_type == T_SINGLE_QUOTED_STRING)) {
+ *error = "Value must be an unquoted string";
+ return_rhs:
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return -(rhs_p - start);
+ }
+
+ /*
+ * The LHS has been cast to a data type, and the RHS is a
+ * literal. Cast the RHS to the type of the cast.
+ */
+ if (c->cast && (c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
+ (tmpl_cast_in_place(c->data.map->rhs, c->cast->type, c->cast) < 0)) {
+ return_rhs("Failed to parse field");
+ }
+
+ /*
+ * The LHS is an attribute, and the RHS is a literal. Cast the
+ * RHS to the data type of the LHS.
+ *
+ * Note: There's a hack in here to always parse RHS as the
+ * equivalent prefix type if the LHS is an IP address.
+ *
+ * This allows Framed-IP-Address < 192.168.0.0./24
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ (c->data.map->rhs->type == TMPL_TYPE_LITERAL)) {
+ PW_TYPE type = c->data.map->lhs->tmpl_da->type;
+
+ switch (c->data.map->lhs->tmpl_da->type) {
+ case PW_TYPE_IPV4_ADDR:
+ if (strchr(c->data.map->rhs->name, '/') != NULL) {
+ type = PW_TYPE_IPV4_PREFIX;
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+ }
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ if (strchr(c->data.map->rhs->name, '/') != NULL) {
+ type = PW_TYPE_IPV6_PREFIX;
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (tmpl_cast_in_place(c->data.map->rhs, type, c->data.map->lhs->tmpl_da) < 0) {
+ DICT_ATTR const *da = c->data.map->lhs->tmpl_da;
+
+ if ((da->vendor == 0) &&
+ ((da->attr == PW_AUTH_TYPE) ||
+ (da->attr == PW_AUTZ_TYPE) ||
+ (da->attr == PW_ACCT_TYPE) ||
+ (da->attr == PW_SESSION_TYPE) ||
+ (da->attr == PW_POST_AUTH_TYPE) ||
+ (da->attr == PW_PRE_PROXY_TYPE) ||
+ (da->attr == PW_POST_PROXY_TYPE) ||
+ (da->attr == PW_PRE_ACCT_TYPE) ||
+ (da->attr == PW_RECV_COA_TYPE) ||
+ (da->attr == PW_SEND_COA_TYPE))) {
+ /*
+ * The types for these attributes are dynamically allocated
+ * by modules.c, so we can't enforce strictness here.
+ */
+ c->pass2_fixup = PASS2_FIXUP_TYPE;
+ } else {
+ return_rhs("Failed to parse value for attribute");
+ }
+ }
+
+ /*
+ * Stupid WiMAX shit.
+ * Cast the LHS to the
+ * type of the RHS.
+ */
+ if (c->data.map->lhs->tmpl_da->type == PW_TYPE_COMBO_IP_ADDR) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbytype(c->data.map->lhs->tmpl_da->attr,
+ c->data.map->lhs->tmpl_da->vendor,
+ c->data.map->rhs->tmpl_data_type);
+ if (!da) {
+ return_rhs("Cannot find type for attribute");
+ }
+ c->data.map->lhs->tmpl_da = da;
+ }
+ } /* attr to literal comparison */
+
+ /*
+ * The RHS will turn into... something. Allow for prefixes
+ * there, too.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_ATTR) &&
+ ((c->data.map->rhs->type == TMPL_TYPE_XLAT) ||
+ (c->data.map->rhs->type == TMPL_TYPE_XLAT_STRUCT) ||
+ (c->data.map->rhs->type == TMPL_TYPE_EXEC))) {
+ if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV4_ADDR) {
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_IPV4_PREFIX, 0);
+ }
+
+ if (c->data.map->lhs->tmpl_da->type == PW_TYPE_IPV6_ADDR) {
+ c->cast = dict_attrbyvalue(PW_CAST_BASE + PW_TYPE_IPV6_PREFIX, 0);
+ }
+ }
+
+ /*
+ * If the LHS is a bare word, AND it looks like
+ * an attribute, try to parse it as such.
+ *
+ * This allows LDAP-Group and SQL-Group to work.
+ *
+ * The real fix is to just read the config files,
+ * and do no parsing until after all of the modules
+ * are loaded. But that has issues, too.
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_LITERAL) && (lhs_type == T_BARE_WORD)) {
+ int hyphens = 0;
+ bool may_be_attr = true;
+ size_t i;
+ ssize_t attr_slen;
+
+ /*
+ * Backwards compatibility: Allow Foo-Bar,
+ * e.g. LDAP-Group and SQL-Group.
+ */
+ for (i = 0; i < c->data.map->lhs->len; i++) {
+ if (!dict_attr_allowed_chars[(unsigned char) c->data.map->lhs->name[i]]) {
+ may_be_attr = false;
+ break;
+ }
+
+ if (c->data.map->lhs->name[i] == '-') {
+ hyphens++;
+ }
+ }
+
+ if (!hyphens || (hyphens > 3)) may_be_attr = false;
+
+ if (may_be_attr) {
+ attr_slen = tmpl_afrom_attr_str(c->data.map, &vpt, lhs,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ true, true);
+ if ((attr_slen > 0) && (vpt->len == c->data.map->lhs->len)) {
+ talloc_free(c->data.map->lhs);
+ c->data.map->lhs = vpt;
+ c->pass2_fixup = PASS2_FIXUP_ATTR;
+ }
+ }
+ }
+ } /* we didn't have a cast */
+
+ keep_going:
+ p += slen;
+
+ while (isspace((uint8_t) *p)) p++; /* skip spaces after RHS */
+ } /* parse OP RHS */
+ } /* parse a condition (COND) or FOO OP BAR*/
+
+ /*
+ * ...COND)
+ */
+ if (*p == ')') {
+ if (!brace) {
+ return_P("Unexpected closing brace");
+ }
+
+ p++;
+ while (isspace((uint8_t) *p)) p++; /* skip spaces after closing brace */
+ goto done;
+ }
+
+ /*
+ * End of string is now allowed.
+ */
+ if (!*p) {
+ if (brace) {
+ return_P("No closing brace at end of string");
+ }
+
+ goto done;
+ }
+
+ if (!(((p[0] == '&') && (p[1] == '&')) ||
+ ((p[0] == '|') && (p[1] == '|')))) {
+ *error = "Unexpected text after condition";
+ return_p:
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return -(p - start);
+ }
+
+ /*
+ * Recurse to parse the next condition.
+ */
+ c->next_op = p[0];
+ p += 2;
+
+ /*
+ * May still be looking for a closing brace.
+ */
+ slen = condition_tokenize(c, ci, p, brace, &c->next, error, flags);
+ if (slen <= 0) {
+ return_slen:
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+ talloc_free(c);
+ return slen - (p - start);
+ }
+ p += slen;
+
+done:
+ /*
+ * Normalize the condition before returning.
+ *
+ * We collapse multiple levels of braces to one. Then
+ * convert maps to literals. Then literals to true/false
+ * statements. Then true/false ||/&& followed by other
+ * conditions to just conditions.
+ *
+ * Order is important. The more complex cases are
+ * converted to simpler ones, from the most complex cases
+ * to the simplest ones.
+ */
+
+ /*
+ * (FOO) --> FOO
+ * (FOO) ... --> FOO ...
+ */
+ if ((c->type == COND_TYPE_CHILD) && !c->data.child->next) {
+ fr_cond_t *child;
+
+ child = talloc_steal(ctx, c->data.child);
+ c->data.child = NULL;
+
+ child->next = talloc_steal(child, c->next);
+ c->next = NULL;
+
+ child->next_op = c->next_op;
+
+ /*
+ * Set the negation properly
+ */
+ if ((c->negate && !child->negate) ||
+ (!c->negate && child->negate)) {
+ child->negate = true;
+ } else {
+ child->negate = false;
+ }
+
+ lhs = rhs = NULL;
+ talloc_free(c);
+ c = child;
+ }
+
+ /*
+ * (FOO ...) --> FOO ...
+ *
+ * But don't do !(FOO || BAR) --> !FOO || BAR
+ * Because that's different.
+ */
+ if ((c->type == COND_TYPE_CHILD) &&
+ !c->next && !c->negate) {
+ fr_cond_t *child;
+
+ child = talloc_steal(ctx, c->data.child);
+ c->data.child = NULL;
+
+ lhs = rhs = NULL;
+ talloc_free(c);
+ c = child;
+ }
+
+ /*
+ * Convert maps to literals. Convert one form of map to
+ * a standardized form. This doesn't make any
+ * theoretical difference, but it does mean that the
+ * run-time evaluation has fewer cases to check.
+ */
+ if (c->type == COND_TYPE_MAP) do {
+ VERIFY_MAP(c->data.map);
+
+ /*
+ * !FOO !~ BAR --> FOO =~ BAR
+ */
+ if (c->negate && (c->data.map->op == T_OP_REG_NE)) {
+ c->negate = false;
+ c->data.map->op = T_OP_REG_EQ;
+ }
+
+ /*
+ * FOO !~ BAR --> !FOO =~ BAR
+ */
+ if (!c->negate && (c->data.map->op == T_OP_REG_NE)) {
+ c->negate = true;
+ c->data.map->op = T_OP_REG_EQ;
+ }
+
+ /*
+ * !FOO != BAR --> FOO == BAR
+ */
+ if (c->negate && (c->data.map->op == T_OP_NE)) {
+ c->negate = false;
+ c->data.map->op = T_OP_CMP_EQ;
+ }
+
+ /*
+ * This next one catches "LDAP-Group != foo",
+ * which doesn't work as-is, but this hack fixes
+ * it.
+ *
+ * FOO != BAR --> !FOO == BAR
+ */
+ if (!c->negate && (c->data.map->op == T_OP_NE)) {
+ c->negate = true;
+ c->data.map->op = T_OP_CMP_EQ;
+ }
+
+ /*
+ * FOO =* BAR --> FOO
+ * FOO !* BAR --> !FOO
+ *
+ * FOO may be a string, or a delayed attribute
+ * reference.
+ */
+ if ((c->data.map->op == T_OP_CMP_TRUE) ||
+ (c->data.map->op == T_OP_CMP_FALSE)) {
+ vp_tmpl_t *vpt;
+
+ vpt = talloc_steal(c, c->data.map->lhs);
+ c->data.map->lhs = NULL;
+
+ /*
+ * Invert the negation bit.
+ */
+ if (c->data.map->op == T_OP_CMP_FALSE) {
+ c->negate = !c->negate;
+ }
+
+ TALLOC_FREE(c->data.map);
+
+ c->type = COND_TYPE_EXISTS;
+ c->data.vpt = vpt;
+ break; /* it's no longer a map */
+ }
+
+ /*
+ * Both are data (IP address, integer, etc.)
+ *
+ * We can do the evaluation here, so that it
+ * doesn't need to be done at run time
+ */
+ if ((c->data.map->lhs->type == TMPL_TYPE_DATA) &&
+ (c->data.map->rhs->type == TMPL_TYPE_DATA)) {
+ int rcode;
+
+ rad_assert(c->cast != NULL);
+
+ rcode = radius_evaluate_map(NULL, 0, 0, c);
+ TALLOC_FREE(c->data.map);
+ c->cast = NULL;
+ if (rcode) {
+ c->type = COND_TYPE_TRUE;
+ } else {
+ c->type = COND_TYPE_FALSE;
+ }
+
+ break; /* it's no longer a map */
+ }
+
+ /*
+ * Both are literal strings. They're not parsed
+ * as TMPL_TYPE_DATA because there's no cast to an
+ * attribute.
+ *
+ * We can do the evaluation here, so that it
+ * doesn't need to be done at run time
+ */
+ if ((c->data.map->rhs->type == TMPL_TYPE_LITERAL) &&
+ (c->data.map->lhs->type == TMPL_TYPE_LITERAL) &&
+ !c->pass2_fixup) {
+ int rcode;
+
+ rad_assert(c->cast == NULL);
+
+ rcode = radius_evaluate_map(NULL, 0, 0, c);
+ if (rcode) {
+ c->type = COND_TYPE_TRUE;
+ } else {
+ DEBUG3("OPTIMIZING (%s %s %s) --> FALSE",
+ c->data.map->lhs->name,
+ fr_int2str(fr_tokens, c->data.map->op, "??"),
+ c->data.map->rhs->name);
+ c->type = COND_TYPE_FALSE;
+ }
+
+ /*
+ * Free map after using it above.
+ */
+ TALLOC_FREE(c->data.map);
+ break;
+ }
+
+ /*
+ * <ipaddr>"foo" CMP &Attribute-Name The cast may
+ * not be necessary, and we can re-write it so
+ * that the attribute reference is on the LHS.
+ */
+ if (c->cast &&
+ (c->data.map->rhs->type == TMPL_TYPE_ATTR) &&
+ (c->cast->type == c->data.map->rhs->tmpl_da->type) &&
+ (c->data.map->lhs->type != TMPL_TYPE_ATTR)) {
+ vp_tmpl_t *tmp;
+
+ tmp = c->data.map->rhs;
+ c->data.map->rhs = c->data.map->lhs;
+ c->data.map->lhs = tmp;
+
+ c->cast = NULL;
+
+ switch (c->data.map->op) {
+ case T_OP_CMP_EQ:
+ /* do nothing */
+ break;
+
+ case T_OP_LE:
+ c->data.map->op = T_OP_GE;
+ break;
+
+ case T_OP_LT:
+ c->data.map->op = T_OP_GT;
+ break;
+
+ case T_OP_GE:
+ c->data.map->op = T_OP_LE;
+ break;
+
+ case T_OP_GT:
+ c->data.map->op = T_OP_LT;
+ break;
+
+ default:
+ return_0("Internal sanity check failed 1");
+ }
+
+ /*
+ * This must have been parsed into TMPL_TYPE_DATA.
+ */
+ rad_assert(c->data.map->rhs->type != TMPL_TYPE_LITERAL);
+ }
+
+ } while (0);
+
+ /*
+ * Existence checks. We short-circuit static strings,
+ * too.
+ *
+ * FIXME: the data types should be in the template, too.
+ * So that we know where a literal came from.
+ *
+ * "foo" is NOT the same as 'foo' or a bare foo.
+ */
+ if (c->type == COND_TYPE_EXISTS) {
+ VERIFY_TMPL(c->data.vpt);
+
+ switch (c->data.vpt->type) {
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_ATTR:
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_EXEC:
+ break;
+
+ /*
+ * 'true' and 'false' are special strings
+ * which mean themselves.
+ *
+ * For integers, 0 is false, all other
+ * integers are true.
+ *
+ * For strings, '' and "" are false.
+ * 'foo' and "foo" are true.
+ *
+ * The str2tmpl function takes care of
+ * marking "%{foo}" as TMPL_TYPE_XLAT, so
+ * the strings here are fixed at compile
+ * time.
+ *
+ * `exec` and "%{...}" are left alone.
+ *
+ * Bare words must be module return
+ * codes.
+ */
+ case TMPL_TYPE_LITERAL:
+ if ((strcmp(c->data.vpt->name, "true") == 0) ||
+ (strcmp(c->data.vpt->name, "1") == 0)) {
+ c->type = COND_TYPE_TRUE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if ((strcmp(c->data.vpt->name, "false") == 0) ||
+ (strcmp(c->data.vpt->name, "0") == 0)) {
+ c->type = COND_TYPE_FALSE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if (!*c->data.vpt->name) {
+ c->type = COND_TYPE_FALSE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if ((lhs_type == T_SINGLE_QUOTED_STRING) ||
+ (lhs_type == T_DOUBLE_QUOTED_STRING)) {
+ c->type = COND_TYPE_TRUE;
+ TALLOC_FREE(c->data.vpt);
+
+ } else if (lhs_type == T_BARE_WORD) {
+ int rcode;
+ bool zeros = true;
+ char const *q;
+
+ for (q = c->data.vpt->name;
+ *q != '\0';
+ q++) {
+ if (!isdigit((uint8_t) *q)) {
+ break;
+ }
+ if (*q != '0') zeros = false;
+ }
+
+ /*
+ * It's all digits, and therefore
+ * 'false' if zero, and 'true' otherwise.
+ */
+ if (!*q) {
+ if (zeros) {
+ c->type = COND_TYPE_FALSE;
+ } else {
+ c->type = COND_TYPE_TRUE;
+ }
+ TALLOC_FREE(c->data.vpt);
+ break;
+ }
+
+ /*
+ * Allow &Foo-Bar where Foo-Bar is an attribute
+ * defined by a module.
+ */
+ if (c->pass2_fixup == PASS2_FIXUP_ATTR) {
+ break;
+ }
+
+ rcode = fr_str2int(allowed_return_codes,
+ c->data.vpt->name, 0);
+ if (!rcode) {
+ return_0("Expected a module return code");
+ }
+ }
+
+ /*
+ * Else lhs_type==T_INVALID, and this
+ * node was made by promoting a child
+ * which had already been normalized.
+ */
+ break;
+
+ case TMPL_TYPE_DATA:
+ return_0("Cannot use data here");
+
+ default:
+ return_0("Internal sanity check failed 2");
+ }
+ }
+
+ /*
+ * !TRUE -> FALSE
+ */
+ if (c->type == COND_TYPE_TRUE) {
+ if (c->negate) {
+ c->negate = false;
+ c->type = COND_TYPE_FALSE;
+ }
+ }
+
+ /*
+ * !FALSE -> TRUE
+ */
+ if (c->type == COND_TYPE_FALSE) {
+ if (c->negate) {
+ c->negate = false;
+ c->type = COND_TYPE_TRUE;
+ }
+ }
+
+ /*
+ * true && FOO --> FOO
+ */
+ if ((c->type == COND_TYPE_TRUE) &&
+ (c->next_op == COND_AND)) {
+ fr_cond_t *next;
+
+ next = talloc_steal(ctx, c->next);
+ c->next = NULL;
+
+ lhs = rhs = NULL;
+ talloc_free(c);
+ c = next;
+ }
+
+ /*
+ * false && FOO --> false
+ */
+ if ((c->type == COND_TYPE_FALSE) &&
+ (c->next_op == COND_AND)) {
+ talloc_free(c->next);
+ c->next = NULL;
+ c->next_op = COND_NONE;
+ }
+
+ /*
+ * false || FOO --> FOO
+ */
+ if ((c->type == COND_TYPE_FALSE) &&
+ (c->next_op == COND_OR)) {
+ fr_cond_t *next;
+
+ next = talloc_steal(ctx, c->next);
+ c->next = NULL;
+
+ lhs = rhs = NULL;
+ talloc_free(c);
+ c = next;
+ }
+
+ /*
+ * true || FOO --> true
+ */
+ if ((c->type == COND_TYPE_TRUE) &&
+ (c->next_op == COND_OR)) {
+ talloc_free(c->next);
+ c->next = NULL;
+ c->next_op = COND_NONE;
+ }
+
+ if (lhs) talloc_free(lhs);
+ if (rhs) talloc_free(rhs);
+
+ *pcond = c;
+ return p - start;
+}
+
+/** Tokenize a conditional check
+ *
+ * @param[in] ctx for talloc
+ * @param[in] ci for CONF_ITEM
+ * @param[in] start the start of the string to process. Should be "(..."
+ * @param[out] head the parsed condition structure
+ * @param[out] error the parse error (if any)
+ * @param[in] flags do one/two pass
+ * @return length of the string skipped, or when negative, the offset to the offending error
+ */
+ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flags)
+{
+ return condition_tokenize(ctx, ci, start, false, head, error, flags);
+}
+
+/*
+ * Walk in order.
+ */
+bool fr_condition_walk(fr_cond_t *c, bool (*callback)(void *, fr_cond_t *), void *ctx)
+{
+ while (c) {
+ /*
+ * Process this one, exit on error.
+ */
+ if (!callback(ctx, c)) return false;
+
+ switch (c->type) {
+ case COND_TYPE_INVALID:
+ return false;
+
+ case COND_TYPE_EXISTS:
+ case COND_TYPE_MAP:
+ case COND_TYPE_TRUE:
+ case COND_TYPE_FALSE:
+ break;
+
+ case COND_TYPE_CHILD:
+ /*
+ * Walk over the child.
+ */
+ if (!fr_condition_walk(c->data.child, callback, ctx)) {
+ return false;
+ }
+ }
+
+ /*
+ * No sibling, stop.
+ */
+ if (c->next_op == COND_NONE) break;
+
+ /*
+ * process the next sibling
+ */
+ c = c->next;
+ }
+
+ return true;
+}
diff --git a/src/main/process.c b/src/main/process.c
new file mode 100644
index 0000000..ed77839
--- /dev/null
+++ b/src/main/process.c
@@ -0,0 +1,6457 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file process.c
+ * @brief Defines the state machines that control how requests are processed.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ * @copyright 2012 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/state.h>
+
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef WITH_DETAIL
+#include <freeradius-devel/detail.h>
+#endif
+
+#include <signal.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifdef HAVE_SYSTEMD_WATCHDOG
+# include <systemd/sd-daemon.h>
+#endif
+
+extern pid_t radius_pid;
+extern fr_cond_t *debug_condition;
+
+#ifdef HAVE_SYSTEMD_WATCHDOG
+struct timeval sd_watchdog_interval;
+static fr_event_t *sd_watchdog_ev;
+#endif
+
+static bool spawn_flag = false;
+static bool just_started = true;
+time_t fr_start_time = (time_t)-1;
+static rbtree_t *pl = NULL;
+static fr_event_list_t *el = NULL;
+
+fr_event_list_t *radius_event_list_corral(UNUSED event_corral_t hint) {
+ /* Currently we do not run a second event loop for modules. */
+ return el;
+}
+
+static char const *action_codes[] = {
+ "INVALID",
+ "run",
+ "done",
+ "dup",
+ "timer",
+#ifdef WITH_PROXY
+ "proxy-reply",
+#endif
+ "request was cancelled",
+ "conflicting packet was received",
+ "max_time was reached",
+ "internal failure",
+ "cleanup_delay was reached",
+ "CoA packet was cancelled, and not sent",
+};
+
+#ifdef DEBUG_STATE_MACHINE
+# define TRACE_STATE_MACHINE \
+if (rad_debug_lvl) do { \
+ struct timeval debug_tv; \
+ gettimeofday(&debug_tv, NULL); \
+ debug_tv.tv_sec -= fr_start_time; \
+ printf("(%u) %d.%06d ********\tSTATE %s action %s live M-%s C-%s\t********\n",\
+ request->number, (int) debug_tv.tv_sec, (int) debug_tv.tv_usec, \
+ __FUNCTION__, action_codes[action], master_state_names[request->master_state], \
+ child_state_names[request->child_state]); \
+} while (0)
+
+static char const *master_state_names[REQUEST_MASTER_NUM_STATES] = {
+ "?",
+ "active",
+ "stop-processing",
+ "counted"
+};
+
+static char const *child_state_names[REQUEST_CHILD_NUM_STATES] = {
+ "?",
+ "queued",
+ "running",
+ "proxied",
+ "reject-delay",
+ "cleanup-delay",
+ "done"
+};
+
+#else
+# define TRACE_STATE_MACHINE {}
+#endif
+
+static NEVER_RETURNS void _rad_panic(char const *file, unsigned int line, char const *msg)
+{
+ ERROR("%s[%u]: %s", file, line, msg);
+ fr_exit_now(1);
+}
+
+#define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
+
+/** Declare a state in the state machine
+ *
+ * Expands to the start of a function definition for a given state.
+ *
+ * @param _x the name of the state.
+ */
+#define STATE_MACHINE_DECL(_x) static void _x(REQUEST *request, int action)
+
+static void request_timer(void *ctx);
+
+/** Insert #REQUEST back into the event heap, to continue executing at a future time
+ *
+ * @param file the state machine timer call occurred in.
+ * @param line the state machine timer call occurred on.
+ * @param request to set add the timer event for.
+ * @param when the event should fine.
+ * @param action to perform when we resume processing the request.
+ */
+static inline void state_machine_timer(char const *file, int line, REQUEST *request,
+ struct timeval *when, fr_state_action_t action)
+{
+ request->timer_action = action;
+ if (!fr_event_insert(el, request_timer, request, when, &request->ev)) {
+ _rad_panic(file, line, "Failed to insert event");
+ }
+}
+
+/** @copybrief state_machine_timer
+ *
+ * @param _x the action to perform when we resume processing the request.
+ */
+#define STATE_MACHINE_TIMER(_x) state_machine_timer(__FILE__, __LINE__, request, &when, _x)
+
+/*
+ * We need a different VERIFY_REQUEST macro in process.c
+ * To avoid the race conditions with the master thread
+ * checking the REQUEST whilst it's being worked on by
+ * the child.
+ */
+#if defined(WITH_VERIFY_PTR) && defined(HAVE_PTHREAD_H)
+# undef VERIFY_REQUEST
+# define VERIFY_REQUEST(_x) if (pthread_equal(pthread_self(), _x->child_pid) != 0) verify_request(__FILE__, __LINE__, _x)
+#endif
+
+/**
+ * @section request_timeline
+ *
+ * Time sequence of a request
+ * @code
+ *
+ * RQ-----------------P=============================Y-J-C
+ * ::::::::::::::::::::::::::::::::::::::::::::::::::::::::M
+ * @endcode
+ *
+ * - R: received. Duplicate detection is done, and request is
+ * cached.
+ *
+ * - Q: Request is placed onto a queue for child threads to pick up.
+ * If there are no child threads, the request goes immediately
+ * to P.
+ *
+ * - P: Processing the request through the modules.
+ *
+ * - Y: Reply is ready. Rejects MAY be delayed here. All other
+ * replies are sent immediately.
+ *
+ * - J: Reject is sent "response_delay" after the reply is ready.
+ *
+ * - C: For Access-Requests, After "cleanup_delay", the request is
+ * deleted. Accounting-Request packets go directly from Y to C.
+ *
+ * - M: Max request time. If the request hits this timer, it is
+ * forcibly stopped.
+ *
+ * Other considerations include duplicate and conflicting
+ * packets. When a dupicate packet is received, it is ignored
+ * until we've reached Y, as no response is ready. If the reply
+ * is a reject, duplicates are ignored until J, when we're ready
+ * to send the reply. In between the reply being sent (Y or J),
+ * and C, the server responds to duplicates by sending the cached
+ * reply.
+ *
+ * Conflicting packets are sent in 2 situations.
+ *
+ * The first is in between R and Y. In that case, we consider
+ * it as a hint that we're taking too long, and the NAS has given
+ * up on the request. We then behave just as if the M timer was
+ * reached, and we discard the current request. This allows us
+ * to process the new one.
+ *
+ * The second case is when we're at Y, but we haven't yet
+ * finished processing the request. This is a race condition in
+ * the threading code (avoiding locks is faster). It means that
+ * a thread has actually encoded and sent the reply, and that the
+ * NAS has responded with a new packet. The server can then
+ * safely mark the current request as "OK to delete", and behaves
+ * just as if the M timer was reached. This usually happens only
+ * in high-load situations.
+ *
+ * Duplicate packets are sent when the NAS thinks we're taking
+ * too long, and wants a reply. From R-Y, duplicates are
+ * ignored. From Y-J (for Access-Rejects), duplicates are also
+ * ignored. From Y-C, duplicates get a duplicate reply. *And*,
+ * they cause the "cleanup_delay" time to be extended. This
+ * extension means that we're more likely to send a duplicate
+ * reply (if we have one), or to suppress processing the packet
+ * twice if we didn't reply to it.
+ *
+ * All functions in this file should be thread-safe, and should
+ * assume thet the REQUEST structure is being accessed
+ * simultaneously by the main thread, and by the child worker
+ * threads. This means that timers, etc. cannot be updated in
+ * the child thread.
+ *
+ * Instead, the master thread periodically calls request->process
+ * with action TIMER. It's up to the individual functions to
+ * determine how to handle that. They need to check if they're
+ * being called from a child thread or the master, and then do
+ * different things based on that.
+ */
+#ifdef WITH_PROXY
+static fr_packet_list_t *proxy_list = NULL;
+static TALLOC_CTX *proxy_ctx = NULL;
+#endif
+
+#ifdef HAVE_PTHREAD_H
+# ifdef WITH_PROXY
+static pthread_mutex_t proxy_mutex;
+static bool proxy_no_new_sockets = false;
+# endif
+
+# define PTHREAD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
+# define PTHREAD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
+
+static pthread_t NO_SUCH_CHILD_PID;
+# define NO_CHILD_THREAD request->child_pid = NO_SUCH_CHILD_PID
+
+#else
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+# define NO_CHILD_THREAD
+#endif
+
+#ifdef HAVE_PTHREAD_H
+static bool we_are_master(void)
+{
+ if (spawn_flag &&
+ (pthread_equal(pthread_self(), NO_SUCH_CHILD_PID) == 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Assertions are debug checks.
+ */
+# ifndef NDEBUG
+# define ASSERT_MASTER if (!we_are_master()) rad_panic("We are not master")
+# endif
+#else
+
+/*
+ * No threads: we're always master.
+ */
+# define we_are_master(_x) (1)
+#endif /* HAVE_PTHREAD_H */
+
+#ifndef ASSERT_MASTER
+# define ASSERT_MASTER
+#endif
+
+/*
+ * Make state transitions simpler.
+ */
+#define FINAL_STATE(_x) NO_CHILD_THREAD; request->component = "<" #_x ">"; request->module = ""; request->child_state = _x
+
+
+static void event_new_fd(rad_listen_t *this);
+
+/*
+ * We need mutexes around the event FD list *only* in certain
+ * cases.
+ */
+#if defined (HAVE_PTHREAD_H) && (defined(WITH_PROXY) || defined(WITH_TCP))
+static rad_listen_t *new_listeners = NULL;
+
+static pthread_mutex_t fd_mutex;
+# define FD_MUTEX_LOCK if (spawn_flag) pthread_mutex_lock
+# define FD_MUTEX_UNLOCK if (spawn_flag) pthread_mutex_unlock
+
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * Just do it ourselves.
+ */
+ if (we_are_master()) {
+ event_new_fd(this);
+ return;
+ }
+
+ FD_MUTEX_LOCK(&fd_mutex);
+
+ /*
+ * If it's already in the list, don't add it again.
+ */
+ if (this->next) {
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ return;
+ }
+
+ /*
+ * Otherwise, add it to the list
+ */
+ this->next = new_listeners;
+ new_listeners = this;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
+}
+#else
+void radius_update_listener(rad_listen_t *this)
+{
+ /*
+ * No threads. Just insert it.
+ */
+ event_new_fd(this);
+}
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+# define FD_MUTEX_LOCK(_x)
+# define FD_MUTEX_UNLOCK(_x)
+#endif
+
+/*
+ * Emit a systemd watchdog notification and reschedule the event.
+ */
+#ifdef HAVE_SYSTEMD_WATCHDOG
+typedef struct {
+ fr_event_list_t *el;
+ struct timeval when;
+} sd_watchdog_data_t;
+
+static sd_watchdog_data_t sdwd;
+
+static void sd_watchdog_event(void *ctx)
+{
+ sd_watchdog_data_t *s = (sd_watchdog_data_t *)ctx;
+
+ DEBUG("Emitting systemd watchdog notification");
+ sd_notify(0, "WATCHDOG=1");
+
+ timeradd(&s->when, &sd_watchdog_interval, &s->when);
+ if (!fr_event_insert(s->el, sd_watchdog_event, ctx, &s->when, &sd_watchdog_ev)) {
+ rad_panic("Failed to insert event");
+ }
+}
+#endif
+
+static int request_num_counter = 1;
+#ifdef WITH_PROXY
+static int request_will_proxy(REQUEST *request) CC_HINT(nonnull);
+static int request_proxy(REQUEST *request) CC_HINT(nonnull);
+STATE_MACHINE_DECL(request_ping) CC_HINT(nonnull);
+
+STATE_MACHINE_DECL(request_response_delay) CC_HINT(nonnull);
+STATE_MACHINE_DECL(request_cleanup_delay) CC_HINT(nonnull);
+STATE_MACHINE_DECL(request_running) CC_HINT(nonnull);
+STATE_MACHINE_DECL(request_done) CC_HINT(nonnull);
+
+STATE_MACHINE_DECL(proxy_no_reply) CC_HINT(nonnull);
+STATE_MACHINE_DECL(proxy_running) CC_HINT(nonnull);
+STATE_MACHINE_DECL(proxy_wait_for_reply) CC_HINT(nonnull);
+
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply) CC_HINT(nonnull (1));
+static void remove_from_proxy_hash(REQUEST *request) CC_HINT(nonnull);
+static void remove_from_proxy_hash_nl(REQUEST *request, bool yank) CC_HINT(nonnull);
+static int insert_into_proxy_hash(REQUEST *request) CC_HINT(nonnull);
+static int setup_post_proxy_fail(REQUEST *request);
+#endif
+
+static REQUEST *request_setup(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet,
+ RADCLIENT *client, RAD_REQUEST_FUNP fun);
+static int request_pre_handler(REQUEST *request, UNUSED int action) CC_HINT(nonnull);
+
+#ifdef WITH_COA
+static void request_coa_originate(REQUEST *request) CC_HINT(nonnull);
+STATE_MACHINE_DECL(coa_wait_for_reply) CC_HINT(nonnull);
+STATE_MACHINE_DECL(coa_no_reply) CC_HINT(nonnull);
+STATE_MACHINE_DECL(coa_running) CC_HINT(nonnull);
+static void coa_separate(REQUEST *request, bool retransmit) CC_HINT(nonnull);
+# define COA_SEPARATE if (request->coa) coa_separate(request->coa, true);
+#else
+# define COA_SEPARATE
+#endif
+
+#define CHECK_FOR_STOP do { if (request->master_state == REQUEST_STOP_PROCESSING) {request_done(request, FR_ACTION_CANCELLED);return;}} while (0)
+
+#undef USEC
+#define USEC (1000000)
+
+#define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
+
+static void tv_add(struct timeval *tv, int usec_delay)
+{
+ if (usec_delay >= USEC) {
+ tv->tv_sec += usec_delay / USEC;
+ usec_delay %= USEC;
+ }
+ tv->tv_usec += usec_delay;
+
+ if (tv->tv_usec >= USEC) {
+ tv->tv_sec += tv->tv_usec / USEC;
+ tv->tv_usec %= USEC;
+ }
+}
+
+/*
+ * Debug the packet if requested.
+ */
+static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, bool received)
+{
+ char src_ipaddr[128];
+ char dst_ipaddr[128];
+
+ if (!packet) return;
+ if (!RDEBUG_ENABLED) return;
+
+#ifdef WITH_DETAIL
+ /*
+ * Don't print IP addresses for detail files.
+ */
+ if (request->listener &&
+ (request->listener->type == RAD_LISTEN_DETAIL)) return;
+
+#endif
+ /*
+ * Client-specific debugging re-prints the input
+ * packet into the client log.
+ *
+ * This really belongs in a utility library
+ */
+ if (is_radius_code(packet->code)) {
+ RDEBUG("%s %s Id %u from %s%s%s:%i to %s%s%s:%i length %zu",
+ received ? "Received" : "Sent",
+ fr_packet_codes[packet->code],
+ packet->id,
+ packet->src_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ipaddr, sizeof(src_ipaddr)),
+ packet->src_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->src_port,
+ packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->dst_port,
+ packet->data_len);
+ } else {
+ RDEBUG("%s code %u Id %u from %s%s%s:%i to %s%s%s:%i length %zu\n",
+ received ? "Received" : "Sent",
+ packet->code,
+ packet->id,
+ packet->src_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ipaddr, sizeof(src_ipaddr)),
+ packet->src_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->src_port,
+ packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ipaddr, sizeof(dst_ipaddr)),
+ packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
+ packet->dst_port,
+ packet->data_len);
+ }
+
+ if (received) {
+ rdebug_pair_list(L_DBG_LVL_1, request, packet->vps, NULL);
+ } else {
+ rdebug_proto_pair_list(L_DBG_LVL_1, request, packet->vps);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * Start of RADIUS server state machine.
+ *
+ ***********************************************************************/
+
+static struct timeval *request_response_window(REQUEST *request)
+{
+ VERIFY_REQUEST(request);
+
+ rad_assert(request->home_server != NULL);
+
+ if (request->client) {
+ /*
+ * The client hasn't set the response window. Return
+ * either the home server one, if set, or the global one.
+ */
+ if (!timerisset(&request->client->response_window)) {
+ return &request->home_server->response_window;
+ }
+
+ if (timercmp(&request->client->response_window,
+ &request->home_server->response_window, <)) {
+ return &request->client->response_window;
+ }
+ }
+
+ return &request->home_server->response_window;
+}
+
+/*
+ * Determine initial request processing delay.
+ */
+static int request_init_delay(REQUEST *request)
+{
+ struct timeval half_response_window;
+
+ VERIFY_REQUEST(request);
+
+ /* Allow client response window to lower initial delay */
+ if (timerisset(&request->client->response_window)) {
+ half_response_window.tv_sec = request->client->response_window.tv_sec >> 1;
+ half_response_window.tv_usec =
+ ((request->client->response_window.tv_sec & 1) * USEC +
+ request->client->response_window.tv_usec) >> 1;
+ if (timercmp(&half_response_window, &request->root->init_delay, <))
+ return (int)half_response_window.tv_sec * USEC +
+ (int)half_response_window.tv_usec;
+ }
+
+ return (int)request->root->init_delay.tv_sec * USEC +
+ (int)request->root->init_delay.tv_usec;
+}
+
+/*
+ * Callback for ALL timer events related to the request.
+ */
+static void request_timer(void *ctx)
+{
+ REQUEST *request = talloc_get_type_abort(ctx, REQUEST);
+ int action;
+
+ action = request->timer_action;
+
+ TRACE_STATE_MACHINE;
+
+ request->process(request, action);
+}
+
+/*
+ * Wrapper for talloc pools. If there's no parent, just free the
+ * request. If there is a parent, free the parent INSTEAD of the
+ * request.
+ */
+static void request_free(REQUEST *request)
+{
+ void *ptr;
+
+ rad_assert(request->ev == NULL);
+ rad_assert(!request->in_request_hash);
+ rad_assert(!request->in_proxy_hash);
+
+ if ((request->options & RAD_REQUEST_OPTION_CTX) == 0) {
+ talloc_free(request);
+ return;
+ }
+
+ ptr = talloc_parent(request);
+ rad_assert(ptr != NULL);
+ talloc_free(ptr);
+}
+
+
+#ifdef WITH_PROXY
+#ifdef WITH_TLS
+void proxy_listener_freeze(rad_listen_t *listener, fr_event_fd_handler_t write_handler)
+{
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_freeze(proxy_list,
+ listener->fd)) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+
+ listener->blocked = true;
+
+ if (fr_event_fd_write_handler(el, 0, listener->fd, write_handler, listener) < 0) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+}
+
+void proxy_listener_thaw(rad_listen_t *listener)
+{
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_thaw(proxy_list,
+ listener->fd)) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+
+ listener->blocked = false;
+
+ if (fr_event_fd_write_handler(el, 0, listener->fd, NULL, listener) < 0) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+}
+#endif /* WITH_TLS */
+
+static void proxy_reply_too_late(REQUEST *request)
+{
+ char buffer[128];
+
+ RDEBUG2("Reply from home server %s port %d - ID: %d arrived too late. Try increasing 'retry_delay' or 'max_request_time'",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port, request->proxy->id);
+}
+#endif
+
+
+/** Mark a request DONE and clean it up.
+ *
+ * When a request is DONE, it can have ties to a number of other
+ * portions of the server. The request hash, proxy hash, events,
+ * child threads, etc. This function takes care of either cleaning
+ * up the request, or managing the timers to wait for the ties to be
+ * removed.
+ *
+ * \dot
+ * digraph done {
+ * stopped -> done
+ * done -> done [ label = "still running" ];
+ * }
+ * \enddot
+ */
+static void request_done(REQUEST *request, int original)
+{
+ struct timeval now, when;
+ int action = original;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+
+ /*
+ * Force this no matter what.
+ */
+ request->process = request_done;
+
+#ifdef WITH_DETAIL
+ /*
+ * Tell the detail listener that we're done.
+ */
+ if (request->listener &&
+ (request->listener->type == RAD_LISTEN_DETAIL) &&
+ (request->simul_max != 1)) {
+ request->simul_max = 1;
+ request->listener->send(request->listener,
+ request);
+ }
+#endif
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If called from a child thread, mark ourselves as done,
+ * and wait for the master thread timer to clean us up.
+ */
+ if (!we_are_master()) {
+ FINAL_STATE(REQUEST_DONE);
+ return;
+ }
+#endif
+
+ /*
+ * Mark the request as STOP.
+ */
+ request->master_state = REQUEST_STOP_PROCESSING;
+
+#ifdef WITH_PROXY
+ /*
+ * Walk through the server pool to see if we need to mark
+ * connections as dead.
+ */
+ if (request->home_pool) {
+ fr_event_now(el, &now);
+ if (request->home_pool->last_serviced < now.tv_sec) {
+ int i;
+
+ request->home_pool->last_serviced = now.tv_sec;
+
+ for (i = 0; i < request->home_pool->num_home_servers; i++) {
+ home_server_t *home = request->home_pool->servers[i];
+
+ if (home->state == HOME_STATE_CONNECTION_FAIL) {
+ mark_home_server_dead(home, &now, false);
+ }
+ }
+ }
+ }
+#endif
+
+ /*
+ * If it was administratively canceled, then it's done.
+ */
+ if (action >= FR_ACTION_CANCELLED) {
+ action = FR_ACTION_DONE;
+
+#ifdef WITH_COA
+ /*
+ * Don't touch request->coa, it's in the middle
+ * of being processed...
+ */
+ } else {
+ /*
+ * Move the CoA request to its own handler, but
+ * only if the request finished normally, and was
+ * not administratively canceled.
+ */
+ if (request->coa) {
+ coa_separate(request->coa, true);
+ } else if (request->parent && (request->parent->coa == request)) {
+ coa_separate(request, true);
+ }
+#endif
+ }
+
+ /*
+ * It doesn't hurt to send duplicate replies. All other
+ * signals are ignored, as the request will be cleaned up
+ * soon anyways.
+ */
+ switch (action) {
+ case FR_ACTION_DUP:
+#ifdef WITH_DETAIL
+ rad_assert(request->listener != NULL);
+#endif
+ if (request->reply->code != 0) {
+ request->listener->send(request->listener, request);
+ return;
+ } else {
+ RDEBUG("No reply. Ignoring retransmit");
+ }
+ break;
+
+ /*
+ * Mark the request as done.
+ */
+ case FR_ACTION_DONE:
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If the child is still running, leave it alone.
+ */
+ if (spawn_flag && (request->child_state <= REQUEST_RUNNING)) {
+ break;
+ }
+#endif
+
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
+#endif
+ request->child_state = REQUEST_DONE;
+ break;
+
+ /*
+ * Called when the child is taking too long to
+ * finish. We've already marked it "please
+ * stop", so we don't complain any more.
+ */
+ case FR_ACTION_TIMER:
+ break;
+
+#ifdef WITH_PROXY
+ case FR_ACTION_PROXY_REPLY:
+ proxy_reply_too_late(request);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ /*
+ * Remove it from the request hash.
+ */
+ if (request->in_request_hash) {
+ if (!rbtree_deletebydata(pl, &request->packet)) {
+ rad_assert(0 == 1);
+ }
+ request->in_request_hash = false;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * Wait for the proxy ID to expire. This allows us to
+ * avoid re-use of proxy IDs for a while.
+ */
+ if (request->in_proxy_hash) {
+ rad_assert(request->proxy != NULL);
+
+ fr_event_now(el, &now);
+ when = request->proxy->timestamp;
+
+#ifdef WITH_COA
+ if (((request->proxy->code == PW_CODE_COA_REQUEST) ||
+ (request->proxy->code == PW_CODE_DISCONNECT_REQUEST)) &&
+ (request->packet->code != request->proxy->code)) {
+ when.tv_sec += request->home_server->coa_mrd;
+ } else
+#endif
+ timeradd(&when, request_response_window(request), &when);
+
+ /*
+ * We haven't received all responses, AND there's still
+ * time to wait. Do so.
+ */
+ if ((request->num_proxied_requests > request->num_proxied_responses) &&
+#ifdef WITH_TCP
+ (request->home_server->proto != IPPROTO_TCP) &&
+#endif
+ timercmp(&now, &when, <)) {
+ RDEBUG("Waiting for more responses from the home server");
+ goto wait_some_more;
+ }
+
+ /*
+ * Time to remove it.
+ */
+ remove_from_proxy_hash(request);
+ }
+#endif
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If there's no children, we can mark the request as done.
+ */
+ if (!spawn_flag) request->child_state = REQUEST_DONE;
+#endif
+
+ /*
+ * If the child is still running, wait for it to be finished.
+ */
+ if (request->child_state <= REQUEST_RUNNING) {
+ gettimeofday(&now, NULL);
+#ifdef WITH_PROXY
+ wait_some_more:
+#endif
+ when = now;
+ if (request->delay < (USEC / 3)) request->delay = USEC / 3;
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
+ if (request->delay > (10 * USEC)) request->delay = 10 * USEC;
+
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
+#endif
+
+#ifdef WITH_COA
+ /*
+ * Now that the child is done, free the CoA packet. If
+ * the CoA is running, it's already been separated.
+ */
+ if (request->coa) TALLOC_FREE(request->coa);
+#endif
+
+
+ /*
+ * @todo: do final states for TCP sockets, too?
+ */
+ request_stats_final(request);
+#ifdef WITH_TCP
+ if (request->listener) {
+ request->listener->count--;
+
+ /*
+ * If we're the last one, remove the listener now.
+ */
+ if ((request->listener->count == 0) &&
+ (request->listener->status >= RAD_LISTEN_STATUS_FROZEN)) {
+ event_new_fd(request->listener);
+ }
+ }
+#endif
+
+ if (request->packet) {
+ RDEBUG2("Cleaning up request packet ID %u with timestamp +%d due to %s",
+ request->packet->id,
+ (unsigned int) (request->timestamp - fr_start_time),
+ action_codes[original]);
+ } /* else don't print anything */
+
+ ASSERT_MASTER;
+ fr_event_delete(el, &request->ev);
+ request_free(request);
+}
+
+
+static void request_cleanup_delay_init(REQUEST *request)
+{
+ struct timeval now, when;
+
+ VERIFY_REQUEST(request);
+
+ /*
+ * Do cleanup delay ONLY for RADIUS packets from a real
+ * client. Everything else just gets cleaned up
+ * immediately.
+ */
+ if (request->packet->dst_port == 0) goto done;
+
+ /*
+ * Accounting packets shouldn't be retransmitted. They
+ * should always be updated with Acct-Delay-Time.
+ */
+#ifdef WITH_ACCOUNTING
+ if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) goto done;
+#endif
+
+#ifdef WITH_DHCP
+ if (request->listener->type == RAD_LISTEN_DHCP) goto done;
+#endif
+
+#ifdef WITH_VMPS
+ if (request->listener->type == RAD_LISTEN_VQP) goto done;
+#endif
+
+ if (!request->root->cleanup_delay) goto done;
+
+ gettimeofday(&now, NULL);
+
+ rad_assert(request->reply->timestamp.tv_sec != 0);
+ when = request->reply->timestamp;
+
+ request->delay = request->root->cleanup_delay;
+ when.tv_sec += request->delay;
+
+ /*
+ * Set timer for when we need to clean it up.
+ */
+ if (timercmp(&when, &now, >)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
+#endif
+ request->process = request_cleanup_delay;
+
+ if (!we_are_master()) {
+ FINAL_STATE(REQUEST_CLEANUP_DELAY);
+ return;
+ }
+
+ /*
+ * Update this if we can, otherwise let the timers pick it up.
+ */
+ request->child_state = REQUEST_CLEANUP_DELAY;
+#ifdef HAVE_PTHREAD_H
+ rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
+#endif
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+
+ /*
+ * Otherwise just clean it up.
+ */
+done:
+ request_done(request, FR_ACTION_DONE);
+}
+
+
+/*
+ * Enforce max_request_time.
+ */
+static bool request_max_time(REQUEST *request)
+{
+ struct timeval now, when;
+ rad_assert(request->magic == REQUEST_MAGIC);
+#ifdef DEBUG_STATE_MACHINE
+ int action = FR_ACTION_TIMER;
+#endif
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+
+ /*
+ * The child thread has acknowledged it's done.
+ * Transition to the DONE state.
+ *
+ * If the request was marked STOP, then the "check for
+ * stop" macro already took care of it.
+ */
+ if (request->child_state == REQUEST_DONE) {
+ request_done(request, FR_ACTION_DONE);
+ return true;
+ }
+
+ /*
+ * The request is still running. Enforce max_request_time.
+ */
+ fr_event_now(el, &now);
+ when = request->packet->timestamp;
+ when.tv_sec += request->root->max_request_time;
+
+ /*
+ * Taking too long: tell it to die.
+ */
+ if (timercmp(&now, &when, >=)) {
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If there's a child thread processing it,
+ * complain.
+ */
+ if (spawn_flag &&
+ (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
+ ERROR("Unresponsive child for request %u, in component %s module %s",
+ request->number,
+ request->component ? request->component : "<core>",
+ request->module ? request->module : "<core>");
+ request->max_time = true;
+
+ exec_trigger(request, NULL, "server.thread.unresponsive", true);
+ }
+#endif
+ /*
+ * Tell the request that it's done.
+ */
+ request_done(request, FR_ACTION_MAX_TIME);
+ return true;
+ }
+
+ /*
+ * Sleep for some more. We HOPE that the child will
+ * become responsive at some point in the future. We do
+ * this by adding 50% to the current timer.
+ */
+ when = now;
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return false;
+}
+
+static void request_queue_or_run(REQUEST *request,
+ fr_request_process_t process)
+{
+#ifdef DEBUG_STATE_MACHINE
+ int action = FR_ACTION_TIMER;
+#endif
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+
+ /*
+ * Do this here so that fewer other functions need to do
+ * it.
+ */
+ if (request->master_state == REQUEST_STOP_PROCESSING) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s M-%s causes C-%s-> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ master_state_names[request->master_state],
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
+#endif
+ request_done(request, FR_ACTION_CANCELLED);
+ return;
+ }
+
+ request->process = process;
+
+ if (we_are_master()) {
+ struct timeval when;
+
+ /*
+ * (re) set the initial delay.
+ */
+ request->delay = request_init_delay(request);
+ if (request->delay > USEC) request->delay = USEC;
+ gettimeofday(&when, NULL);
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
+
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+
+#ifdef HAVE_PTHREAD_H
+ if (spawn_flag) {
+ /*
+ * A child thread will eventually pick it up.
+ */
+ if (request_enqueue(request)) return;
+
+ /*
+ * Otherwise we're not going to do anything with
+ * it...
+ */
+ request_done(request, FR_ACTION_INTERNAL_FAILURE);
+ return;
+ }
+#endif
+ }
+
+ request->child_state = REQUEST_RUNNING;
+ request->process(request, FR_ACTION_RUN);
+
+#ifdef WNOHANG
+ /*
+ * Requests that care about child process exit
+ * codes have already either called
+ * rad_waitpid(), or they've given up.
+ */
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+#endif
+}
+
+void request_inject(REQUEST *request)
+{
+ request_queue_or_run(request, request_running);
+}
+
+
+static void request_dup(REQUEST *request)
+{
+ ERROR("(%u) Ignoring duplicate packet from "
+ "client %s port %d - ID: %u due to unfinished request "
+ "in component %s module %s",
+ request->number, request->client->shortname,
+ request->packet->src_port,request->packet->id,
+ request->component, request->module);
+}
+
+
+/** Sit on a request until it's time to clean it up.
+ *
+ * A NAS may not see a response from the server. When the NAS
+ * retransmits, we want to be able to send a cached reply back. The
+ * alternative is to re-process the packet, which does bad things for
+ * EAP, among others.
+ *
+ * IF we do see a NAS retransmit, we extend the cleanup delay,
+ * because the NAS might miss our cached reply.
+ *
+ * Otherwise, once we reach cleanup_delay, we transition to DONE.
+ *
+ * \dot
+ * digraph cleanup_delay {
+ * cleanup_delay;
+ * send_reply [ label = "send_reply\nincrease cleanup delay" ];
+ *
+ * cleanup_delay -> send_reply [ label = "DUP" ];
+ * send_reply -> cleanup_delay;
+ * cleanup_delay -> proxy_reply_too_late [ label = "PROXY_REPLY", arrowhead = "none" ];
+ * cleanup_delay -> cleanup_delay [ label = "TIMER < timeout" ];
+ * cleanup_delay -> done [ label = "TIMER >= timeout" ];
+ * }
+ * \enddot
+ */
+static void request_cleanup_delay(REQUEST *request, int action)
+{
+ struct timeval when, now;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+ COA_SEPARATE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_DUP:
+ if (request->reply->code != 0) {
+ DEBUG("(%u) Sending duplicate reply to "
+ "client %s port %d - ID: %u",
+ request->number, request->client->shortname,
+ request->packet->src_port,request->packet->id);
+ request->listener->send(request->listener, request);
+ } else {
+ RDEBUG("No reply. Ignoring retransmit");
+ }
+
+ /*
+ * Double the cleanup_delay to catch retransmits.
+ */
+ when = request->reply->timestamp;
+ request->delay += request->delay;
+ when.tv_sec += request->delay;
+
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ break;
+
+#ifdef WITH_PROXY
+ case FR_ACTION_PROXY_REPLY:
+ proxy_reply_too_late(request);
+ break;
+#endif
+
+ case FR_ACTION_TIMER:
+ fr_event_now(el, &now);
+
+ rad_assert(request->root->cleanup_delay > 0);
+
+ when = request->reply->timestamp;
+ when.tv_sec += request->root->cleanup_delay;
+
+ if (timercmp(&when, &now, >)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay");
+#endif
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ } /* else it's time to clean up */
+
+ request_done(request, FR_ACTION_CLEANUP_DELAY);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+
+/** Sit on a request until it's time to respond to it.
+ *
+ * For security reasons, rejects (and maybe some other) packets are
+ * delayed for a while before we respond. This delay means that
+ * badly behaved NASes don't hammer the server with authentication
+ * attempts.
+ *
+ * Otherwise, once we reach response_delay, we send the reply, and
+ * transition to cleanup_delay.
+ *
+ * \dot
+ * digraph response_delay {
+ * response_delay -> proxy_reply_too_late [ label = "PROXY_REPLY", arrowhead = "none" ];
+ * response_delay -> response_delay [ label = "DUP, TIMER < timeout" ];
+ * response_delay -> send_reply [ label = "TIMER >= timeout" ];
+ * send_reply -> cleanup_delay;
+ * }
+ * \enddot
+ */
+static void request_response_delay(REQUEST *request, int action)
+{
+ struct timeval when, now;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+ COA_SEPARATE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_DUP:
+ RDEBUG("(%u) Discarding duplicate request from "
+ "client %s port %d - ID: %u due to delayed response",
+ request->number, request->client->shortname,
+ request->packet->src_port,request->packet->id);
+ break;
+
+#ifdef WITH_PROXY
+ case FR_ACTION_PROXY_REPLY:
+ proxy_reply_too_late(request);
+ break;
+#endif
+
+ case FR_ACTION_TIMER:
+ fr_event_now(el, &now);
+
+ /*
+ * See if it's time to send the reply. If not,
+ * we wait some more.
+ */
+ when = request->reply->timestamp;
+
+ tv_add(&when, request->response_delay.tv_sec * USEC);
+ tv_add(&when, request->response_delay.tv_usec);
+
+ if (timercmp(&when, &now, >)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_response_delay");
+#endif
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ } /* else it's time to send the reject */
+
+ RDEBUG2("Sending delayed response");
+ request->listener->encode(request->listener, request);
+ debug_packet(request, request->reply, false);
+ request->listener->send(request->listener, request);
+
+ /*
+ * Clean up the request.
+ */
+ request_cleanup_delay_init(request);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+
+static int request_pre_handler(REQUEST *request, UNUSED int action)
+{
+ int rcode;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+
+ if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
+
+ /*
+ * Don't decode the packet if it's an internal "fake"
+ * request. Instead, just return so that the caller can
+ * process it.
+ */
+ if (request->packet->dst_port == 0) {
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ return 1;
+ }
+
+ if (!request->packet->vps) { /* FIXME: check for correct state */
+ rcode = request->listener->decode(request->listener, request);
+
+#ifdef WITH_UNLANG
+ if (debug_condition) {
+ /*
+ * Ignore parse errors.
+ */
+ if (radius_evaluate_cond(request, RLM_MODULE_OK, 0, debug_condition) == 1) {
+ request->log.lvl = L_DBG_LVL_2;
+ request->log.func = vradlog_request;
+ }
+ }
+#endif
+
+ debug_packet(request, request->packet, true);
+ } else {
+ rcode = 0;
+ }
+
+ if (rcode < 0) {
+ RATE_LIMIT(INFO("Dropping packet without response because of error: %s (from client %s)", fr_strerror(), request->client->shortname));
+ request->reply->offset = -2; /* bad authenticator */
+ return 0;
+ }
+
+ if (!request->username) {
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+
+ return 1;
+}
+
+
+/** Do the final processing of a request before we reply to the NAS.
+ *
+ * Various cleanups, suppress responses, copy Proxy-State, and set
+ * response_delay or cleanup_delay;
+ */
+static void request_finish(REQUEST *request, int action)
+{
+ VALUE_PAIR *vp;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ (void) action; /* -Wunused */
+
+#ifdef WITH_COA
+ /*
+ * Don't do post-auth if we're a CoA request originated
+ * from an Access-Request. See request_alloc_coa() for
+ * details.
+ */
+ if ((request->options & RAD_REQUEST_OPTION_COA) != 0) goto done;
+#endif
+
+ /*
+ * Override the response code if a control:Response-Packet-Type attribute is present.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer == 256) {
+ RDEBUG2("Not responding to request");
+ fr_pair_delete_by_num(&request->reply->vps, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
+ request->reply->code = 0;
+ } else {
+ request->reply->code = vp->vp_integer;
+ }
+ }
+ /*
+ * Catch Auth-Type := Reject BEFORE proxying the packet.
+ */
+ else if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ if (request->reply->code == 0) {
+ vp = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY);
+ if (!vp || (vp->vp_integer != 5)) {
+ RDEBUG2("There was no response configured: "
+ "rejecting request");
+ }
+
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ }
+ }
+
+ /*
+ * Copy Proxy-State from the request to the reply.
+ */
+ vp = fr_pair_list_copy_by_num(request->reply, request->packet->vps,
+ PW_PROXY_STATE, 0, TAG_ANY);
+ if (vp) fr_pair_add(&request->reply->vps, vp);
+
+ /*
+ * Call Post-Auth for Access-Request packets.
+ */
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ rad_postauth(request);
+
+ vp = fr_pair_find_by_num(request->config, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
+ if (vp && (vp->vp_integer == 256)) {
+ RDEBUG2("Not responding to request");
+ request->reply->code = 0;
+ }
+ }
+
+#ifdef WITH_COA
+ /*
+ * Maybe originate a CoA request.
+ */
+ if ((action == FR_ACTION_RUN) && !request->proxy && request->coa) {
+ request_coa_originate(request);
+ }
+#endif
+
+ /*
+ * Clean up. These are no longer needed.
+ */
+ gettimeofday(&request->reply->timestamp, NULL);
+
+ /*
+ * Fake packets get marked as "done", and have the
+ * proxy-reply section deal with the reply attributes.
+ * We therefore don't free the reply attributes.
+ */
+ if (request->packet->dst_port == 0) {
+ RDEBUG("Finished internally proxied request.");
+ FINAL_STATE(REQUEST_DONE);
+ return;
+ }
+
+#ifdef WITH_DETAIL
+ /*
+ * Always send the reply to the detail listener.
+ */
+ if (request->listener->type == RAD_LISTEN_DETAIL) {
+ request->simul_max = 1;
+
+ /*
+ * But only print the reply if there is one.
+ */
+ if (request->reply->code != 0) {
+ debug_packet(request, request->reply, false);
+ }
+
+ request->listener->send(request->listener, request);
+ goto done;
+ }
+#endif
+
+ /*
+ * Ignore all "do not respond" packets.
+ * Except for the detail ones, which need to ping
+ * the detail file reader so that it will retransmit.
+ */
+ if (!request->reply->code) {
+ RDEBUG("Not sending reply to client.");
+ goto done;
+ }
+
+ /*
+ * If it's not in the request hash, we MIGHT not want to
+ * send a reply.
+ *
+ * If duplicate packets are allowed, then then only
+ * reason to NOT be in the request hash is because we
+ * don't want to send a reply.
+ *
+ * FIXME: this is crap. The rest of the state handling
+ * should use a different field so that we don't have two
+ * meanings for it.
+ *
+ * Otherwise duplicates are forbidden, and the request is
+ * SUPPOSED to avoid the request hash.
+ *
+ * In that case, we need to send a reply.
+ */
+ if (!request->in_request_hash &&
+ !request->listener->nodup) {
+ RDEBUG("Suppressing reply to client.");
+ goto done;
+ }
+
+ /*
+ * See if we need to delay an Access-Reject packet.
+ */
+ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
+ (request->reply->code == PW_CODE_ACCESS_REJECT) &&
+ (request->root->reject_delay.tv_sec > 0)) {
+ request->response_delay = request->root->reject_delay;
+
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10) {
+ request->response_delay.tv_sec = vp->vp_integer;
+ } else {
+ request->response_delay.tv_sec = 10;
+ }
+ request->response_delay.tv_usec = 0;
+ } else {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY_USEC, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10 * USEC) {
+ request->response_delay.tv_sec = vp->vp_integer / USEC;
+ request->response_delay.tv_usec = vp->vp_integer % USEC;
+ } else {
+ request->response_delay.tv_sec = 10;
+ request->response_delay.tv_usec = 0;
+ }
+ }
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * If we timed out a proxy packet, don't delay
+ * the reject any more.
+ */
+ if (request->proxy && !request->proxy_reply) {
+ request->response_delay.tv_sec = 0;
+ request->response_delay.tv_usec = 0;
+ }
+#endif
+ }
+
+ /*
+ * Send the reply.
+ */
+ if ((request->response_delay.tv_sec == 0) &&
+ (request->response_delay.tv_usec == 0)) {
+
+ /*
+ * Don't print a reply if there's none to send.
+ */
+ if (request->reply->code != 0) {
+ if (rad_debug_lvl && request->state &&
+ (request->reply->code == PW_CODE_ACCESS_ACCEPT)) {
+ if (!fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY)) {
+ RWDEBUG2("Unused attributes found in &session-state:");
+ }
+ }
+
+ request->listener->encode(request->listener, request);
+ debug_packet(request, request->reply, false);
+ request->listener->send(request->listener, request);
+ }
+
+ done:
+ RDEBUG2("Finished request");
+ request_cleanup_delay_init(request);
+
+ } else {
+ /*
+ * Encode and sign it here, so that the master
+ * thread can just send the encoded data, which
+ * means it does less work.
+ */
+ RDEBUG2("Delaying response for %d.%06d seconds",
+ (int) request->response_delay.tv_sec, (int) request->response_delay.tv_usec);
+ request->listener->encode(request->listener, request);
+ request->process = request_response_delay;
+
+ FINAL_STATE(REQUEST_RESPONSE_DELAY);
+ }
+}
+
+/** Process a request from a client.
+ *
+ * The outcome might be that the request is proxied.
+ *
+ * \dot
+ * digraph running {
+ * running -> running [ label = "TIMER < max_request_time" ];
+ * running -> done [ label = "TIMER >= max_request_time" ];
+ * running -> proxy [ label = "proxied" ];
+ * running -> dup [ label = "DUP", arrowhead = "none" ];
+ * }
+ * \enddot
+ */
+static void request_running(REQUEST *request, int action)
+{
+ int rcode;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ (void) request_max_time(request);
+ break;
+
+ case FR_ACTION_DUP:
+ request_dup(request);
+ break;
+
+ case FR_ACTION_RUN:
+ if (!request_pre_handler(request, action)) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s failed in pre-handler C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
+#endif
+ FINAL_STATE(REQUEST_DONE);
+ break;
+ }
+
+ rad_assert(request->handle != NULL);
+ request->handle(request);
+
+#ifdef WITH_PROXY
+ /*
+ * We may need to send a proxied request.
+ */
+ rcode = request_will_proxy(request);
+ if (rcode == 1) {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tWill Proxy\t********\n", request->number);
+#endif
+ /*
+ * If this fails, it
+ * takes care of setting
+ * up the post proxy fail
+ * handler.
+ */
+ retry_proxy:
+ if (request_proxy(request) < 0) {
+ if (request->home_server && request->home_server->virtual_server) goto req_finished;
+
+ if (request->home_pool && request->home_server &&
+ HOME_SERVER_IS_DEAD(request->home_server)) {
+ VALUE_PAIR *vp;
+ REALM *realm = NULL;
+ home_server_t *home = NULL;
+
+ vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+ if (vp) realm = realm_find2(vp->vp_strvalue);
+
+ /*
+ * Since request->home_server is dead,
+ * this function won't pick the same home server as before.
+ */
+ if (realm) home = home_server_ldb(vp->vp_strvalue, request->home_pool, request);
+ if (home) {
+ home_server_update_request(home, request);
+ goto retry_proxy;
+ }
+ }
+
+ (void) setup_post_proxy_fail(request);
+ process_proxy_reply(request, NULL);
+ goto req_finished;
+ }
+
+ } else if (rcode < 0) {
+ /*
+ * No live home servers, run Post-Proxy-Type Fail.
+ */
+ (void) setup_post_proxy_fail(request);
+ process_proxy_reply(request, NULL);
+ goto req_finished;
+ } else
+#endif
+ {
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tFinished\t********\n", request->number);
+#endif
+
+#ifdef WITH_PROXY
+ req_finished:
+#endif
+ request_finish(request, action);
+ }
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+int request_receive(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet,
+ RADCLIENT *client, RAD_REQUEST_FUNP fun)
+{
+ uint32_t count;
+ RADIUS_PACKET **packet_p;
+ REQUEST *request = NULL;
+ struct timeval now;
+ listen_socket_t *sock = NULL;
+
+ VERIFY_PACKET(packet);
+
+ /*
+ * Set the last packet received.
+ */
+ gettimeofday(&now, NULL);
+
+ packet->timestamp = now;
+
+#ifdef WITH_ACCOUNTING
+ if (listener->type != RAD_LISTEN_DETAIL)
+#endif
+
+#ifdef WITH_TCP
+ {
+ sock = listener->data;
+ sock->last_packet = now.tv_sec;
+
+ packet->proto = sock->proto;
+ }
+#endif
+
+ /*
+ * Skip everything if required.
+ */
+ if (listener->nodup) goto skip_dup;
+
+ packet_p = rbtree_finddata(pl, &packet);
+ if (packet_p) {
+ rad_child_state_t child_state;
+ char const *old_module;
+
+ request = fr_packet2myptr(REQUEST, packet, packet_p);
+ rad_assert(request->in_request_hash);
+ child_state = request->child_state;
+ old_module = request->module;
+
+ /*
+ * Same src/dst ip/port, length, and
+ * authentication vector: must be a duplicate.
+ */
+ if ((request->packet->data_len == packet->data_len) &&
+ (memcmp(request->packet->vector, packet->vector,
+ sizeof(packet->vector)) == 0)) {
+
+#ifdef WITH_STATS
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ FR_STATS_INC(auth, total_dup_requests);
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ FR_STATS_INC(acct, total_dup_requests);
+ break;
+#endif
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ FR_STATS_INC(coa, total_dup_requests);
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, total_dup_requests);
+ break;
+#endif
+
+ default:
+ break;
+ }
+#endif /* WITH_STATS */
+
+ /*
+ * Tell the state machine that there's a
+ * duplicate request.
+ */
+ request->process(request, FR_ACTION_DUP);
+ return 0; /* duplicate of live request */
+ }
+
+ /*
+ * Mark the request as done ASAP, and before we
+ * log anything. The child may stop processing
+ * the request just as we're logging the
+ * complaint.
+ */
+ request_done(request, FR_ACTION_CONFLICT);
+ request = NULL;
+
+ /*
+ * It's a new request, not a duplicate. If the
+ * old one is done, then we can clean it up.
+ */
+ if (child_state <= REQUEST_RUNNING) {
+ /*
+ * The request is still QUEUED or RUNNING. That's a problem.
+ */
+ ERROR("Received conflicting packet from "
+ "client %s port %d - ID: %u due to "
+ "unfinished request in module %s. Giving up on old request.",
+ client->shortname,
+ packet->src_port, packet->id,
+ old_module);
+
+#ifdef WITH_STATS
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ FR_STATS_INC(auth, total_conflicts);
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ FR_STATS_INC(acct, total_conflicts);
+ break;
+#endif
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ FR_STATS_INC(coa, total_conflicts);
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, total_conflicts);
+ break;
+#endif
+
+ default:
+ break;
+ }
+#endif /* WITH_STATS */
+ }
+ } /* else the new packet is unique */
+
+ /*
+ * Quench maximum number of outstanding requests.
+ */
+ if (main_config.max_requests &&
+ ((count = rbtree_num_elements(pl)) > main_config.max_requests)) {
+ RATE_LIMIT(ERROR("Dropping request (%d is too many): from client %s port %d - ID: %d", count,
+ client->shortname,
+ packet->src_port, packet->id);
+ WARN("Please check the configuration file.\n"
+ "\tThe value for 'max_requests' is probably set too low.\n"));
+
+ exec_trigger(NULL, NULL, "server.max_requests", true);
+ return 0;
+ }
+
+skip_dup:
+ /*
+ * Rate-limit the incoming packets
+ */
+ if (sock && sock->max_rate) {
+ uint32_t pps;
+
+ pps = rad_pps(&sock->rate_pps_old, &sock->rate_pps_now, &sock->rate_time, &now);
+ if (pps > sock->max_rate) {
+ DEBUG("Dropping request due to rate limiting");
+ return 0;
+ }
+ sock->rate_pps_now++;
+ }
+
+ /*
+ * Allocate a pool for the request.
+ */
+ if (!ctx) {
+ ctx = talloc_pool(NULL, main_config.talloc_pool_size);
+ if (!ctx) return 0;
+ talloc_set_name_const(ctx, "request_receive_pool");
+
+ /*
+ * The packet is still allocated from a different
+ * context, but oh well.
+ */
+ (void) talloc_steal(ctx, packet);
+ }
+
+ request = request_setup(ctx, listener, packet, client, fun);
+ if (!request) {
+ talloc_free(ctx);
+ return 1;
+ }
+
+ /*
+ * Mark it as a "real" request with a context.
+ */
+ request->options |= RAD_REQUEST_OPTION_CTX;
+
+ /*
+ * Remember the request in the list.
+ */
+ if (!listener->nodup) {
+ if (!rbtree_insert(pl, &request->packet)) {
+ RERROR("Failed to insert request in the list of live requests: discarding it");
+ request_done(request, FR_ACTION_INTERNAL_FAILURE);
+ return 1;
+ }
+
+ request->in_request_hash = true;
+ }
+
+ /*
+ * Process it. Send a response, and free it.
+ */
+ if (listener->synchronous) {
+#ifdef WITH_DETAIL
+ rad_assert(listener->type != RAD_LISTEN_DETAIL);
+#endif
+
+ request->listener->decode(request->listener, request);
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+ fun(request);
+
+ if (request->reply->code != 0) {
+ request->listener->send(request->listener, request);
+ } else {
+ RDEBUG("Not sending reply");
+ }
+
+ /*
+ * Don't do delayed reject. Oh well.
+ */
+ request_free(request);
+ return 1;
+ }
+
+ /*
+ * Otherwise, insert it into the state machine.
+ * The child threads will take care of processing it.
+ */
+ request_queue_or_run(request, request_running);
+
+ return 1;
+}
+
+
+static REQUEST *request_setup(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet,
+ RADCLIENT *client, RAD_REQUEST_FUNP fun)
+{
+ REQUEST *request;
+
+ /*
+ * Create and initialize the new request.
+ */
+ request = request_alloc(ctx);
+ if (!request) {
+ ERROR("No memory");
+ return NULL;
+ }
+ request->reply = rad_alloc_reply(request, packet);
+ if (!request->reply) {
+ ERROR("No memory");
+ talloc_free(request);
+ return NULL;
+ }
+
+ request->listener = listener;
+ request->client = client;
+ request->packet = talloc_steal(request, packet);
+ request->number = request_num_counter++;
+ request->priority = listener->type;
+ request->master_state = REQUEST_ACTIVE;
+ request->child_state = REQUEST_RUNNING;
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n",
+ request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_RUNNING]);
+#endif
+ request->handle = fun;
+ NO_CHILD_THREAD;
+
+#ifdef WITH_STATS
+ request->listener->stats.last_packet = request->packet->timestamp.tv_sec;
+ if (packet->code == PW_CODE_ACCESS_REQUEST) {
+ request->client->auth.last_packet = request->packet->timestamp.tv_sec;
+ radius_auth_stats.last_packet = request->packet->timestamp.tv_sec;
+#ifdef WITH_ACCOUNTING
+ } else if (packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ request->client->acct.last_packet = request->packet->timestamp.tv_sec;
+ radius_acct_stats.last_packet = request->packet->timestamp.tv_sec;
+#endif
+ }
+#endif /* WITH_STATS */
+
+ /*
+ * Status-Server packets go to the head of the queue.
+ */
+ if (request->packet->code == PW_CODE_STATUS_SERVER) request->priority = 0;
+
+ /*
+ * Set virtual server identity
+ */
+ if (client->server) {
+ request->server = client->server;
+ } else if (listener->server) {
+ request->server = listener->server;
+ } else {
+ request->server = NULL;
+ }
+
+ request->root = &main_config;
+#ifdef WITH_TCP
+ request->listener->count++;
+#endif
+
+ /*
+ * The request passes many of our sanity checks.
+ * From here on in, if anything goes wrong, we
+ * send a reject message, instead of dropping the
+ * packet.
+ */
+
+ /*
+ * Build the reply template from the request.
+ */
+
+ request->reply->sockfd = request->packet->sockfd;
+ request->reply->dst_ipaddr = request->packet->src_ipaddr;
+ request->reply->src_ipaddr = request->packet->dst_ipaddr;
+ request->reply->dst_port = request->packet->src_port;
+ request->reply->src_port = request->packet->dst_port;
+ request->reply->id = request->packet->id;
+ request->reply->code = 0; /* UNKNOWN code */
+ memcpy(request->reply->vector, request->packet->vector,
+ sizeof(request->reply->vector));
+ request->reply->vps = NULL;
+ request->reply->data = NULL;
+ request->reply->data_len = 0;
+
+ return request;
+}
+
+#ifdef WITH_TCP
+/***********************************************************************
+ *
+ * TCP Handlers.
+ *
+ ***********************************************************************/
+
+/*
+ * Timer function for all TCP sockets.
+ */
+static void tcp_socket_timer(void *ctx)
+{
+ rad_listen_t *listener = talloc_get_type_abort(ctx, rad_listen_t);
+ listen_socket_t *sock = listener->data;
+ struct timeval end, now;
+ char buffer[256];
+ fr_socket_limit_t *limit;
+
+ ASSERT_MASTER;
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return;
+
+ fr_event_now(el, &now);
+
+ limit = &sock->limit;
+
+ /*
+ * If we enforce a lifetime, do it now.
+ */
+ if (limit->lifetime > 0) {
+ end.tv_sec = sock->opened + limit->lifetime;
+ end.tv_usec = 0;
+
+ if (timercmp(&end, &now, <=)) {
+ listener->print(listener, buffer, sizeof(buffer));
+ DEBUG("Reached maximum lifetime on socket %s", buffer);
+
+ do_close:
+
+#ifdef WITH_PROXY
+ /*
+ * Proxy sockets get frozen, so that we don't use
+ * them for new requests. But we do keep them
+ * open to listen for replies to requests we had
+ * previously sent.
+ */
+ if (listener->type == RAD_LISTEN_PROXY
+#ifdef WITH_COA_TUNNEL
+ || listener->send_coa
+#endif
+ ) {
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_freeze(proxy_list,
+ listener->fd)) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ }
+#endif
+
+ /*
+ * Mark the socket as "don't use if at all possible".
+ */
+ listener->status = RAD_LISTEN_STATUS_FROZEN;
+
+ /*
+ * If it's blocked, then push all of the requests to other sockets.
+ */
+#ifdef WITH_TLS
+ if (listener->blocked) {
+ listener->status = RAD_LISTEN_STATUS_REMOVE_NOW;
+ }
+#endif
+
+ event_new_fd(listener);
+ return;
+ }
+ } else {
+ end = now;
+ end.tv_sec += 3600;
+ }
+
+ /*
+ * Enforce an idle timeout.
+ */
+ if (limit->idle_timeout > 0) {
+ struct timeval idle;
+
+ rad_assert(sock->last_packet != 0);
+ idle.tv_sec = sock->last_packet + limit->idle_timeout;
+ idle.tv_usec = 0;
+
+ if (timercmp(&idle, &now, <=)) {
+ listener->print(listener, buffer, sizeof(buffer));
+ DEBUG("Reached idle timeout on socket %s", buffer);
+ goto do_close;
+ }
+
+ /*
+ * Enforce the minimum of idle timeout or lifetime.
+ */
+ if (timercmp(&idle, &end, <)) {
+ end = idle;
+ }
+ }
+
+ /*
+ * Wake up at t + 0.5s. The code above checks if the timers
+ * are <= t. This addition gives us a bit of leeway.
+ */
+ end.tv_usec = USEC / 2;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el, tcp_socket_timer, listener, &end, &sock->ev)) {
+ rad_panic("Failed to insert event");
+ }
+}
+
+
+#ifdef WITH_PROXY
+/*
+ * Called by socket_del to remove requests with this socket
+ */
+static int eol_proxy_listener(void *ctx, void *data)
+{
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
+ RADIUS_PACKET **proxy_p = data;
+ REQUEST *request;
+
+ request = fr_packet2myptr(REQUEST, proxy, proxy_p);
+ if (request->proxy_listener != this) return 0;
+
+ /*
+ * The normal "remove_from_proxy_hash" tries to grab the
+ * proxy mutex. We already have it held, so grabbing it
+ * again will cause a deadlock. Instead, call the "no
+ * lock" version of the function.
+ */
+ rad_assert(request->in_proxy_hash == true);
+ remove_from_proxy_hash_nl(request, false);
+
+ /*
+ * Don't mark it as DONE. The client can retransmit, and
+ * the packet SHOULD be re-proxied somewhere else.
+ *
+ * Return "2" means that the rbtree code will remove it
+ * from the tree, and we don't need to do it ourselves.
+ */
+ return 2;
+}
+#endif /* WITH_PROXY */
+
+static int eol_listener(void *ctx, void *data)
+{
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
+ RADIUS_PACKET **packet_p = data;
+ REQUEST *request;
+
+ request = fr_packet2myptr(REQUEST, packet, packet_p);
+ if (request->listener != this) return 0;
+
+ request->master_state = REQUEST_STOP_PROCESSING;
+ request->process = request_done;
+
+ return 0;
+}
+#endif /* WITH_TCP */
+
+#ifdef WITH_PROXY
+/***********************************************************************
+ *
+ * Proxy handlers for the state machine.
+ *
+ ***********************************************************************/
+
+/*
+ * Called with the proxy mutex held
+ */
+static void remove_from_proxy_hash_nl(REQUEST *request, bool yank)
+{
+ VERIFY_REQUEST(request);
+
+ if (!request->in_proxy_hash) return;
+
+#ifdef COA_TUNNEL
+ /*
+ * Track how many IDs are used. This information
+ * helps the listen_coa_find() function get a
+ * listener which has free IDs.
+ */
+ rad_assert(request->proxy_listener->num_ids_used > 0);
+ request->proxy_listener->num_ids_used--;
+#endif
+
+ fr_packet_list_id_free(proxy_list, request->proxy, yank);
+ request->in_proxy_hash = false;
+
+ /*
+ * On the FIRST reply, decrement the count of outstanding
+ * requests. Note that this is NOT the count of sent
+ * packets, but whether or not the home server has
+ * responded at all.
+ */
+ if (request->home_server &&
+ request->home_server->currently_outstanding) {
+ request->home_server->currently_outstanding--;
+
+ /*
+ * If we're NOT sending it packets, AND it's been
+ * a while since we got a response, then we don't
+ * know if it's alive or dead.
+ */
+ if ((request->home_server->currently_outstanding == 0) &&
+ (request->home_server->state == HOME_STATE_ALIVE)) {
+ struct timeval when, now;
+
+ when.tv_sec = request->home_server->last_packet_recv ;
+ when.tv_usec = 0;
+
+ timeradd(&when, request_response_window(request), &when);
+ gettimeofday(&now, NULL);
+
+ /*
+ * last_packet + response_window
+ *
+ * We *administratively* mark the home
+ * server as "unknown" state, because we
+ * haven't seen a packet for a while.
+ */
+ if (timercmp(&now, &when, >)) {
+ request->home_server->state = HOME_STATE_UNKNOWN;
+ request->home_server->last_packet_sent = 0;
+ request->home_server->last_packet_recv = 0;
+ }
+ }
+ }
+
+ if (request->proxy_listener) {
+ request->proxy_listener->count--;
+ }
+ request->proxy_listener = NULL;
+
+ /*
+ * Got from YES in hash, to NO, not in hash while we hold
+ * the mutex. This guarantees that when another thread
+ * grabs the mutex, the "not in hash" flag is correct.
+ */
+}
+
+static void remove_from_proxy_hash(REQUEST *request)
+{
+ VERIFY_REQUEST(request);
+
+ /*
+ * Check this without grabbing the mutex because it's a
+ * lot faster that way.
+ */
+ if (!request->in_proxy_hash) return;
+
+#ifdef WITH_TCP
+ /*
+ * Status-Server packets aren't removed from the proxy hash. They're reused.
+ *
+ * Unless we're tearing down the listener.
+ */
+ if ((request->proxy->proto == IPPROTO_TCP) && (request->proxy->code == PW_CODE_STATUS_SERVER) &&
+ request->proxy_listener && (request->proxy_listener->status < RAD_LISTEN_STATUS_EOL)) {
+ return;
+ }
+#endif
+
+ /*
+ * The "not in hash" flag is definitive. However, if the
+ * flag says that it IS in the hash, there might still be
+ * a race condition where it isn't.
+ */
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+
+ if (!request->in_proxy_hash) {
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ return;
+ }
+
+ remove_from_proxy_hash_nl(request, true);
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+}
+
+static int insert_into_proxy_hash(REQUEST *request)
+{
+ char buf[128];
+ int tries;
+ bool success = false;
+ void *proxy_listener;
+#ifdef WITH_COA_TUNNEL
+ bool reverse_coa = request->proxy_listener && (request->proxy_listener->type != RAD_LISTEN_PROXY);
+#endif
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(request->proxy != NULL);
+ rad_assert(request->home_server != NULL);
+ rad_assert(proxy_list != NULL);
+
+
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ proxy_listener = request->proxy_listener; /* may or may not be NULL */
+ request->num_proxied_requests = 1;
+ request->num_proxied_responses = 0;
+
+ for (tries = 0; tries < 2; tries++) {
+ rad_listen_t *this;
+ listen_socket_t *sock;
+
+ RDEBUG3("proxy: Trying to allocate ID (%d/2)", tries);
+ success = fr_packet_list_id_alloc(proxy_list,
+ request->home_server->proto,
+ &request->proxy, &proxy_listener);
+ if (success) break;
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Can't allocate an ID here, try to grab another
+ * listener by key.
+ */
+ if (reverse_coa) {
+ int rcode;
+ VALUE_PAIR *vp;
+
+ /*
+ * Find the Originating-Realm key, which
+ * might not be the same as
+ * proxy_listener->key.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_ORIGINATING_REALM, 0, TAG_ANY);
+ if (!vp) break;
+
+ /*
+ * We don't want to hold multiple mutexes
+ * at the same time.
+ */
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ rcode = listen_coa_find(request, vp->vp_strvalue);
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (rcode < 0) continue;
+ break;
+ }
+#endif
+
+ if (tries > 0) continue; /* try opening new socket only once */
+
+#ifdef HAVE_PTHREAD_H
+ if (proxy_no_new_sockets) break;
+#endif
+
+ RDEBUG3("proxy: Trying to open a new listener to the home server");
+ this = proxy_new_listener(proxy_ctx, request->home_server, 0);
+ if (!this) {
+ request->home_server->state = HOME_STATE_CONNECTION_FAIL;
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ goto fail;
+ }
+
+ request->proxy->src_port = 0; /* Use any new socket */
+ proxy_listener = this;
+
+ sock = this->data;
+ if (!fr_packet_list_socket_add(proxy_list, this->fd,
+ sock->proto,
+#ifdef WITH_RADIUSV11
+ sock->radiusv11,
+#endif
+ &sock->other_ipaddr, sock->other_port,
+ this)) {
+
+#ifdef HAVE_PTHREAD_H
+ proxy_no_new_sockets = true;
+#endif
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ /*
+ * This is bad. However, the
+ * packet list now supports 256
+ * open sockets, which should
+ * minimize this problem.
+ */
+ ERROR("Failed adding proxy socket: %s",
+ fr_strerror());
+ goto fail;
+ }
+
+#ifdef COA_TUNNEL
+ /*
+ * Track how many IDs are used. This information
+ * helps the listen_coa_find() function get a
+ * listener which has free IDs.
+ */
+ request->proxy_listener->num_ids_used++;
+#endif
+
+ /*
+ * Add it to the event loop. Ensure that we have
+ * only one mutex locked at a time.
+ */
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ radius_update_listener(this);
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ }
+
+ if (!proxy_listener || !success) {
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ REDEBUG2("proxy: Failed allocating Id for proxied request");
+ fail:
+ request->proxy_listener = NULL;
+ request->in_proxy_hash = false;
+ return 0;
+ }
+
+#ifndef WITH_RADIUSV11
+ rad_assert(request->proxy->id >= 0);
+#endif
+
+ request->proxy_listener = proxy_listener;
+ request->in_proxy_hash = true;
+ RDEBUG3("proxy: request is now in proxy hash");
+
+ /*
+ * Keep track of maximum outstanding requests to a
+ * particular home server. 'max_outstanding' is
+ * enforced in home_server_ldb(), in realms.c.
+ */
+ request->home_server->currently_outstanding++;
+
+ request->proxy_listener->count++;
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ RDEBUG3("proxy: allocating destination %s port %d - Id %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
+ request->proxy->dst_port,
+ request->proxy->id);
+
+ return 1;
+}
+
+static int process_proxy_reply(REQUEST *request, RADIUS_PACKET *reply)
+{
+ int rcode;
+ int post_proxy_type = 0;
+ VALUE_PAIR *vp;
+ char const *old_server;
+#ifdef WITH_COA_TUNNEL
+ bool reverse_coa = false;
+#endif
+
+ VERIFY_REQUEST(request);
+
+ /*
+ * There may be a proxy reply, but it may be too late.
+ */
+ if ((request->home_server && !request->home_server->virtual_server) && !request->proxy_listener) return 0;
+
+ /*
+ * Delete any reply we had accumulated until now.
+ */
+ RDEBUG2("Clearing existing &reply: attributes");
+ fr_pair_list_free(&request->reply->vps);
+
+ /*
+ * Run the packet through the post-proxy stage,
+ * BEFORE playing games with the attributes.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_POST_PROXY_TYPE, 0, TAG_ANY);
+ if (vp) {
+ post_proxy_type = vp->vp_integer;
+ /*
+ * If we have a proxy_reply, and it was a reject, or a NAK
+ * setup Post-Proxy <type>.
+ *
+ * If the <type> doesn't have a section, then the Post-Proxy
+ * section is ignored.
+ */
+ } else if (reply) {
+ DICT_VALUE *dval = NULL;
+
+ switch (reply->code) {
+ case PW_CODE_ACCESS_REJECT:
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Reject");
+ if (dval) post_proxy_type = dval->value;
+ break;
+
+ case PW_CODE_DISCONNECT_NAK:
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, fr_packet_codes[reply->code]);
+ if (dval) post_proxy_type = dval->value;
+ break;
+
+ case PW_CODE_COA_NAK:
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, fr_packet_codes[reply->code]);
+ if (dval) post_proxy_type = dval->value;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Create config:Post-Proxy-Type
+ */
+ if (dval) {
+ vp = radius_pair_create(request, &request->config, PW_POST_PROXY_TYPE, 0);
+ vp->vp_integer = dval->value;
+ }
+ }
+
+ if (post_proxy_type > 0) RDEBUG2("Found Post-Proxy-Type %s",
+ dict_valnamebyattr(PW_POST_PROXY_TYPE, 0, post_proxy_type));
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Cache this, as request->proxy_listener will be
+ * NULL after removing the request from the proxy
+ * hash.
+ */
+ if (request->proxy_listener) reverse_coa = request->proxy_listener->type != RAD_LISTEN_PROXY;
+#endif
+
+ if (reply) {
+ VERIFY_PACKET(reply);
+
+ /*
+ * Decode the packet if required.
+ */
+ if (request->proxy_listener) {
+ rcode = request->proxy_listener->proxy_decode(request->proxy_listener, request);
+ debug_packet(request, reply, true);
+
+ /*
+ * Pro-actively remove it from the proxy hash.
+ * This is later than in 2.1.x, but it means that
+ * the replies are authenticated before being
+ * removed from the hash.
+ */
+ if ((rcode == 0) &&
+ (request->num_proxied_requests <= request->num_proxied_responses)) {
+ remove_from_proxy_hash(request);
+ }
+ } else {
+ rad_assert(!request->in_proxy_hash);
+ }
+ } else if (request->in_proxy_hash) {
+ remove_from_proxy_hash(request);
+ }
+
+
+ /*
+ * Run the request through the virtual server for the
+ * home server, OR through the virtual server for the
+ * home server pool.
+ */
+ old_server = request->server;
+ if (request->home_server && request->home_server->virtual_server) {
+ request->server = request->home_server->virtual_server;
+
+#ifdef WITH_COA_TUNNEL
+ } else if (reverse_coa) {
+ rad_assert((request->proxy->code == PW_CODE_COA_REQUEST) ||
+ (request->proxy->code == PW_CODE_DISCONNECT_REQUEST));
+ rad_assert(request->home_server != NULL);
+ rad_assert(request->home_server->recv_coa_server != NULL);
+ request->server = request->home_server->recv_coa_server;
+#endif
+
+ } else if (request->home_pool && request->home_pool->virtual_server) {
+ request->server = request->home_pool->virtual_server;
+ }
+
+ /*
+ * Run the request through the given virtual server.
+ */
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
+ rcode = process_post_proxy(post_proxy_type, request);
+ REXDENT();
+ RDEBUG2("}");
+ request->server = old_server;
+
+#ifdef WITH_COA
+ if (request->proxy && request->packet->code == request->proxy->code) {
+ /*
+ * Don't run the next bit if we originated a CoA
+ * packet, after receiving an Access-Request or
+ * Accounting-Request.
+ */
+#endif
+
+ /*
+ * There may NOT be a proxy reply, as we may be
+ * running Post-Proxy-Type = Fail.
+ */
+ if (reply) {
+ fr_pair_add(&request->reply->vps, fr_pair_list_copy(request->reply, reply->vps));
+
+ /*
+ * Delete the Proxy-State Attributes from
+ * the reply. These include Proxy-State
+ * attributes from us and remote server.
+ */
+ fr_pair_delete_by_num(&request->reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+
+ } else {
+ vp = fr_pair_find_by_num(request->config, PW_RESPONSE_PACKET_TYPE, 0, TAG_ANY);
+ if (vp && (vp->vp_integer != 256)) {
+ request->proxy_reply = rad_alloc_reply(request, request->proxy);
+ request->proxy_reply->code = vp->vp_integer;
+ }
+ }
+#ifdef WITH_COA
+ }
+#endif
+ switch (rcode) {
+ default: /* Don't do anything */
+ break;
+ case RLM_MODULE_FAIL:
+ return 0;
+
+ case RLM_MODULE_HANDLED:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void mark_home_server_alive(REQUEST *request, home_server_t *home)
+{
+ char buffer[128];
+
+ home->state = HOME_STATE_ALIVE;
+ home->response_timeouts = 0;
+ exec_trigger(request, home->cs, "home_server.alive", false);
+ home->currently_outstanding = 0;
+ home->num_sent_pings = 0;
+ home->num_received_pings = 0;
+ gettimeofday(&home->revive_time, NULL);
+
+ fr_event_delete(el, &home->ev);
+
+ RPROXY("Marking home server %s port %d alive",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+}
+
+
+int request_proxy_reply(RADIUS_PACKET *packet)
+{
+ RADIUS_PACKET **proxy_p;
+ REQUEST *request;
+ struct timeval now;
+ char buffer[128];
+
+ VERIFY_PACKET(packet);
+
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ proxy_p = fr_packet_list_find_byreply(proxy_list, packet);
+
+ if (!proxy_p) {
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ PROXY("No outstanding request was found for %s packet from host %s port %d - ID %u",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port, packet->id);
+ return 0;
+ }
+
+ request = fr_packet2myptr(REQUEST, proxy, proxy_p);
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ /*
+ * No reply, BUT the current packet fails verification:
+ * ignore it. This does the MD5 calculations in the
+ * server core, but I guess we can fix that later.
+ */
+ if (!request->proxy_reply) {
+ if (!request->home_server) {
+ proxy_reply_too_late(request);
+ return 0;
+ }
+
+ if (rad_verify(packet, request->proxy,
+ request->home_server->secret) != 0) {
+ DEBUG("Ignoring spoofed proxy reply. Signature is invalid");
+ return 0;
+ }
+ }
+
+ /*
+ * The home server sent us a packet which doesn't match
+ * something we have: ignore it. This is done only to
+ * catch the case of broken systems.
+ */
+ if (request->proxy_reply &&
+ (memcmp(request->proxy_reply->vector,
+ packet->vector,
+ sizeof(request->proxy_reply->vector)) != 0)) {
+ RDEBUG2("Ignoring conflicting proxy reply");
+ return 0;
+ }
+
+ /*
+ * This shouldn't happen, but threads and race
+ * conditions.
+ */
+ if (!request->proxy_listener || !request->proxy_listener->data) {
+ proxy_reply_too_late(request);
+ return 0;
+ }
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Status-Server packets don't count as real packets.
+ */
+ if (request->proxy->code != PW_CODE_STATUS_SERVER) {
+#ifdef WITH_TCP
+ listen_socket_t *sock = request->proxy_listener->data;
+
+ sock->last_packet = now.tv_sec;
+#endif
+ request->home_server->last_packet_recv = now.tv_sec;
+ }
+
+ request->num_proxied_responses++;
+
+ /*
+ * If we have previously seen a reply, ignore the
+ * duplicate.
+ */
+ if (request->proxy_reply) {
+ RDEBUG2("Discarding duplicate reply from host %s port %d - ID: %d",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port, packet->id);
+ return 0;
+ }
+
+ /*
+ * Call the state machine to do something useful with the
+ * request.
+ */
+ request->proxy_reply = talloc_steal(request, packet);
+ packet->timestamp = now;
+ request->priority = RAD_LISTEN_PROXY;
+
+#ifdef WITH_STATS
+ /*
+ * Update the proxy listener stats here, because only one
+ * thread accesses that at a time. The home_server and
+ * main proxy_*_stats structures are updated once the
+ * request is cleaned up.
+ */
+ request->proxy_listener->stats.total_responses++;
+
+ request->home_server->stats.last_packet = packet->timestamp.tv_sec;
+ request->proxy_listener->stats.last_packet = packet->timestamp.tv_sec;
+
+ switch (request->proxy->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ proxy_auth_stats.last_packet = packet->timestamp.tv_sec;
+
+ if (request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT) {
+ request->proxy_listener->stats.total_access_accepts++;
+
+ } else if (request->proxy_reply->code == PW_CODE_ACCESS_REJECT) {
+ request->proxy_listener->stats.total_access_rejects++;
+
+ } else if (request->proxy_reply->code == PW_CODE_ACCESS_CHALLENGE) {
+ request->proxy_listener->stats.total_access_challenges++;
+ }
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ request->proxy_listener->stats.total_responses++;
+ proxy_acct_stats.last_packet = packet->timestamp.tv_sec;
+ break;
+
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ request->proxy_listener->stats.total_responses++;
+ proxy_coa_stats.last_packet = packet->timestamp.tv_sec;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ request->proxy_listener->stats.total_responses++;
+ proxy_dsc_stats.last_packet = packet->timestamp.tv_sec;
+ break;
+
+#endif
+ default:
+ break;
+ }
+#endif
+
+ /*
+ * If we hadn't been sending the home server packets for
+ * a while, just mark it alive. Or, if it was zombie,
+ * it's now responded, and is therefore alive.
+ */
+ if ((request->home_server->state == HOME_STATE_UNKNOWN) ||
+ (request->home_server->state == HOME_STATE_ZOMBIE)) {
+ mark_home_server_alive(request, request->home_server);
+ }
+
+ /*
+ * Tell the request state machine that we have a proxy
+ * reply. Depending on the function, this should either
+ * ignore it, or process it.
+ */
+ request->process(request, FR_ACTION_PROXY_REPLY);
+
+ return 1;
+}
+
+
+static int setup_post_proxy_fail(REQUEST *request)
+{
+ DICT_VALUE const *dval = NULL;
+ VALUE_PAIR *vp;
+ RADIUS_PACKET *packet;
+
+ VERIFY_REQUEST(request);
+
+ packet = request->proxy ? request->proxy : request->packet;
+
+ if (packet->code == PW_CODE_ACCESS_REQUEST) {
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
+ "Fail-Authentication");
+#ifdef WITH_ACCOUNTING
+ } else if (packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0,
+ "Fail-Accounting");
+#endif
+
+#ifdef WITH_COA
+ } else if (packet->code == PW_CODE_COA_REQUEST) {
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-CoA");
+
+ } else if (packet->code == PW_CODE_DISCONNECT_REQUEST) {
+ dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail-Disconnect");
+#endif
+ } else {
+ WARN("Unknown packet type in Post-Proxy-Type Fail: ignoring");
+ return 0;
+ }
+
+ if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, 0, "Fail");
+
+ if (!dval) {
+ fr_pair_delete_by_num(&request->config, PW_POST_PROXY_TYPE, 0, TAG_ANY);
+ return 0;
+ }
+
+ vp = fr_pair_find_by_num(request->config, PW_POST_PROXY_TYPE, 0, TAG_ANY);
+ if (!vp) vp = radius_pair_create(request, &request->config,
+ PW_POST_PROXY_TYPE, 0);
+ vp->vp_integer = dval->value;
+
+ return 1;
+}
+
+
+/** Process a request after the proxy has timed out.
+ *
+ * Run the packet through Post-Proxy-Type Fail
+ *
+ * \dot
+ * digraph proxy_no_reply {
+ * proxy_no_reply;
+ *
+ * proxy_no_reply -> dup [ label = "DUP", arrowhead = "none" ];
+ * proxy_no_reply -> timer [ label = "TIMER < max_request_time" ];
+ * proxy_no_reply -> proxy_reply_too_late [ label = "PROXY_REPLY" arrowhead = "none"];
+ * proxy_no_reply -> process_proxy_reply [ label = "RUN" ];
+ * proxy_no_reply -> done [ label = "TIMER >= timeout" ];
+ * }
+ * \enddot
+ */
+static void proxy_no_reply(REQUEST *request, int action)
+{
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_DUP:
+ request_dup(request);
+ break;
+
+ case FR_ACTION_TIMER:
+ (void) request_max_time(request);
+ break;
+
+ case FR_ACTION_PROXY_REPLY:
+ proxy_reply_too_late(request);
+ break;
+
+ case FR_ACTION_RUN:
+ if (process_proxy_reply(request, NULL)) {
+ request->handle(request);
+ }
+ request_finish(request, action);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+/** Process the request after receiving a proxy reply.
+ *
+ * Throught the post-proxy section, and the through the handler
+ * function.
+ *
+ * \dot
+ * digraph proxy_running {
+ * proxy_running;
+ *
+ * proxy_running -> dup [ label = "DUP", arrowhead = "none" ];
+ * proxy_running -> timer [ label = "TIMER < max_request_time" ];
+ * proxy_running -> process_proxy_reply [ label = "RUN" ];
+ * proxy_running -> done [ label = "TIMER >= timeout" ];
+ * }
+ * \enddot
+ */
+static void proxy_running(REQUEST *request, int action)
+{
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_DUP:
+ request_dup(request);
+ break;
+
+ case FR_ACTION_TIMER:
+ (void) request_max_time(request);
+ break;
+
+ case FR_ACTION_RUN:
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ }
+ request_finish(request, action);
+ break;
+
+ default: /* duplicate proxy replies are suppressed */
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+/** Determine if a #REQUEST needs to be proxied, and perform pre-proxy operations
+ *
+ * Whether a request will be proxied is determined by the attributes present
+ * in request->config. If any of the following attributes are found, the
+ * request may be proxied.
+ *
+ * The key attributes are:
+ * - PW_PROXY_TO_REALM - Specifies a realm the request should be proxied to.
+ * - PW_HOME_SERVER_POOL - Specifies a specific home server pool to proxy to.
+ * - PW_HOME_SERVER_NAME - Specifies a home server by name
+ * - PW_PACKET_DST_IP_ADDRESS - Specifies a home server by IPv4 address
+ * - PW_PACKET_DST_IPV6_ADDRESS - Specifies a home server by IPv5 address
+ *
+ * Certain packet types such as #PW_CODE_STATUS_SERVER will never be proxied.
+ *
+ * If request should be proxied, will:
+ * - Add request:Proxy-State
+ * - Strip the current username value of its realm (depending on config)
+ * - Create a CHAP-Challenge from the original request vector, if one doesn't already
+ * exist.
+ * - Call the pre-process section in the current server, or in the virtual server
+ * associated with the home server pool we're proxying to.
+ *
+ * @todo A lot of this logic is RADIUS specific, and should be moved out into a protocol
+ * specific function.
+ *
+ * @param request The #REQUEST to evaluate for proxying.
+ * @return 0 if not proxying, 1 if request should be proxied, -1 on error.
+ */
+static int request_will_proxy(REQUEST *request)
+{
+ int rcode, pre_proxy_type = 0;
+ char const *realmname = NULL;
+ VALUE_PAIR *vp, *strippedname;
+ home_server_t *home;
+ REALM *realm = NULL;
+ home_pool_t *pool = NULL;
+ char const *old_server;
+
+ VERIFY_REQUEST(request);
+
+ if (!request->root->proxy_requests) {
+ return 0;
+ }
+ if (request->packet->dst_port == 0) return 0;
+ if (request->packet->code == PW_CODE_STATUS_SERVER) return 0;
+ if (request->in_proxy_hash) return 0;
+
+ /*
+ * FIXME: for 3.0, allow this only for rejects?
+ */
+ if (request->reply->code != 0) return 0;
+
+ vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+ if (vp) {
+ realm = realm_find2(vp->vp_strvalue);
+ if (!realm) {
+ REDEBUG2("Cannot proxy to unknown realm %s",
+ vp->vp_strvalue);
+ return 0;
+ }
+
+ realmname = vp->vp_strvalue;
+
+ /*
+ * Figure out which pool to use.
+ */
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ DEBUG3("Using home pool auth for realm %s", realm->name);
+ pool = realm->auth_pool;
+
+#ifdef WITH_ACCOUNTING
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ DEBUG3("Using home pool acct for realm %s", realm->name);
+ pool = realm->acct_pool;
+#endif
+
+#ifdef WITH_COA
+ } else if ((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST)) {
+ DEBUG3("Using home pool coa for realm %s", realm->name);
+ pool = realm->coa_pool;
+#endif
+
+ } else {
+ return 0;
+ }
+
+ } else if ((vp = fr_pair_find_by_num(request->config, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) {
+ int pool_type;
+
+ DEBUG3("Using Home-Server-Pool %s", vp->vp_strvalue);
+
+ switch (request->packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ pool_type = HOME_TYPE_AUTH;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ pool_type = HOME_TYPE_ACCT;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ pool_type = HOME_TYPE_COA;
+ break;
+#endif
+
+ default:
+ return 0;
+ }
+
+ pool = home_pool_byname(vp->vp_strvalue, pool_type);
+
+ /*
+ * Send it directly to a home server (i.e. NAS)
+ */
+ } else if (((vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY)) != NULL) ||
+ ((vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL)) {
+ uint16_t dst_port;
+ fr_ipaddr_t dst_ipaddr;
+
+ memset(&dst_ipaddr, 0, sizeof(dst_ipaddr));
+
+ if (vp->da->attr == PW_PACKET_DST_IP_ADDRESS) {
+ dst_ipaddr.af = AF_INET;
+ dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ dst_ipaddr.prefix = 32;
+ } else {
+ dst_ipaddr.af = AF_INET6;
+ memcpy(&dst_ipaddr.ipaddr.ip6addr, &vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
+ dst_ipaddr.prefix = 128;
+ }
+
+ vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_PORT, 0, TAG_ANY);
+ if (!vp) {
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ dst_port = PW_AUTH_UDP_PORT;
+
+#ifdef WITH_ACCOUNTING
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ dst_port = PW_ACCT_UDP_PORT;
+#endif
+
+#ifdef WITH_COA
+ } else if ((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST)) {
+ dst_port = PW_COA_UDP_PORT;
+#endif
+ } else { /* shouldn't happen for RADIUS... */
+ return 0;
+ }
+
+ } else {
+ dst_port = vp->vp_integer;
+ }
+
+ /*
+ * Find the home server.
+ */
+ home = home_server_find(&dst_ipaddr, dst_port, IPPROTO_UDP);
+ if (!home) home = home_server_find(&dst_ipaddr, dst_port, IPPROTO_TCP);
+ if (!home) {
+ char buffer[256];
+
+ RWDEBUG("No such home server %s port %u",
+ inet_ntop(dst_ipaddr.af, &dst_ipaddr.ipaddr, buffer, sizeof(buffer)),
+ (unsigned int) dst_port);
+ return 0;
+ }
+
+ /*
+ * The home server is alive (or may be alive).
+ * Send the packet to the IP.
+ */
+ if (!HOME_SERVER_IS_DEAD(home)) goto do_home;
+
+ /*
+ * The home server is dead. If you wanted
+ * fail-over, you should have proxied to a pool.
+ * Sucks to be you.
+ */
+
+ return 0;
+
+ } else if ((vp = fr_pair_find_by_num(request->config, PW_HOME_SERVER_NAME, 0, TAG_ANY)) != NULL) {
+ int type;
+
+ switch (request->packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ type = HOME_TYPE_AUTH;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ type = HOME_TYPE_ACCT;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ type = HOME_TYPE_COA;
+ break;
+#endif
+
+ default:
+ return 0;
+ }
+
+ /*
+ * Find the home server by name.
+ */
+ home = home_server_byname(vp->vp_strvalue, type);
+ if (!home) {
+ RWDEBUG("No such home server %s", vp->vp_strvalue);
+ return 0;
+ }
+
+ /*
+ * The home server is alive (or may be alive).
+ * Send the packet to the IP.
+ */
+ if (!HOME_SERVER_IS_DEAD(home)) goto do_home;
+
+ /*
+ * The home server is dead. If you wanted
+ * fail-over, you should have proxied to a pool.
+ * Sucks to be you.
+ */
+
+ return 0;
+
+#ifdef WITH_COA_TUNNEL
+ } else if (((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST)) &&
+ ((vp = fr_pair_find_by_num(request->config, PW_PROXY_TO_ORIGINATING_REALM, 0, TAG_ANY)) != NULL)) {
+
+ /*
+ * This function will set request->home_server,
+ * and also request->proxy_listener.
+ */
+ if (listen_coa_find(request, vp->vp_strvalue) < 0) {
+ vp_cursor_t cursor;
+
+ (void) fr_cursor_init(&cursor, &request->config); /* already checked it above */
+
+ while ((vp = fr_cursor_next(&cursor)) != NULL) {
+ if (listen_coa_find(request, vp->vp_strvalue) == 0) break;
+ }
+
+ /*
+ * Not found.
+ */
+ return 0;
+ }
+
+ /*
+ * Initialise request->proxy, and copy VPs over.
+ */
+ home_server_update_request(request->home_server, request);
+ goto add_proxy_state;
+#endif
+ } else {
+
+ return 0;
+ }
+
+ if (!pool) {
+ RWDEBUG2("Cancelling proxy as no home pool exists");
+ return 0;
+ }
+
+ if (request->listener->synchronous) {
+ WARN("Cannot proxy a request which is from a 'synchronous' socket");
+ return 0;
+ }
+
+ request->home_pool = pool;
+
+ home = home_server_ldb(realmname, pool, request);
+
+ if (!home) {
+ REDEBUG2("Failed to find live home server: Cancelling proxy");
+ return -1;
+ }
+
+do_home:
+ home_server_update_request(home, request);
+
+#ifdef WITH_COA
+ /*
+ * Once we've decided to proxy a request, we cannot send
+ * a CoA packet. So we free up any CoA packet here.
+ */
+ if (request->coa) request_done(request->coa, FR_ACTION_COA_CANCELLED);
+#endif
+
+ /*
+ * Remember that we sent the request to a Realm.
+ */
+ if (realmname && !fr_pair_find_by_num(request->packet->vps, PW_REALM, 0, TAG_ANY)) {
+ pair_make_request("Realm", realmname, T_OP_EQ);
+ }
+
+ /*
+ * Strip the name, if told to.
+ *
+ * Doing it here catches the case of proxied tunneled
+ * requests.
+ */
+ if (realm && (realm->strip_realm == true) &&
+ (strippedname = fr_pair_find_by_num(request->proxy->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY)) != NULL) {
+ /*
+ * If there's a Stripped-User-Name attribute in
+ * the request, then use THAT as the User-Name
+ * for the proxied request, instead of the
+ * original name.
+ *
+ * This is done by making a copy of the
+ * Stripped-User-Name attribute, turning it into
+ * a User-Name attribute, deleting the
+ * Stripped-User-Name and User-Name attributes
+ * from the vps list, and making the new
+ * User-Name the head of the vps list.
+ */
+ vp = fr_pair_find_by_num(request->proxy->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ vp_cursor_t cursor;
+ vp = radius_pair_create(NULL, NULL,
+ PW_USER_NAME, 0);
+ rad_assert(vp != NULL); /* handled by above function */
+ /* Insert at the START of the list */
+ /* FIXME: Can't make assumptions about ordering */
+ fr_cursor_init(&cursor, &vp);
+ fr_cursor_merge(&cursor, request->proxy->vps);
+ request->proxy->vps = vp;
+ }
+ fr_pair_value_strcpy(vp, strippedname->vp_strvalue);
+
+ /*
+ * Do NOT delete Stripped-User-Name.
+ */
+ }
+
+ /*
+ * If there is no PW_CHAP_CHALLENGE attribute but
+ * there is a PW_CHAP_PASSWORD we need to add it
+ * since we can't use the request authenticator
+ * anymore - we changed it.
+ */
+ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
+ fr_pair_find_by_num(request->proxy->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
+ fr_pair_find_by_num(request->proxy->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
+ vp = radius_pair_create(request->proxy, &request->proxy->vps, PW_CHAP_CHALLENGE, 0);
+ fr_pair_value_memcpy(vp, request->packet->vector, sizeof(request->packet->vector));
+ }
+
+ /*
+ * The RFC's say we have to do this, but FreeRADIUS
+ * doesn't need it.
+ */
+#ifdef WITH_COA_TUNNEL
+add_proxy_state:
+#endif
+
+ vp = radius_pair_create(request->proxy, &request->proxy->vps, PW_PROXY_STATE, 0);
+ fr_pair_value_sprintf(vp, "%u", request->packet->id);
+
+ /*
+ * Should be done BEFORE inserting into proxy hash, as
+ * pre-proxy may use this information, or change it.
+ */
+ request->proxy->code = request->packet->code;
+
+ /*
+ * Call the pre-proxy routines.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
+ if (vp) {
+ DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
+ /* Must be a validation issue */
+ rad_assert(dval);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
+ pre_proxy_type = vp->vp_integer;
+ }
+
+ /*
+ * Run the request through the virtual server for the
+ * home server, OR through the virtual server for the
+ * home server pool.
+ */
+ old_server = request->server;
+ if (request->home_server && request->home_server->virtual_server) {
+ request->server = request->home_server->virtual_server;
+
+#ifdef WITH_COA_TUNNEL
+ } else if (request->proxy_listener && (request->proxy_listener->type != RAD_LISTEN_PROXY)) {
+ rad_assert((request->packet->code == PW_CODE_COA_REQUEST) ||
+ (request->packet->code == PW_CODE_DISCONNECT_REQUEST));
+ rad_assert(request->home_server != NULL);
+ rad_assert(request->home_server->recv_coa_server != NULL);
+ request->server = request->home_server->recv_coa_server;
+#endif
+
+ } else {
+ char buffer[128];
+
+ RDEBUG2("Starting proxy to home server %s port %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+
+ if (request->home_pool && request->home_pool->virtual_server) {
+ request->server = request->home_pool->virtual_server;
+ }
+ }
+
+ /*
+ * Run the request through the given virtual server.
+ */
+ RDEBUG2("server %s {", request->server);
+ RINDENT();
+ rcode = process_pre_proxy(pre_proxy_type, request);
+ REXDENT();
+ RDEBUG2("}");
+ request->server = old_server;
+
+ switch (rcode) {
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOTFOUND:
+ case RLM_MODULE_USERLOCK:
+ default:
+ /* FIXME: debug print failed stuff */
+ return -1;
+
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_HANDLED:
+ return 0;
+
+ /*
+ * Only proxy the packet if the pre-proxy code succeeded.
+ */
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ return 1;
+ }
+}
+
+static int proxy_to_virtual_server(REQUEST *request)
+{
+ REQUEST *fake;
+
+ if (request->packet->dst_port == 0) {
+ WARN("Cannot proxy an internal request");
+ return 0;
+ }
+
+ DEBUG("Proxying to virtual server %s",
+ request->home_server->virtual_server);
+
+ /*
+ * Packets to virtual servers don't get
+ * retransmissions sent to them. And the virtual
+ * server is run ONLY if we have no child
+ * threads, or we're running in a child thread.
+ */
+ rad_assert(!spawn_flag || !we_are_master());
+
+ fake = request_alloc_fake(request);
+
+ fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps);
+ talloc_free(request->proxy);
+
+ fake->server = request->home_server->virtual_server;
+ fake->handle = request->handle;
+ fake->process = NULL; /* should never be run for anything */
+
+ /*
+ * Run the virtual server.
+ */
+ request_running(fake, FR_ACTION_RUN);
+
+ request->proxy = talloc_steal(request, fake->packet);
+ fake->packet = NULL;
+ request->proxy_reply = talloc_steal(request, fake->reply);
+ fake->reply = NULL;
+
+ talloc_free(fake);
+
+ /*
+ * No reply code, toss the reply we have,
+ * and do post-proxy-type Fail.
+ */
+ if (!request->proxy_reply->code) {
+ TALLOC_FREE(request->proxy_reply);
+ setup_post_proxy_fail(request);
+ }
+
+ /*
+ * Do the proxy reply (if any)
+ */
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ }
+
+ return -1; /* so we call request_finish */
+}
+
+
+static int request_proxy(REQUEST *request)
+{
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(request->parent == NULL);
+
+ if (request->master_state == REQUEST_STOP_PROCESSING) return 0;
+
+#ifdef WITH_COA
+ if (request->coa) {
+ RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request");
+ request_done(request->coa, FR_ACTION_COA_CANCELLED);
+ }
+#endif
+
+ if (!request->home_server) {
+ RWDEBUG("No home server selected");
+ return -1;
+ }
+
+ /*
+ * The request may need sending to a virtual server.
+ * This code is more than a little screwed up. The rest
+ * of the state machine doesn't handle parent / child
+ * relationships well. i.e. if the child request takes
+ * too long, the core will mark the *parent* as "stop
+ * processing". And the child will continue without
+ * knowing anything...
+ *
+ * So, we have some horrible hacks to get around that.
+ */
+ if (request->home_server->virtual_server) return proxy_to_virtual_server(request);
+
+ /*
+ * We're actually sending a proxied packet. Do that now.
+ */
+ if (!request->in_proxy_hash && !insert_into_proxy_hash(request)) {
+ RPROXY("Failed to insert request into the proxy list");
+ return -1;
+ }
+
+#ifndef WITH_RADIUSV11
+ rad_assert(request->proxy->id >= 0);
+#endif
+
+ if (rad_debug_lvl) {
+ struct timeval *response_window;
+
+ response_window = request_response_window(request);
+
+#ifdef WITH_TLS
+ if (request->home_server->tls) {
+#ifdef WITH_RADIUSV11
+ listen_socket_t *sock = request->proxy_listener->data;
+
+ if (sock->radiusv11) {
+ fr_pair_delete_by_num(&request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ }
+#endif
+
+ RDEBUG2("Proxying request to home server %s port %d (TLS) timeout %d.%06d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ (int) response_window->tv_sec, (int) response_window->tv_usec);
+ } else
+#endif
+ RDEBUG2("Proxying request to home server %s port %d timeout %d.%06d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ (int) response_window->tv_sec, (int) response_window->tv_usec);
+
+
+ }
+
+ gettimeofday(&request->proxy->timestamp, NULL);
+ request->home_server->last_packet_sent = request->proxy->timestamp.tv_sec;
+
+ /*
+ * Encode the packet before we do anything else.
+ */
+ request->proxy_listener->proxy_encode(request->proxy_listener, request);
+ debug_packet(request, request->proxy, false);
+
+ /*
+ * Set the state function, then the state, no child, and
+ * send the packet.
+ *
+ * The order here is different from other state changes
+ * due to race conditions with replies from the home
+ * server.
+ */
+ request->process = proxy_wait_for_reply;
+ request->child_state = REQUEST_PROXIED;
+ request->component = "<REQUEST_PROXIED>";
+ request->module = "";
+ NO_CHILD_THREAD;
+
+ /*
+ * And send the packet.
+ */
+ request->proxy_listener->proxy_send(request->proxy_listener, request);
+ return 1;
+}
+
+/*
+ * Proxy the packet as if it was new.
+ */
+static int request_proxy_anew(REQUEST *request)
+{
+ home_server_t *home;
+
+ VERIFY_REQUEST(request);
+
+ /*
+ * Delete the request from the proxy list.
+ *
+ * The packet list code takes care of ensuring that IDs
+ * aren't reused until all 256 IDs have been used. So
+ * there's a 1/256 chance of re-using the same ID when
+ * we're sending to the same home server. Which is
+ * acceptable.
+ */
+ remove_from_proxy_hash(request);
+
+ /*
+ * Find a live home server for the request.
+ */
+ home = home_server_ldb(NULL, request->home_pool, request);
+ if (!home) {
+ REDEBUG2("Failed to find live home server for request");
+ post_proxy_fail:
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, proxy_running);
+ } else {
+ gettimeofday(&request->reply->timestamp, NULL);
+ request_cleanup_delay_init(request);
+ }
+ return 0;
+ }
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Update the Acct-Delay-Time attribute, since the LAST
+ * time we tried to retransmit this packet.
+ */
+ if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_find_by_num(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
+ if (!vp) vp = radius_pair_create(request->proxy,
+ &request->proxy->vps,
+ PW_ACCT_DELAY_TIME, 0);
+ if (vp) {
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ vp->vp_integer += now.tv_sec - request->proxy->timestamp.tv_sec;
+ }
+ }
+#endif
+
+ /*
+ * May have failed over to a "fallback" virtual server.
+ * If so, run that instead of doing proxying to a real
+ * server.
+ */
+ if (home->virtual_server) {
+ request->home_server = home;
+ TALLOC_FREE(request->proxy);
+
+ (void) proxy_to_virtual_server(request);
+ return 0;
+ }
+
+ home_server_update_request(home, request);
+
+ if (!insert_into_proxy_hash(request)) {
+ RPROXY("Failed to insert retransmission into the proxy list");
+ goto post_proxy_fail;
+ }
+
+ /*
+ * Free the old packet, to force re-encoding
+ */
+ talloc_free(request->proxy->data);
+ request->proxy->data = NULL;
+ request->proxy->data_len = 0;
+
+ if (request_proxy(request) != 1) goto post_proxy_fail;
+
+ return 1;
+}
+
+
+/** Ping a home server.
+ *
+ */
+static void request_ping(REQUEST *request, int action)
+{
+ home_server_t *home = request->home_server;
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ ERROR("No response to status check %d ID %u for home server %s port %d",
+ request->number,
+ request->proxy->id,
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+ remove_from_proxy_hash(request);
+ break;
+
+ case FR_ACTION_PROXY_REPLY:
+ rad_assert(request->in_proxy_hash);
+
+ request->home_server->num_received_pings++;
+ RPROXY("Received response to status check %d ID %u (%d in current sequence)",
+ request->number, request->proxy->id, home->num_received_pings);
+
+ /*
+ * Remove the request from any hashes
+ */
+ fr_event_delete(el, &request->ev);
+ remove_from_proxy_hash(request);
+
+ /*
+ * The control socket may have marked the home server as
+ * alive. OR, it may have suddenly started responding to
+ * requests again. If so, don't re-do the "make alive"
+ * work.
+ */
+ if (home->state == HOME_STATE_ALIVE) break;
+
+ /*
+ * It's dead, and we haven't received enough ping
+ * responses to mark it "alive". Wait a bit.
+ *
+ * If it's zombie, we mark it alive immediately.
+ */
+ if (HOME_SERVER_IS_DEAD(home) &&
+ (home->num_received_pings < home->num_pings_to_alive)) {
+ return;
+ }
+
+ /*
+ * Mark it alive and delete any outstanding
+ * pings.
+ */
+ mark_home_server_alive(request, home);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+
+ rad_assert(!request->in_request_hash);
+ rad_assert(!request->in_proxy_hash);
+ rad_assert(request->ev == NULL);
+ NO_CHILD_THREAD;
+ request_done(request, FR_ACTION_DONE);
+}
+
+/*
+ * Add +/- 2s of jitter, as suggested in RFC 3539
+ * and in RFC 5080.
+ */
+static void add_jitter(struct timeval *when)
+{
+ uint32_t jitter;
+
+ when->tv_sec -= 2;
+
+ jitter = fr_rand();
+ jitter ^= (jitter >> 10);
+ jitter &= ((1 << 22) - 1); /* 22 bits of 1 */
+
+ /*
+ * Add in ~ (4 * USEC) of jitter.
+ */
+ tv_add(when, jitter);
+}
+
+/*
+ * Called from start of zombie period, OR after control socket
+ * marks the home server dead.
+ */
+static void ping_home_server(void *ctx)
+{
+ home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
+ REQUEST *request;
+ VALUE_PAIR *vp;
+ struct timeval when, now;
+
+ if ((home->state == HOME_STATE_ALIVE) ||
+ (home->ev != NULL)) {
+ return;
+ }
+
+ gettimeofday(&now, NULL);
+ ASSERT_MASTER;
+
+ /*
+ * We've run out of zombie time. Mark it dead.
+ */
+ if (home->state == HOME_STATE_ZOMBIE) {
+ when = home->zombie_period_start;
+ when.tv_sec += home->zombie_period;
+
+ if (timercmp(&when, &now, <)) {
+ DEBUG("PING: Zombie period is over for home server %s", home->log_name);
+ mark_home_server_dead(home, &now, false);
+ }
+ }
+
+ /*
+ * We're not supposed to be pinging it. Just wake up
+ * when we're supposed to mark it dead.
+ */
+ if (home->ping_check == HOME_PING_CHECK_NONE) {
+ if (home->state == HOME_STATE_ZOMBIE) {
+ home->when = home->zombie_period_start;
+ home->when.tv_sec += home->zombie_period;
+ INSERT_EVENT(ping_home_server, home);
+ }
+
+ /*
+ * Else mark_home_server_dead will set a timer
+ * for revive_interval.
+ */
+ return;
+ }
+
+
+ request = request_alloc(NULL);
+ if (!request) return;
+ request->number = request_num_counter++;
+ NO_CHILD_THREAD;
+
+ request->proxy = rad_alloc(request, true);
+ request->root = &main_config;
+ rad_assert(request->proxy != NULL);
+
+ if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
+ request->proxy->code = PW_CODE_STATUS_SERVER;
+
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Message-Authenticator", "0x00", T_OP_SET);
+
+ } else if ((home->type == HOME_TYPE_AUTH) ||
+ (home->type == HOME_TYPE_AUTH_ACCT)) {
+ request->proxy->code = PW_CODE_ACCESS_REQUEST;
+
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "User-Name", home->ping_user_name, T_OP_SET);
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "User-Password", home->ping_user_password, T_OP_SET);
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Service-Type", "Authenticate-Only", T_OP_SET);
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Message-Authenticator", "0x00", T_OP_SET);
+
+#ifdef WITH_ACCOUNTING
+ } else if (home->type == HOME_TYPE_ACCT) {
+ request->proxy->code = PW_CODE_ACCOUNTING_REQUEST;
+
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "User-Name", home->ping_user_name, T_OP_SET);
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Acct-Status-Type", "Stop", T_OP_SET);
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Acct-Session-Id", "00000000", T_OP_SET);
+ vp = fr_pair_make(request->proxy, &request->proxy->vps,
+ "Event-Timestamp", "0", T_OP_SET);
+ vp->vp_date = now.tv_sec;
+#endif
+
+ } else {
+ /*
+ * Unkown home server type.
+ */
+ talloc_free(request);
+ return;
+ }
+
+ vp = fr_pair_make(request->proxy, &request->proxy->vps,
+ "NAS-Identifier", "", T_OP_SET);
+ if (vp) {
+ fr_pair_value_sprintf(vp, "Status Check %u. Are you alive?",
+ home->num_sent_pings);
+ }
+
+#ifdef WITH_TCP
+ request->proxy->proto = home->proto;
+#endif
+ request->proxy->src_ipaddr = home->src_ipaddr;
+ request->proxy->dst_ipaddr = home->ipaddr;
+ request->proxy->dst_port = home->port;
+ request->home_server = home;
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_DONE]);
+ if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_ping");
+#endif
+#ifdef HAVE_PTHREAD_H
+ rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
+#endif
+ request->child_state = REQUEST_PROXIED;
+ request->process = request_ping;
+
+ rad_assert(request->proxy_listener == NULL);
+
+ if (!insert_into_proxy_hash(request)) {
+ RPROXY("Failed to insert status check %d into proxy list. Discarding it.",
+ request->number);
+
+ rad_assert(!request->in_request_hash);
+ rad_assert(!request->in_proxy_hash);
+ rad_assert(request->ev == NULL);
+ talloc_free(request);
+ return;
+ }
+
+ /*
+ * Set up the timer callback.
+ */
+ when = now;
+ when.tv_sec += home->ping_timeout;
+
+ DEBUG("PING: Waiting %u seconds for response to ping",
+ home->ping_timeout);
+
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ home->num_sent_pings++;
+
+ rad_assert(request->proxy_listener != NULL);
+ request->proxy_listener->proxy_encode(request->proxy_listener, request);
+ debug_packet(request, request->proxy, false);
+ request->proxy_listener->proxy_send(request->proxy_listener,
+ request);
+
+ /*
+ * Add +/- 2s of jitter, as suggested in RFC 3539
+ * and in the Issues and Fixes draft.
+ */
+ home->when = now;
+ home->when.tv_sec += home->ping_interval;
+
+ add_jitter(&home->when);
+
+ DEBUG("PING: Next status packet in %u seconds", home->ping_interval);
+ INSERT_EVENT(ping_home_server, home);
+}
+
+static void home_trigger(home_server_t *home, char const *trigger)
+{
+ REQUEST *my_request;
+ RADIUS_PACKET *my_packet;
+
+ my_request = talloc_zero(NULL, REQUEST);
+ my_packet = talloc_zero(my_request, RADIUS_PACKET);
+ my_request->proxy = my_packet;
+ my_packet->dst_ipaddr = home->ipaddr;
+ my_packet->src_ipaddr = home->src_ipaddr;
+
+ exec_trigger(my_request, home->cs, trigger, false);
+ talloc_free(my_request);
+}
+
+static void mark_home_server_zombie(home_server_t *home, struct timeval *now, struct timeval *response_window)
+{
+ time_t start;
+ char buffer[128];
+
+ ASSERT_MASTER;
+
+ rad_assert((home->state == HOME_STATE_ALIVE) ||
+ (home->state == HOME_STATE_UNKNOWN));
+
+ /*
+ * We've received a real packet recently. Don't mark the
+ * server as zombie until we've received NO packets for a
+ * while. The "1/4" of zombie period was chosen rather
+ * arbitrarily. It's a balance between too short, which
+ * gives quick fail-over and fail-back, or too long,
+ * where the proxy still sends packets to an unresponsive
+ * home server.
+ */
+ start = now->tv_sec - ((home->zombie_period + 3) / 4);
+ if (home->last_packet_recv >= start) {
+ DEBUG("Received reply from home server %d seconds ago. Might not be zombie.",
+ (int) (now->tv_sec - home->last_packet_recv));
+ return;
+ }
+
+ home->state = HOME_STATE_ZOMBIE;
+ home_trigger(home, "home_server.zombie");
+
+ /*
+ * Set the home server to "zombie", as of the time
+ * calculated above.
+ */
+ home->zombie_period_start.tv_sec = start;
+ home->zombie_period_start.tv_usec = USEC / 2;
+
+ fr_event_delete(el, &home->ev);
+
+ home->num_sent_pings = 0;
+ home->num_received_pings = 0;
+
+ PROXY( "Marking home server %s port %d as zombie (it has not responded in %d.%06d seconds).",
+ inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ home->port, (int) response_window->tv_sec, (int) response_window->tv_usec);
+
+ ping_home_server(home);
+}
+
+
+void revive_home_server(void *ctx)
+{
+ home_server_t *home = talloc_get_type_abort(ctx, home_server_t);
+ char buffer[128];
+
+ home->state = HOME_STATE_ALIVE;
+ home->response_timeouts = 0;
+ home_trigger(home, "home_server.alive");
+ home->currently_outstanding = 0;
+ gettimeofday(&home->revive_time, NULL);
+
+ /*
+ * Delete any outstanding events.
+ */
+ ASSERT_MASTER;
+ if (home->ev) fr_event_delete(el, &home->ev);
+
+ PROXY( "Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
+ inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ home->port);
+}
+
+#ifdef WITH_TLS
+static int eol_home_listener(UNUSED void *ctx, void *data)
+{
+ rad_listen_t *this = talloc_get_type_abort(data, rad_listen_t);
+
+ /*
+ * The socket isn't blocked, we can still use it.
+ *
+ * i.e. the home server is dead for a reason OTHER than
+ * "all available sockets are blocked".
+ *
+ * We can still ping the home server via sockets which
+ * are writable.
+ */
+ if (!this->blocked) return 0;
+
+ this->status = RAD_LISTEN_STATUS_EOL;
+
+ FD_MUTEX_LOCK(&fd_mutex);
+ this->next = new_listeners;
+ new_listeners = this;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+
+ return 1; /* alway delete from this tree */
+}
+#endif
+
+void mark_home_server_dead(home_server_t *home, struct timeval *when, bool down)
+{
+ int previous_state = home->state;
+ char buffer[128];
+
+ PROXY( "Marking home server %s port %d as dead.",
+ inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ home->port);
+
+ home->state = HOME_STATE_IS_DEAD;
+ home_trigger(home, "home_server.dead");
+
+#ifdef WITH_TLS
+ /*
+ * If the home server is dead, then close all of the sockets associated with it.
+ *
+ * Note that the "EOL listener" code expects to _also_
+ * delete the listeners. At which point we end up with a
+ * mutex locked twice, and bad things happen. The
+ * solution is to move the listeners to the global
+ * "waiting for update" list, and then notify ourselves
+ * that there are listeners waiting to be updated.
+ */
+ if (home->listeners) {
+ ASSERT_MASTER;
+
+ rbtree_walk(home->listeners, RBTREE_DELETE_ORDER, eol_home_listener, NULL);
+ radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
+ }
+#endif
+
+ /*
+ * Administratively down - don't do anything to bring it
+ * up.
+ */
+ if (down) {
+ home->state = HOME_STATE_ADMIN_DOWN;
+ return;
+ }
+
+ /*
+ * Ping it if configured, AND we can ping it.
+ */
+ if ((home->ping_check != HOME_PING_CHECK_NONE) &&
+ (previous_state != HOME_STATE_CONNECTION_FAIL)) {
+ /*
+ * If the control socket marks us dead, start
+ * pinging. Otherwise, we already started
+ * pinging when it was marked "zombie".
+ */
+ if (previous_state == HOME_STATE_ALIVE) {
+ ping_home_server(home);
+ } else {
+ DEBUG("PING: Already pinging home server %s", home->log_name);
+ }
+
+ } else {
+ /*
+ * Revive it after a fixed period of time. This
+ * is very, very, bad.
+ */
+ home->when = *when;
+ home->when.tv_sec += home->revive_interval;
+
+ DEBUG("PING: Reviving home server %s in %u seconds", home->log_name, home->revive_interval);
+ ASSERT_MASTER;
+ INSERT_EVENT(revive_home_server, home);
+ }
+}
+
+/** Wait for a reply after proxying a request.
+ *
+ * Retransmit the proxied packet, or time out and go to
+ * proxy_no_reply. Mark the home server unresponsive, etc.
+ *
+ * If we do receive a reply, we transition to proxy_running.
+ *
+ * \dot
+ * digraph proxy_wait_for_reply {
+ * proxy_wait_for_reply;
+ *
+ * proxy_wait_for_reply -> retransmit_proxied_request [ label = "DUP", arrowhead = "none" ];
+ * proxy_wait_for_reply -> proxy_no_reply [ label = "TIMER >= response_window" ];
+ * proxy_wait_for_reply -> timer [ label = "TIMER < max_request_time" ];
+ * proxy_wait_for_reply -> proxy_running [ label = "PROXY_REPLY" arrowhead = "none"];
+ * proxy_wait_for_reply -> done [ label = "TIMER >= max_request_time" ];
+ * }
+ * \enddot
+ */
+static void proxy_wait_for_reply(REQUEST *request, int action)
+{
+ struct timeval now, when;
+ struct timeval *response_window = NULL;
+ home_server_t *home = request->home_server;
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ rad_assert(request->packet->code != PW_CODE_STATUS_SERVER);
+ rad_assert(request->home_server != NULL);
+
+ gettimeofday(&now, NULL);
+
+ switch (action) {
+ case FR_ACTION_DUP:
+ /*
+ * The request was proxied to a virtual server.
+ * Ignore the retransmit.
+ */
+ if (request->home_server->virtual_server) return;
+
+ /*
+ * Failed connections get the home server marked
+ * as dead.
+ */
+ if (home->state == HOME_STATE_CONNECTION_FAIL) {
+ mark_home_server_dead(home, &now, false);
+ }
+
+ /*
+ * We have a reply, ignore the retransmit.
+ */
+ if (request->proxy_reply) return;
+
+ /*
+ * Use a new connection when the home server is
+ * dead, or when there's no proxy listener, or
+ * when the listener is failed or dead.
+ *
+ * If the listener is known or frozen, use it for
+ * retransmits.
+ */
+ if (HOME_SERVER_IS_DEAD(home) ||
+ !request->proxy_listener ||
+ (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) {
+ request_proxy_anew(request);
+ return;
+ }
+
+#ifdef WITH_TCP
+ /*
+ * The home server is still alive, but TCP. We
+ * rely on TCP to get the request and reply back.
+ * So there's no need to retransmit.
+ */
+ if (home->proto == IPPROTO_TCP) {
+ DEBUG2("Suppressing duplicate proxied request (tcp) to home server %s port %d proto TCP - ID: %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ request->proxy->id);
+ return;
+ }
+#endif
+
+ /*
+ * More than one retransmit a second is stupid,
+ * and should be suppressed by the proxy.
+ */
+ when = request->proxy->timestamp;
+ when.tv_sec++;
+
+ if (timercmp(&now, &when, <)) {
+ DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d proto TCP - ID: %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ request->proxy->id);
+ return;
+ }
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * If we update the Acct-Delay-Time, we need to
+ * get a new ID.
+ */
+ if ((request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
+ fr_pair_find_by_num(request->proxy->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY)) {
+ request_proxy_anew(request);
+ return;
+ }
+#endif
+
+ RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ request->proxy->id);
+ request->num_proxied_requests++;
+
+ rad_assert(request->proxy_listener != NULL);
+ FR_STATS_TYPE_INC(home->stats.total_requests);
+ home->last_packet_sent = now.tv_sec;
+ request->proxy->timestamp = now;
+ debug_packet(request, request->proxy, false);
+ request->proxy_listener->proxy_send(request->proxy_listener, request);
+ break;
+
+ case FR_ACTION_TIMER:
+ /*
+ * Failed connections get the home server marked
+ * as dead.
+ */
+ if (home->state == HOME_STATE_CONNECTION_FAIL) {
+ mark_home_server_dead(home, &now, false);
+ }
+
+ response_window = request_response_window(request);
+
+#ifdef WITH_TCP
+ if (!request->proxy_listener ||
+ (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) {
+ remove_from_proxy_hash(request);
+
+ when = request->packet->timestamp;
+ when.tv_sec += request->root->max_request_time;
+
+ if (timercmp(&when, &now, >)) {
+ RDEBUG("Waiting for client retransmission in order to do a proxy retransmit");
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+ } else
+#endif
+ {
+ /*
+ * Wake up "response_window" time in the future.
+ * i.e. when MY packet hasn't received a response.
+ *
+ * Note that we DO NOT mark the home server as
+ * zombie if it doesn't respond to us. It may be
+ * responding to other (better looking) packets.
+ */
+ when = request->proxy->timestamp;
+ timeradd(&when, response_window, &when);
+
+ /*
+ * Not at the response window. Set the timer for
+ * that.
+ */
+ if (timercmp(&when, &now, >)) {
+ struct timeval diff;
+ timersub(&when, &now, &diff);
+
+ RDEBUG("Expecting proxy response no later than %d.%06d seconds from now",
+ (int) diff.tv_sec, (int) diff.tv_usec);
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+ }
+
+ RDEBUG("No proxy response, giving up on request and marking it done");
+
+ /*
+ * If we haven't received any packets for
+ * "response_window", then mark the home server
+ * as zombie.
+ *
+ * This check should really be part of a home
+ * server state machine.
+ */
+ if ((home->state == HOME_STATE_ALIVE) ||
+ (home->state == HOME_STATE_UNKNOWN)) {
+ home->response_timeouts++;
+ if (home->response_timeouts >= home->max_response_timeouts)
+ mark_home_server_zombie(home, &now, response_window);
+ }
+
+ FR_STATS_TYPE_INC(home->stats.total_timeouts);
+ if (home->type == HOME_TYPE_AUTH) {
+ if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
+ FR_STATS_TYPE_INC(proxy_auth_stats.total_timeouts);
+ }
+#ifdef WITH_ACCT
+ else if (home->type == HOME_TYPE_ACCT) {
+ if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
+ FR_STATS_TYPE_INC(proxy_acct_stats.total_timeouts);
+ }
+#endif
+#ifdef WITH_COA
+ else if (home->type == HOME_TYPE_COA) {
+ if (request->proxy_listener) FR_STATS_TYPE_INC(request->proxy_listener->stats.total_timeouts);
+
+ if (request->packet->code == PW_CODE_COA_REQUEST) {
+ FR_STATS_TYPE_INC(proxy_coa_stats.total_timeouts);
+ } else {
+ FR_STATS_TYPE_INC(proxy_dsc_stats.total_timeouts);
+ }
+ }
+#endif
+
+ /*
+ * There was no response within the window. Stop
+ * the request. If the client retransmitted, it
+ * may have failed over to another home server.
+ * But that one may be dead, too.
+ *
+ * The extra verbose message if we have a username,
+ * is extremely useful if the proxy is part of a chain
+ * and the final home server, is not the one we're
+ * proxying to.
+ */
+ if (request->username) {
+ RERROR("Failing proxied request for user \"%s\", due to lack of any response from home "
+ "server %s port %d",
+ request->username->vp_strvalue,
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+ } else {
+ RERROR("Failing proxied request, due to lack of any response from home server %s port %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+ }
+
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, proxy_no_reply);
+ } else {
+ gettimeofday(&request->reply->timestamp, NULL);
+ request_cleanup_delay_init(request);
+ }
+ break;
+
+ /*
+ * We received a new reply. Go process it.
+ */
+ case FR_ACTION_PROXY_REPLY:
+ request_queue_or_run(request, proxy_running);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+#endif /* WITH_PROXY */
+
+
+/***********************************************************************
+ *
+ * CoA code
+ *
+ ***********************************************************************/
+#ifdef WITH_COA
+/*
+ * See if we need to originate a CoA request.
+ */
+static void request_coa_originate(REQUEST *request)
+{
+ int rcode, pre_proxy_type = 0;
+ VALUE_PAIR *vp;
+ REQUEST *coa;
+ fr_ipaddr_t ipaddr;
+ char const *old_server;
+ char buffer[256];
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(request->coa != NULL);
+ rad_assert(request->proxy == NULL);
+ rad_assert(!request->in_proxy_hash);
+ rad_assert(request->proxy_reply == NULL);
+
+ /*
+ * Check whether we want to originate one, or cancel one.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_SEND_COA_REQUEST, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_find_by_num(request->coa->proxy->vps, PW_SEND_COA_REQUEST, 0, TAG_ANY);
+ }
+
+ if (vp) {
+ if (vp->vp_integer == 0) {
+ fail:
+ TALLOC_FREE(request->coa);
+ return;
+ }
+ }
+
+ if (!main_config.proxy_requests) {
+ RWDEBUG("Cannot originate CoA packets unless 'proxy_requests = yes'");
+ TALLOC_FREE(request->coa);
+ return;
+ }
+
+ coa = request->coa;
+ coa->listener = NULL; /* copied here by request_alloc_fake(), but not needed */
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Proxy-To-Originating-Realm is preferred to any other
+ * method of originating CoA requests.
+ */
+ vp = fr_pair_find_by_num(coa->proxy->vps, PW_PROXY_TO_ORIGINATING_REALM, 0, TAG_ANY);
+ if (vp) {
+ /*
+ * This function will set request->home_server,
+ * and also request->proxy_listener.
+ */
+ if (listen_coa_find(coa, vp->vp_strvalue) < 0) {
+ RWDEBUG("Unknown Originating realm '%s'", vp->vp_strvalue);
+ return;
+ }
+
+ goto set_packet_type;
+ }
+#endif
+
+ /*
+ * src_ipaddr will be set up in proxy_encode.
+ */
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ vp = fr_pair_find_by_num(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ ipaddr.af = AF_INET;
+ ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ ipaddr.prefix = 32;
+ } else if ((vp = fr_pair_find_by_num(coa->proxy->vps, PW_PACKET_DST_IPV6_ADDRESS, 0, TAG_ANY)) != NULL) {
+ ipaddr.af = AF_INET6;
+ ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ ipaddr.prefix = 128;
+ } else if ((vp = fr_pair_find_by_num(coa->proxy->vps, PW_HOME_SERVER_POOL, 0, TAG_ANY)) != NULL) {
+ coa->home_pool = home_pool_byname(vp->vp_strvalue,
+ HOME_TYPE_COA);
+ if (!coa->home_pool) {
+ RWDEBUG2("No such home_server_pool %s",
+ vp->vp_strvalue);
+ goto fail;
+ }
+
+ /*
+ * Prefer the pool to one server
+ */
+ } else if (request->client->coa_home_pool) {
+ coa->home_pool = request->client->coa_home_pool;
+
+ } else if (request->client->coa_home_server) {
+ coa->home_server = request->client->coa_home_server;
+
+ } else {
+ /*
+ * If all else fails, send it to the client that
+ * originated this request.
+ */
+ memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
+ }
+
+ /*
+ * Use the pool, if it exists.
+ */
+ if (coa->home_pool) {
+ coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
+ if (!coa->home_server) {
+ RWDEBUG("No live home server for home_server_pool %s", coa->home_pool->name);
+ goto fail;
+ }
+ home_server_update_request(coa->home_server, coa);
+
+ } else if (!coa->home_server) {
+ uint16_t port = PW_COA_UDP_PORT;
+
+ vp = fr_pair_find_by_num(coa->proxy->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
+ if (vp) port = vp->vp_integer;
+
+ coa->home_server = home_server_find(&ipaddr, port, IPPROTO_UDP);
+ if (!coa->home_server) {
+ RWDEBUG2("Unknown destination %s:%d for CoA request.",
+ inet_ntop(ipaddr.af, &ipaddr.ipaddr,
+ buffer, sizeof(buffer)), port);
+ goto fail;
+ }
+ }
+
+#ifdef WITH_COA_TUNNEL
+set_packet_type:
+#endif
+ vp = fr_pair_find_by_num(coa->proxy->vps, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (vp) {
+ switch (vp->vp_integer) {
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ coa->proxy->code = vp->vp_integer;
+ break;
+
+ default:
+ DEBUG("Cannot set CoA Packet-Type to code %d",
+ vp->vp_integer);
+ goto fail;
+ }
+ }
+
+ if (!coa->proxy->code) coa->proxy->code = PW_CODE_COA_REQUEST;
+
+ /*
+ * The rest of the server code assumes that
+ * request->packet && request->reply exist. Copy them
+ * from the original request.
+ */
+ rad_assert(coa->packet != NULL);
+ rad_assert(coa->packet->vps == NULL);
+
+ coa->packet = rad_copy_packet(coa, request->packet);
+ coa->reply = rad_copy_packet(coa, request->reply);
+
+ coa->config = fr_pair_list_copy(coa, request->config);
+ coa->num_coa_requests = 0;
+ coa->number = request->number; /* it's associated with the same request */
+
+ /*
+ * Call the pre-proxy routines.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_PRE_PROXY_TYPE, 0, TAG_ANY);
+ if (vp) {
+ DICT_VALUE const *dval = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
+ /* Must be a validation issue */
+ rad_assert(dval);
+ RDEBUG2("Found Pre-Proxy-Type %s", dval->name);
+ pre_proxy_type = vp->vp_integer;
+ }
+
+ /*
+ * Run the request through the virtual server for the
+ * home server, OR through the virtual server for the
+ * home server pool.
+ */
+ old_server = request->server;
+ if (coa->home_server && coa->home_server->virtual_server) {
+ coa->server = coa->home_server->virtual_server;
+
+#ifdef WITH_COA_TUNNEL
+ } else if (coa->proxy_listener && (coa->proxy_listener->type != RAD_LISTEN_PROXY)) {
+ rad_assert((coa->proxy->code == PW_CODE_COA_REQUEST) ||
+ (coa->proxy->code == PW_CODE_DISCONNECT_REQUEST));
+ rad_assert(coa->home_server != NULL);
+ rad_assert(coa->home_server->recv_coa_server != NULL);
+ coa->server = coa->home_server->recv_coa_server;
+#endif
+
+ } else if (coa->home_pool && coa->home_pool->virtual_server) {
+ coa->server = coa->home_pool->virtual_server;
+ }
+
+ RDEBUG2("server %s {", coa->server);
+ RINDENT();
+ rcode = process_pre_proxy(pre_proxy_type, coa);
+ REXDENT();
+ RDEBUG2("}");
+ coa->server = old_server;
+
+ switch (rcode) {
+ default:
+ goto fail;
+
+ /*
+ * Only send the CoA packet if the pre-proxy code succeeded.
+ */
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ break;
+ }
+
+ /*
+ * Source IP / port is set when the proxy socket
+ * is chosen.
+ */
+ coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
+ coa->proxy->dst_port = coa->home_server->port;
+
+ if (!insert_into_proxy_hash(coa)) {
+ radlog_request(L_PROXY, 0, coa, "Failed to insert CoA request into proxy list");
+ goto fail;
+ }
+
+ /*
+ * We CANNOT divorce the CoA request from the parent
+ * request. This function is running in a child thread,
+ * and we need access to the main event loop in order to
+ * to add the timers for the CoA packet.
+ *
+ * Instead, we wait for the timer on the parent request
+ * to fire.
+ */
+ gettimeofday(&coa->proxy->timestamp, NULL);
+ coa->packet->timestamp = coa->proxy->timestamp; /* for max_request_time */
+ coa->home_server->last_packet_sent = coa->proxy->timestamp.tv_sec;
+ coa->delay = 0; /* need to calculate a new delay */
+
+ /*
+ * If requested, put a State attribute into the packet,
+ * and cache the VPS.
+ */
+ fr_state_put_vps(coa, NULL, coa->packet);
+
+ /*
+ * Encode the packet before we do anything else.
+ */
+ coa->proxy_listener->proxy_encode(coa->proxy_listener, coa);
+ debug_packet(coa, coa->proxy, false);
+
+#ifdef DEBUG_STATE_MACHINE
+ if (rad_debug_lvl) printf("(%u) ********\tSTATE %s C-%s -> C-%s\t********\n", request->number, __FUNCTION__,
+ child_state_names[request->child_state],
+ child_state_names[REQUEST_PROXIED]);
+#endif
+
+ /*
+ * Set the state function, then the state, no child, and
+ * send the packet.
+ */
+ coa->process = coa_wait_for_reply;
+ coa->child_state = REQUEST_PROXIED;
+
+#ifdef HAVE_PTHREAD_H
+ coa->child_pid = NO_SUCH_CHILD_PID;
+#endif
+
+ if (we_are_master()) coa_separate(request->coa, true);
+
+ /*
+ * And send the packet.
+ */
+ coa->proxy_listener->proxy_send(coa->proxy_listener, coa);
+}
+
+
+static void coa_retransmit(REQUEST *request)
+{
+ uint32_t delay, frac;
+ struct timeval now, when, mrd;
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ /*
+ * Don't do fail-over. This is a 3.1 feature.
+ */
+ if (!request->home_server ||
+ HOME_SERVER_IS_DEAD(request->home_server) ||
+ request->proxy_reply ||
+ !request->proxy_listener ||
+ (request->proxy_listener->status >= RAD_LISTEN_STATUS_EOL)) {
+ request_done(request, FR_ACTION_COA_CANCELLED);
+ return;
+ }
+
+ fr_event_now(el, &now);
+
+ /*
+ * Home server has gone away. The request is done.
+ */
+ if (!request->home_server) {
+ RDEBUG("No home server for CoA packet. Failing it.");
+ goto fail;
+ }
+
+ if (request->delay == 0) {
+ /*
+ * Implement re-transmit algorithm as per RFC 5080
+ * Section 2.2.1.
+ *
+ * We want IRT + RAND*IRT
+ * or 0.9 IRT + rand(0,.2) IRT
+ *
+ * 2^20 ~ USEC, and we want 2.
+ * rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
+ */
+ delay = (fr_rand() & ((1 << 22) - 1)) / 10;
+ request->delay = delay * request->home_server->coa_irt;
+ delay = request->home_server->coa_irt * USEC;
+ delay -= delay / 10;
+ delay += request->delay;
+ request->delay = delay;
+
+ when = request->proxy->timestamp;
+ tv_add(&when, delay);
+
+ if (timercmp(&when, &now, >)) {
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return;
+ }
+ }
+
+ /*
+ * Retransmit CoA request.
+ */
+
+ /*
+ * Cap count at MRC, if it is non-zero.
+ */
+ if (request->home_server->coa_mrc &&
+ (request->num_coa_requests >= request->home_server->coa_mrc)) {
+ RERROR("Failing request - originate-coa ID %u, due to lack of any response from coa server %s port %d",
+ request->proxy->id,
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port);
+
+ fail:
+ if (setup_post_proxy_fail(request)) {
+ request_queue_or_run(request, coa_no_reply);
+ } else {
+ request_done(request, FR_ACTION_DONE);
+ }
+ return;
+ }
+
+ /*
+ * RFC 5080 Section 2.2.1
+ *
+ * RT = 2*RTprev + RAND*RTprev
+ * = 1.9 * RTprev + rand(0,.2) * RTprev
+ * = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
+ */
+ delay = fr_rand();
+ delay ^= (delay >> 16);
+ delay &= 0xffff;
+ frac = request->delay / 5;
+ delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
+
+ delay += (2 * request->delay) - (request->delay / 10);
+
+ /*
+ * Cap delay at MRT, if MRT is non-zero.
+ */
+ if (request->home_server->coa_mrt &&
+ (delay > (request->home_server->coa_mrt * USEC))) {
+ int mrt_usec = request->home_server->coa_mrt * USEC;
+
+ /*
+ * delay = MRT + RAND * MRT
+ * = 0.9 MRT + rand(0,.2) * MRT
+ */
+ delay = fr_rand();
+ delay ^= (delay >> 15);
+ delay &= 0x1ffff;
+ delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
+ delay += mrt_usec - (mrt_usec / 10);
+ }
+
+ request->delay = delay;
+ when = now;
+ tv_add(&when, request->delay);
+ mrd = request->proxy->timestamp;
+ mrd.tv_sec += request->home_server->coa_mrd;
+
+ /*
+ * Cap duration at MRD.
+ */
+ if (timercmp(&mrd, &when, <)) {
+ when = mrd;
+ }
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+
+ request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
+
+ FR_STATS_TYPE_INC(request->home_server->stats.total_requests);
+
+ RDEBUG2("Sending duplicate CoA request to home server %s port %d - ID: %d",
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ request->proxy->id);
+
+ request->proxy_listener->proxy_send(request->proxy_listener,
+ request);
+}
+
+
+/*
+ * Enforce maximum time for CoA packets
+ */
+static bool coa_max_time(REQUEST *request)
+{
+ struct timeval now, when;
+ rad_assert(request->magic == REQUEST_MAGIC);
+#ifdef DEBUG_STATE_MACHINE
+ int action = FR_ACTION_TIMER;
+#endif
+ int mrd;
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+
+ /*
+ * The child thread has acknowledged it's done.
+ * Transition to the DONE state.
+ *
+ * If the request was marked STOP, then the "check for
+ * stop" macro already took care of it.
+ */
+ if (request->child_state == REQUEST_DONE) {
+ done:
+ request->max_time = true;
+ request_done(request, FR_ACTION_MAX_TIME);
+ return true;
+ }
+
+ /*
+ * The request is still running. Enforce max_request_time.
+ *
+ * Note that the *proxy* timestamp is the one we use, as
+ * that's when the CoA packet was sent.
+ *
+ * Note also that if there's an error, the home server
+ * may not exist.
+ */
+ fr_event_now(el, &now);
+ when = request->proxy->timestamp;
+ if (request->home_server && (request->process != coa_running)) {
+ mrd = request->home_server->coa_mrd;
+ } else {
+ mrd = request->root->max_request_time;
+ }
+ when.tv_sec += mrd;
+
+ /*
+ * Taking too long: tell it to die.
+ */
+ if (timercmp(&now, &when, >=)) {
+ char buffer[256];
+
+ if (request->process != coa_running) {
+ RERROR("Failing request - originate-coa ID %u, due to lack of any response from coa server %s port %d within %d seconds",
+ request->proxy->id,
+ inet_ntop(request->proxy->dst_ipaddr.af,
+ &request->proxy->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port,
+ mrd);
+ request_done(request, FR_ACTION_DONE);
+ return true;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * If there's a child thread processing it,
+ * complain.
+ */
+ if (spawn_flag &&
+ (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
+ RERROR("Unresponsive child for originate-coa, in component %s module %s",
+ request->component ? request->component : "<core>",
+ request->module ? request->module : "<core>");
+ exec_trigger(request, NULL, "server.thread.unresponsive", true);
+ } else
+#endif
+ {
+ RERROR("originate-coa hit max_request_time. Cancelling it.");
+ }
+
+ /*
+ * Tell the request that it's done.
+ */
+ goto done;
+ }
+
+ /*
+ * Let coa_retransmit() handle the retransmission timers.
+ */
+ if (request->process != coa_running) return false;
+
+ /*
+ * Sleep for some more. We HOPE that the child will
+ * become responsive at some point in the future. We do
+ * this by adding 50% to the current timer.
+ */
+ when = now;
+ tv_add(&when, request->delay);
+ request->delay += request->delay >> 1;
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+ return false;
+}
+
+
+/** Wait for a reply after originating a CoA a request.
+ *
+ * Retransmit the proxied packet, or time out and go to
+ * coa_no_reply. Mark the home server unresponsive, etc.
+ *
+ * If we do receive a reply, we transition to coa_running.
+ *
+ * \dot
+ * digraph coa_wait_for_reply {
+ * coa_wait_for_reply;
+ *
+ * coa_wait_for_reply -> coa_no_reply [ label = "TIMER >= response_window" ];
+ * coa_wait_for_reply -> timer [ label = "TIMER < max_request_time" ];
+ * coa_wait_for_reply -> coa_running [ label = "PROXY_REPLY" arrowhead = "none"];
+ * coa_wait_for_reply -> done [ label = "TIMER >= max_request_time" ];
+ * }
+ * \enddot
+ */
+static void coa_wait_for_reply(REQUEST *request, int action)
+{
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+ CHECK_FOR_STOP;
+
+ if (request->parent) coa_separate(request, false);
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ if (coa_max_time(request)) break;
+
+ coa_retransmit(request);
+ break;
+
+ case FR_ACTION_PROXY_REPLY:
+ /*
+ * Reset the initial delay for checking if we
+ * should still run.
+ */
+ request->delay = (int)request->root->init_delay.tv_sec * USEC +
+ (int)request->root->init_delay.tv_usec;
+
+ request_queue_or_run(request, coa_running);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+static void coa_separate(REQUEST *request, bool retransmit)
+{
+ VERIFY_REQUEST(request);
+#ifdef DEBUG_STATE_MACHINE
+ int action = FR_ACTION_TIMER;
+#endif
+
+ TRACE_STATE_MACHINE;
+ ASSERT_MASTER;
+
+ rad_assert(request->parent != NULL);
+ rad_assert(request->parent->coa == request);
+ rad_assert(request->ev == NULL);
+ rad_assert(!request->in_request_hash);
+ rad_assert(request->coa == NULL);
+
+ (void) talloc_steal(NULL, request);
+ request->parent->coa = NULL;
+ request->parent = NULL;
+
+ if (retransmit && (request->delay == 0) && !request->proxy_reply) {
+ coa_retransmit(request);
+ }
+}
+
+
+/** Process a request after the CoA has timed out.
+ *
+ * Run the packet through Post-Proxy-Type Fail
+ *
+ * \dot
+ * digraph coa_no_reply {
+ * coa_no_reply;
+ *
+ * coa_no_reply -> dup [ label = "DUP", arrowhead = "none" ];
+ * coa_no_reply -> timer [ label = "TIMER < max_request_time" ];
+ * coa_no_reply -> coa_reply_too_late [ label = "PROXY_REPLY" arrowhead = "none"];
+ * coa_no_reply -> process_proxy_reply [ label = "RUN" ];
+ * coa_no_reply -> done [ label = "TIMER >= timeout" ];
+ * }
+ * \enddot
+ */
+static void coa_no_reply(REQUEST *request, int action)
+{
+ char buffer[128];
+
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ (void) coa_max_time(request);
+ break;
+
+ case FR_ACTION_PROXY_REPLY: /* too late! */
+ RDEBUG2("Reply from CoA server %s port %d - ID: %d arrived too late.",
+ inet_ntop(request->proxy->src_ipaddr.af,
+ &request->proxy->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ request->proxy->dst_port, request->proxy->id);
+ break;
+
+ case FR_ACTION_RUN:
+ if (process_proxy_reply(request, NULL)) {
+ request->handle(request);
+ }
+ request_done(request, FR_ACTION_DONE);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+
+
+/** Process the request after receiving a coa reply.
+ *
+ * Throught the post-proxy section, and the through the handler
+ * function.
+ *
+ * \dot
+ * digraph coa_running {
+ * coa_running;
+ *
+ * coa_running -> timer [ label = "TIMER < max_request_time" ];
+ * coa_running -> process_proxy_reply [ label = "RUN" ];
+ * coa_running -> done [ label = "TIMER >= timeout" ];
+ * }
+ * \enddot
+ */
+static void coa_running(REQUEST *request, int action)
+{
+ VERIFY_REQUEST(request);
+
+ TRACE_STATE_MACHINE;
+ CHECK_FOR_STOP;
+
+ switch (action) {
+ case FR_ACTION_TIMER:
+ (void) coa_max_time(request);
+ break;
+
+ case FR_ACTION_RUN:
+ if (process_proxy_reply(request, request->proxy_reply)) {
+ request->handle(request);
+ }
+ request_done(request, FR_ACTION_DONE);
+ break;
+
+ default:
+ RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]);
+ break;
+ }
+}
+#endif /* WITH_COA */
+
+/***********************************************************************
+ *
+ * End of the State machine. Start of additional helper code.
+ *
+ ***********************************************************************/
+
+/***********************************************************************
+ *
+ * Event handlers.
+ *
+ ***********************************************************************/
+static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, void *ctx)
+{
+ rad_listen_t *listener = talloc_get_type_abort(ctx, rad_listen_t);
+
+ rad_assert(xel == el);
+
+ if ((listener->fd < 0)
+#ifdef WITH_DETAIL
+#ifndef WITH_DETAIL_THREAD
+ && (listener->type != RAD_LISTEN_DETAIL)
+#endif
+#endif
+ ) {
+ char buffer[256];
+
+ listener->print(listener, buffer, sizeof(buffer));
+ ERROR("FATAL: Asked to read from closed socket: %s",
+ buffer);
+
+ rad_panic("Socket was closed on us!");
+ fr_exit_now(1);
+ }
+
+ listener->recv(listener);
+}
+
+#ifdef WITH_DETAIL
+#ifdef WITH_DETAIL_THREAD
+#else
+/*
+ * This function is called periodically to see if this detail
+ * file is available for reading.
+ */
+static void event_poll_detail(void *ctx)
+{
+ int delay;
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
+ struct timeval when, now;
+ listen_detail_t *detail = this->data;
+
+ rad_assert(this->type == RAD_LISTEN_DETAIL);
+
+ redo:
+ event_socket_handler(el, this->fd, this);
+
+ fr_event_now(el, &now);
+ when = now;
+
+ /*
+ * Backdoor API to get the delay until the next poll
+ * time.
+ */
+ delay = this->encode(this, NULL);
+ if (delay == 0) goto redo;
+
+ tv_add(&when, delay);
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el, event_poll_detail, this,
+ &when, &detail->ev)) {
+ ERROR("Failed creating handler");
+ fr_exit(1);
+ }
+}
+#endif /* WITH_DETAIL_THREAD */
+#endif /* WITH_DETAIL */
+
+static void event_status(struct timeval *wake)
+{
+ if (rad_debug_lvl == 0) {
+ if (just_started) {
+ INFO("Ready to process requests");
+ just_started = false;
+ }
+ return;
+ }
+
+ if (!wake) {
+ INFO("Ready to process requests");
+
+ } else if ((wake->tv_sec != 0) ||
+ (wake->tv_usec >= 100000)) {
+ DEBUG("Waking up in %d.%01u seconds.",
+ (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
+ }
+
+
+ /*
+ * FIXME: Put this somewhere else, where it isn't called
+ * all of the time...
+ */
+
+ if (!spawn_flag) {
+ int argval;
+
+ /*
+ * If there are no child threads, then there may
+ * be child processes. In that case, wait for
+ * their exit status, and throw that exit status
+ * away. This helps get rid of zxombie children.
+ */
+ while (waitpid(-1, &argval, WNOHANG) > 0) {
+ /* do nothing */
+ }
+ }
+}
+
+static void listener_free_cb(void *ctx)
+{
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
+ listen_socket_t *sock = this->data;
+ char buffer[1024];
+
+ if (this->count > 0) {
+ struct timeval when;
+
+ fr_event_now(el, &when);
+ when.tv_sec += 3;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el, listener_free_cb, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
+
+ return;
+ }
+
+ /*
+ * It's all free, close the socket.
+ */
+
+ this->print(this, buffer, sizeof(buffer));
+ DEBUG("... cleaning up socket %s", buffer);
+ rad_assert(this->next == NULL);
+#ifdef WITH_TCP
+ fr_event_delete(el, &sock->ev);
+#endif
+ talloc_free(this);
+}
+
+#ifdef WITH_TCP
+#ifdef WITH_PROXY
+static int proxy_eol_cb(void *ctx, void *data)
+{
+ struct timeval when;
+ REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
+
+ if (request->proxy_listener != ctx) return 0;
+
+ /*
+ * We don't care if it's being processed in a child thread.
+ */
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Accounting packets should be deleted immediately.
+ * They will never be retransmitted by the client.
+ */
+ if (request->proxy->code == PW_CODE_ACCOUNTING_REQUEST) {
+ RDEBUG("Stopping request due to failed connection to home server");
+ request->master_state = REQUEST_STOP_PROCESSING;
+ }
+#endif
+
+ /*
+ * Reset the timer to be now, so that the request is
+ * quickly updated. But spread the requests randomly
+ * over the next second, so that we don't overload the
+ * server.
+ */
+ fr_event_now(el, &when);
+ tv_add(&when, fr_rand() % USEC);
+ STATE_MACHINE_TIMER(FR_ACTION_TIMER);
+
+ /*
+ * Don't delete it from the list.
+ */
+ return 0;
+}
+#endif /* WITH_PROXY */
+#endif /* WITH_TCP */
+
+static void event_new_fd(rad_listen_t *this)
+{
+ char buffer[1024];
+ listen_socket_t *sock = NULL;
+
+ ASSERT_MASTER;
+
+ if (this->status == RAD_LISTEN_STATUS_KNOWN) return;
+
+ this->print(this, buffer, sizeof(buffer));
+
+ if (this->type != RAD_LISTEN_DETAIL) {
+ sock = this->data;
+ rad_assert(sock != NULL);
+ }
+
+ if (this->status == RAD_LISTEN_STATUS_INIT) {
+ if (just_started) {
+ DEBUG("Listening on %s", buffer);
+
+#ifdef WITH_PROXY
+ } else if (this->type == RAD_LISTEN_PROXY) {
+ home_server_t *home = sock->home;
+
+ if (home && home->limit.max_connections) {
+ INFO(" ... adding new socket %s (%u of %u)", buffer,
+ home->limit.num_connections, home->limit.max_connections);
+ } else {
+ INFO(" ... adding new socket %s", buffer);
+ }
+#endif
+ } else {
+ INFO(" ... adding new socket %s", buffer);
+ }
+
+ switch (this->type) {
+#ifdef WITH_DETAIL
+ /*
+ * Detail files are always known, and aren't
+ * put into the socket event loop.
+ */
+ case RAD_LISTEN_DETAIL:
+ this->status = RAD_LISTEN_STATUS_KNOWN;
+
+#ifndef WITH_DETAIL_THREAD
+ /*
+ * Set up the first poll interval.
+ */
+ event_poll_detail(this);
+ return;
+#else
+ break; /* add the FD to the list */
+#endif
+#endif /* WITH_DETAIL */
+
+#ifdef WITH_PROXY
+ /*
+ * Add it to the list of sockets we can use.
+ * Server sockets (i.e. auth/acct) are never
+ * added to the packet list.
+ */
+ case RAD_LISTEN_PROXY:
+#ifdef WITH_TCP
+ rad_assert(sock != NULL);
+ rad_assert((sock->proto == IPPROTO_UDP) || (sock->home != NULL));
+
+ /*
+ * Add timers to outgoing child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->home->limit.lifetime || sock->home->limit.idle_timeout)) {
+ struct timeval when;
+
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
+ }
+
+ /*
+ * Run a callback to do any specific
+ * signalling on "connection up".
+ *
+ * For TLS sockets and WITH_COA_TUNNEL,
+ * this function should be similar to
+ * ping_home_server(), except that it
+ * should send a Status-Server packet,
+ * with Originating-Realm-Key as a VSA.
+ */
+// process_listener_up(this);
+
+#endif /* WITH_TCP */
+ break;
+#endif /* WITH_PROXY */
+
+ /*
+ * FIXME: put idle timers on command sockets.
+ */
+
+ default:
+#ifdef WITH_TCP
+ /*
+ * Add timers to incoming child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->limit.lifetime || sock->limit.idle_timeout)) {
+ struct timeval when;
+
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ ERROR("Failed adding timer for socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+ }
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * If we're allowed to send CoA requests
+ * back down this incoming socket, then
+ * add the socket to the proxy listener
+ * list. We need to check for "parent",
+ * as the main incoming listener has
+ * "send_coa" set, but it just calls
+ * accept(), and doesn't actually send
+ * any packets.
+ */
+ if (this->send_coa && this->parent) {
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_add(proxy_list, this->fd,
+ sock->proto,
+#ifdef WITH_RADIUSV11
+ sock->radiusv11,
+#endif
+ &sock->other_ipaddr, sock->other_port,
+ this)) {
+ ERROR("Failed adding coa proxy socket");
+ fr_exit_now(1);
+ }
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ }
+#endif /* WITH_COA_TUNNEL */
+
+#endif /* WITH_TCP */
+ break;
+ } /* switch over listener types */
+
+ /*
+ * All sockets: add the FD to the event handler.
+ */
+ insert_fd:
+ if (fr_event_fd_insert(el, 0, this->fd,
+ event_socket_handler, this)) {
+ this->status = RAD_LISTEN_STATUS_KNOWN;
+ return;
+ }
+
+ /*
+ * Print out which socket failed.
+ *
+ * If we're trying to add the socket, then
+ * forcibly remove it immediately, without any
+ * additional cleanups. There cannot, and MUST
+ * NOT be any packets associated with the socket.
+ */
+ this->print(this, buffer, sizeof(buffer));
+ ERROR("Failed adding event handler for socket %s: %s", buffer, fr_strerror());
+ this->status = RAD_LISTEN_STATUS_EOL;
+ goto listener_is_eol;
+ } /* end of INIT */
+
+ if (this->status == RAD_LISTEN_STATUS_PAUSE) {
+ fr_event_fd_delete(el, 0, this->fd);
+ return;
+ }
+
+ if (this->status == RAD_LISTEN_STATUS_RESUME) goto insert_fd;
+
+#ifdef WITH_TCP
+ /*
+ * The socket has reached a timeout. Try to close it.
+ */
+ if (this->status == RAD_LISTEN_STATUS_FROZEN) {
+ /*
+ * Requests are still using the socket. Wait for
+ * them to finish.
+ */
+ if (this->count > 0) {
+ struct timeval when;
+
+ /*
+ * Try again to clean up the socket in 30
+ * seconds.
+ */
+ gettimeofday(&when, NULL);
+ when.tv_sec += 30;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el,
+ (fr_event_callback_t) event_new_fd,
+ this, &when, &sock->ev)) {
+ rad_panic("Failed to insert event");
+ }
+
+ return;
+ }
+
+ fr_event_fd_delete(el, 0, this->fd);
+ this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
+ }
+
+ /*
+ * The socket has had a catastrophic error. Close it.
+ */
+ if (this->status == RAD_LISTEN_STATUS_EOL) {
+ /*
+ * Remove it from the list of live FD's.
+ */
+ fr_event_fd_delete(el, 0, this->fd);
+
+ listener_is_eol:
+#ifdef WITH_PROXY
+ /*
+ * Tell all requests using this socket that the socket is dead.
+ */
+ if (this->type == RAD_LISTEN_PROXY
+#ifdef WITH_COA_TUNNEL
+ || (this->send_coa && this->parent)
+#endif
+ ) {
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_freeze(proxy_list,
+ this->fd)) {
+ ERROR("Fatal error freezing socket: %s", fr_strerror());
+ fr_exit(1);
+ }
+
+ if (this->count > 0) {
+ fr_packet_list_walk(proxy_list, this, proxy_eol_cb);
+ }
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ }
+#endif /* WITH_PROXY */
+
+ /*
+ * Requests are still using the socket. Wait for
+ * them to finish.
+ */
+ if (this->count > 0) {
+ struct timeval when;
+
+ /*
+ * Try again to clean up the socket in 30
+ * seconds.
+ */
+ gettimeofday(&when, NULL);
+ when.tv_sec += 30;
+
+ ASSERT_MASTER;
+ if (!fr_event_insert(el,
+ (fr_event_callback_t) event_new_fd,
+ this, &when, &sock->ev)) {
+ rad_panic("Failed to insert event");
+ }
+
+ return;
+ }
+
+ /*
+ * No one is using the socket. We can remove it now.
+ */
+ this->status = RAD_LISTEN_STATUS_REMOVE_NOW;
+ } /* socket is at EOL */
+#endif /* WITH_TCP */
+
+ if (this->dead) goto wait_some_more;
+
+ /*
+ * Nuke the socket.
+ */
+ if (this->status == RAD_LISTEN_STATUS_REMOVE_NOW) {
+ int devnull;
+
+ this->dead = true;
+
+ /*
+ * Re-open the socket, pointing it to /dev/null.
+ * This means that all writes proceed without
+ * blocking, and all reads return "no data".
+ *
+ * This leaves the socket active, so any child
+ * threads won't go insane. But it means that
+ * they cannot send or receive any packets.
+ *
+ * This is EXTRA work in the normal case, when
+ * sockets are closed without error. But it lets
+ * us have one simple processing method for all
+ * sockets.
+ */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ERROR("FATAL failure opening /dev/null: %s",
+ fr_syserror(errno));
+ fr_exit(1);
+ }
+ if (dup2(devnull, this->fd) < 0) {
+ ERROR("FATAL failure closing socket: %s",
+ fr_syserror(errno));
+ fr_exit(1);
+ }
+ close(devnull);
+
+#ifdef WITH_DETAIL
+ rad_assert(this->type != RAD_LISTEN_DETAIL);
+#endif
+
+#ifdef WITH_TCP
+#ifdef WITH_PROXY
+ /*
+ * The socket is dead. Force all proxied packets
+ * to stop using it. And then remove it from the
+ * list of outgoing sockets.
+ */
+ if (this->type == RAD_LISTEN_PROXY
+#ifdef WITH_COA_TUNNEL
+ || (this->send_coa && this->parent)
+#endif
+ ) {
+ home_server_t *home;
+ sock = this->data;
+
+ home = sock->home;
+ if (!home || !home->limit.max_connections) {
+ INFO(" ... shutting down socket %s", buffer);
+ } else {
+ INFO(" ... shutting down socket %s (%u of %u)", buffer,
+ home->limit.num_connections, home->limit.max_connections);
+ }
+
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ fr_packet_list_walk(proxy_list, this, eol_proxy_listener);
+
+ if (!fr_packet_list_socket_del(proxy_list, this->fd)) {
+ ERROR("Fatal error removing socket %s: %s",
+ buffer, fr_strerror());
+ fr_exit(1);
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Remove this socket from the list of sockets assocated with this home server.
+ *
+ * This MUST be done with the proxy mutex locked!
+ */
+ if (home && home->tls) {
+ fr_assert(home->listeners);
+
+ (void) rbtree_deletebydata(home->listeners, this);
+ }
+#endif
+
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Clean up the proxied packets AND the
+ * normal one.
+ */
+ if (this->send_coa && this->parent) goto shutdown;
+#endif
+
+ } else
+#endif /* WITH_PROXY */
+ {
+#ifdef WITH_COA_TUNNEL
+ shutdown:
+#endif
+ INFO(" ... shutting down socket %s", buffer);
+
+ /*
+ * EOL all requests using this socket.
+ */
+ rbtree_walk(pl, RBTREE_DELETE_ORDER, eol_listener, this);
+ }
+
+ /*
+ * No child threads, clean it up now.
+ */
+ if (!spawn_flag) {
+ ASSERT_MASTER;
+
+ if (this->type != RAD_LISTEN_DETAIL && sock && sock->ev) {
+ fr_event_delete(el, &sock->ev);
+ }
+ listen_free(&this);
+ return;
+ }
+
+ /*
+ * Wait until all requests using this socket are done.
+ */
+ wait_some_more:
+ listener_free_cb(this);
+#endif /* WITH_TCP */
+ }
+
+ return;
+}
+
+/***********************************************************************
+ *
+ * Signal handlers.
+ *
+ ***********************************************************************/
+
+static void handle_signal_self(int flag)
+{
+ ASSERT_MASTER;
+
+ if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
+ if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
+ INFO("Signalled to exit");
+ fr_event_loop_exit(el, 1);
+ } else {
+ INFO("Signalled to terminate");
+ fr_event_loop_exit(el, 2);
+ }
+
+ return;
+ } /* else exit/term flags weren't set */
+
+ /*
+ * Tell the even loop to stop processing.
+ */
+ if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
+ time_t when;
+ static time_t last_hup = 0;
+
+ when = time(NULL);
+ if ((int) (when - last_hup) < 5) {
+ INFO("Ignoring HUP (less than 5s since last one)");
+ return;
+ }
+
+ INFO("Received HUP signal");
+
+ last_hup = when;
+
+ exec_trigger(NULL, NULL, "server.signal.hup", true);
+ fr_event_loop_exit(el, 0x80);
+ }
+
+#if defined(WITH_DETAIL) && !defined(WITH_DETAIL_THREAD)
+ if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
+ rad_listen_t *this;
+
+ /*
+ * FIXME: O(N) loops suck.
+ */
+ for (this = main_config.listen;
+ this != NULL;
+ this = this->next) {
+ if (this->type != RAD_LISTEN_DETAIL) continue;
+
+ /*
+ * This one didn't send the signal, skip
+ * it.
+ */
+ if (!this->decode(this, NULL)) continue;
+
+ /*
+ * Go service the interrupt.
+ */
+ event_poll_detail(this);
+ }
+ }
+#endif
+
+#if defined(WITH_PROXY) && defined(HAVE_PTHREAD_H)
+ /*
+ * There are new listeners in the list. Run
+ * event_new_fd() on them.
+ */
+ if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
+ rad_listen_t *this, *next;
+
+ FD_MUTEX_LOCK(&fd_mutex);
+
+ /*
+ * FIXME: unlock the mutex before calling
+ * event_new_fd()?
+ */
+ for (this = new_listeners; this != NULL; this = next) {
+ next = this->next;
+ this->next = NULL;
+
+ event_new_fd(this);
+ }
+
+ new_listeners = NULL;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+ }
+#endif
+}
+
+#ifndef HAVE_PTHREAD_H
+void radius_signal_self(int flag)
+{
+ if (flag == RADIUS_SIGNAL_SELF_TERM) {
+ main_config.exiting = true;
+ }
+
+ return handle_signal_self(flag);
+}
+
+#else
+static int self_pipe[2] = { -1, -1 };
+
+/*
+ * Inform ourselves that we received a signal.
+ */
+void radius_signal_self(int flag)
+{
+ ssize_t rcode;
+ uint8_t buffer[16];
+
+ if (flag == RADIUS_SIGNAL_SELF_TERM) {
+ main_config.exiting = true;
+ }
+
+ /*
+ * The read MUST be non-blocking for this to work.
+ */
+ rcode = read(self_pipe[0], buffer, sizeof(buffer));
+ if (rcode > 0) {
+ ssize_t i;
+
+ for (i = 0; i < rcode; i++) {
+ buffer[0] |= buffer[i];
+ }
+ } else {
+ buffer[0] = 0;
+ }
+
+ buffer[0] |= flag;
+
+ if (write(self_pipe[1], buffer, 1) < 0) fr_exit(0);
+}
+
+
+static void event_signal_handler(UNUSED fr_event_list_t *xel,
+ UNUSED int fd, UNUSED void *ctx)
+{
+ ssize_t i, rcode;
+ uint8_t buffer[32];
+
+ rcode = read(self_pipe[0], buffer, sizeof(buffer));
+ if (rcode <= 0) return;
+
+ /*
+ * Merge pending signals.
+ */
+ for (i = 0; i < rcode; i++) {
+ buffer[0] |= buffer[i];
+ }
+
+ handle_signal_self(buffer[0]);
+}
+#endif /* HAVE_PTHREAD_H */
+
+/***********************************************************************
+ *
+ * Bootstrapping code.
+ *
+ ***********************************************************************/
+
+/*
+ * Externally-visibly functions.
+ */
+int radius_event_init(TALLOC_CTX *ctx) {
+ el = fr_event_list_create(ctx, event_status);
+ if (!el) return 0;
+
+#ifdef HAVE_SYSTEMD_WATCHDOG
+ if (sd_watchdog_interval.tv_sec || sd_watchdog_interval.tv_usec) {
+ struct timeval now;
+
+ fr_event_now(el, &now);
+
+ sdwd.when = now;
+ sdwd.el = el;
+
+ sd_watchdog_event(&sdwd);
+ }
+#endif
+
+ return 1;
+}
+
+static int packet_entry_cmp(void const *one, void const *two)
+{
+ RADIUS_PACKET const * const *a = one;
+ RADIUS_PACKET const * const *b = two;
+
+ return fr_packet_cmp(*a, *b);
+}
+
+#ifdef WITH_PROXY
+/*
+ * They haven't defined a proxy listener. Automatically
+ * add one for them, with the correct address family.
+ */
+static void create_default_proxy_listener(int af)
+{
+ uint16_t port = 0;
+ home_server_t home;
+ listen_socket_t *sock;
+ rad_listen_t *this;
+
+ memset(&home, 0, sizeof(home));
+
+ /*
+ * Open a default UDP port
+ */
+ home.proto = IPPROTO_UDP;
+ port = 0;
+
+ /*
+ * Set the address family.
+ */
+ home.src_ipaddr.af = af;
+ home.ipaddr.af = af;
+
+ /*
+ * Get the correct listener.
+ */
+ this = proxy_new_listener(proxy_ctx, &home, port);
+ if (!this) {
+ fr_exit_now(1);
+ }
+
+ sock = this->data;
+ if (!fr_packet_list_socket_add(proxy_list, this->fd,
+ sock->proto,
+#ifdef WITH_RADIUSV11
+ sock->radiusv11,
+#endif
+ &sock->other_ipaddr, sock->other_port,
+ this)) {
+ ERROR("Failed adding proxy socket");
+ fr_exit_now(1);
+ }
+
+ /*
+ * Insert the FD into list of FDs to listen on.
+ */
+ radius_update_listener(this);
+}
+
+/*
+ * See if we automatically need to open a proxy socket.
+ */
+static void check_proxy(rad_listen_t *head)
+{
+ bool defined_proxy;
+ bool has_v4, has_v6;
+ rad_listen_t *this;
+
+ if (check_config) return;
+ if (!main_config.proxy_requests) {
+ DEBUG3("Cannot proxy packets unless 'proxy_requests = yes'");
+ return;
+ }
+ if (!head) return;
+#ifdef WITH_TCP
+ if (!home_servers_udp) return;
+#endif
+
+ /*
+ * We passed "-i" on the command line. Use that address
+ * family for the proxy socket.
+ */
+ if (main_config.myip.af != AF_UNSPEC) {
+ create_default_proxy_listener(main_config.myip.af);
+ return;
+ }
+
+ defined_proxy = has_v4 = has_v6 = false;
+
+ /*
+ * Figure out if we need to open a proxy socket, and if
+ * so, which one.
+ */
+ for (this = head; this != NULL; this = this->next) {
+ listen_socket_t *sock;
+
+ switch (this->type) {
+ case RAD_LISTEN_PROXY:
+ defined_proxy = true;
+ break;
+
+ case RAD_LISTEN_AUTH:
+#ifdef WITH_ACCT
+ case RAD_LISTEN_ACCT:
+#endif
+#ifdef WITH_COA
+ case RAD_LISTEN_COA:
+#endif
+ sock = this->data;
+ if (sock->my_ipaddr.af == AF_INET) has_v4 = true;
+ if (sock->my_ipaddr.af == AF_INET6) has_v6 = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Assume they know what they're doing.
+ */
+ if (defined_proxy) return;
+
+ if (has_v4) create_default_proxy_listener(AF_INET);
+
+ if (has_v6) create_default_proxy_listener(AF_INET6);
+}
+#endif
+
+int radius_event_start(CONF_SECTION *cs, bool have_children)
+{
+ rad_listen_t *head = NULL;
+
+ if (fr_start_time != (time_t)-1) return 0;
+
+ time(&fr_start_time);
+
+ if (!check_config) {
+ /*
+ * radius_event_init() must be called first
+ */
+ rad_assert(el);
+
+ pl = rbtree_create(NULL, packet_entry_cmp, NULL, 0);
+ if (!pl) return 0; /* leak el */
+ }
+
+ request_num_counter = 0;
+
+#ifdef WITH_PROXY
+ if (main_config.proxy_requests && !check_config) {
+ /*
+ * Create the tree for managing proxied requests and
+ * responses.
+ */
+ proxy_list = fr_packet_list_create(1);
+ if (!proxy_list) return 0;
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
+ ERROR("FATAL: Failed to initialize proxy mutex: %s",
+ fr_syserror(errno));
+ fr_exit(1);
+ }
+#endif
+
+ /*
+ * The "init_delay" is set to "response_window".
+ * Reset it to half of "response_window" in order
+ * to give the event loop enough time to service
+ * the event before hitting "response_window".
+ */
+ main_config.init_delay.tv_usec += (main_config.init_delay.tv_sec & 0x01) * USEC;
+ main_config.init_delay.tv_usec >>= 1;
+ main_config.init_delay.tv_sec >>= 1;
+
+ proxy_ctx = talloc_init("proxy");
+ }
+#endif
+
+ /*
+ * Move all of the thread calls to this file?
+ *
+ * It may be best for the mutexes to be in this file...
+ */
+ spawn_flag = have_children;
+
+#ifdef HAVE_PTHREAD_H
+ NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
+
+ /*
+ * Initialize the threads ONLY if we're spawning, AND
+ * we're running normally.
+ */
+ if (have_children && !check_config &&
+ (thread_pool_init(cs, &spawn_flag) < 0)) {
+ fr_exit(1);
+ }
+#endif
+
+ if (check_config) {
+ DEBUG("%s: #### Skipping IP addresses and Ports ####",
+ main_config.name);
+ if (listen_init(cs, &head, spawn_flag) < 0) {
+ fflush(NULL);
+ fr_exit(1);
+ }
+ return 1;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Child threads need a pipe to signal us, as do the
+ * signal handlers.
+ */
+ if (pipe(self_pipe) < 0) {
+ ERROR("Error opening internal pipe: %s", fr_syserror(errno));
+ fr_exit(1);
+ }
+ if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
+ (fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
+ ERROR("Error setting internal flags: %s", fr_syserror(errno));
+ fr_exit(1);
+ }
+ if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
+ (fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
+ ERROR("Error setting internal flags: %s", fr_syserror(errno));
+ fr_exit(1);
+ }
+ DEBUG4("Created signal pipe. Read end FD %i, write end FD %i", self_pipe[0], self_pipe[1]);
+
+ if (!fr_event_fd_insert(el, 0, self_pipe[0], event_signal_handler, el)) {
+ ERROR("Failed creating signal pipe handler: %s", fr_strerror());
+ fr_exit(1);
+ }
+#endif
+
+ DEBUG("%s: #### Opening IP addresses and Ports ####", main_config.name);
+
+ /*
+ * The server temporarily switches to an unprivileged
+ * user very early in the bootstrapping process.
+ * However, some sockets MAY require privileged access
+ * (bind to device, or to port < 1024, or to raw
+ * sockets). Those sockets need to call suid up/down
+ * themselves around the functions that need a privileged
+ * uid.
+ */
+ if (listen_init(cs, &head, spawn_flag) < 0) {
+ fr_exit_now(1);
+ }
+
+ main_config.listen = head;
+
+#ifdef WITH_PROXY
+ check_proxy(head);
+#endif
+
+ /*
+ * At this point, no one has any business *ever* going
+ * back to root uid.
+ */
+ rad_suid_down_permanent();
+
+ return 1;
+}
+
+
+#ifdef WITH_PROXY
+static int proxy_delete_cb(UNUSED void *ctx, void *data)
+{
+ REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
+
+ VERIFY_REQUEST(request);
+
+ request->master_state = REQUEST_STOP_PROCESSING;
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
+#endif
+
+ /*
+ * If it's queued we can't delete it from the queue.
+ *
+ * Otherwise, it's OK to delete it. Even RUNNING, because
+ * that will get caught by the check above.
+ */
+ if (request->child_state == REQUEST_QUEUED) return 0;
+
+ request->in_proxy_hash = false;
+
+ if (!request->in_request_hash) {
+ request_done(request, FR_ACTION_CANCELLED);
+ }
+
+ /*
+ * Delete it from the list.
+ */
+ return 2;
+}
+#endif
+
+
+static int request_delete_cb(UNUSED void *ctx, void *data)
+{
+ REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
+
+ VERIFY_REQUEST(request);
+
+ request->master_state = REQUEST_STOP_PROCESSING;
+
+ /*
+ * Not done, or the child thread is still processing it.
+ */
+ if (request->child_state < REQUEST_RESPONSE_DELAY) return 0; /* continue */
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0) return 0;
+#endif
+
+#ifdef WITH_PROXY
+ rad_assert(request->in_proxy_hash == false);
+#endif
+
+ request->in_request_hash = false;
+ ASSERT_MASTER;
+ if (request->ev) fr_event_delete(el, &request->ev);
+
+ if (main_config.memory_report) {
+ RDEBUG2("Cleaning up request packet ID %u with timestamp +%d",
+ request->packet->id,
+ (unsigned int) (request->timestamp - fr_start_time));
+ }
+
+#ifdef WITH_COA
+ if (request->coa) {
+ rad_assert(!request->coa->in_proxy_hash);
+ }
+#endif
+
+ request_free(request);
+
+ /*
+ * Delete it from the list, and continue;
+ */
+ return 2;
+}
+
+
+void radius_event_free(void)
+{
+ ASSERT_MASTER;
+
+#ifdef WITH_PROXY
+ /*
+ * There are requests in the proxy hash that aren't
+ * referenced from anywhere else. Remove them first.
+ */
+ if (proxy_list) {
+ fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
+ }
+#endif
+
+ rbtree_walk(pl, RBTREE_DELETE_ORDER, request_delete_cb, NULL);
+
+ if (spawn_flag) {
+ /*
+ * Now that all requests have been marked "please stop",
+ * ensure that all of the threads have exited.
+ */
+#ifdef HAVE_PTHREAD_H
+ thread_pool_stop();
+#endif
+
+ /*
+ * Walk the lists again, ensuring that all
+ * requests are done.
+ */
+ if (main_config.memory_report) {
+ int num;
+
+#ifdef WITH_PROXY
+ if (proxy_list) {
+ fr_packet_list_walk(proxy_list, NULL, proxy_delete_cb);
+ num = fr_packet_list_num_elements(proxy_list);
+ if (num > 0) {
+ ERROR("Proxy list has %d requests still in it.", num);
+ }
+ }
+#endif
+
+ rbtree_walk(pl, RBTREE_DELETE_ORDER, request_delete_cb, NULL);
+ num = rbtree_num_elements(pl);
+ if (num > 0) {
+ ERROR("Request list has %d requests still in it.", num);
+ }
+ }
+ }
+
+ rbtree_free(pl);
+ pl = NULL;
+
+#ifdef WITH_PROXY
+ fr_packet_list_free(proxy_list);
+ proxy_list = NULL;
+
+ if (proxy_ctx) talloc_free(proxy_ctx);
+#endif
+
+ TALLOC_FREE(el);
+
+ if (debug_condition) talloc_free(debug_condition);
+}
+
+int radius_event_process(void)
+{
+ if (!el) return 0;
+
+ return fr_event_loop(el);
+}
diff --git a/src/main/radattr.c b/src/main/radattr.c
new file mode 100644
index 0000000..8accd0d
--- /dev/null
+++ b/src/main/radattr.c
@@ -0,0 +1,1123 @@
+/*
+ * radattr.c RADIUS Attribute debugging tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2010 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+typedef struct REQUEST REQUEST;
+
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/xlat.h>
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/dhcp.h>
+
+#include <ctype.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <assert.h>
+
+#include <freeradius-devel/log.h>
+extern log_lvl_t rad_debug_lvl;
+
+#include <sys/wait.h>
+#ifdef HAVE_PTHREAD_H
+pid_t rad_fork(void);
+pid_t rad_waitpid(pid_t pid, int *status);
+
+pid_t rad_fork(void)
+{
+ return fork();
+}
+
+pid_t rad_waitpid(pid_t pid, int *status)
+{
+ return waitpid(pid, status, 0);
+}
+#endif
+
+static TALLOC_CTX *autofree;
+
+static ssize_t xlat_test(UNUSED void *instance, UNUSED REQUEST *request,
+ UNUSED char const *fmt, UNUSED char *out, UNUSED size_t outlen)
+{
+ return 0;
+}
+
+static RADIUS_PACKET access_request = {
+ .sockfd = -1,
+ .id = 0,
+ .code = PW_CODE_ACCESS_REQUEST,
+ .vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+};
+
+static RADIUS_PACKET access_accept = {
+ .sockfd = -1,
+ .id = 0,
+ .code = PW_CODE_ACCESS_ACCEPT,
+ .vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+};
+
+static RADIUS_PACKET coa_request = {
+ .sockfd = -1,
+ .id = 0,
+ .code = PW_CODE_COA_REQUEST,
+ .vector = { 0 },
+};
+
+static RADIUS_PACKET *my_original = &access_request;
+static RADIUS_PACKET *my_packet = &access_accept;
+
+static char const *my_secret = "testing123";
+
+/*
+ * End of hacks for xlat
+ *
+ **********************************************************************/
+
+static int encode_tlv(char *buffer, uint8_t *output, size_t outlen);
+
+static char const hextab[] = "0123456789abcdef";
+
+static int encode_data_string(char *buffer,
+ uint8_t *output, size_t outlen)
+{
+ int length = 0;
+ char *p;
+
+ p = buffer + 1;
+
+ while (*p && (outlen > 0)) {
+ if (*p == '"') {
+ return length;
+ }
+
+ if (*p != '\\') {
+ *(output++) = *(p++);
+ outlen--;
+ length++;
+ continue;
+ }
+
+ switch (p[1]) {
+ default:
+ *(output++) = p[1];
+ break;
+
+ case 'n':
+ *(output++) = '\n';
+ break;
+
+ case 'r':
+ *(output++) = '\r';
+ break;
+
+ case 't':
+ *(output++) = '\t';
+ break;
+ }
+
+ outlen--;
+ length++;
+ }
+
+ fprintf(stderr, "String is not terminated\n");
+ return 0;
+}
+
+static int encode_data_tlv(char *buffer, char **endptr,
+ uint8_t *output, size_t outlen)
+{
+ int depth = 0;
+ int length;
+ char *p;
+
+ for (p = buffer; *p != '\0'; p++) {
+ if (*p == '{') depth++;
+ if (*p == '}') {
+ depth--;
+ if (depth == 0) break;
+ }
+ }
+
+ if (*p != '}') {
+ fprintf(stderr, "No trailing '}' in string starting "
+ "with \"%s\"\n",
+ buffer);
+ return 0;
+ }
+
+ *endptr = p + 1;
+ *p = '\0';
+
+ p = buffer + 1;
+ while (isspace((uint8_t) *p)) p++;
+
+ length = encode_tlv(p, output, outlen);
+ if (length == 0) return 0;
+
+ return length;
+}
+
+static int encode_hex(char *p, uint8_t *output, size_t outlen)
+{
+ int length = 0;
+ while (*p) {
+ char *c1, *c2;
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if (!*p) break;
+
+ if(!(c1 = memchr(hextab, tolower((uint8_t) p[0]), 16)) ||
+ !(c2 = memchr(hextab, tolower((uint8_t) p[1]), 16))) {
+ fprintf(stderr, "Invalid data starting at "
+ "\"%s\"\n", p);
+ return 0;
+ }
+
+ *output = ((c1 - hextab) << 4) + (c2 - hextab);
+ output++;
+ length++;
+ p += 2;
+
+ outlen--;
+ if (outlen == 0) {
+ fprintf(stderr, "Too much data\n");
+ return 0;
+ }
+ }
+
+ return length;
+}
+
+
+static int encode_data(char *p, uint8_t *output, size_t outlen)
+{
+ int length;
+
+ if (!isspace((uint8_t) *p)) {
+ fprintf(stderr, "Invalid character following attribute "
+ "definition\n");
+ return 0;
+ }
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if (*p == '{') {
+ int sublen;
+ char *q;
+
+ length = 0;
+
+ do {
+ while (isspace((uint8_t) *p)) p++;
+ if (!*p) {
+ if (length == 0) {
+ fprintf(stderr, "No data\n");
+ return 0;
+ }
+
+ break;
+ }
+
+ sublen = encode_data_tlv(p, &q, output, outlen);
+ if (sublen == 0) return 0;
+
+ length += sublen;
+ output += sublen;
+ outlen -= sublen;
+ p = q;
+ } while (*q);
+
+ return length;
+ }
+
+ if (*p == '"') {
+ length = encode_data_string(p, output, outlen);
+ return length;
+ }
+
+ length = encode_hex(p, output, outlen);
+
+ if (length == 0) {
+ fprintf(stderr, "Empty string\n");
+ return 0;
+ }
+
+ return length;
+}
+
+static int decode_attr(char *buffer, char **endptr)
+{
+ long attr;
+
+ attr = strtol(buffer, endptr, 10);
+ if (*endptr == buffer) {
+ fprintf(stderr, "No valid number found in string "
+ "starting with \"%s\"\n", buffer);
+ return 0;
+ }
+
+ if (!**endptr) {
+ fprintf(stderr, "Nothing follows attribute number\n");
+ return 0;
+ }
+
+ if ((attr <= 0) || (attr > 256)) {
+ fprintf(stderr, "Attribute number is out of valid "
+ "range\n");
+ return 0;
+ }
+
+ return (int) attr;
+}
+
+static int decode_vendor(char *buffer, char **endptr)
+{
+ long vendor;
+
+ if (*buffer != '.') {
+ fprintf(stderr, "Invalid separator before vendor id\n");
+ return 0;
+ }
+
+ vendor = strtol(buffer + 1, endptr, 10);
+ if (*endptr == (buffer + 1)) {
+ fprintf(stderr, "No valid vendor number found\n");
+ return 0;
+ }
+
+ if (!**endptr) {
+ fprintf(stderr, "Nothing follows vendor number\n");
+ return 0;
+ }
+
+ if ((vendor <= 0) || (vendor > (1 << 24))) {
+ fprintf(stderr, "Vendor number is out of valid range\n");
+ return 0;
+ }
+
+ if (**endptr != '.') {
+ fprintf(stderr, "Invalid data following vendor number\n");
+ return 0;
+ }
+ (*endptr)++;
+
+ return (int) vendor;
+}
+
+static int encode_tlv(char *buffer, uint8_t *output, size_t outlen)
+{
+ int attr;
+ int length;
+ char *p;
+
+ attr = decode_attr(buffer, &p);
+ if (attr == 0) return 0;
+
+ output[0] = attr;
+ output[1] = 2;
+
+ if (*p == '.') {
+ p++;
+ length = encode_tlv(p, output + 2, outlen - 2);
+
+ } else {
+ length = encode_data(p, output + 2, outlen - 2);
+ }
+
+ if (length == 0) return 0;
+ if (length > (255 - 2)) {
+ fprintf(stderr, "TLV data is too long\n");
+ return 0;
+ }
+
+ output[1] += length;
+
+ return length + 2;
+}
+
+static int encode_vsa(char *buffer, uint8_t *output, size_t outlen)
+{
+ int vendor;
+ int length;
+ char *p;
+
+ vendor = decode_vendor(buffer, &p);
+ if (vendor == 0) return 0;
+
+ output[0] = 0;
+ output[1] = (vendor >> 16) & 0xff;
+ output[2] = (vendor >> 8) & 0xff;
+ output[3] = vendor & 0xff;
+
+ length = encode_tlv(p, output + 4, outlen - 4);
+ if (length == 0) return 0;
+ if (length > (255 - 6)) {
+ fprintf(stderr, "VSA data is too long\n");
+ return 0;
+ }
+
+
+ return length + 4;
+}
+
+static int encode_evs(char *buffer, uint8_t *output, size_t outlen)
+{
+ int vendor;
+ int attr;
+ int length;
+ char *p;
+
+ vendor = decode_vendor(buffer, &p);
+ if (vendor == 0) return 0;
+
+ attr = decode_attr(p, &p);
+ if (attr == 0) return 0;
+
+ output[0] = 0;
+ output[1] = (vendor >> 16) & 0xff;
+ output[2] = (vendor >> 8) & 0xff;
+ output[3] = vendor & 0xff;
+ output[4] = attr;
+
+ length = encode_data(p, output + 5, outlen - 5);
+ if (length == 0) return 0;
+
+ return length + 5;
+}
+
+static int encode_extended(char *buffer,
+ uint8_t *output, size_t outlen)
+{
+ int attr;
+ int length;
+ char *p;
+
+ attr = decode_attr(buffer, &p);
+ if (attr == 0) return 0;
+
+ output[0] = attr;
+
+ if (attr == 26) {
+ length = encode_evs(p, output + 1, outlen - 1);
+ } else {
+ length = encode_data(p, output + 1, outlen - 1);
+ }
+ if (length == 0) return 0;
+ if (length > (255 - 3)) {
+ fprintf(stderr, "Extended Attr data is too long\n");
+ return 0;
+ }
+
+ return length + 1;
+}
+
+static int encode_long_extended(char *buffer,
+ uint8_t *output, size_t outlen)
+{
+ int attr;
+ int length, total;
+ char *p;
+
+ attr = decode_attr(buffer, &p);
+ if (attr == 0) return 0;
+
+ /* output[0] is the extended attribute */
+ output[1] = 4;
+ output[2] = attr;
+ output[3] = 0;
+
+ if (attr == 26) {
+ length = encode_evs(p, output + 4, outlen - 4);
+ if (length == 0) return 0;
+
+ output[1] += 5;
+ length -= 5;
+ } else {
+ length = encode_data(p, output + 4, outlen - 4);
+ }
+ if (length == 0) return 0;
+
+ total = 0;
+ while (1) {
+ int sublen = 255 - output[1];
+
+ if (length <= sublen) {
+ output[1] += length;
+ total += output[1];
+ break;
+ }
+
+ length -= sublen;
+
+ memmove(output + 255 + 4, output + 255, length);
+ memcpy(output + 255, output, 4);
+
+ output[1] = 255;
+ output[3] |= 0x80;
+
+ output += 255;
+ output[1] = 4;
+ total += 255;
+ }
+
+ return total;
+}
+
+static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
+{
+ int attr;
+ int length, sublen;
+ char *p;
+
+ attr = decode_attr(buffer, &p);
+ if (attr == 0) return 0;
+
+ length = 2;
+ output[0] = attr;
+ output[1] = 2;
+
+ if (attr == 26) {
+ sublen = encode_vsa(p, output + 2, outlen - 2);
+
+ } else if ((attr < 241) || (attr > 246)) {
+ sublen = encode_data(p, output + 2, outlen - 2);
+
+ } else {
+ if (*p != '.') {
+ fprintf(stderr, "Invalid data following "
+ "attribute number\n");
+ return 0;
+ }
+
+ if (attr < 245) {
+ sublen = encode_extended(p + 1,
+ output + 2, outlen - 2);
+ } else {
+
+ /*
+ * Not like the others!
+ */
+ return encode_long_extended(p + 1, output, outlen);
+ }
+ }
+ if (sublen == 0) return 0;
+ if (sublen > (255 -2)) {
+ fprintf(stderr, "RFC Data is too long\n");
+ return 0;
+ }
+
+ output[1] += sublen;
+ return length + sublen;
+}
+
+static void parse_condition(char const *input, char *output, size_t outlen)
+{
+ ssize_t slen;
+ char const *error = NULL;
+ fr_cond_t *cond;
+
+ slen = fr_condition_tokenize(NULL, NULL, input, &cond, &error, FR_COND_ONE_PASS);
+ if (slen <= 0) {
+ snprintf(output, outlen, "ERROR offset %d %s", (int) -slen, error);
+ return;
+ }
+
+ input += slen;
+ if (*input != '\0') {
+ talloc_free(cond);
+ snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
+ return;
+ }
+
+ fr_cond_sprint(output, outlen, cond);
+
+ talloc_free(cond);
+}
+
+static void parse_xlat(char const *input, char *output, size_t outlen)
+{
+ ssize_t slen;
+ char const *error = NULL;
+ char *fmt = talloc_typed_strdup(autofree, input);
+ xlat_exp_t *head;
+
+ slen = xlat_tokenize(autofree, fmt, &head, &error);
+ if (slen <= 0) {
+ snprintf(output, outlen, "ERROR offset %d '%s'", (int) -slen, error);
+ return;
+ }
+
+ if (input[slen] != '\0') {
+ snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
+ talloc_free(fmt);
+ return;
+ }
+
+ xlat_sprint(output, outlen, head);
+ talloc_free(fmt);
+}
+
+static void process_file(const char *root_dir, char const *filename)
+{
+ int lineno;
+ size_t i, outlen;
+ ssize_t len, data_len;
+ FILE *fp;
+ char input[8192], buffer[8192];
+ char output[8192];
+ char directory[8192];
+ uint8_t *attr, data[2048];
+
+ if (strcmp(filename, "-") == 0) {
+ fp = stdin;
+ directory[0] = '\0';
+
+ } else {
+ if (root_dir && *root_dir) {
+ snprintf(directory, sizeof(directory), "%s/%s", root_dir, filename);
+ } else {
+ strlcpy(directory, filename, sizeof(directory));
+ }
+
+ fp = fopen(directory, "r");
+ if (!fp) {
+ fprintf(stderr, "Error opening %s: %s\n",
+ directory, fr_syserror(errno));
+ exit(1);
+ }
+
+ filename = directory;
+ }
+
+ lineno = 0;
+ *output = '\0';
+ data_len = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ char *p = strchr(buffer, '\n');
+ VALUE_PAIR *vp, *head;
+ VALUE_PAIR **tail = &head;
+
+ lineno++;
+ head = NULL;
+
+ if (!p) {
+ if (!feof(fp)) {
+ fprintf(stderr, "Line %d too long in %s\n",
+ lineno, directory);
+ exit(1);
+ }
+ } else {
+ *p = '\0';
+ }
+
+ /*
+ * Comments, with hacks for User-Name[#]
+ */
+ p = strchr(buffer, '#');
+ if (p && ((p == buffer) ||
+ ((p > buffer) && (p[-1] != '[')))) *p = '\0';
+
+ p = buffer;
+ while (isspace((uint8_t) *p)) p++;
+ if (!*p) continue;
+
+ DEBUG2("%s[%d]: %s\n", filename, lineno, buffer);
+
+ strlcpy(input, p, sizeof(input));
+
+ if (strncmp(p, "raw ", 4) == 0) {
+ outlen = encode_rfc(p + 4, data, sizeof(data));
+ if (outlen == 0) {
+ fprintf(stderr, "Parse error in line %d of %s\n",
+ lineno, directory);
+ exit(1);
+ }
+
+ print_hex:
+ if (outlen == 0) {
+ output[0] = 0;
+ continue;
+ }
+
+ if (outlen > sizeof(data)) outlen = sizeof(data);
+
+ if (outlen >= (sizeof(output) / 2)) {
+ outlen = (sizeof(output) / 2) - 1;
+ }
+
+ data_len = outlen;
+ for (i = 0; i < outlen; i++) {
+ if (sizeof(output) < (3*i)) break;
+
+ snprintf(output + 3*i, sizeof(output) - (3*i) - 1,
+ "%02x ", data[i]);
+ }
+ outlen = strlen(output);
+ output[outlen - 1] = '\0';
+ continue;
+ }
+
+ if (strncmp(p, "data ", 5) == 0) {
+ if (strcmp(p + 5, output) != 0) {
+ fprintf(stderr, "Mismatch at line %d of %s\n\tgot : %s\n\texpected : %s\n",
+ lineno, directory, output, p + 5);
+ exit(1);
+ }
+ continue;
+ }
+
+ if (strncmp(p, "packet ", 7) == 0) {
+ p += 7;
+ if (strncmp(p, "access_accept", 13) == 0) {
+ my_packet = &access_accept;
+ } else if (strncmp(p, "coa_request", 11) == 0) {
+ my_packet = &coa_request;
+ } else {
+ fprintf(stderr, "Unsupported packet type at line %d of %s: %s\n",
+ lineno, directory, p);
+ exit(1);
+ }
+ continue;
+ }
+ if (strncmp(p, "original ", 9) == 0) {
+ p += 9;
+ if (strncmp(p, "null", 4) == 0) {
+ my_original = NULL;
+ } else if (strncmp(p, "access_request", 14) == 0) {
+ my_original = &access_request;
+ } else {
+ fprintf(stderr, "Unsupported original type at line %d of %s: %s\n",
+ lineno, directory, p);
+ exit(1);
+ }
+ continue;
+ }
+
+ if (strncmp(p, "encode ", 7) == 0) {
+ if (strcmp(p + 7, "-") == 0) {
+ p = output;
+ } else {
+ p += 7;
+ }
+
+ if (fr_pair_list_afrom_str(autofree, p, &head) != T_EOL) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+ continue;
+ }
+
+ attr = data;
+ vp = head;
+ while (vp) {
+ VALUE_PAIR **pvp = &vp;
+ VALUE_PAIR const **qvp;
+
+ memcpy(&qvp, &pvp, sizeof(pvp));
+
+ len = rad_vp2attr(my_packet, my_original, my_secret, qvp,
+ attr, data + sizeof(data) - attr);
+ if (len < 0) {
+ fprintf(stderr, "Failed encoding %s: %s\n",
+ vp->da->name, fr_strerror());
+ fr_pair_list_free(&head);
+ exit(1);
+ }
+
+ attr += len;
+ if (len == 0) break;
+ }
+
+ fr_pair_list_free(&head);
+ outlen = attr - data;
+ goto print_hex;
+ }
+
+ if (strncmp(p, "decode ", 7) == 0) {
+ ssize_t my_len;
+
+ if (strcmp(p + 7, "-") == 0) {
+ attr = data;
+ len = data_len;
+ } else {
+ attr = data;
+ len = encode_hex(p + 7, data, sizeof(data));
+ if (len == 0) {
+ fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, directory);
+ exit(1);
+ }
+ }
+
+ my_len = 0;
+ while (len > 0) {
+ vp = NULL;
+ my_len = rad_attr2vp(autofree, my_packet, my_original, my_secret, attr, len, &vp);
+ if (my_len < 0) {
+ fr_pair_list_free(&head);
+ break;
+ }
+
+ if (my_len > len) {
+ fprintf(stderr, "Internal sanity check failed at %d\n", __LINE__);
+ exit(1);
+ }
+
+ *tail = vp;
+ while (vp) {
+ tail = &(vp->next);
+ vp = vp->next;
+ }
+
+ attr += my_len;
+ len -= my_len;
+ }
+
+ /*
+ * Output may be an error, and we ignore
+ * it if so.
+ */
+ if (head) {
+ vp_cursor_t cursor;
+ p = output;
+ for (vp = fr_cursor_init(&cursor, &head);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vp_prints(p, sizeof(output) - (p - output), vp);
+ p += strlen(p);
+
+ if (vp->next) {
+ strcpy(p, ", ");
+ p += 2;
+ }
+ }
+
+ fr_pair_list_free(&head);
+ } else if (my_len < 0) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+
+ } else { /* zero-length attribute */
+ *output = '\0';
+ }
+
+ continue;
+ }
+
+#ifdef WITH_DHCP
+ /*
+ * And some DHCP tests
+ */
+ if (strncmp(p, "encode-dhcp ", 12) == 0) {
+ vp_cursor_t cursor;
+
+ if (strcmp(p + 12, "-") == 0) {
+ p = output;
+ } else {
+ p += 12;
+ }
+
+ if (fr_pair_list_afrom_str(NULL, p, &head) != T_EOL) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+ continue;
+ }
+
+ fr_cursor_init(&cursor, &head);
+
+
+ attr = data;
+ vp = head;
+
+ while ((vp = fr_cursor_current(&cursor))) {
+ len = fr_dhcp_encode_option(NULL, attr, data + sizeof(data) - attr, &cursor);
+ if (len < 0) {
+ fprintf(stderr, "Failed encoding %s: %s\n",
+ vp->da->name, fr_strerror());
+ exit(1);
+ }
+ attr += len;
+ };
+
+ fr_pair_list_free(&head);
+ outlen = attr - data;
+ goto print_hex;
+ }
+
+ if (strncmp(p, "decode-dhcp ", 12) == 0) {
+ ssize_t my_len;
+
+ if (strcmp(p + 12, "-") == 0) {
+ attr = data;
+ len = data_len;
+ } else {
+ attr = data;
+ len = encode_hex(p + 12, data, sizeof(data));
+ if (len == 0) {
+ fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, directory);
+ exit(1);
+ }
+ }
+
+ my_len = fr_dhcp_decode_options(NULL, &head, attr, len);
+
+ /*
+ * Output may be an error, and we ignore
+ * it if so.
+ */
+ if (head) {
+ vp_cursor_t cursor;
+ p = output;
+ for (vp = fr_cursor_init(&cursor, &head);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vp_prints(p, sizeof(output) - (p - output), vp);
+ p += strlen(p);
+
+ if (vp->next) {strcpy(p, ", ");
+ p += 2;
+ }
+ }
+
+ fr_pair_list_free(&head);
+ } else if (my_len < 0) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+
+ } else { /* zero-length attribute */
+ *output = '\0';
+ }
+ continue;
+ }
+#endif
+
+ if (strncmp(p, "attribute ", 10) == 0) {
+ p += 10;
+
+ if (fr_pair_list_afrom_str(NULL, p, &head) != T_EOL) {
+ strlcpy(output, fr_strerror(), sizeof(output));
+ continue;
+ }
+
+ vp_prints(output, sizeof(output), head);
+
+ fr_pair_list_free(&head);
+ continue;
+ }
+
+ if (strncmp(p, "$INCLUDE ", 9) == 0) {
+ char *q;
+
+ p += 9;
+ while (isspace((uint8_t) *p)) p++;
+
+ q = strrchr(directory, '/');
+ if (q) {
+ *q = '\0';
+ process_file(directory, p);
+ *q = '/';
+ } else {
+ process_file(NULL, p);
+ }
+ continue;
+ }
+
+ if (strncmp(p, "condition ", 10) == 0) {
+ p += 10;
+ parse_condition(p, output, sizeof(output));
+ continue;
+ }
+
+ if (strncmp(p, "xlat ", 5) == 0) {
+ p += 5;
+ parse_xlat(p, output, sizeof(output));
+ continue;
+ }
+
+ fprintf(stderr, "Unknown input at line %d of %s\n",
+ lineno, directory);
+ exit(1);
+ }
+
+ if (fp != stdin) fclose(fp);
+}
+
+/** Dump all of the dictionary entries as
+ *
+ * ALIAS name OID
+ *
+ * To create dictionaries which allow files to be used with v4.
+ *
+ * rm -rf alias;mkdir alias;./build/make/jlibtool --mode=execute ./build/bin/radattr -D ./share/ -A | sort -n -k6 -k7 -k8 -k9 -k10 -k11 | gawk '{printf "%s\t%-40s\t%s\n", $1, $2, $3 >> "alias/alias." tolower($5) }'
+ *
+ * And then post-process each file to remove the comments.
+ *
+ * Note that we have to use GNU Awk, as OSX awk doesn't like redirection to a file which includes a variable.
+ */
+static int dump_aliases(void *ctx, void *data)
+{
+ DICT_ATTR *da = data;
+ FILE *fp = ctx;
+ int nest, attr, dv_type;
+ DICT_VENDOR *dv;
+ char buffer[1024];
+
+ if (!da->vendor || (da->vendor > FR_MAX_VENDOR)) return 0;
+
+ dv = dict_vendorbyvalue(da->vendor);
+ dv_type = dv->type;
+
+ (void) dict_print_oid(buffer, sizeof(buffer), da);
+ fprintf(fp, "ALIAS\t%s\t%s # %s %u", da->name, buffer, dv->name, da->vendor);
+
+ attr = da->attr;
+ switch (dv_type) {
+ default:
+ case 1:
+ fprintf(fp, " %u", attr & 0xff);
+
+ /*
+ * Only these ones are bit-packed.
+ */
+ for (nest = 1; nest <= fr_attr_max_tlv; nest++) {
+ if (((attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]) == 0) break;
+
+ fprintf(fp, " %u",
+ (attr >> fr_attr_shift[nest]) & fr_attr_mask[nest]);
+ }
+ break;
+
+ case 2:
+ fprintf(fp, " %u", attr & 0xffff);
+ break;
+
+ case 4:
+ fprintf(fp, " %u", attr);
+ break;
+ }
+
+ printf("\n");
+
+ return 0;
+}
+
+static void NEVER_RETURNS usage(void)
+{
+ fprintf(stderr, "usage: radattr [OPTS] filename\n");
+ fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stderr, " -x Debugging mode.\n");
+ fprintf(stderr, " -M Show talloc memory report.\n");
+
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ bool report = false;
+ bool dump_alias = false;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
+ int *inst = &c;
+
+DIAG_OFF(deprecated-declarations)
+ autofree = talloc_autofree_context();
+DIAG_ON(deprecated-declarations)
+
+ cf_new_escape = true; /* fix the tests */
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radattr");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ while ((c = getopt(argc, argv, "Ad:D:xMh")) != EOF) switch (c) {
+ case 'A':
+ dump_alias = true;
+ break;
+ case 'd':
+ radius_dir = optarg;
+ break;
+ case 'D':
+ dict_dir = optarg;
+ break;
+ case 'x':
+ fr_debug_lvl++;
+ rad_debug_lvl = fr_debug_lvl;
+ break;
+ case 'M':
+ report = true;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (xlat_register("test", xlat_test, NULL, inst) < 0) {
+ fprintf(stderr, "Failed registering xlat");
+ return 1;
+ }
+
+ if (dump_alias) {
+ (void) dict_walk(dump_aliases, stdout);
+ return 0;
+ }
+
+ if (argc < 2) {
+ process_file(NULL, "-");
+
+ } else {
+ process_file(NULL, argv[1]);
+ }
+
+ if (report) {
+ dict_free();
+ fr_log_talloc_report(NULL);
+ }
+
+ return 0;
+}
diff --git a/src/main/radattr.mk b/src/main/radattr.mk
new file mode 100644
index 0000000..1a184bd
--- /dev/null
+++ b/src/main/radattr.mk
@@ -0,0 +1,10 @@
+TARGET := radattr
+SOURCES := radattr.c
+
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+
+ifneq "$(WITH_DHCP)" "no"
+TGT_PREREQS += libfreeradius-dhcp.a
+endif
+
+TGT_LDLIBS := $(LIBS)
diff --git a/src/main/radclient.c b/src/main/radclient.c
new file mode 100644
index 0000000..49da461
--- /dev/null
+++ b/src/main/radclient.c
@@ -0,0 +1,1712 @@
+/*
+ * radclient.c General radius packet debug tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006,2014 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radclient.h>
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/udpfromto.h>
+#include <freeradius-devel/conf.h>
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#include <freeradius-devel/openssl3.h>
+#endif
+#include <ctype.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <assert.h>
+
+USES_APPLE_DEPRECATED_API
+
+typedef struct REQUEST REQUEST; /* to shut up warnings about mschap.h */
+
+#include "smbdes.h"
+#include "mschap.h"
+
+static int retries = 3;
+static float timeout = 5;
+static char const *secret = NULL;
+static bool do_output = true;
+
+static rc_stats_t stats;
+
+static uint16_t server_port = 0;
+static int packet_code = PW_CODE_UNDEFINED;
+static fr_ipaddr_t server_ipaddr;
+static int resend_count = 1;
+static bool done = true;
+static bool print_filename = false;
+
+static fr_ipaddr_t client_ipaddr;
+static uint16_t client_port = 0;
+
+static int sockfd;
+
+#ifdef WITH_TCP
+static char const *proto = NULL;
+#endif
+static int ipproto = IPPROTO_UDP;
+
+static rbtree_t *filename_tree = NULL;
+static fr_packet_list_t *pl = NULL;
+
+static int sleep_time = -1;
+
+static rc_request_t *request_head = NULL;
+static rc_request_t *rc_request_tail = NULL;
+
+static char const *radclient_version = "radclient version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+static void NEVER_RETURNS usage(void)
+{
+ fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
+
+ fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
+ fprintf(stderr, " -4 Use IPv4 address of server\n");
+ fprintf(stderr, " -6 Use IPv6 address of server.\n");
+ fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
+ fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
+ fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
+ fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
+ fprintf(stderr, " -h Print usage help information.\n");
+ fprintf(stderr, " -n <num> Send N requests/s\n");
+ fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
+ fprintf(stderr, " -q Do not print anything out.\n");
+ fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
+ fprintf(stderr, " -s Print out summary information of auth results.\n");
+ fprintf(stderr, " -S <file> read secret from file, not command line.\n");
+ fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
+ fprintf(stderr, " -v Show program version information.\n");
+ fprintf(stderr, " -x Debugging mode.\n");
+
+#ifdef WITH_TCP
+ fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
+#endif
+
+ exit(1);
+}
+
+static const FR_NAME_NUMBER request_types[] = {
+ { "auth", PW_CODE_ACCESS_REQUEST },
+ { "challenge", PW_CODE_ACCESS_CHALLENGE },
+ { "acct", PW_CODE_ACCOUNTING_REQUEST },
+ { "status", PW_CODE_STATUS_SERVER },
+ { "disconnect", PW_CODE_DISCONNECT_REQUEST },
+ { "coa", PW_CODE_COA_REQUEST },
+ { "auto", PW_CODE_UNDEFINED },
+
+ { NULL, 0}
+};
+
+/*
+ * Free a radclient struct, which may (or may not)
+ * already be in the list.
+ */
+static int _rc_request_free(rc_request_t *request)
+{
+ rc_request_t *prev, *next;
+
+ prev = request->prev;
+ next = request->next;
+
+ if (prev) {
+ assert(request_head != request);
+ prev->next = next;
+ } else if (request_head) {
+ assert(request_head == request);
+ request_head = next;
+ }
+
+ if (next) {
+ assert(rc_request_tail != request);
+ next->prev = prev;
+ } else if (rc_request_tail) {
+ assert(rc_request_tail == request);
+ rc_request_tail = prev;
+ }
+
+ return 0;
+}
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/provider.h>
+
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+
+static int openssl3_init(void)
+{
+ /*
+ * Load the default provider for most algorithms
+ */
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+ if (!openssl_default_provider) {
+ ERROR("(TLS) Failed loading default provider");
+ return -1;
+ }
+
+ /*
+ * Needed for MD4
+ *
+ * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
+ */
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+ if (!openssl_legacy_provider) {
+ ERROR("(TLS) Failed loading legacy provider");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void openssl3_free(void)
+{
+ if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
+ ERROR("Failed unloading default provider");
+ }
+ openssl_default_provider = NULL;
+
+ if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
+ ERROR("Failed unloading legacy provider");
+ }
+ openssl_legacy_provider = NULL;
+}
+#else
+#define openssl3_init()
+#define openssl3_free()
+#endif
+
+
+
+static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request,
+ char const *password)
+{
+ int rcode;
+ unsigned int i;
+ uint8_t *p;
+ VALUE_PAIR *challenge, *reply;
+ uint8_t nthash[16];
+
+ fr_pair_delete_by_num(&packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ challenge = fr_pair_afrom_num(packet, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
+ if (!challenge) {
+ return 0;
+ }
+
+ fr_pair_add(request, challenge);
+ challenge->vp_length = 8;
+ challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->vp_length);
+ for (i = 0; i < challenge->vp_length; i++) {
+ p[i] = fr_rand();
+ }
+
+ reply = fr_pair_afrom_num(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
+ if (!reply) {
+ return 0;
+ }
+
+ fr_pair_add(request, reply);
+ reply->vp_length = 50;
+ reply->vp_octets = p = talloc_array(reply, uint8_t, reply->vp_length);
+ memset(p, 0, reply->vp_length);
+
+ p[1] = 0x01; /* NT hash */
+
+ rcode = mschap_ntpwdhash(nthash, password);
+ if (rcode < 0) return 0;
+
+ smbdes_mschap(nthash, challenge->vp_octets, p + 26);
+ return 1;
+}
+
+
+static int getport(char const *name)
+{
+ struct servent *svp;
+
+ svp = getservbyname(name, "udp");
+ if (!svp) return 0;
+
+ return ntohs(svp->s_port);
+}
+
+/*
+ * Set a port from the request type if we don't already have one
+ */
+static void radclient_get_port(PW_CODE type, uint16_t *port)
+{
+ switch (type) {
+ default:
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_STATUS_SERVER:
+ if (*port == 0) *port = getport("radius");
+ if (*port == 0) *port = PW_AUTH_UDP_PORT;
+ return;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (*port == 0) *port = getport("radacct");
+ if (*port == 0) *port = PW_ACCT_UDP_PORT;
+ return;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ if (*port == 0) *port = PW_POD_UDP_PORT;
+ return;
+
+ case PW_CODE_COA_REQUEST:
+ if (*port == 0) *port = PW_COA_UDP_PORT;
+ return;
+
+ case PW_CODE_UNDEFINED:
+ if (*port == 0) *port = 0;
+ return;
+ }
+}
+
+/*
+ * Resolve a port to a request type
+ */
+static PW_CODE radclient_get_code(uint16_t port)
+{
+ /*
+ * getport returns 0 if the service doesn't exist
+ * so we need to return early, to avoid incorrect
+ * codes.
+ */
+ if (port == 0) return PW_CODE_UNDEFINED;
+
+ if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
+ return PW_CODE_ACCESS_REQUEST;
+ }
+ if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
+ return PW_CODE_ACCOUNTING_REQUEST;
+ }
+ if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
+ if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
+
+ return PW_CODE_UNDEFINED;
+}
+
+
+static bool already_hex(VALUE_PAIR *vp)
+{
+ size_t i;
+
+ if (!vp || (vp->da->type != PW_TYPE_OCTETS)) return true;
+
+ /*
+ * If it's 17 octets, it *might* be already encoded.
+ * Or, it might just be a 17-character password (maybe UTF-8)
+ * Check it for non-printable characters. The odds of ALL
+ * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
+ * or 1/(2^51), which is pretty much zero.
+ */
+ for (i = 0; i < vp->vp_length; i++) {
+ if (vp->vp_octets[i] < 32) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/*
+ * Initialize a radclient data structure and add it to
+ * the global linked list.
+ */
+static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
+{
+ FILE *packets, *filters = NULL;
+
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ rc_request_t *request;
+ bool packets_done = false;
+ uint64_t num = 0;
+
+ assert(files->packets != NULL);
+
+ /*
+ * Determine where to read the VP's from.
+ */
+ if (strcmp(files->packets, "-") != 0) {
+ packets = fopen(files->packets, "r");
+ if (!packets) {
+ ERROR("Error opening %s: %s", files->packets, strerror(errno));
+ return 0;
+ }
+
+ /*
+ * Read in the pairs representing the expected response.
+ */
+ if (files->filters) {
+ filters = fopen(files->filters, "r");
+ if (!filters) {
+ ERROR("Error opening %s: %s", files->filters, strerror(errno));
+ fclose(packets);
+ return 0;
+ }
+ }
+ } else {
+ packets = stdin;
+ }
+
+
+ /*
+ * Loop until the file is done.
+ */
+ do {
+ /*
+ * Allocate it.
+ */
+ request = talloc_zero(ctx, rc_request_t);
+ if (!request) {
+ ERROR("Out of memory");
+ goto error;
+ }
+
+ request->packet = rad_alloc(request, true);
+ if (!request->packet) {
+ ERROR("Out of memory");
+ goto error;
+ }
+
+ request->packet->src_ipaddr = client_ipaddr;
+ request->packet->src_port = client_port;
+ request->packet->dst_ipaddr = server_ipaddr;
+ request->packet->dst_port = server_port;
+#ifdef WITH_TCP
+ request->packet->proto = ipproto;
+#endif
+
+ request->files = files;
+ request->packet->id = -1; /* allocate when sending */
+ request->num = num++;
+
+ /*
+ * Read the request VP's.
+ */
+ if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, packets, &packets_done) < 0) {
+ char const *input;
+
+ if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
+ input = "stdin";
+ } else {
+ input = files->packets;
+ }
+
+ REDEBUG("Error parsing \"%s\"", input);
+ goto error;
+ }
+
+ /*
+ * Skip empty entries
+ */
+ if (!request->packet->vps) {
+ talloc_free(request);
+ continue;
+ }
+
+ /*
+ * Read in filter VP's.
+ */
+ if (filters) {
+ bool filters_done;
+
+ if (fr_pair_list_afrom_file(request, &request->filter, filters, &filters_done) < 0) {
+ REDEBUG("Error parsing \"%s\"", files->filters);
+ goto error;
+ }
+
+ if (filters_done && !packets_done) {
+ REDEBUG("Differing number of packets/filters in %s:%s "
+ "(too many requests))", files->packets, files->filters);
+ goto error;
+ }
+
+ if (!filters_done && packets_done) {
+ REDEBUG("Differing number of packets/filters in %s:%s "
+ "(too many filters))", files->packets, files->filters);
+ goto error;
+ }
+
+ /*
+ * xlat expansions aren't supported here
+ */
+ for (vp = fr_cursor_init(&cursor, &request->filter);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ }
+
+ if (vp->da->vendor == 0 ) switch (vp->da->attr) {
+ case PW_RESPONSE_PACKET_TYPE:
+ case PW_PACKET_TYPE:
+ fr_cursor_remove(&cursor); /* so we don't break the filter */
+ request->filter_code = vp->vp_integer;
+ talloc_free(vp);
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * This allows efficient list comparisons later
+ */
+ fr_pair_list_sort(&request->filter, fr_pair_cmp_by_da_tag);
+ }
+
+ /*
+ * Process special attributes
+ */
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Double quoted strings get marked up as xlat expansions,
+ * but we don't support that in request.
+ */
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ }
+
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ default:
+ break;
+
+ /*
+ * Allow it to set the packet type in
+ * the attributes read from the file.
+ */
+ case PW_PACKET_TYPE:
+ request->packet->code = vp->vp_integer;
+ break;
+
+ case PW_RESPONSE_PACKET_TYPE:
+ request->filter_code = vp->vp_integer;
+ break;
+
+ case PW_PACKET_DST_PORT:
+ request->packet->dst_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_DST_IP_ADDRESS:
+ request->packet->dst_ipaddr.af = AF_INET;
+ request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->dst_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_DST_IPV6_ADDRESS:
+ request->packet->dst_ipaddr.af = AF_INET6;
+ request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->dst_ipaddr.prefix = 128;
+ break;
+
+ case PW_PACKET_SRC_PORT:
+ if ((vp->vp_integer < 1024) ||
+ (vp->vp_integer > 65535)) {
+ ERROR("Invalid value '%u' for Packet-Src-Port", vp->vp_integer);
+ goto error;
+ }
+ request->packet->src_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_SRC_IP_ADDRESS:
+ request->packet->src_ipaddr.af = AF_INET;
+ request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->src_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_SRC_IPV6_ADDRESS:
+ request->packet->src_ipaddr.af = AF_INET6;
+ request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->src_ipaddr.prefix = 128;
+ break;
+
+ case PW_DIGEST_REALM:
+ case PW_DIGEST_NONCE:
+ case PW_DIGEST_METHOD:
+ case PW_DIGEST_URI:
+ case PW_DIGEST_QOP:
+ case PW_DIGEST_ALGORITHM:
+ case PW_DIGEST_BODY_DIGEST:
+ case PW_DIGEST_CNONCE:
+ case PW_DIGEST_NONCE_COUNT:
+ case PW_DIGEST_USER_NAME:
+ /* overlapping! */
+ {
+ DICT_ATTR const *da;
+ uint8_t *p, *q;
+
+ p = talloc_array(vp, uint8_t, vp->vp_length + 2);
+
+ memcpy(p + 2, vp->vp_octets, vp->vp_length);
+ p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
+ vp->vp_length += 2;
+ p[1] = vp->vp_length;
+
+ da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
+ if (!da) {
+ ERROR("Out of memory");
+ goto error;
+ }
+ vp->da = da;
+
+ /*
+ * Re-do fr_pair_value_memsteal ourselves,
+ * because we play games with
+ * vp->da, and fr_pair_value_memsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
+ }
+ break;
+
+ /*
+ * Cache this for later.
+ */
+ case PW_CLEARTEXT_PASSWORD:
+ request->password = vp;
+ break;
+
+ /*
+ * Keep a copy of the the password attribute.
+ */
+ case PW_CHAP_PASSWORD:
+ /*
+ * If it's already hex, do nothing.
+ */
+ if ((vp->vp_length == 17) &&
+ (already_hex(vp))) break;
+
+ /*
+ * CHAP-Password is octets, so it may not be zero terminated.
+ */
+ request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
+ "", T_OP_EQ);
+ fr_pair_value_bstrncpy(request->password, vp->vp_strvalue, vp->vp_length);
+ break;
+
+ case PW_USER_PASSWORD:
+ case PW_MS_CHAP_PASSWORD:
+ request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
+ vp->vp_strvalue, T_OP_EQ);
+ break;
+
+ case PW_RADCLIENT_TEST_NAME:
+ request->name = vp->vp_strvalue;
+ break;
+ }
+ } /* loop over the VP's we read in */
+
+ /*
+ * Use the default set on the command line
+ */
+ if (request->packet->code == PW_CODE_UNDEFINED) request->packet->code = packet_code;
+
+ /*
+ * Default to the filename
+ */
+ if (!request->name) request->name = request->files->packets;
+
+ /*
+ * Automatically set the response code from the request code
+ * (if one wasn't already set).
+ */
+ if (request->filter_code == PW_CODE_UNDEFINED) {
+ switch (request->packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ request->filter_code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ request->filter_code = PW_CODE_COA_ACK;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ request->filter_code = PW_CODE_DISCONNECT_ACK;
+ break;
+
+ case PW_CODE_STATUS_SERVER:
+ switch (radclient_get_code(request->packet->dst_port)) {
+ case PW_CODE_ACCESS_REQUEST:
+ request->filter_code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ default:
+ request->filter_code = PW_CODE_UNDEFINED;
+ break;
+ }
+ break;
+
+ case PW_CODE_UNDEFINED:
+ REDEBUG("Both Packet-Type and Response-Packet-Type undefined, specify at least one, "
+ "or a well known RADIUS port");
+ goto error;
+
+ default:
+ REDEBUG("Can't determine expected Response-Packet-Type for Packet-Type %i",
+ request->packet->code);
+ goto error;
+ }
+ /*
+ * Automatically set the request code from the response code
+ * (if one wasn't already set).
+ */
+ } else if (request->packet->code == PW_CODE_UNDEFINED) {
+ switch (request->filter_code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ request->packet->code = PW_CODE_ACCESS_REQUEST;
+ break;
+
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ request->packet->code = PW_CODE_ACCOUNTING_REQUEST;
+ break;
+
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ request->packet->code = PW_CODE_DISCONNECT_REQUEST;
+ break;
+
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ request->packet->code = PW_CODE_COA_REQUEST;
+ break;
+
+ default:
+ REDEBUG("Can't determine expected Packet-Type for Response-Packet-Type %i",
+ request->filter_code);
+ goto error;
+ }
+ }
+
+ /*
+ * Automatically set the dst port (if one wasn't already set).
+ */
+ if (request->packet->dst_port == 0) {
+ radclient_get_port(request->packet->code, &request->packet->dst_port);
+ if (request->packet->dst_port == 0) {
+ REDEBUG("Can't determine destination port");
+ goto error;
+ }
+ }
+
+ /*
+ * Add it to the tail of the list.
+ */
+ if (!request_head) {
+ assert(rc_request_tail == NULL);
+ request_head = request;
+ request->prev = NULL;
+ } else {
+ assert(rc_request_tail->next == NULL);
+ rc_request_tail->next = request;
+ request->prev = rc_request_tail;
+ }
+ rc_request_tail = request;
+ request->next = NULL;
+
+ /*
+ * Set the destructor so it removes itself from the
+ * request list when freed. We don't set this until
+ * the packet is actually in the list, else we trigger
+ * the asserts in the free callback.
+ */
+ talloc_set_destructor(request, _rc_request_free);
+ } while (!packets_done); /* loop until the file is done. */
+
+ if (packets != stdin) fclose(packets);
+ if (filters) fclose(filters);
+
+ /*
+ * And we're done.
+ */
+ return 1;
+
+error:
+ talloc_free(request);
+
+ if (packets != stdin) fclose(packets);
+ if (filters) fclose(filters);
+
+ return 0;
+}
+
+
+/*
+ * Sanity check each argument.
+ */
+static int radclient_sane(rc_request_t *request)
+{
+ if (request->packet->dst_port == 0) {
+ request->packet->dst_port = server_port;
+ }
+ if (request->packet->dst_ipaddr.af == AF_UNSPEC) {
+ if (server_ipaddr.af == AF_UNSPEC) {
+ ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
+ "Packet-Dst-IP-Address", request->num, request->files->packets);
+ return -1;
+ }
+ request->packet->dst_ipaddr = server_ipaddr;
+ }
+ if (request->packet->code == 0) {
+ if (packet_code == -1) {
+ ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
+ request->num, request->files->packets);
+ return -1;
+ }
+ request->packet->code = packet_code;
+ }
+ request->packet->sockfd = -1;
+
+ return 0;
+}
+
+
+/*
+ * For request handling.
+ */
+static int filename_cmp(void const *one, void const *two)
+{
+ int cmp;
+
+ rc_file_pair_t const *a = one;
+ rc_file_pair_t const *b = two;
+
+ cmp = strcmp(a->packets, b->packets);
+ if (cmp != 0) return cmp;
+
+ return strcmp(a->filters, b->filters);
+}
+
+static int filename_walk(UNUSED void *context, void *data)
+{
+ rc_file_pair_t *files = data;
+
+ /*
+ * Read request(s) from the file.
+ */
+ if (!radclient_init(files, files)) return -1; /* stop walking */
+
+ return 0;
+}
+
+
+/*
+ * Deallocate packet ID, etc.
+ */
+static void deallocate_id(rc_request_t *request)
+{
+ if (!request || !request->packet ||
+ (request->packet->id < 0)) {
+ return;
+ }
+
+ /*
+ * One more unused RADIUS ID.
+ */
+ fr_packet_list_id_free(pl, request->packet, true);
+
+ /*
+ * If we've already sent a packet, free up the old one,
+ * and ensure that the next packet has a unique
+ * authentication vector.
+ */
+ if (request->packet->data) TALLOC_FREE(request->packet->data);
+ if (request->reply) rad_free(&request->reply);
+}
+
+/*
+ * Send one packet.
+ */
+static int send_one_packet(rc_request_t *request)
+{
+ assert(request->done == false);
+
+ /*
+ * Remember when we have to wake up, to re-send the
+ * request, of we didn't receive a reply.
+ */
+ if ((sleep_time == -1) || (sleep_time > (int) timeout)) sleep_time = (int) timeout;
+
+ /*
+ * Haven't sent the packet yet. Initialize it.
+ */
+ if (request->packet->id == -1) {
+ int i;
+ bool rcode;
+
+ assert(request->reply == NULL);
+
+ /*
+ * Didn't find a free packet ID, we're not done,
+ * we don't sleep, and we stop trying to process
+ * this packet.
+ */
+ retry:
+ request->packet->src_ipaddr.af = server_ipaddr.af;
+ rcode = fr_packet_list_id_alloc(pl, ipproto, &request->packet, NULL);
+ if (!rcode) {
+ int mysockfd;
+
+#ifdef WITH_TCP
+ if (proto) {
+ mysockfd = fr_socket_client_tcp(NULL,
+ &request->packet->dst_ipaddr,
+ request->packet->dst_port, false);
+ if (mysockfd < 0) {
+ ERROR("Failed opening socket");
+ exit(1);
+ }
+ } else
+#endif
+ {
+ mysockfd = fr_socket(&client_ipaddr, 0);
+ if (mysockfd < 0) {
+ ERROR("Failed opening socket");
+ exit(1);
+ }
+
+#ifdef WITH_UDPFROMTO
+ if (udpfromto_init(mysockfd) < 0) {
+ ERROR("Failed initializing socket");
+ exit(1);
+ }
+#endif
+ }
+ if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
+#ifdef WITH_RADIUSV11
+ false,
+#endif
+ &request->packet->dst_ipaddr,
+ request->packet->dst_port, NULL)) {
+ ERROR("Can't add new socket");
+ exit(1);
+ }
+ goto retry;
+ }
+
+ assert(request->packet->id != -1);
+ assert(request->packet->data == NULL);
+
+ for (i = 0; i < 4; i++) {
+ ((uint32_t *) request->packet->vector)[i] = fr_rand();
+ }
+
+ /*
+ * Update the password, so it can be encrypted with the
+ * new authentication vector.
+ */
+ if (request->password) {
+ VALUE_PAIR *vp;
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
+ fr_pair_value_strcpy(vp, request->password->vp_strvalue);
+
+ } else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
+ uint8_t buffer[17];
+
+ rad_chap_encode(request->packet, buffer, fr_rand() & 0xff, request->password);
+ fr_pair_value_memcpy(vp, buffer, 17);
+
+ } else if (fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
+ mschapv1_encode(request->packet, &request->packet->vps, request->password->vp_strvalue);
+
+ } else {
+ DEBUG("WARNING: No password in the request");
+ }
+ }
+
+ request->timestamp = time(NULL);
+ request->tries = 1;
+ request->resend++;
+
+ } else { /* request->packet->id >= 0 */
+ time_t now = time(NULL);
+
+ /*
+ * FIXME: Accounting packets are never retried!
+ * The Acct-Delay-Time attribute is updated to
+ * reflect the delay, and the packet is re-sent
+ * from scratch!
+ */
+
+ /*
+ * Not time for a retry, do so.
+ */
+ if ((now - request->timestamp) < timeout) {
+ /*
+ * When we walk over the tree sending
+ * packets, we update the minimum time
+ * required to sleep.
+ */
+ if ((sleep_time == -1) ||
+ (sleep_time > (now - request->timestamp))) {
+ sleep_time = now - request->timestamp;
+ }
+ return 0;
+ }
+
+ /*
+ * We're not trying later, maybe the packet is done.
+ */
+ if (request->tries == retries) {
+ assert(request->packet->id >= 0);
+
+ /*
+ * Delete the request from the tree of
+ * outstanding requests.
+ */
+ fr_packet_list_yank(pl, request->packet);
+
+ RDEBUG("No reply from server for ID %d socket %d",
+ request->packet->id, request->packet->sockfd);
+ deallocate_id(request);
+
+ /*
+ * Normally we mark it "done" when we've received
+ * the reply, but this is a special case.
+ */
+ if (request->resend == resend_count) {
+ request->done = true;
+ }
+ stats.lost++;
+ return -1;
+ }
+
+ /*
+ * We are trying later.
+ */
+ request->timestamp = now;
+ request->tries++;
+ }
+
+ /*
+ * Send the packet.
+ */
+ if (rad_send(request->packet, NULL, secret) < 0) {
+ REDEBUG("Failed to send packet for ID %d", request->packet->id);
+ deallocate_id(request);
+ request->done = true;
+ return -1;
+ }
+
+ if (fr_log_fp) {
+ fr_packet_header_print(fr_log_fp, request->packet, false);
+ if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, request->packet->vps);
+ }
+
+ return 0;
+}
+
+/*
+ * Receive one packet, maybe.
+ */
+static int recv_one_packet(int wait_time)
+{
+ fd_set set;
+ struct timeval tv;
+ rc_request_t *request;
+ RADIUS_PACKET *reply, **packet_p;
+ volatile int max_fd;
+
+ /* And wait for reply, timing out as necessary */
+ FD_ZERO(&set);
+
+ max_fd = fr_packet_list_fd_set(pl, &set);
+ if (max_fd < 0) exit(1); /* no sockets to listen on! */
+
+ tv.tv_sec = (wait_time <= 0) ? 0 : wait_time;
+ tv.tv_usec = 0;
+
+ /*
+ * No packet was received.
+ */
+ if (select(max_fd, &set, NULL, NULL, &tv) <= 0) return 0;
+
+ /*
+ * Look for the packet.
+ */
+ reply = fr_packet_list_recv(pl, &set);
+ if (!reply) {
+ ERROR("Received bad packet");
+#ifdef WITH_TCP
+ /*
+ * If the packet is bad, we close the socket.
+ * I'm not sure how to do that now, so we just
+ * die...
+ */
+ if (proto) exit(1);
+#endif
+ return -1; /* bad packet */
+ }
+
+ packet_p = fr_packet_list_find_byreply(pl, reply);
+ if (!packet_p) {
+ ERROR("Received reply to request we did not send. (id=%d socket %d)",
+ reply->id, reply->sockfd);
+ rad_free(&reply);
+ return -1; /* got reply to packet we didn't send */
+ }
+ request = fr_packet2myptr(rc_request_t, packet, packet_p);
+
+ /*
+ * Fails the signature validation: not a real reply.
+ * FIXME: Silently drop it and listen for another packet.
+ */
+ if (rad_verify(reply, request->packet, secret) < 0) {
+ REDEBUG("Reply verification failed");
+ stats.lost++;
+ goto packet_done; /* shared secret is incorrect */
+ }
+
+ if (print_filename) {
+ RDEBUG("%s response code %d", request->files->packets, reply->code);
+ }
+
+ deallocate_id(request);
+ request->reply = reply;
+ reply = NULL;
+
+ /*
+ * If this fails, we're out of memory.
+ */
+ if (rad_decode(request->reply, request->packet, secret) != 0) {
+ REDEBUG("Reply decode failed");
+ stats.lost++;
+ goto packet_done;
+ }
+
+ if (fr_log_fp) {
+ fr_packet_header_print(fr_log_fp, request->reply, true);
+ if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, request->reply->vps);
+ }
+
+ /*
+ * Increment counters...
+ */
+ switch (request->reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_DISCONNECT_ACK:
+ stats.accepted++;
+ break;
+
+ case PW_CODE_ACCESS_CHALLENGE:
+ break;
+
+ default:
+ stats.rejected++;
+ }
+
+ /*
+ * If we had an expected response code, check to see if the
+ * packet matched that.
+ */
+ if ((request->filter_code != PW_CODE_UNDEFINED) && (request->reply->code != request->filter_code)) {
+ fr_strerror_printf(NULL);
+
+ if (is_radius_code(request->reply->code)) {
+ REDEBUG("%s: Expected %s got %s", request->name, fr_packet_codes[request->filter_code],
+ fr_packet_codes[request->reply->code]);
+ } else {
+ REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
+ request->reply->code);
+ }
+ stats.failed++;
+ /*
+ * Check if the contents of the packet matched the filter
+ */
+ } else if (!request->filter) {
+ stats.passed++;
+ } else {
+ VALUE_PAIR const *failed[2];
+
+ fr_pair_list_sort(&request->reply->vps, fr_pair_cmp_by_da_tag);
+ if (fr_pair_validate(failed, request->filter, request->reply->vps)) {
+ RDEBUG("%s: Response passed filter", request->name);
+ stats.passed++;
+ } else {
+ fr_pair_validate_debug(request, failed);
+ REDEBUG("%s: Response for failed filter", request->name);
+ stats.failed++;
+ }
+ }
+
+ if (request->resend == resend_count) {
+ request->done = true;
+ }
+
+packet_done:
+ rad_free(&request->reply);
+ rad_free(&reply); /* may be NULL */
+
+ return 0;
+}
+
+DIAG_OFF(deprecated-declarations)
+int main(int argc, char **argv)
+{
+ int c;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
+ char filesecret[256];
+ FILE *fp;
+ int do_summary = false;
+ int persec = 0;
+ int parallel = 1;
+ rc_request_t *this;
+ int force_af = AF_UNSPEC;
+
+ /*
+ * It's easier having two sets of flags to set the
+ * verbosity of library calls and the verbosity of
+ * radclient.
+ */
+ fr_debug_lvl = 0;
+ fr_log_fp = stdout;
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radclient");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ talloc_set_log_stderr();
+
+ filename_tree = rbtree_create(NULL, filename_cmp, NULL, 0);
+ if (!filename_tree) {
+ oom:
+ ERROR("Out of memory");
+ exit(1);
+ }
+
+ while ((c = getopt(argc, argv, "46c:d:D:f:Fhn:p:qr:sS:t:vx"
+#ifdef WITH_TCP
+ "P:"
+#endif
+ )) != EOF) switch (c) {
+ case '4':
+ force_af = AF_INET;
+ break;
+
+ case '6':
+ force_af = AF_INET6;
+ break;
+
+ case 'c':
+ if (!isdigit((uint8_t) *optarg)) usage();
+
+ resend_count = atoi(optarg);
+
+ if (resend_count < 1) usage();
+ break;
+
+ case 'D':
+ dict_dir = optarg;
+ break;
+
+ case 'd':
+ radius_dir = optarg;
+ break;
+
+ case 'f':
+ {
+ char const *p;
+ rc_file_pair_t *files;
+
+ files = talloc(talloc_autofree_context(), rc_file_pair_t);
+ if (!files) goto oom;
+
+ p = strchr(optarg, ':');
+ if (p) {
+ files->packets = talloc_strndup(files, optarg, p - optarg);
+ if (!files->packets) goto oom;
+ files->filters = p + 1;
+ } else {
+ files->packets = optarg;
+ files->filters = NULL;
+ }
+ rbtree_insert(filename_tree, (void *) files);
+ }
+ break;
+
+ case 'F':
+ print_filename = true;
+ break;
+
+ case 'n':
+ persec = atoi(optarg);
+ if (persec <= 0) usage();
+ break;
+
+ /*
+ * Note that sending MANY requests in
+ * parallel can over-run the kernel
+ * queues, and Linux will happily discard
+ * packets. So even if the server responds,
+ * the client may not see the reply.
+ */
+ case 'p':
+ parallel = atoi(optarg);
+ if (parallel <= 0) usage();
+ break;
+
+#ifdef WITH_TCP
+ case 'P':
+ proto = optarg;
+ if (strcmp(proto, "tcp") != 0) {
+ if (strcmp(proto, "udp") == 0) {
+ proto = NULL;
+ } else {
+ usage();
+ }
+ } else {
+ ipproto = IPPROTO_TCP;
+ }
+ break;
+
+#endif
+
+ case 'q':
+ do_output = false;
+ fr_log_fp = NULL; /* no output from you, either! */
+ break;
+
+ case 'r':
+ if (!isdigit((uint8_t) *optarg)) usage();
+ retries = atoi(optarg);
+ if ((retries == 0) || (retries > 1000)) usage();
+ break;
+
+ case 's':
+ do_summary = true;
+ break;
+
+ case 'S':
+ {
+ char *p;
+ fp = fopen(optarg, "r");
+ if (!fp) {
+ ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
+ exit(1);
+ }
+ if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
+ ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
+ exit(1);
+ }
+ fclose(fp);
+
+ /* truncate newline */
+ p = filesecret + strlen(filesecret) - 1;
+ while ((p >= filesecret) &&
+ (*p < ' ')) {
+ *p = '\0';
+ --p;
+ }
+
+ if (strlen(filesecret) < 2) {
+ ERROR("Secret in %s is too short", optarg);
+ exit(1);
+ }
+ secret = filesecret;
+ }
+ break;
+
+ case 't':
+ if (!isdigit((uint8_t) *optarg))
+ usage();
+ timeout = atof(optarg);
+ break;
+
+ case 'v':
+ fr_debug_lvl = 1;
+ DEBUG("%s", radclient_version);
+ exit(0);
+
+ case 'x':
+ fr_debug_lvl++;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
+ ERROR("Insufficient arguments");
+ usage();
+ }
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radclient");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radclient");
+ return 1;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radclient");
+ return 1;
+ }
+ fr_strerror(); /* Clear the error buffer */
+
+ /*
+ * Get the request type
+ */
+ if (!isdigit((uint8_t) argv[2][0])) {
+ packet_code = fr_str2int(request_types, argv[2], -2);
+ if (packet_code == -2) {
+ ERROR("Unrecognised request type \"%s\"", argv[2]);
+ usage();
+ }
+ } else {
+ packet_code = atoi(argv[2]);
+ }
+
+ /*
+ * Resolve hostname.
+ */
+ if (strcmp(argv[1], "-") != 0) {
+ if (fr_pton_port(&server_ipaddr, &server_port, argv[1], -1, force_af, true) < 0) {
+ ERROR("%s", fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * Work backwards from the port to determine the packet type
+ */
+ if (packet_code == PW_CODE_UNDEFINED) packet_code = radclient_get_code(server_port);
+ }
+ radclient_get_port(packet_code, &server_port);
+
+ /*
+ * Add the secret.
+ */
+ if (argv[3]) secret = argv[3];
+
+ /*
+ * If no '-f' is specified, we're reading from stdin.
+ */
+ if (rbtree_num_elements(filename_tree) == 0) {
+ rc_file_pair_t *files;
+
+ files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
+ files->packets = "-";
+ if (!radclient_init(files, files)) {
+ exit(1);
+ }
+ }
+
+ /*
+ * Walk over the list of filenames, creating the requests.
+ */
+ if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) {
+ ERROR("Failed parsing input files");
+ exit(1);
+ }
+
+ /*
+ * No packets read. Die.
+ */
+ if (!request_head) {
+ ERROR("Nothing to send");
+ exit(1);
+ }
+
+ openssl3_init();
+
+ /*
+ * Bind to the first specified IP address and port.
+ * This means we ignore later ones.
+ */
+ if (request_head->packet->src_ipaddr.af == AF_UNSPEC) {
+ memset(&client_ipaddr, 0, sizeof(client_ipaddr));
+ client_ipaddr.af = server_ipaddr.af;
+ } else {
+ client_ipaddr = request_head->packet->src_ipaddr;
+ }
+
+ client_port = request_head->packet->src_port;
+
+#ifdef WITH_TCP
+ if (proto) {
+ sockfd = fr_socket_client_tcp(NULL, &server_ipaddr, server_port, false);
+ if (sockfd < 0) {
+ ERROR("Error opening socket");
+ exit(1);
+ }
+ } else
+#endif
+ {
+ sockfd = fr_socket(&client_ipaddr, client_port);
+ if (sockfd < 0) {
+ ERROR("Error opening socket");
+ exit(1);
+ }
+
+#ifdef WITH_UDPFROMTO
+ if (udpfromto_init(sockfd) < 0) {
+ ERROR("Failed initializing socket");
+ exit(1);
+ }
+#endif
+ }
+
+ pl = fr_packet_list_create(1);
+ if (!pl) {
+ ERROR("Out of memory");
+ exit(1);
+ }
+
+ if (!fr_packet_list_socket_add(pl, sockfd, ipproto,
+#ifdef WITH_RADIUSV11
+ false,
+#endif
+ &server_ipaddr, server_port, NULL)) {
+ ERROR("Out of memory");
+ exit(1);
+ }
+
+ /*
+ * Walk over the list of packets, sanity checking
+ * everything.
+ */
+ for (this = request_head; this != NULL; this = this->next) {
+ this->packet->src_ipaddr = client_ipaddr;
+ this->packet->src_port = client_port;
+ if (radclient_sane(this) != 0) {
+ exit(1);
+ }
+ }
+
+ /*
+ * Walk over the packets to send, until
+ * we're all done.
+ *
+ * FIXME: This currently busy-loops until it receives
+ * all of the packets. It should really have some sort of
+ * send packet, get time to wait, select for time, etc.
+ * loop.
+ */
+ do {
+ int n = parallel;
+ rc_request_t *next;
+ char const *filename = NULL;
+
+ done = true;
+ sleep_time = -1;
+
+ /*
+ * Walk over the packets, sending them.
+ */
+
+ for (this = request_head; this != NULL; this = next) {
+ next = this->next;
+
+ /*
+ * If there's a packet to receive,
+ * receive it, but don't wait for a
+ * packet.
+ */
+ recv_one_packet(0);
+
+ /*
+ * This packet is done. Delete it.
+ */
+ if (this->done) {
+ talloc_free(this);
+ continue;
+ }
+
+ /*
+ * Packets from multiple '-f' are sent
+ * in parallel.
+ *
+ * Packets from one file are sent in
+ * series, unless '-p' is specified, in
+ * which case N packets from each file
+ * are sent in parallel.
+ */
+ if (this->files->packets != filename) {
+ filename = this->files->packets;
+ n = parallel;
+ }
+
+ if (n > 0) {
+ n--;
+
+ /*
+ * Send the current packet.
+ */
+ if (send_one_packet(this) < 0) {
+ talloc_free(this);
+ break;
+ }
+
+ /*
+ * Wait a little before sending
+ * the next packet, if told to.
+ */
+ if (persec) {
+ struct timeval tv;
+
+ /*
+ * Don't sleep elsewhere.
+ */
+ sleep_time = 0;
+
+ if (persec == 1) {
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ } else {
+ tv.tv_sec = 0;
+ tv.tv_usec = 1000000/persec;
+ }
+
+ /*
+ * Sleep for milliseconds,
+ * portably.
+ *
+ * If we get an error or
+ * a signal, treat it like
+ * a normal timeout.
+ */
+ select(0, NULL, NULL, NULL, &tv);
+ }
+
+ /*
+ * If we haven't sent this packet
+ * often enough, we're not done,
+ * and we shouldn't sleep.
+ */
+ if (this->resend < resend_count) {
+ done = false;
+ sleep_time = 0;
+ }
+ } else { /* haven't sent this packet, we're not done */
+ assert(this->done == false);
+ assert(this->reply == NULL);
+ done = false;
+ }
+ }
+
+ /*
+ * Still have outstanding requests.
+ */
+ if (fr_packet_list_num_elements(pl) > 0) {
+ done = false;
+ } else {
+ sleep_time = 0;
+ }
+
+ /*
+ * Nothing to do until we receive a request, so
+ * sleep until then. Once we receive one packet,
+ * we go back, and walk through the whole list again,
+ * sending more packets (if necessary), and updating
+ * the sleep time.
+ */
+ if (!done && (sleep_time > 0)) {
+ recv_one_packet(sleep_time);
+ }
+ } while (!done);
+
+ rbtree_free(filename_tree);
+ fr_packet_list_free(pl);
+ while (request_head) TALLOC_FREE(request_head);
+ dict_free();
+
+ if (do_summary) {
+ printf("Packet summary:\n"
+ "\tAccepted : %" PRIu64 "\n"
+ "\tRejected : %" PRIu64 "\n"
+ "\tLost : %" PRIu64 "\n"
+ "\tPassed filter : %" PRIu64 "\n"
+ "\tFailed filter : %" PRIu64 "\n",
+ stats.accepted,
+ stats.rejected,
+ stats.lost,
+ stats.passed,
+ stats.failed
+ );
+ }
+
+ if ((stats.lost > 0) || (stats.failed > 0)) {
+ exit(1);
+ }
+
+ openssl3_free();
+
+ exit(0);
+}
+DIAG_ON(deprecated-declarations)
diff --git a/src/main/radclient.mk b/src/main/radclient.mk
new file mode 100644
index 0000000..0db0a8a
--- /dev/null
+++ b/src/main/radclient.mk
@@ -0,0 +1,8 @@
+TARGET := radclient
+SOURCES := radclient.c ${top_srcdir}/src/modules/rlm_mschap/smbdes.c \
+ ${top_srcdir}/src/modules/rlm_mschap/mschap.c
+
+TGT_PREREQS := libfreeradius-radius.a
+
+SRC_CFLAGS := -I${top_srcdir}/src/modules/rlm_mschap
+TGT_LDLIBS := $(LIBS)
diff --git a/src/main/radiusd.c b/src/main/radiusd.c
new file mode 100644
index 0000000..f2acec7
--- /dev/null
+++ b/src/main/radiusd.c
@@ -0,0 +1,794 @@
+/*
+ * radiusd.c Main loop of the radius server.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2019 The FreeRADIUS server project
+ * Copyright 1999,2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ * Copyright 2000 Alan Curry <pacman-radius@cqc.com>
+ * Copyright 2000 Jeff Carneal <jeff@apex.net>
+ * Copyright 2000 Chad Miller <cmiller@surfsouth.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/state.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/autoconf.h>
+
+#include <sys/file.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#ifdef HAVE_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+
+/*
+ * Global variables.
+ */
+char const *radacct_dir = NULL;
+char const *radlog_dir = NULL;
+
+bool log_stripped_names;
+
+char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+", for host " HOSTINFO
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+static pid_t radius_pid;
+
+/*
+ * Configuration items.
+ */
+
+/*
+ * Static functions.
+ */
+static void usage(int);
+
+static void sig_fatal (int);
+#ifdef SIGHUP
+static void sig_hup (int);
+#endif
+
+/*
+ * The main guy.
+ */
+int main(int argc, char *argv[])
+{
+ int rcode = EXIT_SUCCESS;
+ int status;
+ int argval;
+ bool spawn_flag = true;
+ bool display_version = false;
+ int flag = 0;
+ int from_child[2] = {-1, -1};
+ char *p;
+ fr_state_t *state = NULL;
+
+ /*
+ * We probably don't want to free the talloc autofree context
+ * directly, so we'll allocate a new context beneath it, and
+ * free that before any leak reports.
+ */
+ TALLOC_CTX *autofree = talloc_init("main");
+
+#ifdef OSFC2
+ set_auth_parameters(argc, argv);
+#endif
+
+#ifdef WIN32
+ {
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ fprintf(stderr, "%s: Unable to initialize socket library.\n",
+ main_config.name);
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
+ rad_debug_lvl = 0;
+ set_radius_dir(autofree, RADIUS_DIR);
+
+ /*
+ * Ensure that the configuration is initialized.
+ */
+ memset(&main_config, 0, sizeof(main_config));
+ main_config.myip.af = AF_UNSPEC;
+ main_config.port = 0;
+ main_config.daemonize = true;
+
+ p = strrchr(argv[0], FR_DIR_SEP);
+ if (!p) {
+ main_config.name = argv[0];
+ } else {
+ main_config.name = p + 1;
+ }
+
+ /*
+ * Don't put output anywhere until we get told a little
+ * more.
+ */
+ default_log.dst = L_DST_NULL;
+ default_log.fd = -1;
+ main_config.log_file = NULL;
+
+ /* Process the options. */
+ while ((argval = getopt(argc, argv, "Cd:D:fhi:l:mMn:p:PstvxX")) != EOF) {
+
+ switch (argval) {
+ case 'C':
+ check_config = true;
+ spawn_flag = false;
+ main_config.daemonize = false;
+ break;
+
+ case 'd':
+ set_radius_dir(autofree, optarg);
+ break;
+
+ case 'D':
+ main_config.dictionary_dir = talloc_typed_strdup(autofree, optarg);
+ break;
+
+ case 'f':
+ main_config.daemonize = false;
+ break;
+
+ case 'h':
+ usage(0);
+ break;
+
+ case 'l':
+ if (strcmp(optarg, "stdout") == 0) {
+ goto do_stdout;
+ }
+ main_config.log_file = strdup(optarg);
+ default_log.dst = L_DST_FILES;
+ default_log.fd = open(main_config.log_file,
+ O_WRONLY | O_APPEND | O_CREAT, 0640);
+ if (default_log.fd < 0) {
+ fprintf(stderr, "%s: Failed to open log file %s: %s\n",
+ main_config.name, main_config.log_file, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+ fr_log_fp = fdopen(default_log.fd, "a");
+ break;
+
+ case 'i':
+ if (ip_hton(&main_config.myip, AF_UNSPEC, optarg, false) < 0) {
+ fprintf(stderr, "%s: Invalid IP Address or hostname \"%s\"\n",
+ main_config.name, optarg);
+ exit(EXIT_FAILURE);
+ }
+ flag |= 1;
+ break;
+
+ case 'n':
+ main_config.name = optarg;
+ break;
+
+ case 'm':
+ main_config.debug_memory = true;
+ break;
+
+ case 'M':
+ main_config.memory_report = true;
+ main_config.debug_memory = true;
+ break;
+
+ case 'p':
+ {
+ unsigned long port;
+
+ port = strtoul(optarg, 0, 10);
+ if ((port == 0) || (port > UINT16_MAX)) {
+ fprintf(stderr, "%s: Invalid port number \"%s\"\n",
+ main_config.name, optarg);
+ exit(EXIT_FAILURE);
+ }
+
+ main_config.port = (uint16_t) port;
+ flag |= 2;
+ }
+ break;
+
+ case 'P':
+ /* Force the PID to be written, even in -f mode */
+ main_config.write_pid = true;
+ break;
+
+ case 's': /* Single process mode */
+ spawn_flag = false;
+ main_config.daemonize = false;
+ break;
+
+ case 't': /* no child threads */
+ spawn_flag = false;
+ break;
+
+ case 'v':
+ display_version = true;
+ break;
+
+ case 'X':
+ spawn_flag = false;
+ main_config.daemonize = false;
+ rad_debug_lvl += 2;
+ main_config.log_auth = true;
+ main_config.log_auth_badpass = true;
+ main_config.log_auth_goodpass = true;
+ do_stdout:
+ fr_log_fp = stdout;
+ default_log.dst = L_DST_STDOUT;
+ default_log.fd = STDOUT_FILENO;
+ break;
+
+ case 'x':
+ rad_debug_lvl++;
+ break;
+
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ /*
+ * Mismatch between the binary and the libraries it depends on.
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("%s", main_config.name);
+ exit(EXIT_FAILURE);
+ }
+
+ if (rad_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) exit(EXIT_FAILURE);
+
+ /*
+ * Mismatch between build time OpenSSL and linked SSL, better to die
+ * here than segfault later.
+ */
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ if (ssl_check_consistency() < 0) exit(EXIT_FAILURE);
+#endif
+
+ if (flag && (flag != 0x03)) {
+ fprintf(stderr, "%s: The options -i and -p cannot be used individually.\n",
+ main_config.name);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * According to the talloc peeps, no two threads may modify any part of
+ * a ctx tree with a common root without synchronisation.
+ *
+ * So we can't run with a null context and threads.
+ */
+ if (main_config.memory_report) {
+ if (spawn_flag) {
+ fprintf(stderr, "%s: The server cannot produce memory reports (-M) in threaded mode\n",
+ main_config.name);
+ exit(EXIT_FAILURE);
+ }
+ talloc_enable_null_tracking();
+ } else {
+ talloc_disable_null_tracking();
+ }
+
+ /*
+ * Better here, so it doesn't matter whether we get passed -xv or -vx.
+ */
+ if (display_version) {
+ if (rad_debug_lvl == 0) rad_debug_lvl = 1;
+ fr_log_fp = stdout;
+ default_log.dst = L_DST_STDOUT;
+ default_log.fd = STDOUT_FILENO;
+
+ INFO("%s: %s", main_config.name, radiusd_version);
+ version_print();
+ exit(EXIT_SUCCESS);
+ }
+
+ if (rad_debug_lvl) version_print();
+
+ /*
+ * Under linux CAP_SYS_PTRACE is usually only available before setuid/setguid,
+ * so we need to check whether we can attach before calling those functions
+ * (in main_config_init()).
+ */
+ fr_store_debug_state();
+
+ /*
+ * Initialising OpenSSL once, here, is safer than having individual modules do it.
+ */
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ if (tls_global_init(spawn_flag, check_config) < 0) exit(EXIT_FAILURE);
+#endif
+
+ /*
+ * Write the PID always if we're running as a daemon.
+ */
+ if (main_config.daemonize) main_config.write_pid = true;
+
+ /*
+ * Read the configuration files, BEFORE doing anything else.
+ */
+ if (main_config_init() < 0) exit(EXIT_FAILURE);
+
+ /*
+ * This is very useful in figuring out why the panic_action didn't fire.
+ */
+ INFO("%s", fr_debug_state_to_msg(fr_debug_state));
+
+ /*
+ * Check for vulnerabilities in the version of libssl were linked against.
+ */
+#if defined(HAVE_OPENSSL_CRYPTO_H) && defined(ENABLE_OPENSSL_VERSION_CHECK)
+ if (tls_global_version_check(main_config.allow_vulnerable_openssl) < 0) exit(EXIT_FAILURE);
+#endif
+
+ fr_talloc_fault_setup();
+
+ /*
+ * Set the panic action (if required)
+ */
+ {
+ char const *panic_action = NULL;
+
+ panic_action = getenv("PANIC_ACTION");
+ if (!panic_action) panic_action = main_config.panic_action;
+
+ if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) {
+ fr_perror("%s", main_config.name);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * The systemd watchdog enablement must be checked before we
+ * daemonize, but the notifications can come from any process.
+ */
+#ifdef HAVE_SYSTEMD_WATCHDOG
+ if (!check_config) {
+ uint64_t usec;
+
+ if ((sd_watchdog_enabled(0, &usec) > 0) && (usec > 0)) {
+ usec /= 2;
+ fr_timeval_from_usec(&sd_watchdog_interval, usec);
+
+ INFO("systemd watchdog interval is %ld.%.2ld secs", sd_watchdog_interval.tv_sec, sd_watchdog_interval.tv_usec);
+ } else {
+ INFO("systemd watchdog is disabled");
+ }
+ }
+#else
+ /*
+ * Some users get frustrated due to can't handle the service using "systemctl start radiusd"
+ * even when the SO supports systemd. The reason is because the FreeRADIUS version was built
+ * without the proper support.
+ *
+ * Then, as can be seen in https://www.systutorials.com/docs/linux/man/3-sd_notify/
+ * We could assume that if find the NOTIFY_SOCKET, it's because we are under systemd.
+ *
+ */
+ if (getenv("NOTIFY_SOCKET"))
+ WARN("Built without support for systemd watchdog, but running under systemd.");
+#endif
+
+#ifndef __MINGW32__
+ /*
+ * Disconnect from session
+ */
+ if (main_config.daemonize) {
+ pid_t pid;
+ int devnull;
+
+ /*
+ * Really weird things happen if we leave stdin open and call things like
+ * system() later.
+ */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ERROR("Failed opening /dev/null: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+ dup2(devnull, STDIN_FILENO);
+
+ close(devnull);
+
+ if (pipe(from_child) != 0) {
+ ERROR("Couldn't open pipe for child status: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ ERROR("Couldn't fork: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * The parent exits, so the child can run in the background.
+ *
+ * As the child can still encounter an error during initialisation
+ * we do a blocking read on a pipe between it and the parent.
+ *
+ * Just before entering the event loop the child will send a success
+ * or failure message to the parent, via the pipe.
+ */
+ if (pid > 0) {
+ uint8_t ret = 0;
+ int stat_loc;
+
+ /* So the pipe is correctly widowed if the child exits */
+ close(from_child[1]);
+
+ /*
+ * The child writes a 0x01 byte on success, and closes
+ * the pipe on error.
+ */
+ if ((read(from_child[0], &ret, 1) < 0)) {
+ ret = 0;
+ }
+
+ /* For cleanliness... */
+ close(from_child[0]);
+
+ /* Don't turn children into zombies */
+ if (!ret) {
+ waitpid(pid, &stat_loc, WNOHANG);
+ exit(EXIT_FAILURE);
+ }
+
+#ifdef HAVE_SYSTEMD
+ /*
+ * Update the systemd MAINPID to be our child,
+ * as the parent is about to exit.
+ */
+ sd_notifyf(0, "MAINPID=%lu", (unsigned long)pid);
+#endif
+
+ exit(EXIT_SUCCESS);
+ }
+
+ /* so the pipe is correctly widowed if the parent exits?! */
+ close(from_child[0]);
+# ifdef HAVE_SETSID
+ setsid();
+# endif
+ }
+#endif
+
+ /*
+ * Ensure that we're using the CORRECT pid after forking, NOT the one
+ * we started with.
+ */
+ radius_pid = getpid();
+
+ /*
+ * Initialize any event loops just enough so module instantiations can
+ * add fd/event to them, but do not start them yet.
+ *
+ * This has to be done post-fork in case we're using kqueue, where the
+ * queue isn't inherited by the child process.
+ */
+ if (!radius_event_init(autofree)) exit(EXIT_FAILURE);
+
+ /*
+ * Load the modules
+ */
+ if (modules_init(main_config.config) < 0) exit(EXIT_FAILURE);
+
+ /*
+ * Redirect stderr/stdout as appropriate.
+ */
+ if (radlog_init(&default_log, main_config.daemonize) < 0) {
+ ERROR("%s", fr_strerror());
+ exit(EXIT_FAILURE);
+ }
+
+ event_loop_started = true;
+
+ /*
+ * Start the event loop(s) and threads.
+ */
+ radius_event_start(main_config.config, spawn_flag);
+
+ /*
+ * Now that we've set everything up, we can install the signal
+ * handlers. Before this, if we get any signal, we don't know
+ * what to do, so we might as well do the default, and die.
+ */
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ if ((fr_set_signal(SIGHUP, sig_hup) < 0) ||
+ (fr_set_signal(SIGTERM, sig_fatal) < 0)) {
+ set_signal_error:
+ ERROR("%s", fr_strerror());
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * If we're debugging, then a CTRL-C will cause the server to die
+ * immediately. Use SIGTERM to shut down the server cleanly in
+ * that case.
+ */
+ if (fr_set_signal(SIGINT, sig_fatal) < 0) goto set_signal_error;
+
+#ifdef SIGQUIT
+ if (main_config.debug_memory || (rad_debug_lvl == 0)) {
+ if (fr_set_signal(SIGQUIT, sig_fatal) < 0) goto set_signal_error;
+ }
+#endif
+
+ /*
+ * Everything seems to have loaded OK, exit gracefully.
+ */
+ if (check_config) {
+ DEBUG("Configuration appears to be OK");
+
+ /* for -C -m|-M */
+ if (main_config.debug_memory) goto cleanup;
+
+ exit(EXIT_SUCCESS);
+ }
+
+#ifdef WITH_STATS
+ radius_stats_init(0);
+#endif
+
+ /*
+ * Write the PID after we've forked, so that we write the correct one.
+ */
+ if (main_config.write_pid) {
+ FILE *fp;
+
+ fp = fopen(main_config.pid_file, "w");
+ if (fp != NULL) {
+ /*
+ * @fixme What about following symlinks,
+ * and having it over-write a normal file?
+ */
+ fprintf(fp, "%d\n", (int) radius_pid);
+ fclose(fp);
+ } else {
+ ERROR("Failed creating PID file %s: %s", main_config.pid_file, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ exec_trigger(NULL, NULL, "server.start", false);
+
+ /*
+ * Inform the parent (who should still be waiting) that the rest of
+ * initialisation went OK, and that it should exit with a 0 status.
+ * If we don't get this far, then we just close the pipe on exit, and the
+ * parent gets a read failure.
+ */
+ if (main_config.daemonize) {
+ if (write(from_child[1], "\001", 1) < 0) {
+ WARN("Failed informing parent of successful start: %s",
+ fr_syserror(errno));
+ }
+ close(from_child[1]);
+ }
+
+ /*
+ * Clear the libfreeradius error buffer.
+ */
+ fr_strerror();
+
+ /*
+ * Initialise the state rbtree (used to link multiple rounds of challenges).
+ */
+ state = fr_state_init(NULL);
+
+#ifdef HAVE_SYSTEMD
+ {
+ int ret_notif;
+
+ ret_notif = sd_notify(0, "READY=1\nSTATUS=Processing requests");
+ if (ret_notif < 0)
+ WARN("Failed notifying systemd that process is READY: %s", fr_syserror(ret_notif));
+ }
+#endif
+
+ /*
+ * Process requests until HUP or exit.
+ */
+ while ((status = radius_event_process()) == 0x80) {
+#ifdef WITH_STATS
+ radius_stats_init(1);
+#endif
+ main_config_hup();
+ }
+ if (status < 0) {
+ ERROR("Exiting due to internal error: %s", fr_strerror());
+ rcode = EXIT_FAILURE;
+ } else {
+ INFO("Exiting normally");
+ }
+
+ /*
+ * Ignore the TERM signal: we're about to die.
+ */
+ signal(SIGTERM, SIG_IGN);
+
+ /*
+ * Fire signal and stop triggers after ignoring SIGTERM, so handlers are
+ * not killed with the rest of the process group, below.
+ */
+ if (status == 2) exec_trigger(NULL, NULL, "server.signal.term", true);
+ exec_trigger(NULL, NULL, "server.stop", false);
+
+ /*
+ * Send a TERM signal to all associated processes
+ * (including us, which gets ignored.)
+ */
+#ifndef __MINGW32__
+ if (spawn_flag) kill(-radius_pid, SIGTERM);
+#endif
+
+ /*
+ * We're exiting, so we can delete the PID file.
+ * (If it doesn't exist, we can ignore the error returned by unlink)
+ */
+ if (main_config.daemonize) unlink(main_config.pid_file);
+
+ radius_event_free();
+
+cleanup:
+ /*
+ * Detach any modules.
+ */
+ modules_free();
+
+ xlat_free(); /* modules may have xlat's */
+
+ fr_state_delete(state);
+
+ /*
+ * Free the configuration items.
+ */
+ main_config_free();
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * This should be after freeing all of the listeners.
+ */
+ listen_coa_free();
+#endif
+
+#ifdef WIN32
+ WSACleanup();
+#endif
+
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ tls_global_cleanup();
+#endif
+
+ /*
+ * So we don't see autofreed memory in the talloc report
+ */
+ talloc_free(autofree);
+
+ if (main_config.memory_report) {
+ INFO("Allocated memory at time of report:");
+ fr_log_talloc_report(NULL);
+ talloc_disable_null_tracking();
+ }
+
+ return rcode;
+}
+
+
+/*
+ * Display the syntax for starting this program.
+ */
+static void NEVER_RETURNS usage(int status)
+{
+ FILE *output = status?stderr:stdout;
+
+ fprintf(output, "Usage: %s [options]\n", main_config.name);
+ fprintf(output, "Options:\n");
+ fprintf(output, " -C Check configuration and exit.\n");
+ fprintf(stderr, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -f Run as a foreground process, not a daemon.\n");
+ fprintf(output, " -h Print this help message.\n");
+ fprintf(output, " -i <ipaddr> Listen on ipaddr ONLY.\n");
+ fprintf(output, " -l <log_file> Logging output will be written to this file.\n");
+ fprintf(output, " -m On SIGINT or SIGQUIT clean up all used memory instead of just exiting.\n");
+ fprintf(output, " -n <name> Read raddb/name.conf instead of raddb/radiusd.conf.\n");
+ fprintf(output, " -p <port> Listen on port ONLY.\n");
+ fprintf(output, " -P Always write out PID, even with -f.\n");
+ fprintf(output, " -s Do not spawn child processes to handle requests (same as -ft).\n");
+ fprintf(output, " -t Disable threads.\n");
+ fprintf(output, " -v Print server version information.\n");
+ fprintf(output, " -X Turn on full debugging (similar to -tfxxl stdout).\n");
+ fprintf(output, " -x Turn on additional debugging (-xx gives more debugging).\n");
+ exit(status);
+}
+
+
+/*
+ * We got a fatal signal.
+ */
+static void sig_fatal(int sig)
+{
+ if (getpid() != radius_pid) _exit(sig);
+
+ switch (sig) {
+ case SIGTERM:
+ radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
+ break;
+
+ case SIGINT:
+#ifdef SIGQUIT
+ case SIGQUIT:
+#endif
+ if (main_config.debug_memory || main_config.memory_report) {
+ radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
+ break;
+ }
+ /* FALL-THROUGH */
+
+ default:
+ fr_exit(sig);
+ }
+}
+
+#ifdef SIGHUP
+/*
+ * We got the hangup signal.
+ * Re-read the configuration files.
+ */
+static void sig_hup(UNUSED int sig)
+{
+ reset_signal(SIGHUP, sig_hup);
+
+ radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
+}
+#endif
diff --git a/src/main/radiusd.mk b/src/main/radiusd.mk
new file mode 100644
index 0000000..651413a
--- /dev/null
+++ b/src/main/radiusd.mk
@@ -0,0 +1,21 @@
+TARGET := radiusd
+SOURCES := acct.c auth.c client.c crypt.c files.c \
+ listen.c mainconfig.c modules.c modcall.c \
+ radiusd.c state.c stats.c soh.c connection.c \
+ session.c threads.c channel.c \
+ process.c realms.c detail.c
+ifneq ($(OPENSSL_LIBS),)
+SOURCES += cb.c tls.c tls_listen.c
+endif
+
+SRC_CFLAGS := -DHOSTINFO=\"${HOSTINFO}\"
+
+TGT_INSTALLDIR := ${sbindir}
+TGT_LDLIBS := $(LIBS) $(OPENSSL_LIBS) $(SYSTEMD_LIBS) $(LCRYPT)
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+
+# Libraries can't depend on libraries (oops), so make the binary
+# depend on the EAP code...
+ifneq "$(filter rlm_eap_%,${ALL_TGTS})" ""
+TGT_PREREQS += libfreeradius-eap.a
+endif
diff --git a/src/main/radlast.in b/src/main/radlast.in
new file mode 100755
index 0000000..69867bb
--- /dev/null
+++ b/src/main/radlast.in
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+prefix=@prefix@
+localstatedir=@localstatedir@
+logdir=@logdir@
+
+exec last -f $logdir/radwtmp "$@"
diff --git a/src/main/radlast.mk b/src/main/radlast.mk
new file mode 100644
index 0000000..766ce1f
--- /dev/null
+++ b/src/main/radlast.mk
@@ -0,0 +1,5 @@
+install: $(R)$(bindir)/radlast
+
+$(R)$(bindir)/radlast: src/main/radlast | $(R)$(bindir)
+ @echo INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(bindir)
diff --git a/src/main/radmin.c b/src/main/radmin.c
new file mode 100644
index 0000000..badc186
--- /dev/null
+++ b/src/main/radmin.c
@@ -0,0 +1,773 @@
+/*
+ * radmin.c RADIUS Administration tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2012 The FreeRADIUS server project
+ * Copyright 2012 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/channel.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifndef READLINE_MAX_HISTORY_LINES
+# define READLINE_MAX_HISTORY_LINES 1000
+#endif
+
+#ifdef HAVE_LIBREADLINE
+
+# include <stdio.h>
+#if defined(HAVE_READLINE_READLINE_H)
+# include <readline/readline.h>
+# define USE_READLINE (1)
+#elif defined(HAVE_READLINE_H)
+# include <readline.h>
+# define USE_READLINE (1)
+#endif /* !defined(HAVE_READLINE_H) */
+
+#ifdef HAVE_READLINE_HISTORY
+# if defined(HAVE_READLINE_HISTORY_H)
+# include <readline/history.h>
+# define USE_READLINE_HISTORY (1)
+# elif defined(HAVE_HISTORY_H)
+# include <history.h>
+# define USE_READLINE_HISTORY (1)
+#endif /* defined(HAVE_READLINE_HISTORY_H) */
+
+#endif /* HAVE_READLINE_HISTORY */
+
+#endif /* HAVE_LIBREADLINE */
+
+/*
+ * For configuration file stuff.
+ */
+static char const *progname = "radmin";
+static char const *radmin_version = "radmin version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+
+/*
+ * The rest of this is because the conffile.c, etc. assume
+ * they're running inside of the server. And we don't (yet)
+ * have a "libfreeradius-server", or "libfreeradius-util".
+ */
+main_config_t main_config;
+
+static bool echo = false;
+static char const *secret = "testing123";
+
+#include <sys/wait.h>
+
+#ifdef HAVE_PTHREAD_H
+pid_t rad_fork(void)
+{
+ return fork();
+}
+pid_t rad_waitpid(pid_t pid, int *status)
+{
+ return waitpid(pid, status, 0);
+}
+#endif
+
+static void NEVER_RETURNS usage(int status)
+{
+ FILE *output = status ? stderr : stdout;
+ fprintf(output, "Usage: %s [ args ]\n", progname);
+ fprintf(output, " -d raddb_dir Configuration files are in \"raddbdir/*\".\n");
+ fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -e command Execute 'command' and then exit.\n");
+ fprintf(output, " -E Echo commands as they are being executed.\n");
+ fprintf(output, " -f socket_file Open socket_file directly, without reading radius.conf\n");
+ fprintf(output, " -h Print usage help information.\n");
+ fprintf(output, " -i input_file Read commands from 'input_file'.\n");
+ fprintf(output, " -n name Read raddb/name.conf instead of raddb/radiusd.conf\n");
+ fprintf(output, " -q Quiet mode.\n");
+ fprintf(output, " -v Show program version information.\n");
+
+ exit(status);
+}
+
+static int client_socket(char const *server)
+{
+ int sockfd;
+ uint16_t port;
+ fr_ipaddr_t ipaddr;
+ char *p, buffer[1024];
+
+ strlcpy(buffer, server, sizeof(buffer));
+
+ p = strchr(buffer, ':');
+ if (!p) {
+ port = PW_RADMIN_PORT;
+ } else {
+ port = atoi(p + 1);
+ *p = '\0';
+ }
+
+ if (ip_hton(&ipaddr, AF_INET, buffer, false) < 0) {
+ fprintf(stderr, "%s: Failed looking up host %s: %s\n",
+ progname, buffer, fr_syserror(errno));
+ exit(1);
+ }
+
+ sockfd = fr_socket_client_tcp(NULL, &ipaddr, port, false);
+ if (sockfd < 0) {
+ fprintf(stderr, "%s: Failed opening socket %s: %s\n",
+ progname, server, fr_syserror(errno));
+ exit(1);
+ }
+
+ return sockfd;
+}
+
+static ssize_t do_challenge(int sockfd)
+{
+ ssize_t r;
+ fr_channel_type_t channel;
+ uint8_t challenge[16];
+
+ challenge[0] = 0;
+
+ /*
+ * When connecting over a socket, the server challenges us.
+ */
+ r = fr_channel_read(sockfd, &channel, challenge, sizeof(challenge));
+ if (r <= 0) return r;
+
+ if ((r != 16) || (channel != FR_CHANNEL_AUTH_CHALLENGE)) {
+ fprintf(stderr, "%s: Failed to read challenge.\n",
+ progname);
+ exit(1);
+ }
+
+ fr_hmac_md5(challenge, (uint8_t const *) secret, strlen(secret),
+ challenge, sizeof(challenge));
+
+ r = fr_channel_write(sockfd, FR_CHANNEL_AUTH_RESPONSE, challenge, sizeof(challenge));
+ if (r <= 0) return r;
+
+ /*
+ * If the server doesn't like us, he just closes the
+ * socket. So we don't look for an ACK.
+ */
+
+ return r;
+}
+
+
+/*
+ * Returns -1 on error. 0 on connection failed. +1 on OK.
+ */
+static ssize_t run_command(int sockfd, char const *command,
+ char *buffer, size_t bufsize)
+{
+ ssize_t r;
+ uint32_t status;
+ fr_channel_type_t channel;
+
+ if (echo) {
+ fprintf(stdout, "%s\n", command);
+ }
+
+ /*
+ * Write the text to the socket.
+ */
+ r = fr_channel_write(sockfd, FR_CHANNEL_STDIN, command, strlen(command));
+ if (r <= 0) return r;
+
+ while (true) {
+ r = fr_channel_read(sockfd, &channel, buffer, bufsize - 1);
+ if (r <= 0) return r;
+
+ buffer[r] = '\0'; /* for C strings */
+
+ switch (channel) {
+ case FR_CHANNEL_STDOUT:
+ fprintf(stdout, "%s", buffer);
+ break;
+
+ case FR_CHANNEL_STDERR:
+ fprintf(stderr, "ERROR: %s", buffer);
+ break;
+
+ case FR_CHANNEL_CMD_STATUS:
+ if (r < 4) return 1;
+
+ memcpy(&status, buffer, sizeof(status));
+ status = ntohl(status);
+ return status;
+
+ default:
+ fprintf(stderr, "Unexpected response\n");
+ return -1;
+ }
+ }
+
+ /* never gets here */
+}
+
+static int do_connect(int *out, char const *file, char const *server)
+{
+ int sockfd;
+ ssize_t r;
+ fr_channel_type_t channel;
+ char buffer[65536];
+
+ uint32_t magic;
+
+ /*
+ * Close stale file descriptors
+ */
+ if (*out != -1) {
+ close(*out);
+ *out = -1;
+ }
+
+ if (file) {
+ /*
+ * FIXME: Get destination from command line, if possible?
+ */
+ sockfd = fr_socket_client_unix(file, false);
+ if (sockfd < 0) {
+ fr_perror("radmin");
+ if (errno == ENOENT) {
+ fprintf(stderr, "Perhaps you need to run the commands:");
+ fprintf(stderr, "\tcd /etc/raddb\n");
+ fprintf(stderr, "\tln -s sites-available/control-socket "
+ "sites-enabled/control-socket\n");
+ fprintf(stderr, "and then re-start the server?\n");
+ }
+ return -1;
+ }
+ } else {
+ sockfd = client_socket(server);
+ }
+
+ /*
+ * Only works for BSD, but Linux allows us
+ * to mask SIGPIPE, so that's fine.
+ */
+#ifdef SO_NOSIGPIPE
+ {
+ int set = 1;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+ }
+#endif
+
+ /*
+ * Set up the initial header data.
+ */
+ magic = 0xf7eead16;
+ magic = htonl(magic);
+ memcpy(buffer, &magic, sizeof(magic));
+ memset(buffer + sizeof(magic), 0, sizeof(magic));
+
+ r = fr_channel_write(sockfd, FR_CHANNEL_INIT_ACK, buffer, 8);
+ if (r <= 0) {
+ do_close:
+ fprintf(stderr, "%s: Error in socket: %s\n",
+ progname, fr_syserror(errno));
+ close(sockfd);
+ return -1;
+ }
+
+ r = fr_channel_read(sockfd, &channel, buffer + 8, 8);
+ if (r <= 0) goto do_close;
+
+ if ((r != 8) || (channel != FR_CHANNEL_INIT_ACK) ||
+ (memcmp(buffer, buffer + 8, 8) != 0)) {
+ fprintf(stderr, "%s: Incompatible versions\n", progname);
+ close(sockfd);
+ return -1;
+ }
+
+ if (server && secret) {
+ r = do_challenge(sockfd);
+ if (r <= 0) goto do_close;
+ }
+
+ *out = sockfd;
+
+ return 0;
+}
+
+#define MAX_COMMANDS (4)
+
+int main(int argc, char **argv)
+{
+ int argval;
+ bool quiet = false;
+ int sockfd = -1;
+ char *line = NULL;
+ ssize_t len;
+ char const *file = NULL;
+ char const *name = "radiusd";
+ char *p, buffer[65536];
+ char const *input_file = NULL;
+ FILE *inputfp = stdin;
+ char const *server = NULL;
+
+ char const *radius_dir = RADIUS_DIR;
+ char const *dict_dir = DICTDIR;
+#ifdef USE_READLINE_HISTORY
+ char history_file[PATH_MAX];
+#endif
+
+ char *commands[MAX_COMMANDS];
+ int num_commands = -1;
+
+ int exit_status = EXIT_SUCCESS;
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radmin");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ talloc_set_log_stderr();
+
+ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) {
+ progname = argv[0];
+ } else {
+ progname++;
+ }
+
+ while ((argval = getopt(argc, argv, "d:D:hi:e:Ef:n:qs:vS")) != EOF) {
+ switch (argval) {
+ case 'd':
+ if (file) {
+ fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname);
+ exit(1);
+ }
+ if (server) {
+ fprintf(stderr, "%s: -d and -s cannot be used together.\n", progname);
+ exit(1);
+ }
+ radius_dir = optarg;
+ break;
+
+ case 'D':
+ dict_dir = optarg;
+ break;
+
+ case 'e':
+ num_commands++; /* starts at -1 */
+ if (num_commands >= MAX_COMMANDS) {
+ fprintf(stderr, "%s: Too many '-e'\n",
+ progname);
+ exit(1);
+ }
+
+ commands[num_commands] = optarg;
+ break;
+
+ case 'E':
+ echo = true;
+ break;
+
+ case 'f':
+ radius_dir = NULL;
+ file = optarg;
+ break;
+
+ default:
+ case 'h':
+ usage(0); /* never returns */
+
+ case 'i':
+#ifdef __clang_analyzer__
+ if (!optarg) exit(1);
+#endif
+
+ if (strcmp(optarg, "-") != 0) {
+ input_file = optarg;
+ }
+ quiet = true;
+ break;
+
+ case 'n':
+ name = optarg;
+ break;
+
+ case 'q':
+ quiet = true;
+ break;
+
+ case 's':
+ if (file) {
+ fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname);
+ usage(1);
+ }
+ radius_dir = NULL;
+ server = optarg;
+ break;
+
+ case 'S':
+ secret = NULL;
+ break;
+
+ case 'v':
+ printf("%s\n", radmin_version);
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radmin");
+ exit(1);
+ }
+
+ if (radius_dir) {
+ int rcode;
+ CONF_SECTION *cs, *subcs;
+ uid_t uid;
+ gid_t gid;
+ char const *uid_name = NULL;
+ char const *gid_name = NULL;
+ struct passwd *pwd;
+ struct group *grp;
+
+ file = NULL; /* MUST read it from the conffile now */
+
+ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name);
+
+ /*
+ * Need to read in the dictionaries, else we may get
+ * validation errors when we try and parse the config.
+ */
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radmin");
+ exit(64);
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radmin");
+ exit(64);
+ }
+
+ cs = cf_section_alloc(NULL, "main", NULL);
+ if (!cs) exit(1);
+
+ if (cf_file_read(cs, buffer) < 0) {
+ fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, buffer);
+ talloc_free(cs);
+ usage(1);
+ }
+
+ uid = getuid();
+ gid = getgid();
+
+ subcs = NULL;
+ while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) {
+ char const *value;
+ CONF_PAIR *cp = cf_pair_find(subcs, "type");
+
+ if (!cp) continue;
+
+ value = cf_pair_value(cp);
+ if (!value) continue;
+
+ if (strcmp(value, "control") != 0) continue;
+
+ /*
+ * Now find the socket name (sigh)
+ */
+ rcode = cf_item_parse(subcs, "socket", FR_ITEM_POINTER(PW_TYPE_STRING, &file), NULL);
+ if (rcode < 0) {
+ fprintf(stderr, "%s: Failed parsing listen section 'socket'\n", progname);
+ exit(1);
+ }
+
+ if (!file) {
+ fprintf(stderr, "%s: No path given for socket\n", progname);
+ usage(1);
+ }
+
+ /*
+ * If we're root, just use the first one we find
+ */
+ if (uid == 0) break;
+
+ /*
+ * Check UID and GID.
+ */
+ rcode = cf_item_parse(subcs, "uid", FR_ITEM_POINTER(PW_TYPE_STRING, &uid_name), NULL);
+ if (rcode < 0) {
+ fprintf(stderr, "%s: Failed parsing listen section 'uid'\n", progname);
+ exit(1);
+ }
+
+ if (!uid_name) break;
+
+ pwd = getpwnam(uid_name);
+ if (!pwd) {
+ fprintf(stderr, "%s: Failed getting UID for user %s: %s\n", progname, uid_name, strerror(errno));
+ exit(1);
+ }
+
+ if (uid != pwd->pw_uid) continue;
+
+ rcode = cf_item_parse(subcs, "gid", FR_ITEM_POINTER(PW_TYPE_STRING, &gid_name), NULL);
+ if (rcode < 0) {
+ fprintf(stderr, "%s: Failed parsing listen section 'gid'\n", progname);
+ exit(1);
+ }
+
+ if (!gid_name) break;
+
+ grp = getgrnam(gid_name);
+ if (!grp) {
+ fprintf(stderr, "%s: Failed getting GID for group %s: %s\n", progname, gid_name, strerror(errno));
+ exit(1);
+ }
+
+ if (gid != grp->gr_gid) continue;
+
+ break;
+ }
+
+ if (!file) {
+ fprintf(stderr, "%s: Could not find control socket in %s\n", progname, buffer);
+ exit(1);
+ }
+ }
+
+ if (input_file) {
+ inputfp = fopen(input_file, "r");
+ if (!inputfp) {
+ fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno));
+ exit(1);
+ }
+ }
+
+ if (!file && !server) {
+ fprintf(stderr, "%s: Must use one of '-d' or '-f' or '-s'\n",
+ progname);
+ exit(1);
+ }
+
+ /*
+ * Check if stdin is a TTY only if input is from stdin
+ */
+ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = true;
+
+#ifdef USE_READLINE
+ if (!quiet) {
+#ifdef USE_READLINE_HISTORY
+ using_history();
+ stifle_history(READLINE_MAX_HISTORY_LINES);
+
+ snprintf(history_file, sizeof(history_file), "%s/%s", getenv("HOME"), ".radmin_history");
+ read_history(history_file);
+#endif
+ rl_bind_key('\t', rl_insert);
+ }
+#endif
+
+ /*
+ * Prevent SIGPIPEs from terminating the process
+ */
+ signal(SIGPIPE, SIG_IGN);
+
+ if (do_connect(&sockfd, file, server) < 0) exit(1);
+
+ /*
+ * Run one command.
+ */
+ if (num_commands >= 0) {
+ int i;
+
+ for (i = 0; i <= num_commands; i++) {
+ len = run_command(sockfd, commands[i], buffer, sizeof(buffer));
+ if (len < 0) exit(1);
+
+ if (len == FR_CHANNEL_FAIL) exit_status = EXIT_FAILURE;
+ }
+ exit(exit_status);
+ }
+
+ if (!quiet) {
+ printf("%s - FreeRADIUS Server administration tool.\n", radmin_version);
+ printf("Copyright (C) 2008-2019 The FreeRADIUS server project and contributors.\n");
+ printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
+ printf("PARTICULAR PURPOSE.\n");
+ printf("You may redistribute copies of FreeRADIUS under the terms of the\n");
+ printf("GNU General Public License v2.\n");
+ }
+
+ /*
+ * FIXME: Do login?
+ */
+
+ while (1) {
+ int retries;
+
+#ifndef USE_READLINE
+ if (!quiet) {
+ printf("radmin> ");
+ fflush(stdout);
+ }
+#else
+ if (!quiet) {
+ line = readline("radmin> ");
+
+ if (!line) break;
+
+ if (!*line) {
+ free(line);
+ continue;
+ }
+
+#ifdef USE_READLINE_HISTORY
+ add_history(line);
+ write_history(history_file);
+#endif
+ } else /* quiet, or no readline */
+#endif
+ {
+ line = fgets(buffer, sizeof(buffer), inputfp);
+ if (!line) break;
+
+ p = strchr(buffer, '\n');
+ if (!p) {
+ fprintf(stderr, "%s: Input line too long\n",
+ progname);
+ exit(1);
+ }
+
+ *p = '\0';
+
+ /*
+ * Strip off leading spaces.
+ */
+ for (p = line; *p != '\0'; p++) {
+ if ((p[0] == ' ') ||
+ (p[0] == '\t')) {
+ line = p + 1;
+ continue;
+ }
+
+ if (p[0] == '#') {
+ line = NULL;
+ break;
+ }
+
+ break;
+ }
+
+ /*
+ * Comments: keep going.
+ */
+ if (!line) continue;
+
+ /*
+ * Strip off CR / LF
+ */
+ for (p = line; *p != '\0'; p++) {
+ if ((p[0] == '\r') ||
+ (p[0] == '\n')) {
+ p[0] = '\0';
+ break;
+ }
+ }
+ }
+
+ if (strcmp(line, "reconnect") == 0) {
+ if (do_connect(&sockfd, file, server) < 0) exit(1);
+ line = NULL;
+ continue;
+ }
+
+ if (strncmp(line, "secret ", 7) == 0) {
+ if (!secret) {
+ secret = line + 7;
+ do_challenge(sockfd);
+ }
+ line = NULL;
+ continue;
+ }
+
+ /*
+ * Exit, done, etc.
+ */
+ if ((strcmp(line, "exit") == 0) ||
+ (strcmp(line, "quit") == 0)) {
+ break;
+ }
+
+ if (server && !secret) {
+ fprintf(stderr, "ERROR: You must enter 'secret <SECRET>' before running any commands\n");
+ line = NULL;
+ continue;
+ }
+
+ retries = 0;
+ retry:
+ len = run_command(sockfd, line, buffer, sizeof(buffer));
+ if (len < 0) {
+ if (!quiet) fprintf(stderr, "... reconnecting ...\n");
+
+ if (do_connect(&sockfd, file, server) < 0) {
+ exit(1);
+ }
+
+ retries++;
+ if (retries < 2) goto retry;
+
+ fprintf(stderr, "Failed to connect to server\n");
+ exit(1);
+
+ } else if (len == FR_CHANNEL_SUCCESS) {
+ break;
+
+ } else if (len == FR_CHANNEL_FAIL) {
+ exit_status = EXIT_FAILURE;
+ }
+ }
+
+ fprintf(stdout, "\n");
+
+ if (inputfp != stdin) fclose(inputfp);
+
+ return exit_status;
+}
+
diff --git a/src/main/radmin.mk b/src/main/radmin.mk
new file mode 100644
index 0000000..9e58e6b
--- /dev/null
+++ b/src/main/radmin.mk
@@ -0,0 +1,7 @@
+TARGET := radmin
+
+SOURCES := radmin.c channel.c
+
+TGT_INSTALLDIR := ${sbindir}
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS) $(LIBREADLINE)
diff --git a/src/main/radsniff.c b/src/main/radsniff.c
new file mode 100644
index 0000000..e0d2b65
--- /dev/null
+++ b/src/main/radsniff.c
@@ -0,0 +1,2683 @@
+/*
+ * 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 radsniff.c
+ * @brief Capture, filter, and generate statistics for RADIUS traffic
+ *
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Nicolas Baradakis <nicolas.baradakis@cegetel.net>
+ */
+
+RCSID("$Id$")
+
+#define _LIBRADIUS 1
+#include <time.h>
+#include <math.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/event.h>
+
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/pcap.h>
+#include <freeradius-devel/radsniff.h>
+
+#ifdef HAVE_COLLECTDC_H
+# include <collectd/client.h>
+#endif
+
+#define RS_ASSERT(_x) if (!(_x) && !fr_assert(_x)) exit(1)
+
+static rs_t *conf;
+static struct timeval start_pcap = {0, 0};
+static char timestr[50];
+
+static rbtree_t *request_tree = NULL;
+static rbtree_t *link_tree = NULL;
+static fr_event_list_t *events;
+static bool cleanup;
+
+static int self_pipe[2] = {-1, -1}; //!< Signals from sig handlers
+
+typedef int (*rbcmp)(void const *, void const *);
+
+static char const *radsniff_version = "radsniff version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+static int rs_useful_codes[] = {
+ PW_CODE_ACCESS_REQUEST, //!< RFC2865 - Authentication request
+ PW_CODE_ACCESS_ACCEPT, //!< RFC2865 - Access-Accept
+ PW_CODE_ACCESS_REJECT, //!< RFC2865 - Access-Reject
+ PW_CODE_ACCOUNTING_REQUEST, //!< RFC2866 - Accounting-Request
+ PW_CODE_ACCOUNTING_RESPONSE, //!< RFC2866 - Accounting-Response
+ PW_CODE_ACCESS_CHALLENGE, //!< RFC2865 - Access-Challenge
+ PW_CODE_STATUS_SERVER, //!< RFC2865/RFC5997 - Status Server (request)
+ PW_CODE_STATUS_CLIENT, //!< RFC2865/RFC5997 - Status Server (response)
+ PW_CODE_DISCONNECT_REQUEST, //!< RFC3575/RFC5176 - Disconnect-Request
+ PW_CODE_DISCONNECT_ACK, //!< RFC3575/RFC5176 - Disconnect-Ack (positive)
+ PW_CODE_DISCONNECT_NAK, //!< RFC3575/RFC5176 - Disconnect-Nak (not willing to perform)
+ PW_CODE_COA_REQUEST, //!< RFC3575/RFC5176 - CoA-Request
+ PW_CODE_COA_ACK, //!< RFC3575/RFC5176 - CoA-Ack (positive)
+ PW_CODE_COA_NAK, //!< RFC3575/RFC5176 - CoA-Nak (not willing to perform)
+};
+
+static const FR_NAME_NUMBER rs_events[] = {
+ { "received", RS_NORMAL },
+ { "norsp", RS_LOST },
+ { "rtx", RS_RTX },
+ { "noreq", RS_UNLINKED },
+ { "reused", RS_REUSED },
+ { "error", RS_ERROR },
+ { NULL , -1 }
+};
+
+static void NEVER_RETURNS usage(int status);
+
+/** Fork and kill the parent process, writing out our PID
+ *
+ * @param pidfile the PID file to write our PID to
+ */
+static void rs_daemonize(char const *pidfile)
+{
+ FILE *fp;
+ pid_t pid, sid;
+
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Kill the parent...
+ */
+ if (pid > 0) {
+ close(self_pipe[0]);
+ close(self_pipe[1]);
+ exit(EXIT_SUCCESS);
+ }
+
+ /*
+ * Continue as the child.
+ */
+
+ /* Create a new SID for the child process */
+ sid = setsid();
+ if (sid < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Change the current working directory. This prevents the current
+ * directory from being locked; hence not being able to remove it.
+ */
+ if ((chdir("/")) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * And write it AFTER we've forked, so that we write the
+ * correct PID.
+ */
+ fp = fopen(pidfile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", (int) sid);
+ fclose(fp);
+ } else {
+ ERROR("Failed creating PID file %s: %s", pidfile, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Close stdout and stderr if they've not been redirected.
+ */
+ if (isatty(fileno(stdout))) {
+ if (!freopen("/dev/null", "w", stdout)) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (isatty(fileno(stderr))) {
+ if (!freopen("/dev/null", "w", stderr)) {
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+#define USEC 1000000
+static void rs_tv_sub(struct timeval const *end, struct timeval const *start, struct timeval *elapsed)
+{
+ elapsed->tv_sec = end->tv_sec - start->tv_sec;
+ if (elapsed->tv_sec > 0) {
+ elapsed->tv_sec--;
+ elapsed->tv_usec = USEC;
+ } else {
+ elapsed->tv_usec = 0;
+ }
+ elapsed->tv_usec += end->tv_usec;
+ elapsed->tv_usec -= start->tv_usec;
+
+ if (elapsed->tv_usec >= USEC) {
+ elapsed->tv_usec -= USEC;
+ elapsed->tv_sec++;
+ }
+}
+
+static void rs_tv_add_ms(struct timeval const *start, unsigned long interval, struct timeval *result) {
+ result->tv_sec = start->tv_sec + (interval / 1000);
+ result->tv_usec = start->tv_usec + ((interval % 1000) * 1000);
+
+ if (result->tv_usec > USEC) {
+ result->tv_usec -= USEC;
+ result->tv_sec++;
+ }
+}
+
+static void rs_time_print(char *out, size_t len, struct timeval const *t)
+{
+ size_t ret;
+ struct timeval now;
+ uint32_t usec;
+
+ if (!t) {
+ gettimeofday(&now, NULL);
+ t = &now;
+ }
+
+ ret = strftime(out, len, "%Y-%m-%d %H:%M:%S", localtime(&t->tv_sec));
+ if (ret >= len) {
+ return;
+ }
+
+ usec = t->tv_usec;
+
+ if (usec) {
+ while (usec < 100000) usec *= 10;
+ snprintf(out + ret, len - ret, ".%i", usec);
+ } else {
+ snprintf(out + ret, len - ret, ".000000");
+ }
+}
+
+static size_t rs_prints_csv(char *out, size_t outlen, char const *in, size_t inlen)
+{
+ char const *start = out;
+ uint8_t const *str = (uint8_t const *) in;
+
+ if (!in) {
+ if (outlen) {
+ *out = '\0';
+ }
+
+ return 0;
+ }
+
+ if (inlen == 0) {
+ inlen = strlen(in);
+ }
+
+ while ((inlen > 0) && (outlen > 2)) {
+ /*
+ * Escape double quotes with... MORE DOUBLE QUOTES!
+ */
+ if (*str == '"') {
+ *out++ = '"';
+ outlen--;
+ }
+
+ /*
+ * Safe chars which require no escaping
+ */
+ if ((*str == '\r') || (*str == '\n') || ((*str >= '\x20') && (*str <= '\x7E'))) {
+ *out++ = *str++;
+ outlen--;
+ inlen--;
+
+ continue;
+ }
+
+ /*
+ * Everything else is dropped
+ */
+ str++;
+ inlen--;
+ }
+ *out = '\0';
+
+ return out - start;
+}
+
+static void rs_packet_print_csv_header(void)
+{
+ char buffer[2048];
+ char *p = buffer;
+ int i;
+
+ ssize_t len, s = sizeof(buffer);
+
+ len = strlcpy(p, "\"Status\",\"Count\",\"Time\",\"Latency\",\"Type\",\"Interface\","
+ "\"Src IP\",\"Src Port\",\"Dst IP\",\"Dst Port\",\"ID\",", s);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ char const *in;
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+
+ for (in = conf->list_da[i]->name; *in; in++) {
+ *p++ = *in;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *p++ = '"';
+ s -= 1;
+ if (s <= 0) return;
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_csv(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ UNUSED struct timeval *elapsed, struct timeval *latency, UNUSED bool response,
+ bool body)
+{
+ char const *status_str;
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ RS_ASSERT(status_str);
+
+ len = snprintf(p, s, "%s,%" PRIu64 ",%s,", status_str, count, timestr);
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (latency) {
+ len = snprintf(p, s, "%u.%03u,",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ } else {
+ *p = ',';
+ p += 1;
+ s -= 1;
+ }
+
+ if (s <= 0) return;
+
+ /* Status, Type, Interface, Src, Src port, Dst, Dst port, ID */
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s,%s,%s,%i,%s,%i,%i,", fr_packet_codes[packet->code], handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ } else {
+ len = snprintf(p, s, "%u,%s,%s,%i,%s,%i,%i,", packet->code, handle->name,
+ src, packet->src_port, dst, packet->dst_port, packet->id);
+ }
+ p += len;
+ s -= len;
+
+ if (s <= 0) return;
+
+ if (body) {
+ int i;
+ VALUE_PAIR *vp;
+
+ for (i = 0; i < conf->list_da_num; i++) {
+ vp = fr_pair_find_by_da(packet->vps, conf->list_da[i], TAG_ANY);
+ if (vp && (vp->vp_length > 0)) {
+ if (conf->list_da[i]->type == PW_TYPE_STRING) {
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+
+ len = rs_prints_csv(p, s, vp->vp_strvalue, vp->vp_length);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ *p++ = '"';
+ s--;
+ if (s <= 0) return;
+ } else {
+ len = vp_prints_value(p, s, vp, 0);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+ }
+
+ *p++ = ',';
+ s -= 1;
+ if (s <= 0) return;
+ }
+ } else {
+ s -= conf->list_da_num;
+ if (s <= 0) return;
+
+ memset(p, ',', conf->list_da_num);
+ p += conf->list_da_num;
+ }
+
+ *--p = '\0';
+ fprintf(stdout , "%s\n", buffer);
+}
+
+static void rs_packet_print_fancy(uint64_t count, rs_status_t status, fr_pcap_t *handle, RADIUS_PACKET *packet,
+ struct timeval *elapsed, struct timeval *latency, bool response, bool body)
+{
+ char buffer[2048];
+ char *p = buffer;
+
+ char src[INET6_ADDRSTRLEN];
+ char dst[INET6_ADDRSTRLEN];
+
+ ssize_t len, s = sizeof(buffer);
+
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src, sizeof(src));
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst, sizeof(dst));
+
+ /* Only print out status str if something's not right */
+ if (status != RS_NORMAL) {
+ char const *status_str;
+
+ status_str = fr_int2str(rs_events, status, NULL);
+ RS_ASSERT(status_str);
+
+ len = snprintf(p, s, "** %s ** ", status_str);
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (is_radius_code(packet->code)) {
+ len = snprintf(p, s, "%s Id %i %s:%s:%d %s %s:%i ",
+ fr_packet_codes[packet->code],
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ } else {
+ len = snprintf(p, s, "%u Id %i %s:%s:%i %s %s:%i ",
+ packet->code,
+ packet->id,
+ handle->name,
+ response ? dst : src,
+ response ? packet->dst_port : packet->src_port,
+ response ? "<-" : "->",
+ response ? src : dst ,
+ response ? packet->src_port : packet->dst_port);
+ }
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+
+ if (elapsed) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) elapsed->tv_sec, ((unsigned int) elapsed->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ if (latency) {
+ len = snprintf(p, s, "+%u.%03u ",
+ (unsigned int) latency->tv_sec, ((unsigned int) latency->tv_usec / 1000));
+ p += len;
+ s -= len;
+ if (s <= 0) return;
+ }
+
+ *--p = '\0';
+
+ RIDEBUG("%s", buffer);
+
+ if (body) {
+ /*
+ * Print out verbose HEX output
+ */
+ if (conf->print_packet && (fr_debug_lvl > 3)) {
+ rad_print_hex(packet);
+ }
+
+ if (conf->print_packet && (fr_debug_lvl > 1)) {
+ char vector[(AUTH_VECTOR_LEN * 2) + 1];
+
+ if (packet->vps) {
+ fr_pair_list_sort(&packet->vps, fr_pair_cmp_by_da_tag);
+ vp_printlist(fr_log_fp, packet->vps);
+ }
+
+ fr_bin2hex(vector, packet->vector, AUTH_VECTOR_LEN);
+ INFO("\tAuthenticator-Field = 0x%s", vector);
+ }
+ }
+}
+
+static inline void rs_packet_print(rs_request_t *request, uint64_t count, rs_status_t status, fr_pcap_t *handle,
+ RADIUS_PACKET *packet, struct timeval *elapsed, struct timeval *latency,
+ bool response, bool body)
+{
+ if (!conf->logger) return;
+
+ if (request) request->logged = true;
+ conf->logger(count, status, handle, packet, elapsed, latency, response, body);
+}
+
+static void rs_stats_print(rs_latency_t *stats, PW_CODE code)
+{
+ int i;
+ bool have_rt = false;
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (stats->interval.rt[i]) {
+ have_rt = true;
+ }
+ }
+
+ if (!stats->interval.received && !have_rt && !stats->interval.reused) {
+ return;
+ }
+
+ if (stats->interval.received || stats->interval.linked) {
+ INFO("%s counters:", fr_packet_codes[code]);
+ if (stats->interval.received > 0) {
+ INFO("\tTotal : %.3lf/s" , stats->interval.received);
+ }
+ }
+
+ if (stats->interval.linked > 0) {
+ INFO("\tLinked : %.3lf/s", stats->interval.linked);
+ INFO("\tUnlinked : %.3lf/s", stats->interval.unlinked);
+ INFO("%s latency:", fr_packet_codes[code]);
+ INFO("\tHigh : %.3lfms", stats->interval.latency_high);
+ INFO("\tLow : %.3lfms", stats->interval.latency_low);
+ INFO("\tAverage : %.3lfms", stats->interval.latency_average);
+ INFO("\tMA : %.3lfms", stats->latency_smoothed);
+ }
+
+ if (have_rt || stats->interval.lost || stats->interval.reused) {
+ INFO("%s retransmits & loss:", fr_packet_codes[code]);
+
+ if (stats->interval.lost) {
+ INFO("\tLost : %.3lf/s", stats->interval.lost);
+ }
+
+ if (stats->interval.reused) {
+ INFO("\tID Reused : %.3lf/s", stats->interval.reused);
+ }
+
+ for (i = 0; i <= RS_RETRANSMIT_MAX; i++) {
+ if (!stats->interval.rt[i]) {
+ continue;
+ }
+
+ if (i != RS_RETRANSMIT_MAX) {
+ INFO("\tRT (%i) : %.3lf/s", i, stats->interval.rt[i]);
+ } else {
+ INFO("\tRT (%i+) : %.3lf/s", i, stats->interval.rt[i]);
+ }
+ }
+ }
+}
+
+/** Query libpcap to see if it dropped any packets
+ *
+ * We need to check to see if libpcap dropped any packets and if it did, we need to stop stats output for long
+ * enough for inaccurate statistics to be cleared out.
+ *
+ * @param in pcap handle to check.
+ * @param interval time between checks (used for debug output)
+ * @return 0, no drops, -1 we couldn't check, -2 dropped because of buffer exhaustion, -3 dropped because of NIC.
+ */
+static int rs_check_pcap_drop(fr_pcap_t *in, int interval) {
+ int ret = 0;
+ struct pcap_stat pstats;
+
+ if (pcap_stats(in->handle, &pstats) != 0) {
+ ERROR("%s failed retrieving pcap stats: %s", in->name, pcap_geterr(in->handle));
+ return -1;
+ }
+
+ INFO("\t%s%*s: %.3lf/s", in->name, (int) (10 - strlen(in->name)), "",
+ ((double) (pstats.ps_recv - in->pstats.ps_recv)) / interval);
+
+ if (pstats.ps_drop - in->pstats.ps_drop > 0) {
+ ERROR("%s dropped %i packets: Buffer exhaustion", in->name, pstats.ps_drop - in->pstats.ps_drop);
+ ret = -2;
+ }
+
+ if (pstats.ps_ifdrop - in->pstats.ps_ifdrop > 0) {
+ ERROR("%s dropped %i packets: Interface", in->name, pstats.ps_ifdrop - in->pstats.ps_ifdrop);
+ ret = -3;
+ }
+
+ in->pstats = pstats;
+
+ return ret;
+}
+
+/** Update smoothed average
+ *
+ */
+static void rs_stats_process_latency(rs_latency_t *stats)
+{
+ /*
+ * If we didn't link any packets during this interval, we don't have a value to return.
+ * returning 0 is misleading as it would be like saying the latency had dropped to 0.
+ * We instead set NaN which libcollectd converts to a 'U' or unknown value.
+ *
+ * This will cause gaps in graphs, but is completely legitimate as we are missing data.
+ * This is unfortunately an effect of being just a passive observer.
+ */
+ if (stats->interval.linked_total == 0) {
+ double unk = strtod("NAN()", (char **) NULL);
+
+ stats->interval.latency_average = unk;
+ stats->interval.latency_high = unk;
+ stats->interval.latency_low = unk;
+
+ /*
+ * We've not yet been able to determine latency, so latency_smoothed is also NaN
+ */
+ if (stats->latency_smoothed_count == 0) {
+ stats->latency_smoothed = unk;
+ }
+ return;
+ }
+
+ if (stats->interval.linked_total && stats->interval.latency_total) {
+ stats->interval.latency_average = (stats->interval.latency_total / stats->interval.linked_total);
+ }
+
+ if (isnan(stats->latency_smoothed)) {
+ stats->latency_smoothed = 0;
+ }
+ if (stats->interval.latency_average > 0) {
+ stats->latency_smoothed_count++;
+ stats->latency_smoothed += ((stats->interval.latency_average - stats->latency_smoothed) /
+ ((stats->latency_smoothed_count < 100) ? stats->latency_smoothed_count : 100));
+ }
+}
+
+static void rs_stats_process_counters(rs_latency_t *stats)
+{
+ int i;
+
+ stats->interval.received = ((long double) stats->interval.received_total) / conf->stats.interval;
+ stats->interval.linked = ((long double) stats->interval.linked_total) / conf->stats.interval;
+ stats->interval.unlinked = ((long double) stats->interval.unlinked_total) / conf->stats.interval;
+ stats->interval.reused = ((long double) stats->interval.reused_total) / conf->stats.interval;
+ stats->interval.lost = ((long double) stats->interval.lost_total) / conf->stats.interval;
+
+ for (i = 0; i < RS_RETRANSMIT_MAX; i++) {
+ stats->interval.rt[i] = ((long double) stats->interval.rt_total[i]) / conf->stats.interval;
+ }
+}
+
+/** Process stats for a single interval
+ *
+ */
+static void rs_stats_process(void *ctx)
+{
+ size_t i;
+ size_t rs_codes_len = (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes));
+ fr_pcap_t *in_p;
+ rs_update_t *this = ctx;
+ rs_stats_t *stats = this->stats;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ stats->intervals++;
+
+ INFO("######### Stats Iteration %i #########", stats->intervals);
+
+ /*
+ * Verify that none of the pcap handles have dropped packets.
+ */
+ INFO("Interface capture rate:");
+ for (in_p = this->in;
+ in_p;
+ in_p = in_p->next) {
+ if (rs_check_pcap_drop(in_p, conf->stats.interval) < 0) {
+ ERROR("Muting stats for the next %i milliseconds", conf->stats.timeout);
+
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats->quiet);
+ goto clear;
+ }
+ }
+
+ if ((stats->quiet.tv_sec + (stats->quiet.tv_usec / 1000000.0)) -
+ (now.tv_sec + (now.tv_usec / 1000000.0)) > 0) {
+ INFO("Stats muted because of warmup, or previous error");
+ goto clear;
+ }
+
+ /*
+ * Latency stats need a bit more work to calculate the SMA.
+ *
+ * No further work is required for codes.
+ */
+ for (i = 0; i < rs_codes_len; i++) {
+ rs_stats_process_latency(&stats->exchange[rs_useful_codes[i]]);
+ rs_stats_process_counters(&stats->exchange[rs_useful_codes[i]]);
+ if (fr_debug_lvl > 0) {
+ rs_stats_print(&stats->exchange[rs_useful_codes[i]], rs_useful_codes[i]);
+ }
+ }
+
+#ifdef HAVE_COLLECTDC_H
+ /*
+ * Update stats in collectd using the complex structures we
+ * initialised earlier.
+ */
+ if ((conf->stats.out == RS_STATS_OUT_COLLECTD) && conf->stats.handle) {
+ rs_stats_collectd_do_stats(conf, conf->stats.tmpl, &now);
+ }
+#endif
+
+ clear:
+ /*
+ * Rinse and repeat...
+ */
+ for (i = 0; i < rs_codes_len; i++) {
+ memset(&stats->exchange[rs_useful_codes[i]].interval, 0,
+ sizeof(stats->exchange[rs_useful_codes[i]].interval));
+ }
+
+ {
+ static fr_event_t *event;
+
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+
+ if (!fr_event_insert(this->list, rs_stats_process, ctx, &now, &event)) {
+ ERROR("Failed inserting stats interval event");
+ }
+ }
+}
+
+
+/** Update latency statistics for request/response and forwarded packets
+ *
+ */
+static void rs_stats_update_latency(rs_latency_t *stats, struct timeval *latency)
+{
+ double lint;
+
+ stats->interval.linked_total++;
+ /* More useful is this in milliseconds */
+ lint = (latency->tv_sec + (latency->tv_usec / 1000000.0)) * 1000;
+ if (lint > stats->interval.latency_high) {
+ stats->interval.latency_high = lint;
+ }
+ if (!stats->interval.latency_low || (lint < stats->interval.latency_low)) {
+ stats->interval.latency_low = lint;
+ }
+ stats->interval.latency_total += lint;
+
+}
+
+/** Copy a subset of attributes from one list into the other
+ *
+ * Should be O(n) if all the attributes exist. List must be pre-sorted.
+ */
+static int rs_get_pairs(TALLOC_CTX *ctx, VALUE_PAIR **out, VALUE_PAIR *vps, DICT_ATTR const *da[], int num)
+{
+ vp_cursor_t list_cursor, out_cursor;
+ VALUE_PAIR *match, *last_match, *copy;
+ uint64_t count = 0;
+ int i;
+
+ last_match = vps;
+
+ fr_cursor_init(&list_cursor, &last_match);
+ fr_cursor_init(&out_cursor, out);
+ for (i = 0; i < num; i++) {
+ match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY);
+ if (!match) {
+ fr_cursor_init(&list_cursor, &last_match);
+ continue;
+ }
+
+ do {
+ copy = fr_pair_copy(ctx, match);
+ if (!copy) {
+ fr_pair_list_free(out);
+ return -1;
+ }
+ fr_cursor_insert(&out_cursor, copy);
+ last_match = match;
+
+ count++;
+ } while ((match = fr_cursor_next_by_da(&list_cursor, da[i], TAG_ANY)));
+ }
+
+ return count;
+}
+
+static int _request_free(rs_request_t *request)
+{
+ bool ret;
+
+ /*
+ * If were attempting to cleanup the request, and it's no longer in the request_tree
+ * something has gone very badly wrong.
+ */
+ if (request->in_request_tree) {
+ ret = rbtree_deletebydata(request_tree, request);
+ RS_ASSERT(ret);
+ }
+
+ if (request->in_link_tree) {
+ ret = rbtree_deletebydata(link_tree, request);
+ RS_ASSERT(ret);
+ }
+
+ if (request->event) {
+ ret = fr_event_delete(events, &request->event);
+ RS_ASSERT(ret);
+ }
+
+ rad_free(&request->packet);
+ rad_free(&request->expect);
+ rad_free(&request->linked);
+
+ return 0;
+}
+
+static void rs_packet_cleanup(rs_request_t *request)
+{
+
+ RADIUS_PACKET *packet = request->packet;
+ uint64_t count = request->id;
+
+ RS_ASSERT(request->stats_req);
+ RS_ASSERT(!request->rt_rsp || request->stats_rsp);
+ RS_ASSERT(packet);
+
+ /*
+ * Don't pollute stats or print spurious messages as radsniff closes.
+ */
+ if (cleanup) {
+ talloc_free(request);
+ return;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &request->when);
+ }
+
+ /*
+ * Were at packet cleanup time which is when the packet was received + timeout
+ * and it's not been linked with a forwarded packet or a response.
+ *
+ * We now count it as lost.
+ */
+ if (!request->silent_cleanup) {
+ if (!request->linked) {
+ if (!request->stats_req) return;
+
+ request->stats_req->interval.lost_total++;
+
+ if (conf->event_flags & RS_LOST) {
+ /* @fixme We should use flags in the request to indicate whether it's been dumped
+ * to a PCAP file or logged yet, this simplifies the body logging logic */
+ rs_packet_print(request, request->id, RS_LOST, request->in, packet, NULL, NULL, false,
+ conf->filter_response_vps || !(conf->event_flags & RS_NORMAL));
+ }
+ }
+
+ if ((request->in->type == PCAP_INTERFACE_IN) && request->logged) {
+ RDEBUG("Cleaning up request packet ID %i", request->expect->id);
+ }
+ }
+
+ /*
+ * Now the request is done, we can update the retransmission stats
+ */
+ if (request->rt_req > RS_RETRANSMIT_MAX) {
+ request->stats_req->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_req->interval.rt_total[request->rt_req]++;
+ }
+
+ if (request->rt_rsp) {
+ if (request->rt_rsp > RS_RETRANSMIT_MAX) {
+ request->stats_rsp->interval.rt_total[RS_RETRANSMIT_MAX]++;
+ } else {
+ request->stats_rsp->interval.rt_total[request->rt_rsp]++;
+ }
+ }
+
+ talloc_free(request);
+}
+
+static void _rs_event(void *ctx)
+{
+ rs_request_t *request = talloc_get_type_abort(ctx, rs_request_t);
+ request->event = NULL;
+ rs_packet_cleanup(request);
+}
+
+/** Wrapper around fr_packet_cmp to strip off the outer request struct
+ *
+ */
+static int rs_packet_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ return fr_packet_cmp(a->expect, b->expect);
+}
+
+static inline int rs_response_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header,
+ uint8_t const *data)
+{
+ if (!event->out) return 0;
+
+ /*
+ * If we're filtering by response then the requests then the capture buffer
+ * associated with the request should contain buffered request packets.
+ */
+ if (conf->filter_response && request) {
+ rs_capture_t *start;
+
+ /*
+ * Record the current position in the header
+ */
+ start = request->capture_p;
+
+ /*
+ * Buffer hasn't looped set capture_p to the start of the buffer
+ */
+ if (!start->header) request->capture_p = request->capture;
+
+ /*
+ * If where capture_p points to, has a header set, write out the
+ * packet to the PCAP file, looping over the buffer until we
+ * hit our start point.
+ */
+ if (request->capture_p->header) do {
+ pcap_dump((void *)event->out->dumper, request->capture_p->header,
+ request->capture_p->data);
+ TALLOC_FREE(request->capture_p->header);
+ TALLOC_FREE(request->capture_p->data);
+
+ /* Reset the pointer to the start of the circular buffer */
+ if (request->capture_p++ >=
+ (request->capture +
+ sizeof(request->capture) / sizeof(*request->capture))) {
+ request->capture_p = request->capture;
+ }
+ } while (request->capture_p != start);
+ }
+
+ /*
+ * Now log the response
+ */
+ pcap_dump((void *)event->out->dumper, header, data);
+
+ return 0;
+}
+
+static inline int rs_request_to_pcap(rs_event_t *event, rs_request_t *request, struct pcap_pkthdr const *header,
+ uint8_t const *data)
+{
+ if (!event->out) return 0;
+
+ /*
+ * If we're filtering by response, then we need to wait to write out the requests
+ */
+ if (conf->filter_response) {
+ /* Free the old capture */
+ if (request->capture_p->header) {
+ talloc_free(request->capture_p->header);
+ TALLOC_FREE(request->capture_p->data);
+ }
+
+ if (!(request->capture_p->header = talloc(request, struct pcap_pkthdr))) return -1;
+ if (!(request->capture_p->data = talloc_array(request, uint8_t, header->caplen))) {
+ TALLOC_FREE(request->capture_p->header);
+ return -1;
+ }
+ memcpy(request->capture_p->header, header, sizeof(struct pcap_pkthdr));
+ memcpy(request->capture_p->data, data, header->caplen);
+
+ /* Reset the pointer to the start of the circular buffer */
+ if (++request->capture_p >=
+ (request->capture +
+ sizeof(request->capture) / sizeof(*request->capture))) {
+ request->capture_p = request->capture;
+ }
+ return 0;
+ }
+
+ pcap_dump((void *)event->out->dumper, header, data);
+
+ return 0;
+}
+
+/* This is the same as immediately scheduling the cleanup event */
+#define RS_CLEANUP_NOW(_x, _s)\
+ {\
+ _x->silent_cleanup = _s;\
+ _x->when = header->ts;\
+ rs_packet_cleanup(_x);\
+ _x = NULL;\
+ } while (0)
+
+static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
+{
+ rs_stats_t *stats = event->stats;
+ struct timeval elapsed = {0, 0};
+ struct timeval latency;
+
+ /*
+ * Pointers into the packet data we just received
+ */
+ ssize_t len;
+ uint8_t const *p = data;
+
+ ip_header_t const *ip = NULL; /* The IP header */
+ ip_header6_t const *ip6 = NULL; /* The IPv6 header */
+ udp_header_t const *udp; /* The UDP header */
+ uint8_t version; /* IP header version */
+ bool response; /* Was it a response code */
+
+ decode_fail_t reason; /* Why we failed decoding the packet */
+ static uint64_t captured = 0;
+
+ rs_status_t status = RS_NORMAL; /* Any special conditions (RTX, Unlinked, ID-Reused) */
+ RADIUS_PACKET *current; /* Current packet were processing */
+ rs_request_t *original = NULL;
+
+ rs_request_t search;
+
+ memset(&search, 0, sizeof(search));
+
+ if (!start_pcap.tv_sec) {
+ start_pcap = header->ts;
+ }
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ len = fr_pcap_link_layer_offset(data, header->caplen, event->in->link_layer);
+ if (len < 0) {
+ REDEBUG("Failed determining link layer header offset");
+ return;
+ }
+ p += len;
+
+ version = (p[0] & 0xf0) >> 4;
+ switch (version) {
+ case 4:
+ ip = (ip_header_t const *)p;
+ len = (0x0f & ip->ip_vhl) * 4; /* ip_hl specifies length in 32bit words */
+ p += len;
+ break;
+
+ case 6:
+ ip6 = (ip_header6_t const *)p;
+ p += sizeof(ip_header6_t);
+
+ break;
+
+ default:
+ REDEBUG("IP version invalid %i", version);
+ return;
+ }
+
+ /*
+ * End of variable length bits, do basic check now to see if packet looks long enough
+ */
+ len = (p - data) + sizeof(udp_header_t) + sizeof(radius_packet_t); /* length value */
+ if ((size_t) len > header->caplen) {
+ REDEBUG("Packet too small, we require at least %zu bytes, captured %i bytes",
+ (size_t) len, header->caplen);
+ return;
+ }
+
+ /*
+ * UDP header validation.
+ */
+ udp = (udp_header_t const *)p;
+ {
+ uint16_t udp_len;
+ ssize_t diff;
+
+ udp_len = ntohs(udp->len);
+ diff = udp_len - (header->caplen - (p - data));
+ /* Truncated data */
+ if (diff > 0) {
+ REDEBUG("Packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff, udp_len);
+ return;
+ }
+
+#if 0
+ /*
+ * It seems many probes add trailing garbage to the end
+ * of each capture frame. This has been observed with
+ * the F5 and Netscout.
+ *
+ * Leaving the code here in case it's ever needed for
+ * debugging.
+ */
+ else if (diff < 0) {
+ REDEBUG("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
+ diff * -1, udp_len);
+ return;
+ }
+#endif
+ }
+ if ((version == 4) && conf->verify_udp_checksum) {
+ uint16_t expected;
+
+ expected = fr_udp_checksum((uint8_t const *) udp, ntohs(udp->len), udp->checksum,
+ ip->ip_src, ip->ip_dst);
+ if (udp->checksum != expected) {
+ REDEBUG("UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
+ ntohs(udp->checksum), ntohs(expected));
+ /* Not a fatal error */
+ }
+ }
+ p += sizeof(udp_header_t);
+
+ /*
+ * With artificial talloc memory limits there's a good chance we can
+ * recover once some requests timeout, so make an effort to deal
+ * with allocation failures gracefully.
+ */
+ current = rad_alloc(conf, false);
+ if (!current) {
+ REDEBUG("Failed allocating memory to hold decoded packet");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ return;
+ }
+
+ current->timestamp = header->ts;
+ current->data_len = header->caplen - (p - data);
+ memcpy(&current->data, &p, sizeof(current->data));
+
+ /*
+ * Populate IP/UDP fields from PCAP data
+ */
+ if (ip) {
+ current->src_ipaddr.af = AF_INET;
+ current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
+
+ current->dst_ipaddr.af = AF_INET;
+ current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
+ } else {
+ current->src_ipaddr.af = AF_INET6;
+ memcpy(current->src_ipaddr.ipaddr.ip6addr.s6_addr, ip6->ip_src.s6_addr,
+ sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr));
+
+ current->dst_ipaddr.af = AF_INET6;
+ memcpy(current->dst_ipaddr.ipaddr.ip6addr.s6_addr, ip6->ip_dst.s6_addr,
+ sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr));
+ }
+
+ current->src_port = ntohs(udp->src);
+ current->dst_port = ntohs(udp->dst);
+
+ if (!rad_packet_ok(current, 0, &reason)) {
+ REDEBUG("%s", fr_strerror());
+ if (conf->event_flags & RS_ERROR) {
+ rs_packet_print(NULL, count, RS_ERROR, event->in, current, &elapsed, NULL, false, false);
+ }
+ rad_free(&current);
+
+ return;
+ }
+
+ switch (current->code) {
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ case PW_CODE_ACCESS_REJECT:
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_COA_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_STATUS_CLIENT:
+ {
+ /* look for a matching request and use it for decoding */
+ search.expect = current;
+ original = rbtree_finddata(request_tree, &search);
+
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_response_code && (conf->filter_response_code != current->code)) {
+ drop_response:
+ RDEBUG2("Response dropped by filter");
+ rad_free(&current);
+
+ /* We now need to cleanup the original request too */
+ if (original) {
+ RS_CLEANUP_NOW(original, true);
+ }
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, original ? original->expect : NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+ if (ret != 0) {
+ rad_free(&current);
+ REDEBUG("Failed decoding");
+ return;
+ }
+ }
+
+ /*
+ * Check if we've managed to link it to a request
+ */
+ if (original) {
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_response_vps) {
+ fr_pair_list_sort(&current->vps, fr_pair_cmp_by_da_tag);
+ if (!fr_pair_validate_relaxed(NULL, conf->filter_response_vps, current->vps)) {
+ goto drop_response;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original->linked) {
+ status = RS_RTX;
+ original->rt_rsp++;
+
+ rad_free(&original->linked);
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's the first response to a request.
+ */
+ } else {
+ original->stats_rsp = &stats->exchange[current->code];
+ }
+
+ /*
+ * Insert a callback to remove the request and response
+ * from the tree after the timeout period.
+ * The delay is so we can detect retransmissions.
+ */
+ original->linked = talloc_steal(original, current);
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original, &original->when,
+ &original->event)) {
+ REDEBUG("Failed inserting new event");
+ /*
+ * Delete the original request/event, it's no longer valid
+ * for statistics.
+ */
+ talloc_free(original);
+ return;
+ }
+ /*
+ * No request seen, or request was dropped by attribute filter
+ */
+ } else {
+ /*
+ * If conf->filter_request_vps are set assume the original request was dropped,
+ * the alternative is maintaining another 'filter', but that adds
+ * complexity, reduces max capture rate, and is generally a PITA.
+ */
+ if (conf->filter_request) {
+ rad_free(&current);
+ RDEBUG2("Original request dropped by filter");
+ return;
+ }
+
+ status = RS_UNLINKED;
+ stats->exchange[current->code].interval.unlinked_total++;
+ }
+
+ rs_response_to_pcap(event, original, header, data);
+ response = true;
+ break;
+ }
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ case PW_CODE_STATUS_SERVER:
+ {
+ /*
+ * Verify this code is allowed
+ */
+ if (conf->filter_request_code && (conf->filter_request_code != current->code)) {
+ drop_request:
+
+ RDEBUG2("Request dropped by filter");
+ rad_free(&current);
+
+ return;
+ }
+
+ /*
+ * Only decode attributes if we want to print them or filter on them
+ * rad_packet_ok does checks to verify the packet is actually valid.
+ */
+ if (conf->decode_attrs) {
+ int ret;
+ FILE *log_fp = fr_log_fp;
+
+ fr_log_fp = NULL;
+ ret = rad_decode(current, NULL, conf->radius_secret);
+ fr_log_fp = log_fp;
+
+ if (ret != 0) {
+ rad_free(&current);
+ REDEBUG("Failed decoding");
+ return;
+ }
+
+ fr_pair_list_sort(&current->vps, fr_pair_cmp_by_da_tag);
+ }
+
+ /*
+ * Save the request for later matching
+ */
+ search.expect = rad_alloc_reply(current, current);
+ if (!search.expect) {
+ REDEBUG("Failed allocating memory to hold expected reply");
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
+ rad_free(&current);
+ return;
+ }
+ search.expect->code = current->code;
+
+ if ((conf->link_da_num > 0) && current->vps) {
+ int ret;
+ ret = rs_get_pairs(current, &search.link_vps, current->vps, conf->link_da,
+ conf->link_da_num);
+ if (ret < 0) {
+ ERROR("Failed extracting RTX linking pairs from request");
+ rad_free(&current);
+ return;
+ }
+ }
+
+ /*
+ * If we have linking attributes set, attempt to find a request in the linking tree.
+ */
+ if (search.link_vps) {
+ rs_request_t *tuple;
+
+ original = rbtree_finddata(link_tree, &search);
+ tuple = rbtree_finddata(request_tree, &search);
+
+ /*
+ * If the packet we matched using attributes is not the same
+ * as the packet in the request tree, then we need to clean up
+ * the packet in the request tree.
+ */
+ if (tuple && (original != tuple)) {
+ RS_CLEANUP_NOW(tuple, true);
+ }
+ /*
+ * Detect duplicates using the normal 5-tuple of src/dst ips/ports id
+ */
+ } else {
+ original = rbtree_finddata(request_tree, &search);
+ if (original && (memcmp(original->expect->vector, current->vector,
+ sizeof(original->expect->vector)) != 0)) {
+ /*
+ * ID reused before the request timed out (which may be an issue)...
+ */
+ if (!original->linked) {
+ status = RS_REUSED;
+ stats->exchange[current->code].interval.reused_total++;
+ /* Occurs regularly downstream of proxy servers (so don't complain) */
+ RS_CLEANUP_NOW(original, true);
+ /*
+ * ...and before we saw a response (which may be a bigger issue).
+ */
+ } else {
+ RS_CLEANUP_NOW(original, false);
+ }
+ /* else it's a proper RTX with the same src/dst id authenticator/nonce */
+ }
+ }
+
+ /*
+ * Now verify the packet passes the attribute filter
+ */
+ if (conf->filter_request_vps) {
+ if (!fr_pair_validate_relaxed(NULL, conf->filter_request_vps, current->vps)) {
+ goto drop_request;
+ }
+ }
+
+ /*
+ * Is this a retransmission?
+ */
+ if (original) {
+ status = RS_RTX;
+ original->rt_req++;
+
+ rad_free(&original->packet);
+
+ /* We may of seen the response, but it may of been lost upstream */
+ rad_free(&original->linked);
+
+ original->packet = talloc_steal(original, current);
+
+ /* Request may need to be reinserted as the 5 tuple of the response may of changed */
+ if (rs_packet_cmp(original, &search) != 0) {
+ rbtree_deletebydata(request_tree, original);
+ }
+
+ rad_free(&original->expect);
+ original->expect = talloc_steal(original, search.expect);
+
+ /* Disarm the timer for the cleanup event for the original request */
+ fr_event_delete(event->list, &original->event);
+ /*
+ * ...nope it's a new request.
+ */
+ } else {
+ original = talloc_zero(conf, rs_request_t);
+ talloc_set_destructor(original, _request_free);
+
+ original->id = count;
+ original->in = event->in;
+ original->stats_req = &stats->exchange[current->code];
+
+ /* Set the packet pointer to the start of the buffer*/
+ original->capture_p = original->capture;
+
+ original->packet = talloc_steal(original, current);
+ original->expect = talloc_steal(original, search.expect);
+
+ if (search.link_vps) {
+ bool ret;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ for (vp = fr_cursor_init(&cursor, &search.link_vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ fr_pair_steal(original, search.link_vps);
+ }
+ original->link_vps = search.link_vps;
+
+ /* We should never have conflicts */
+ ret = rbtree_insert(link_tree, original);
+ RS_ASSERT(ret);
+ original->in_link_tree = true;
+ }
+
+ /*
+ * Special case for when were filtering by response,
+ * we never count any requests as lost, because we
+ * don't know what the response to that request would
+ * of been.
+ */
+ if (conf->filter_response_vps) {
+ original->silent_cleanup = true;
+ }
+ }
+
+ if (!original->in_request_tree) {
+ bool ret;
+
+ /* We should never have conflicts */
+ ret = rbtree_insert(request_tree, original);
+ RS_ASSERT(ret);
+ original->in_request_tree = true;
+ }
+
+ /*
+ * Insert a callback to remove the request from the tree
+ */
+ original->packet->timestamp = header->ts;
+ rs_tv_add_ms(&header->ts, conf->stats.timeout, &original->when);
+ if (!fr_event_insert(event->list, _rs_event, original,
+ &original->when, &original->event)) {
+ REDEBUG("Failed inserting new event");
+
+ talloc_free(original);
+ return;
+ }
+ rs_request_to_pcap(event, original, header, data);
+ response = false;
+ break;
+ }
+
+ default:
+ REDEBUG("Unsupported code %i", current->code);
+ rad_free(&current);
+
+ return;
+ }
+
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+
+ /*
+ * Increase received count
+ */
+ stats->exchange[current->code].interval.received_total++;
+
+ /*
+ * It's a linked response
+ */
+ if (original && original->linked) {
+ rs_tv_sub(&current->timestamp, &original->packet->timestamp, &latency);
+
+ /*
+ * Update stats for both the request and response types.
+ *
+ * This isn't useful for things like Access-Requests, but will be useful for
+ * CoA and Disconnect Messages, as we get the average latency across both
+ * response types.
+ *
+ * It also justifies allocating PW_CODE_MAX instances of rs_latency_t.
+ */
+ rs_stats_update_latency(&stats->exchange[current->code], &latency);
+ rs_stats_update_latency(&stats->exchange[original->expect->code], &latency);
+
+ /*
+ * Were filtering on response, now print out the full data from the request
+ */
+ if (conf->filter_response && RIDEBUG_ENABLED() && (conf->event_flags & RS_NORMAL)) {
+ rs_time_print(timestr, sizeof(timestr), &original->packet->timestamp);
+ rs_tv_sub(&original->packet->timestamp, &start_pcap, &elapsed);
+ rs_packet_print(original, original->id, RS_NORMAL, original->in,
+ original->packet, &elapsed, NULL, false, true);
+ rs_tv_sub(&header->ts, &start_pcap, &elapsed);
+ rs_time_print(timestr, sizeof(timestr), &header->ts);
+ }
+
+ if (conf->event_flags & status) {
+ rs_packet_print(original, count, status, event->in, current,
+ &elapsed, &latency, response, true);
+ }
+ /*
+ * It's the original request
+ *
+ * If were filtering on responses we can only indicate we received it on response, or timeout.
+ */
+ } else if (!conf->filter_response && (conf->event_flags & status)) {
+ rs_packet_print(original, original ? original->id : count, status, event->in,
+ current, &elapsed, NULL, response, true);
+ }
+
+ fflush(fr_log_fp);
+
+ /*
+ * If it's a unlinked response, we need to free it explicitly, as it will
+ * not be done by the event queue.
+ */
+ if (response && !original) {
+ rad_free(&current);
+ }
+
+ captured++;
+ /*
+ * We've hit our capture limit, break out of the event loop
+ */
+ if ((conf->limit > 0) && (captured >= conf->limit)) {
+ INFO("Captured %" PRIu64 " packets, exiting...", captured);
+ fr_event_loop_exit(events, 1);
+ }
+}
+
+static void rs_got_packet(fr_event_list_t *el, int fd, void *ctx)
+{
+ static uint64_t count = 0; /* Packets seen */
+ rs_event_t *event = ctx;
+ pcap_t *handle = event->in->handle;
+
+ int i;
+ int ret;
+ const uint8_t *data;
+ struct pcap_pkthdr *header;
+
+ /*
+ * Consume entire capture, interleaving not currently possible
+ */
+ if ((event->in->type == PCAP_FILE_IN) || (event->in->type == PCAP_STDIO_IN)) {
+ while (!fr_event_loop_exiting(el)) {
+ struct timeval now;
+
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret == -2) {
+ DEBUG("Done reading packets (%s)", event->in->name);
+ fr_event_fd_delete(events, 0, fd);
+
+ /* Signal pipe takes one slot which is why this is == 1 */
+ if (fr_event_list_num_fds(events) == 1) {
+ fr_event_loop_exit(events, 1);
+ }
+
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ do {
+ now = header->ts;
+ } while (fr_event_run(el, &now) == 1);
+ count++;
+
+ rs_packet_process(count, event, header, data);
+ }
+ return;
+ }
+
+ /*
+ * Consume multiple packets from the capture buffer.
+ * We occasionally need to yield to allow events to run.
+ */
+ for (i = 0; i < RS_FORCE_YIELD; i++) {
+ ret = pcap_next_ex(handle, &header, &data);
+ if (ret == 0) {
+ /* No more packets available at this time */
+ return;
+ }
+ if (ret < 0) {
+ ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
+ return;
+ }
+
+ count++;
+ rs_packet_process(count, event, header, data);
+ }
+}
+
+static void _rs_event_status(struct timeval *wake)
+{
+ if (wake && ((wake->tv_sec != 0) || (wake->tv_usec >= 100000))) {
+ DEBUG2("Waking up in %d.%01u seconds.", (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
+
+ if (RIDEBUG_ENABLED()) {
+ rs_time_print(timestr, sizeof(timestr), wake);
+ }
+ }
+}
+
+/** Compare requests using packet info and lists of attributes
+ *
+ */
+static int rs_rtx_cmp(rs_request_t const *a, rs_request_t const *b)
+{
+ int rcode;
+
+ RS_ASSERT(a->link_vps);
+ RS_ASSERT(b->link_vps);
+
+ rcode = (int) a->expect->code - (int) b->expect->code;
+ if (rcode != 0) return rcode;
+
+ rcode = a->expect->sockfd - b->expect->sockfd;
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->src_ipaddr, &b->expect->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ rcode = fr_ipaddr_cmp(&a->expect->dst_ipaddr, &b->expect->dst_ipaddr);
+ if (rcode != 0) return rcode;
+
+ return fr_pair_list_cmp(a->link_vps, b->link_vps);
+}
+
+static int rs_build_dict_list(DICT_ATTR const **out, size_t len, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
+
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ DICT_ATTR const *da;
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
+
+ if (i == len) {
+ ERROR("Too many attributes, maximum allowed is %zu", len);
+ return -1;
+ }
+
+ da = dict_attrbyname(tok);
+ if (!da) {
+ ERROR("Error parsing attribute name \"%s\"", tok);
+ return -1;
+ }
+
+ out[i] = da;
+ i++;
+ }
+
+ /*
+ * This allows efficient list comparisons later
+ */
+ if (i > 1) fr_quick_sort((void const **)out, 0, i - 1, fr_pointer_cmp);
+
+ return i;
+}
+
+static int rs_build_filter(VALUE_PAIR **out, char const *filter)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ FR_TOKEN code;
+
+ code = fr_pair_list_afrom_str(conf, filter, out);
+ if (code == T_INVALID) {
+ ERROR("Invalid RADIUS filter \"%s\" (%s)", filter, fr_strerror());
+ return -1;
+ }
+
+ if (!*out) {
+ ERROR("Empty RADIUS filter '%s'", filter);
+ return -1;
+ }
+
+ for (vp = fr_cursor_init(&cursor, out);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * xlat expansion isn't supported here
+ */
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ }
+ }
+
+ /*
+ * This allows efficient list comparisons later
+ */
+ fr_pair_list_sort(out, fr_pair_cmp_by_da_tag);
+
+ return 0;
+}
+
+static int rs_build_event_flags(int *flags, FR_NAME_NUMBER const *map, char *list)
+{
+ size_t i = 0;
+ char *p, *tok;
+
+ p = list;
+ while ((tok = strsep(&p, "\t ,")) != NULL) {
+ int flag;
+
+ if ((*tok == '\t') || (*tok == ' ') || (*tok == '\0')) {
+ continue;
+ }
+
+ *flags |= flag = fr_str2int(map, tok, -1);
+ if (flag < 0) {
+ ERROR("Invalid flag \"%s\"", tok);
+ return -1;
+ }
+
+ i++;
+ }
+
+ return i;
+}
+
+/** Callback for when the request is removed from the request tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_request(void *request)
+{
+ rs_request_t *this = request;
+ this->in_request_tree = false;
+}
+
+/** Callback for when the request is removed from the link tree
+ *
+ * @param request being removed.
+ */
+static void _unmark_link(void *request)
+{
+ rs_request_t *this = request;
+ this->in_link_tree = false;
+}
+
+#ifdef HAVE_COLLECTDC_H
+/** Re-open the collectd socket
+ *
+ */
+static void rs_collectd_reopen(void *ctx)
+{
+ fr_event_list_t *list = ctx;
+ static fr_event_t *event;
+ struct timeval now, when;
+
+ if (rs_stats_collectd_open(conf) == 0) {
+ DEBUG2("Stats output socket (re)opened");
+ return;
+ }
+
+ ERROR("Will attempt to re-establish connection in %i ms", RS_SOCKET_REOPEN_DELAY);
+
+ gettimeofday(&now, NULL);
+ rs_tv_add_ms(&now, RS_SOCKET_REOPEN_DELAY, &when);
+ if (!fr_event_insert(list, rs_collectd_reopen, list, &when, &event)) {
+ ERROR("Failed inserting re-open event");
+ RS_ASSERT(0);
+ }
+}
+#endif
+
+/** Write the last signal to the signal pipe
+ *
+ * @param sig raised
+ */
+static void rs_signal_self(int sig)
+{
+ if (write(self_pipe[1], &sig, sizeof(sig)) < 0) {
+ ERROR("Failed writing signal %s to pipe: %s", strsignal(sig), fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
+
+/** Read the last signal from the signal pipe
+ *
+ */
+static void rs_signal_action(
+#ifndef HAVE_COLLECTDC_H
+UNUSED
+#endif
+fr_event_list_t *list, int fd, UNUSED void *ctx)
+{
+ int sig;
+ ssize_t ret;
+
+ ret = read(fd, &sig, sizeof(sig));
+ if (ret < 0) {
+ ERROR("Failed reading signal from pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret != sizeof(sig)) {
+ ERROR("Failed reading signal from pipe: "
+ "Expected signal to be %zu bytes but only read %zu byes", sizeof(sig), ret);
+ exit(EXIT_FAILURE);
+ }
+
+ switch (sig) {
+#ifdef HAVE_COLLECTDC_H
+ case SIGPIPE:
+ rs_collectd_reopen(list);
+ break;
+#endif
+
+ case SIGINT:
+ case SIGTERM:
+ case SIGQUIT:
+ DEBUG2("Signalling event loop to exit");
+ fr_event_loop_exit(events, 1);
+ break;
+
+ default:
+ ERROR("Unhandled signal %s", strsignal(sig));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void NEVER_RETURNS usage(int status)
+{
+ FILE *output = status ? stderr : stdout;
+ fprintf(output, "Usage: radsniff [options][stats options] -- [pcap files]\n");
+ fprintf(output, "options:\n");
+ fprintf(output, " -a List all interfaces available for capture.\n");
+ fprintf(output, " -c <count> Number of packets to capture.\n");
+ fprintf(output, " -C Enable UDP checksum validation.\n");
+ fprintf(output, " -d <directory> Set dictionary directory.\n");
+ fprintf(output, " -d <raddb> Set configuration directory (defaults to " RADDBDIR ").\n");
+ fprintf(output, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(output, " -e <event>[,<event>] Only log requests with these event flags.\n");
+ fprintf(output, " Event may be one of the following:\n");
+ fprintf(output, " - received - a request or response.\n");
+ fprintf(output, " - norsp - seen for a request.\n");
+ fprintf(output, " - rtx - of a request that we've seen before.\n");
+ fprintf(output, " - noreq - could be matched with the response.\n");
+ fprintf(output, " - reused - ID too soon.\n");
+ fprintf(output, " - error - decoding the packet.\n");
+ fprintf(output, " -f <filter> PCAP filter (default is 'udp port <port> or <port + 1> or 3799')\n");
+ fprintf(output, " -h This help message.\n");
+ fprintf(output, " -i <interface> Capture packets from interface (defaults to all if supported).\n");
+ fprintf(output, " -I <file> Read packets from file (overrides input of -F).\n");
+ fprintf(output, " -l <attr>[,<attr>] Output packet sig and a list of attributes.\n");
+ fprintf(output, " -L <attr>[,<attr>] Detect retransmissions using these attributes to link requests.\n");
+ fprintf(output, " -m Don't put interface(s) into promiscuous mode.\n");
+ fprintf(output, " -p <port> Filter packets by port (default is 1812).\n");
+ fprintf(output, " -P <pidfile> Daemonize and write out <pidfile>.\n");
+ fprintf(output, " -q Print less debugging information.\n");
+ fprintf(output, " -r <filter> RADIUS attribute request filter.\n");
+ fprintf(output, " -R <filter> RADIUS attribute response filter.\n");
+ fprintf(output, " -s <secret> RADIUS secret.\n");
+ fprintf(output, " -S Write PCAP data to stdout.\n");
+ fprintf(output, " -v Show program version information.\n");
+ fprintf(output, " -w <file> Write output packets to file.\n");
+ fprintf(output, " -x Print more debugging information.\n");
+ fprintf(output, "stats options:\n");
+ fprintf(output, " -W <interval> Periodically write out statistics every <interval> seconds.\n");
+ fprintf(output, " -T <timeout> How many milliseconds before the request is counted as lost "
+ "(defaults to %i).\n", RS_DEFAULT_TIMEOUT);
+#ifdef HAVE_COLLECTDC_H
+ fprintf(output, " -N <prefix> The instance name passed to the collectd plugin.\n");
+ fprintf(output, " -O <server> Write statistics to this collectd server.\n");
+#endif
+ exit(status);
+}
+
+int main(int argc, char *argv[])
+{
+ fr_pcap_t *in = NULL, *in_p;
+ fr_pcap_t **in_head = &in;
+ fr_pcap_t *out = NULL;
+
+ int ret = 1; /* Exit status */
+
+ char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */
+ int port = 1812;
+
+ char buffer[1024];
+
+ int opt;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
+
+ rs_stats_t stats;
+
+ fr_debug_lvl = 1;
+ fr_log_fp = stdout;
+
+ /*
+ * Useful if using radsniff as a long running stats daemon
+ */
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radsniff");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ talloc_set_log_stderr();
+
+ conf = talloc_zero(NULL, rs_t);
+ RS_ASSERT(conf);
+
+ /*
+ * We don't really want probes taking down machines
+ */
+#ifdef HAVE_TALLOC_SET_MEMLIMIT
+ /*
+ * @fixme causes hang in talloc steal
+ */
+ //talloc_set_memlimit(conf, 524288000); /* 50 MB */
+#endif
+
+ /*
+ * Set some defaults
+ */
+ conf->print_packet = true;
+ conf->limit = 0;
+ conf->promiscuous = true;
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+ conf->radius_secret = RS_DEFAULT_SECRET;
+ conf->logger = NULL;
+
+#ifdef HAVE_COLLECTDC_H
+ conf->stats.prefix = RS_DEFAULT_PREFIX;
+#endif
+
+ /*
+ * Get options
+ */
+ while ((opt = getopt(argc, argv, "ab:c:Cd:D:e:Ff:hi:I:l:L:mp:P:qr:R:s:Svw:xXW:T:P:N:O:")) != EOF) {
+ switch (opt) {
+ case 'a':
+ {
+ pcap_if_t *all_devices = NULL;
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ int i = 1;
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ INFO("%i.%s", i++, dev_p->name);
+ }
+ ret = 0;
+ pcap_freealldevs(all_devices);
+ goto finish;
+ }
+
+ /* super secret option */
+ case 'b':
+ conf->buffer_pkts = atoi(optarg);
+ if (conf->buffer_pkts == 0) {
+ ERROR("Invalid buffer length \"%s\"", optarg);
+ usage(1);
+ }
+ break;
+
+ case 'c':
+ conf->limit = atoi(optarg);
+ if (conf->limit == 0) {
+ ERROR("Invalid number of packets \"%s\"", optarg);
+ usage(1);
+ }
+ break;
+
+ /* udp checksum */
+ case 'C':
+ conf->verify_udp_checksum = true;
+ break;
+
+ case 'd':
+ radius_dir = optarg;
+ break;
+
+ case 'D':
+ dict_dir = optarg;
+ break;
+
+ case 'e':
+ if (rs_build_event_flags((int *) &conf->event_flags, rs_events, optarg) < 0) {
+ usage(64);
+ }
+ break;
+
+ case 'f':
+ conf->pcap_filter = optarg;
+ break;
+
+ case 'h':
+ usage(0); /* never returns */
+
+ case 'i':
+ *in_head = fr_pcap_init(conf, optarg, PCAP_INTERFACE_IN);
+ if (!*in_head) goto finish;
+ in_head = &(*in_head)->next;
+ conf->from_dev = true;
+ break;
+
+ case 'I':
+ *in_head = fr_pcap_init(conf, optarg, PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ break;
+
+ case 'l':
+ conf->list_attributes = optarg;
+ break;
+
+ case 'L':
+ conf->link_attributes = optarg;
+ break;
+
+ case 'm':
+ conf->promiscuous = false;
+ break;
+
+ case 'p':
+ port = atoi(optarg);
+ break;
+
+ case 'P':
+ conf->daemonize = true;
+ conf->pidfile = optarg;
+ break;
+
+ case 'q':
+ if (fr_debug_lvl > 0) {
+ fr_debug_lvl--;
+ }
+ break;
+
+ case 'r':
+ conf->filter_request = optarg;
+ break;
+
+ case 'R':
+ conf->filter_response = optarg;
+ break;
+
+ case 's':
+ conf->radius_secret = optarg;
+ break;
+
+ case 'S':
+ conf->to_stdout = true;
+ break;
+
+ case 'v':
+#ifdef HAVE_COLLECTDC_H
+ INFO("%s, %s, collectdclient version %s", radsniff_version, pcap_lib_version(),
+ lcc_version_string());
+#else
+ INFO("%s %s", radsniff_version, pcap_lib_version());
+#endif
+ exit(EXIT_SUCCESS);
+
+ case 'w':
+ out = fr_pcap_init(conf, optarg, PCAP_FILE_OUT);
+ if (!out) {
+ ERROR("Failed creating pcap file \"%s\"", optarg);
+ exit(EXIT_FAILURE);
+ }
+ conf->to_file = true;
+ break;
+
+ case 'x':
+ case 'X':
+ fr_debug_lvl++;
+ break;
+
+ case 'W':
+ conf->stats.interval = atoi(optarg);
+ conf->print_packet = false;
+ if (conf->stats.interval <= 0) {
+ ERROR("Stats interval must be > 0");
+ usage(64);
+ }
+ break;
+
+ case 'T':
+ conf->stats.timeout = atoi(optarg);
+ if (conf->stats.timeout <= 0) {
+ ERROR("Timeout value must be > 0");
+ usage(64);
+ }
+ break;
+
+#ifdef HAVE_COLLECTDC_H
+ case 'N':
+ conf->stats.prefix = optarg;
+ break;
+
+ case 'O':
+ conf->stats.collectd = optarg;
+ conf->stats.out = RS_STATS_OUT_COLLECTD;
+ break;
+#endif
+ default:
+ usage(64);
+ }
+ }
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radsniff");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Useful for file globbing */
+ while (optind < argc) {
+ *in_head = fr_pcap_init(conf, argv[optind], PCAP_FILE_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ conf->from_file = true;
+ optind++;
+ }
+
+ /* Is stdin not a tty? If so it's probably a pipe */
+ if (!isatty(fileno(stdin))) {
+ conf->from_stdin = true;
+ }
+
+ /* What's the point in specifying -F ?! */
+ if (conf->from_stdin && conf->from_file && conf->to_file) {
+ usage(64);
+ }
+
+ /* Can't read from both... */
+ if (conf->from_file && conf->from_dev) {
+ usage(64);
+ }
+
+ /* Reading from file overrides stdin */
+ if (conf->from_stdin && (conf->from_file || conf->from_dev)) {
+ conf->from_stdin = false;
+ }
+
+ /* Writing to file overrides stdout */
+ if (conf->to_file && conf->to_stdout) {
+ conf->to_stdout = false;
+ }
+
+ if (conf->to_stdout) {
+ out = fr_pcap_init(conf, "stdout", PCAP_STDIO_OUT);
+ if (!out) {
+ goto finish;
+ }
+ }
+
+ if (conf->from_stdin) {
+ *in_head = fr_pcap_init(conf, "stdin", PCAP_STDIO_IN);
+ if (!*in_head) {
+ goto finish;
+ }
+ in_head = &(*in_head)->next;
+ }
+
+ if (conf->stats.interval && !conf->stats.out) {
+ conf->stats.out = RS_STATS_OUT_STDIO;
+ }
+
+ if (conf->stats.timeout == 0) {
+ conf->stats.timeout = RS_DEFAULT_TIMEOUT;
+ }
+
+ /*
+ * If were writing pcap data, or CSV to stdout we *really* don't want to send
+ * logging there as well.
+ */
+ if (conf->to_stdout || conf->list_attributes) {
+ fr_log_fp = stderr;
+ }
+
+ if (conf->list_attributes) {
+ conf->logger = rs_packet_print_csv;
+ } else if (fr_debug_lvl > 0) {
+ conf->logger = rs_packet_print_fancy;
+ }
+
+#if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN)
+ if (conf->from_stdin || conf->to_stdout) {
+ ERROR("PCAP streams not supported");
+ goto finish;
+ }
+#endif
+
+ if (!conf->pcap_filter) {
+ snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d",
+ port, port + 1, 3799);
+ conf->pcap_filter = buffer;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radsniff");
+ ret = 64;
+ goto finish;
+ }
+
+ fr_strerror(); /* Clear out any non-fatal errors */
+
+ if (conf->list_attributes) {
+ conf->list_da_num = rs_build_dict_list(conf->list_da, sizeof(conf->list_da) / sizeof(*conf->list_da),
+ conf->list_attributes);
+ if (conf->list_da_num < 0) {
+ usage(64);
+ }
+ rs_packet_print_csv_header();
+ }
+
+ if (conf->link_attributes) {
+ conf->link_da_num = rs_build_dict_list(conf->link_da, sizeof(conf->link_da) / sizeof(*conf->link_da),
+ conf->link_attributes);
+ if (conf->link_da_num < 0) {
+ usage(64);
+ }
+
+ link_tree = rbtree_create(conf, (rbcmp) rs_rtx_cmp, _unmark_link, 0);
+ if (!link_tree) {
+ ERROR("Failed creating RTX tree");
+ goto finish;
+ }
+ }
+
+ if (conf->filter_request) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_request_vps, conf->filter_request) < 0) {
+ usage(64);
+ }
+
+ fr_cursor_init(&cursor, &conf->filter_request_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_request_code = type->vp_integer;
+ talloc_free(type);
+ }
+ }
+
+ if (conf->filter_response) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *type;
+
+ if (rs_build_filter(&conf->filter_response_vps, conf->filter_response) < 0) {
+ usage(64);
+ }
+
+ fr_cursor_init(&cursor, &conf->filter_response_vps);
+ type = fr_cursor_next_by_num(&cursor, PW_PACKET_TYPE, 0, TAG_ANY);
+ if (type) {
+ fr_cursor_remove(&cursor);
+ conf->filter_response_code = type->vp_integer;
+ talloc_free(type);
+ }
+ }
+
+ /*
+ * Default to logging and capturing all events
+ */
+ if (conf->event_flags == 0) {
+ DEBUG("Logging all events");
+ memset(&conf->event_flags, 0xff, sizeof(conf->event_flags));
+ }
+
+ /*
+ * If we need to list attributes, link requests using attributes, filter attributes
+ * or print the packet contents, we need to decode the attributes.
+ *
+ * But, if were just logging requests, or graphing packets, we don't need to decode
+ * attributes.
+ */
+ if (conf->list_da_num || conf->link_da_num || conf->filter_response_vps || conf->filter_request_vps ||
+ conf->print_packet) {
+ conf->decode_attrs = true;
+ }
+
+ /*
+ * Setup the request tree
+ */
+ request_tree = rbtree_create(conf, (rbcmp) rs_packet_cmp, _unmark_request, 0);
+ if (!request_tree) {
+ ERROR("Failed creating request tree");
+ goto finish;
+ }
+
+ /*
+ * Get the default capture device
+ */
+ if (!conf->from_stdin && !conf->from_file && !conf->from_dev) {
+ pcap_if_t *all_devices; /* List of all devices libpcap can listen on */
+ pcap_if_t *dev_p;
+
+ if (pcap_findalldevs(&all_devices, errbuf) < 0) {
+ ERROR("Error getting available capture devices: %s", errbuf);
+ goto finish;
+ }
+
+ if (!all_devices) {
+ ERROR("No capture files specified and no live interfaces available");
+ ret = 64;
+ goto finish;
+ }
+
+ for (dev_p = all_devices;
+ dev_p;
+ dev_p = dev_p->next) {
+ int link_layer;
+
+ /* Don't use the any devices, it's horribly broken */
+ if (!strcmp(dev_p->name, "any")) continue;
+
+ link_layer = fr_pcap_if_link_layer(errbuf, dev_p);
+ if (link_layer < 0) {
+ DEBUG2("Skipping %s: %s", dev_p->name, errbuf);
+ continue;
+ }
+
+ if (!fr_pcap_link_layer_supported(link_layer)) {
+ DEBUG2("Skipping %s: datalink type %s not supported",
+ dev_p->name, pcap_datalink_val_to_name(link_layer));
+ continue;
+ }
+
+ *in_head = fr_pcap_init(conf, dev_p->name, PCAP_INTERFACE_IN);
+ in_head = &(*in_head)->next;
+ }
+ conf->from_auto = true;
+ conf->from_dev = true;
+
+ pcap_freealldevs(all_devices);
+
+ INFO("Defaulting to capture on all interfaces");
+ }
+
+ /*
+ * Print captures values which will be used
+ */
+ if (fr_debug_lvl > 2) {
+ DEBUG2("Sniffing with options:");
+ if (conf->from_dev) {
+ char *buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG2(" Device(s) : [%s]", buff);
+ talloc_free(buff);
+ }
+ if (out) {
+ DEBUG2(" Writing to : [%s]", out->name);
+ }
+ if (conf->limit > 0) {
+ DEBUG2(" Capture limit (packets) : [%" PRIu64 "]", conf->limit);
+ }
+ DEBUG2(" PCAP filter : [%s]", conf->pcap_filter);
+ DEBUG2(" RADIUS secret : [%s]", conf->radius_secret);
+
+ if (conf->filter_request_code) {
+ DEBUG2(" RADIUS request code : [%s]", fr_packet_codes[conf->filter_request_code]);
+ }
+
+ if (conf->filter_request_vps){
+ DEBUG2(" RADIUS request filter :");
+ vp_printlist(fr_log_fp, conf->filter_request_vps);
+ }
+
+ if (conf->filter_response_code) {
+ DEBUG2(" RADIUS response code : [%s]", fr_packet_codes[conf->filter_response_code]);
+ }
+
+ if (conf->filter_response_vps){
+ DEBUG2(" RADIUS response filter :");
+ vp_printlist(fr_log_fp, conf->filter_response_vps);
+ }
+ }
+
+ /*
+ * Setup collectd templates
+ */
+#ifdef HAVE_COLLECTDC_H
+ if (conf->stats.out == RS_STATS_OUT_COLLECTD) {
+ size_t i;
+ rs_stats_tmpl_t *tmpl, **next;
+
+ if (rs_stats_collectd_open(conf) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ next = &conf->stats.tmpl;
+
+ for (i = 0; i < (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes)); i++) {
+ tmpl = rs_stats_collectd_init_latency(conf, next, conf, "exchanged",
+ &stats.exchange[rs_useful_codes[i]],
+ rs_useful_codes[i]);
+ if (!tmpl) {
+ ERROR("Error allocating memory for stats template");
+ goto finish;
+ }
+ next = &(tmpl->next);
+ }
+ }
+#endif
+
+ /*
+ * This actually opens the capture interfaces/files (we just allocated the memory earlier)
+ */
+ {
+ fr_pcap_t *tmp;
+ fr_pcap_t **tmp_p = &tmp;
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ in_p->promiscuous = conf->promiscuous;
+ in_p->buffer_pkts = conf->buffer_pkts;
+ if (fr_pcap_open(in_p) < 0) {
+ ERROR("Failed opening pcap handle (%s): %s", in_p->name, fr_strerror());
+ if (conf->from_auto || (in_p->type == PCAP_FILE_IN)) {
+ continue;
+ }
+
+ goto finish;
+ }
+
+ if (!fr_pcap_link_layer_supported(in_p->link_layer)) {
+ ERROR("Failed opening pcap handle (%s): Datalink type %s not supported",
+ in_p->name, pcap_datalink_val_to_name(in_p->link_layer));
+ goto finish;
+ }
+
+ if (conf->pcap_filter) {
+ if (fr_pcap_apply_filter(in_p, conf->pcap_filter) < 0) {
+ ERROR("Failed applying filter");
+ goto finish;
+ }
+ }
+
+ *tmp_p = in_p;
+ tmp_p = &(in_p->next);
+ }
+ *tmp_p = NULL;
+ in = tmp;
+
+ if (!in) {
+ ERROR("No PCAP sources available");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Clear any irrelevant errors */
+ fr_strerror();
+ }
+
+ /*
+ * Open our output interface (if we have one);
+ */
+ if (out) {
+ out->link_layer = -1; /* Infer output link type from input */
+
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ if (out->link_layer < 0) {
+ out->link_layer = in_p->link_layer;
+ continue;
+ }
+
+ if (out->link_layer != in_p->link_layer) {
+ ERROR("Asked to write to output file, but inputs do not have the same link type");
+ ret = 64;
+ goto finish;
+ }
+ }
+
+ RS_ASSERT(out->link_layer >= 0);
+
+ if (fr_pcap_open(out) < 0) {
+ ERROR("Failed opening pcap output (%s): %s", out->name, fr_strerror());
+ goto finish;
+ }
+ }
+
+ /*
+ * Setup and enter the main event loop. Who needs libev when you can roll your own...
+ */
+ {
+ struct timeval now;
+ rs_update_t update;
+
+ char *buff;
+
+ memset(&stats, 0, sizeof(stats));
+ memset(&update, 0, sizeof(update));
+
+ events = fr_event_list_create(conf, _rs_event_status);
+ if (!events) {
+ ERROR();
+ goto finish;
+ }
+
+ /*
+ * Initialise the signal handler pipe
+ */
+ if (pipe(self_pipe) < 0) {
+ ERROR("Couldn't open signal pipe: %s", fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!fr_event_fd_insert(events, 0, self_pipe[0], rs_signal_action, events)) {
+ ERROR("Failed inserting signal pipe descriptor: %s", fr_strerror());
+ goto finish;
+ }
+
+ /*
+ * Now add fd's for each of the pcap sessions we opened
+ */
+ for (in_p = in;
+ in_p;
+ in_p = in_p->next) {
+ rs_event_t *event;
+
+ event = talloc_zero(events, rs_event_t);
+ event->list = events;
+ event->in = in_p;
+ event->out = out;
+ event->stats = &stats;
+
+ if (!fr_event_fd_insert(events, 0, in_p->fd, rs_got_packet, event)) {
+ ERROR("Failed inserting file descriptor");
+ goto finish;
+ }
+ }
+
+ buff = fr_pcap_device_names(conf, in, ' ');
+ DEBUG("Sniffing on (%s)", buff);
+ talloc_free(buff);
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Insert our stats processor
+ */
+ if (conf->stats.interval) {
+ static fr_event_t *event;
+
+ update.list = events;
+ update.stats = &stats;
+ update.in = in;
+
+ now.tv_sec += conf->stats.interval;
+ now.tv_usec = 0;
+ if (!fr_event_insert(events, rs_stats_process, (void *) &update, &now, &event)) {
+ ERROR("Failed inserting stats event");
+ }
+
+ INFO("Muting stats for the next %i milliseconds (warmup)", conf->stats.timeout);
+ rs_tv_add_ms(&now, conf->stats.timeout, &stats.quiet);
+ }
+ }
+
+
+ /*
+ * Do this as late as possible so we can return an error code if something went wrong.
+ */
+ if (conf->daemonize) {
+ rs_daemonize(conf->pidfile);
+ }
+
+ /*
+ * Setup signal handlers so we always exit gracefully, ensuring output buffers are always
+ * flushed.
+ */
+ fr_set_signal(SIGPIPE, rs_signal_self);
+ fr_set_signal(SIGINT, rs_signal_self);
+ fr_set_signal(SIGTERM, rs_signal_self);
+#ifdef SIGQUIT
+ fr_set_signal(SIGQUIT, rs_signal_self);
+#endif
+
+ fr_event_loop(events); /* Enter the main event loop */
+
+ DEBUG("Done sniffing");
+
+ finish:
+
+ cleanup = true;
+
+ /*
+ * Free all the things! This also closes all the sockets and file descriptors
+ */
+ talloc_free(conf);
+
+ if (conf->daemonize) {
+ unlink(conf->pidfile);
+ }
+
+ return ret;
+}
diff --git a/src/main/radsniff.mk.in b/src/main/radsniff.mk.in
new file mode 100644
index 0000000..3de7ebc
--- /dev/null
+++ b/src/main/radsniff.mk.in
@@ -0,0 +1,13 @@
+PCAP_LIBS := @PCAP_LIBS@
+
+ifneq ($(PCAP_LIBS),)
+TARGET := radsniff
+else
+TARGET :=
+endif
+
+SOURCES := radsniff.c collectd.c
+
+TGT_PREREQS := libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS) $(PCAP_LIBS) $(COLLECTDC_LIBS)
+TGT_LDFLAGS := $(LDFLAGS) $(PCAP_LDFLAGS) $(COLLECTDC_LDFLAGS)
diff --git a/src/main/radtest.in b/src/main/radtest.in
new file mode 100644
index 0000000..6b71032
--- /dev/null
+++ b/src/main/radtest.in
@@ -0,0 +1,135 @@
+#! /bin/sh
+#
+# radtest Emulate the user interface of the old
+# radtest that used to be part of FreeRADIUS.
+#
+# Version: $Id$
+#
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+bindir="@bindir@"
+
+usage() {
+ echo "Usage: radtest [OPTIONS] user passwd radius-server[:port] nas-port-number secret [ppphint] [nasname]" >&2
+ echo " -d RADIUS_DIR Set radius directory" >&2
+ echo " -t <type> Set authentication method" >&2
+ echo " type can be pap, chap, mschap, or eap-md5" >&2
+ echo " -P protocol Select udp (default) or tcp" >&2
+ echo " -x Enable debug output" >&2
+ echo " -4 Use IPv4 for the NAS address (default)" >&2
+ echo " -6 Use IPv6 for the NAS address" >&2
+ exit 1
+}
+
+radclient=$bindir/radclient
+if [ ! -x "$radclient" ] && [ -x ./radclient ]
+then
+ radclient=./radclient
+fi
+
+# radeapclient is used for EAP-MD5.
+radeapclient=$bindir/radeapclient
+
+OPTIONS=
+PASSWORD="User-Password"
+NAS_ADDR_ATTR="NAS-IP-Address"
+
+# We need at LEAST these many options
+if [ $# -lt 5 ]
+then
+ usage
+fi
+
+# Parse new command-line options
+while [ `echo "$1" | cut -c 1` = "-" ]
+do
+ case "$1" in
+ -4)
+ OPTIONS="$OPTIONS -4"
+ NAS_ADDR_ATTR="NAS-IP-Address"
+ shift
+ ;;
+ -6)
+ OPTIONS="$OPTIONS -6"
+ NAS_ADDR_ATTR="NAS-IPv6-Address"
+ shift
+ ;;
+ -d)
+ OPTIONS="$OPTIONS -d $2"
+ shift;shift
+ ;;
+ -P)
+ OPTIONS="$OPTIONS -P $2"
+ shift;shift
+ ;;
+ -x)
+ OPTIONS="$OPTIONS -x"
+ shift
+ ;;
+
+ -t)
+ shift;
+ case "$1" in
+ pap)
+ PASSWORD="User-Password"
+ ;;
+ chap)
+ PASSWORD="CHAP-Password"
+ ;;
+ mschap)
+ PASSWORD="MS-CHAP-Password"
+ ;;
+ eap-md5)
+ PASSWORD="Cleartext-Password"
+ if [ ! -x "$radeapclient" ]
+ then
+ echo "radtest: No 'radeapclient' program was found. Cannot perform EAP-MD5." >&1
+ exit 1
+ fi
+ radclient="$radeapclient"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+ ;;
+
+ *)
+ usage
+ ;;
+ esac
+done
+
+# Check that there are enough options left over.
+if [ $# -lt 5 ] || [ $# -gt 7 ]
+then
+ usage
+fi
+
+if [ "$7" ]
+then
+ nas=$7
+else
+ nas=`(hostname || uname -n) 2>/dev/null | sed 1q`
+fi
+
+(
+ echo "User-Name = \"$1\""
+ echo "$PASSWORD = \"$2\""
+ echo "$NAS_ADDR_ATTR = $nas"
+ echo "NAS-Port = $4"
+ echo "Message-Authenticator = 0x00"
+ if [ "$radclient" = "$radeapclient" ]
+ then
+ echo "EAP-Code = Response"
+ echo "EAP-Type-Identity = \"$1\""
+ fi
+ if [ "$6" != "" -a "$6" != "0" ]
+ then
+ echo "Framed-Protocol = PPP"
+ fi
+) | $radclient $OPTIONS -x $3 auth "$5"
+
+exit $?
diff --git a/src/main/radtest.mk b/src/main/radtest.mk
new file mode 100644
index 0000000..3adc133
--- /dev/null
+++ b/src/main/radtest.mk
@@ -0,0 +1,5 @@
+install: $(R)$(bindir)/radtest
+
+$(R)$(bindir)/radtest: src/main/radtest | $(R)$(bindir)
+ @echo INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(bindir)
diff --git a/src/main/radwho.c b/src/main/radwho.c
new file mode 100644
index 0000000..d534760
--- /dev/null
+++ b/src/main/radwho.c
@@ -0,0 +1,565 @@
+/*@-skipposixheaders@*/
+/*
+ * radwho.c Show who is logged in on the terminal servers.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/sysutmp.h>
+#include <freeradius-devel/radutmp.h>
+
+#include <pwd.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+/*
+ * Header above output and format.
+ */
+static char const *hdr1 =
+"Login Name What TTY When From Location";
+
+static char const *hdr2 =
+"Login Port What When From Location";
+
+static char const *eol = "\n";
+static int showname = -1;
+static int showptype = 0;
+static int showcid = 0;
+static char const *progname = "radwho";
+char const *radlog_dir = NULL;
+
+static char const *radutmp_file = NULL;
+static char const *raddb_dir = RADDBDIR;
+static char const *dict_dir = DICTDIR;
+
+char const *radacct_dir = NULL;
+
+bool log_stripped_names;
+
+static char const *radwho_version = "radwho version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+/*
+ * Global, for log.c to use.
+ */
+main_config_t main_config;
+
+#include <sys/wait.h>
+#ifdef HAVE_PTHREAD_H
+pid_t rad_fork(void)
+{
+ return fork();
+}
+
+pid_t rad_waitpid(pid_t pid, int *status)
+{
+ return waitpid(pid, status, 0);
+}
+#endif
+
+static struct radutmp_config_t {
+ char const *radutmp_fn;
+} radutmpconfig;
+
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_POINTER(PW_TYPE_FILE_INPUT, &radutmpconfig.radutmp_fn), RADUTMP },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Get fullname of a user.
+ */
+static char *fullname(char *username)
+{
+#ifdef HAVE_PWD_H
+ struct passwd *pwd;
+ char *s;
+
+ if ((pwd = getpwnam(username)) != NULL) {
+ if ((s = strchr(pwd->pw_gecos, ',')) != NULL) *s = 0;
+ return pwd->pw_gecos;
+ }
+#endif
+
+ return username;
+}
+
+/*
+ * Return protocol type.
+ */
+static char const *proto(int id, int porttype)
+{
+ static char buf[8];
+
+ if (showptype) {
+ if (!strchr("ASITX", porttype))
+ porttype = ' ';
+ if (id == 'S')
+ snprintf(buf, sizeof(buf), "SLP %c", porttype);
+ else if (id == 'P')
+ snprintf(buf, sizeof(buf), "PPP %c", porttype);
+ else
+ snprintf(buf, sizeof(buf), "shl %c", porttype);
+ return buf;
+ }
+ if (id == 'S') return "SLIP";
+ if (id == 'P') return "PPP";
+ return "shell";
+}
+
+/*
+ * Return a time in the form day hh:mm
+ */
+static char *dotime(time_t t)
+{
+ char *s = ctime(&t);
+
+ if (showname) {
+ strlcpy(s + 4, s + 11, 6);
+ s[9] = 0;
+ } else {
+ strlcpy(s + 4, s + 8, 9);
+ s[12] = 0;
+ }
+
+ return s;
+}
+
+
+/*
+ * Print address of NAS.
+ */
+static char const *hostname(char *buf, size_t buflen, uint32_t ipaddr)
+{
+ /*
+ * WTF is this code for?
+ */
+ if (ipaddr == 0 || ipaddr == (uint32_t)-1 || ipaddr == (uint32_t)-2)
+ return "";
+
+ return inet_ntop(AF_INET, &ipaddr, buf, buflen);
+
+}
+
+
+/*
+ * Print usage message and exit.
+ */
+static void NEVER_RETURNS usage(int status)
+{
+ FILE *output = status?stderr:stdout;
+
+ fprintf(output, "Usage: radwho [-d raddb] [-cfihnprRsSZ] [-N nas] [-P nas_port] [-u user] [-U user]\n");
+ fprintf(output, " -c Show caller ID, if available.\n");
+ fprintf(output, " -d Set the raddb directory (default is %s).\n", RADIUS_DIR);
+ fprintf(output, " -F <file> Use radutmp <file>.\n");
+ fprintf(output, " -i Show session ID.\n");
+ fprintf(output, " -n No full name.\n");
+ fprintf(output, " -N <nas-ip-address> Show entries matching the given NAS IP address.\n");
+ fprintf(output, " -p Show port type.\n");
+ fprintf(output, " -P <port> Show entries matching the given nas port.\n");
+ fprintf(output, " -r Print output as raw comma-delimited data.\n");
+ fprintf(output, " -R Print output as RADIUS attributes and values.\n");
+ fprintf(output, " includes ALL information from the radutmp record.\n");
+ fprintf(output, " -s Show full name.\n");
+ fprintf(output, " -S Hide shell users from radius.\n");
+ fprintf(output, " -u <user> Show entries matching the given user.\n");
+ fprintf(output, " -U <user> Like -u, but case-sensitive.\n");
+ fprintf(output, " -v Show program version information.\n");
+ fprintf(output, " -Z Include accounting stop information in radius output. Requires -R.\n");
+ exit(status);
+}
+
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+ CONF_SECTION *maincs, *cs;
+ FILE *fp;
+ struct radutmp rt;
+ char othername[256];
+ char nasname[1024];
+ char session_id[sizeof(rt.session_id)+1];
+ int hideshell = 0;
+ int showsid = 0;
+ int rawoutput = 0;
+ int radiusoutput = 0; /* Radius attributes */
+ char const *portind;
+ int c;
+ unsigned int portno;
+ char buffer[2048];
+ char const *user = NULL;
+ int user_cmp = 0;
+ time_t now = 0;
+ uint32_t nas_port = ~0;
+ uint32_t nas_ip_address = INADDR_NONE;
+ int zap = 0;
+
+ raddb_dir = RADIUS_DIR;
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radwho");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ talloc_set_log_stderr();
+
+ while((c = getopt(argc, argv, "d:D:fF:nN:sSipP:crRu:U:vZ")) != EOF) switch (c) {
+ case 'd':
+ raddb_dir = optarg;
+ break;
+ case 'D':
+ dict_dir = optarg;
+ break;
+ case 'F':
+ radutmp_file = optarg;
+ break;
+ case 'h':
+ usage(0); /* never returns */
+
+ case 'S':
+ hideshell = 1;
+ break;
+ case 'n':
+ showname = 0;
+ break;
+ case 'N':
+ if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) {
+ usage(1);
+ }
+ break;
+ case 's':
+ showname = 1;
+ break;
+ case 'i':
+ showsid = 1;
+ break;
+ case 'p':
+ showptype = 1;
+ break;
+ case 'P':
+ nas_port = atoi(optarg);
+ break;
+ case 'c':
+ showcid = 1;
+ showname = 1;
+ break;
+ case 'r':
+ rawoutput = 1;
+ break;
+ case 'R':
+ radiusoutput = 1;
+ now = time(NULL);
+ break;
+ case 'u':
+ user = optarg;
+ user_cmp = 0;
+ break;
+ case 'U':
+ user = optarg;
+ user_cmp = 1;
+ break;
+ case 'v':
+ printf("%s\n", radwho_version);
+ exit(EXIT_SUCCESS);
+ case 'Z':
+ zap = 1;
+ break;
+
+ default:
+ usage(1); /* never returns */
+ }
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radwho");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radwho");
+ return 1;
+ }
+
+ if (dict_read(raddb_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radwho");
+ return 1;
+ }
+ fr_strerror(); /* Clear the error buffer */
+
+ /*
+ * Be safe.
+ */
+ if (zap && !radiusoutput) zap = 0;
+
+ /*
+ * zap EVERYONE, but only on this nas
+ */
+ if (zap && !user && (~nas_port == 0)) {
+ /*
+ * We need to know which NAS to zap users in.
+ */
+ if (nas_ip_address == INADDR_NONE) usage(1);
+
+ printf("Acct-Status-Type = Accounting-Off\n");
+ printf("NAS-IP-Address = %s\n",
+ hostname(buffer, sizeof(buffer), nas_ip_address));
+ printf("Acct-Delay-Time = 0\n");
+ exit(0); /* don't bother printing anything else */
+ }
+
+ if (radutmp_file) goto have_radutmp;
+
+ /*
+ * Initialize main_config
+ */
+ memset(&main_config, 0, sizeof(main_config));
+
+ /* Read radiusd.conf */
+ maincs = cf_section_alloc(NULL, "main", NULL);
+ if (!maincs) exit(1);
+
+ snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir);
+ if (cf_file_read(maincs, buffer) < 0) {
+ fprintf(stderr, "%s: Error reading or parsing radiusd.conf\n", argv[0]);
+ talloc_free(maincs);
+ exit(1);
+ }
+
+ cs = cf_section_sub_find(maincs, "modules");
+ if (!cs) {
+ fprintf(stderr, "%s: No modules section found in radiusd.conf\n", argv[0]);
+ exit(1);
+ }
+ /* Read the radutmp section of radiusd.conf */
+ cs = cf_section_sub_find_name2(cs, "radutmp", NULL);
+ if (!cs) {
+ fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]);
+ exit(1);
+ }
+
+ cf_section_parse(cs, NULL, module_config);
+
+ /* Assign the correct path for the radutmp file */
+ radutmp_file = radutmpconfig.radutmp_fn;
+
+ have_radutmp:
+ if (showname < 0) showname = 1;
+
+ /*
+ * Show the users logged in on the terminal server(s).
+ */
+ if ((fp = fopen(radutmp_file, "r")) == NULL) {
+ fprintf(stderr, "%s: Error reading %s: %s\n",
+ progname, radutmp_file, fr_syserror(errno));
+ return 0;
+ }
+
+ /*
+ * Don't print the headers if raw or RADIUS
+ */
+ if (!rawoutput && !radiusoutput) {
+ fputs(showname ? hdr1 : hdr2, stdout);
+ fputs(eol, stdout);
+ }
+
+ /*
+ * Read the file, printing out active entries.
+ */
+ while (fread(&rt, sizeof(rt), 1, fp) == 1) {
+ char name[sizeof(rt.login) + 1];
+
+ if (rt.type != P_LOGIN) continue; /* hide logout sessions */
+
+ /*
+ * We don't show shell users if we are
+ * fingerd, as we have done that above.
+ */
+ if (hideshell && !strchr("PCS", rt.proto))
+ continue;
+
+ /*
+ * Print out sessions only for the given user.
+ */
+ if (user) { /* only for a particular user */
+ if (((user_cmp == 0) &&
+ (strncasecmp(rt.login, user, strlen(user)) != 0)) ||
+ ((user_cmp == 1) &&
+ (strncmp(rt.login, user, strlen(user)) != 0))) {
+ continue;
+ }
+ }
+
+ /*
+ * Print out only for the given NAS port.
+ */
+ if (~nas_port != 0) {
+ if (rt.nas_port != nas_port) continue;
+ }
+
+ /*
+ * Print out only for the given NAS IP address
+ */
+ if (nas_ip_address != INADDR_NONE) {
+ if (rt.nas_address != nas_ip_address) continue;
+ }
+
+ memcpy(session_id, rt.session_id, sizeof(rt.session_id));
+ session_id[sizeof(rt.session_id)] = 0;
+
+ if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) {
+ portind = ">";
+ portno = (showname ? 999 : 99999);
+ } else {
+ portind = "S";
+ portno = rt.nas_port;
+ }
+
+ /*
+ * Print output as RADIUS attributes
+ */
+ if (radiusoutput) {
+ memcpy(nasname, rt.login, sizeof(rt.login));
+ nasname[sizeof(rt.login)] = '\0';
+
+ fr_prints(buffer, sizeof(buffer), nasname, -1, '"');
+ printf("User-Name = \"%s\"\n", buffer);
+
+ fr_prints(buffer, sizeof(buffer), session_id, -1, '"');
+ printf("Acct-Session-Id = \"%s\"\n", buffer);
+
+ if (zap) printf("Acct-Status-Type = Stop\n");
+
+ printf("NAS-IP-Address = %s\n",
+ hostname(buffer, sizeof(buffer),
+ rt.nas_address));
+ printf("NAS-Port = %u\n", rt.nas_port);
+
+ switch (rt.proto) {
+ case 'S':
+ printf("Service-Type = Framed-User\n");
+ printf("Framed-Protocol = SLIP\n");
+ break;
+
+ case 'P':
+ printf("Service-Type = Framed-User\n");
+ printf("Framed-Protocol = PPP\n");
+ break;
+
+ default:
+ printf("Service-type = Login-User\n");
+ break;
+ }
+ if (rt.framed_address != INADDR_NONE) {
+ printf("Framed-IP-Address = %s\n",
+ hostname(buffer, sizeof(buffer),
+ rt.framed_address));
+ }
+
+ /*
+ * Some sanity checks on the time
+ */
+ if ((rt.time <= now) &&
+ (now - rt.time) <= (86400 * 365)) {
+ printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time));
+ }
+
+ if (rt.caller_id[0] != '\0') {
+ memcpy(nasname, rt.caller_id,
+ sizeof(rt.caller_id));
+ nasname[sizeof(rt.caller_id)] = '\0';
+
+ fr_prints(buffer, sizeof(buffer), nasname, -1, '"');
+ printf("Calling-Station-Id = \"%s\"\n", buffer);
+ }
+
+ printf("\n"); /* separate entries with a blank line */
+ continue;
+ }
+
+ /*
+ * Show the fill name, or not.
+ */
+ memcpy(name, rt.login, sizeof(rt.login));
+ name[sizeof(rt.login)] = '\0';
+
+ if (showname) {
+ if (rawoutput == 0) {
+ printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s",
+ name,
+ showcid ? rt.caller_id :
+ (showsid? session_id : fullname(rt.login)),
+ proto(rt.proto, rt.porttype),
+ portind, portno,
+ dotime(rt.time),
+ hostname(nasname, sizeof(nasname), rt.nas_address),
+ hostname(othername, sizeof(othername), rt.framed_address), eol);
+ } else {
+ printf("%s,%s,%s,%s%u,%s,%s,%s%s",
+ name,
+ showcid ? rt.caller_id :
+ (showsid? session_id : fullname(rt.login)),
+ proto(rt.proto, rt.porttype),
+ portind, portno,
+ dotime(rt.time),
+ hostname(nasname, sizeof(nasname), rt.nas_address),
+ hostname(othername, sizeof(othername), rt.framed_address), eol);
+ }
+ } else {
+ if (rawoutput == 0) {
+ printf("%-10.10s %s%-5u %-6.6s %-13.13s %-15.15s %-.28s%s",
+ name,
+ portind, portno,
+ proto(rt.proto, rt.porttype),
+ dotime(rt.time),
+ hostname(nasname, sizeof(nasname), rt.nas_address),
+ hostname(othername, sizeof(othername), rt.framed_address),
+ eol);
+ } else {
+ printf("%s,%s%u,%s,%s,%s,%s%s",
+ name,
+ portind, portno,
+ proto(rt.proto, rt.porttype),
+ dotime(rt.time),
+ hostname(nasname, sizeof(nasname), rt.nas_address),
+ hostname(othername, sizeof(othername), rt.framed_address),
+ eol);
+ }
+ }
+ }
+ fclose(fp);
+
+ return 0;
+}
diff --git a/src/main/radwho.mk b/src/main/radwho.mk
new file mode 100644
index 0000000..5d9a92a
--- /dev/null
+++ b/src/main/radwho.mk
@@ -0,0 +1,5 @@
+TARGET := radwho
+SOURCES := radwho.c
+
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS)
diff --git a/src/main/radzap b/src/main/radzap
new file mode 100755
index 0000000..f05f253
--- /dev/null
+++ b/src/main/radzap
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# $Id$
+#
+
+usage() {
+ echo "Usage: radzap [options] server[:port] secret" >&2
+ echo " -h Print usage help information."
+ echo " -d raddb_directory: directory where radiusd.conf is located."
+ echo " -D dict_directory: directory where the dictionaries are located."
+ echo " -N nas_ip_address: IP address of the NAS to zap."
+ echo " -P nas_port: NAS port that the user is logged into."
+ echo " -u username: Name of user to zap (case insensitive)."
+ echo " -U username: like -u, but case-sensitive."
+ echo " -x Enable debugging output."
+ exit ${1:-0}
+}
+
+while test "$#" != "0"
+do
+ case $1 in
+ -h) usage;;
+
+ -d) OPTS="$OPTS -d $2";shift;shift;;
+
+ -D) OPTS="$OPTS -D $2";shift;shift;;
+
+ -N) NAS_IP_ADDR="-N $2";shift;shift;;
+
+ -P) NAS_PORT="-P $2";shift;shift;;
+
+ -u) USER_NAME="-u $2";shift;shift;;
+
+ -U) USER_NAME="-U $2";shift;shift;;
+
+ -x) DEBUG="-x";shift;;
+
+ *) break;;
+
+ esac
+done
+
+if test "$#" != "2"; then
+ usage 1 >&2
+fi
+
+
+SERVER=$1
+SECRET=$2
+
+#
+# Radzap is now a wrapper around radwho & radclient.
+#
+radwho -ZR $OPTS $NAS_IP_ADDR $NAS_PORT $USER_NAME | radclient $DEBUG $OPTS -f - $SERVER acct $SECRET
diff --git a/src/main/radzap.mk b/src/main/radzap.mk
new file mode 100644
index 0000000..bd0eb6d
--- /dev/null
+++ b/src/main/radzap.mk
@@ -0,0 +1,5 @@
+install: $(R)$(bindir)/radzap
+
+$(R)$(bindir)/radzap: src/main/radzap | $(R)$(bindir)
+ @echo INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(bindir)
diff --git a/src/main/realms.c b/src/main/realms.c
new file mode 100644
index 0000000..2959d82
--- /dev/null
+++ b/src/main/realms.c
@@ -0,0 +1,3247 @@
+/*
+ * realms.c Realm handling code
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/realms.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+
+static rbtree_t *realms_byname = NULL;
+#ifdef WITH_TCP
+bool home_servers_udp = false;
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_REGEX
+typedef struct realm_regex realm_regex_t;
+
+/** Regular expression associated with a realm
+ *
+ */
+struct realm_regex {
+ REALM *realm; //!< The realm this regex matches.
+ regex_t *preg; //!< The pre-compiled regular expression.
+ realm_regex_t *next; //!< The next realm in the list of regular expressions.
+};
+static realm_regex_t *realms_regex = NULL;
+#endif /* HAVE_REGEX */
+
+struct realm_config {
+ CONF_SECTION *cs;
+#ifdef HAVE_DIRENT_H
+ char const *directory;
+#endif
+ uint32_t dead_time;
+ uint32_t retry_count;
+ uint32_t retry_delay;
+ bool dynamic;
+ bool fallback;
+ bool wake_all_if_all_dead;
+};
+
+static const FR_NAME_NUMBER home_server_types[] = {
+ { "auth", HOME_TYPE_AUTH },
+ { "acct", HOME_TYPE_ACCT },
+ { "auth+acct", HOME_TYPE_AUTH_ACCT },
+ { "coa", HOME_TYPE_COA },
+#ifdef WITH_COA_TUNNEL
+ { "auth+coa", HOME_TYPE_AUTH_COA },
+ { "auth+acct+coa", HOME_TYPE_AUTH_ACCT_COA },
+#endif
+ { NULL, 0 }
+};
+
+static const FR_NAME_NUMBER home_ping_check[] = {
+ { "none", HOME_PING_CHECK_NONE },
+ { "status-server", HOME_PING_CHECK_STATUS_SERVER },
+ { "request", HOME_PING_CHECK_REQUEST },
+ { NULL, 0 }
+};
+
+static const FR_NAME_NUMBER home_proto[] = {
+ { "UDP", IPPROTO_UDP },
+ { "TCP", IPPROTO_TCP },
+ { NULL, 0 }
+};
+
+#ifdef WITH_RADIUSV11
+extern int fr_radiusv11_client_init(fr_tls_server_conf_t *tls);
+#endif
+
+static realm_config_t *realm_config = NULL;
+
+#ifdef WITH_PROXY
+static rbtree_t *home_servers_byaddr = NULL;
+static rbtree_t *home_servers_byname = NULL;
+#ifdef WITH_STATS
+int home_server_max_number = 0;
+static rbtree_t *home_servers_bynumber = NULL;
+#endif
+
+static rbtree_t *home_pools_byname = NULL;
+
+/*
+ * Map the proxy server configuration parameters to variables.
+ */
+static const CONF_PARSER proxy_config[] = {
+ { "retry_delay", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_delay), STRINGIFY(RETRY_DELAY) },
+
+ { "retry_count", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, retry_count), STRINGIFY(RETRY_COUNT) },
+
+ { "default_fallback", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, fallback), "no" },
+
+ { "dynamic", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, dynamic), NULL },
+
+#ifdef HAVE_DIRENT_H
+ { "directory", FR_CONF_OFFSET(PW_TYPE_STRING, realm_config_t, directory), NULL },
+#endif
+
+ { "dead_time", FR_CONF_OFFSET(PW_TYPE_INTEGER, realm_config_t, dead_time), STRINGIFY(DEAD_TIME) },
+
+ { "wake_all_if_all_dead", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, realm_config_t, wake_all_if_all_dead), "no" },
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+static int realm_name_cmp(void const *one, void const *two)
+{
+ REALM const *a = one;
+ REALM const *b = two;
+
+ return strcasecmp(a->name, b->name);
+}
+
+
+#ifdef WITH_PROXY
+static void home_server_free(void *data)
+{
+ home_server_t *home = talloc_get_type_abort(data, home_server_t);
+
+ talloc_free(home);
+}
+
+static int home_server_name_cmp(void const *one, void const *two)
+{
+ home_server_t const *a = one;
+ home_server_t const *b = two;
+
+ if (a->type < b->type) return -1;
+ if (a->type > b->type) return +1;
+
+ return strcasecmp(a->name, b->name);
+}
+
+static int home_server_addr_cmp(void const *one, void const *two)
+{
+ int rcode;
+ home_server_t const *a = one;
+ home_server_t const *b = two;
+
+ if (a->virtual_server && !b->virtual_server) return -1;
+ if (!a->virtual_server && b->virtual_server) return +1;
+ if (a->virtual_server && b->virtual_server) {
+ rcode = a->type - b->type;
+ if (rcode != 0) return rcode;
+ return strcmp(a->virtual_server, b->virtual_server);
+ }
+
+ if (a->port < b->port) return -1;
+ if (a->port > b->port) return +1;
+
+#ifdef WITH_TCP
+ if (a->proto < b->proto) return -1;
+ if (a->proto > b->proto) return +1;
+#endif
+
+ rcode = fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
+}
+
+#ifdef WITH_STATS
+static int home_server_number_cmp(void const *one, void const *two)
+{
+ home_server_t const *a = one;
+ home_server_t const *b = two;
+
+ return (a->number - b->number);
+}
+#endif
+
+static int home_pool_name_cmp(void const *one, void const *two)
+{
+ home_pool_t const *a = one;
+ home_pool_t const *b = two;
+
+ if (a->server_type < b->server_type) return -1;
+ if (a->server_type > b->server_type) return +1;
+
+ return strcasecmp(a->name, b->name);
+}
+
+
+static size_t xlat_cs(CONF_SECTION *cs, char const *fmt, char *out, size_t outlen)
+{
+ char const *value = NULL;
+
+ if (!fmt) {
+ DEBUG("No configuration item requested. Ignoring.");
+
+ *out = '\0';
+ return 0;
+ }
+
+ /*
+ * Instance name
+ */
+ if (strcmp(fmt, "instance") == 0) {
+ value = cf_section_name2(cs);
+ if (!value) {
+ *out = '\0';
+ return 0;
+ }
+ } else {
+ CONF_PAIR *cp;
+
+ cp = cf_pair_find(cs, fmt);
+ if (!cp || !(value = cf_pair_value(cp))) {
+ *out = '\0';
+ return 0;
+ }
+ }
+
+ strlcpy(out, value, outlen);
+
+ return strlen(out);
+}
+
+
+/*
+ * Xlat for %{home_server:foo}
+ */
+static ssize_t xlat_home_server(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ if (!request->home_server) {
+ RWDEBUG("No home_server associated with this request");
+
+ *out = '\0';
+ return 0;
+ }
+
+ if (!fmt) {
+ RWDEBUG("No configuration item requested. Ignoring.");
+
+ *out = '\0';
+ return 0;
+ }
+
+ if (strcmp(fmt, "state") == 0) {
+ char const *state;
+
+ switch (request->home_server->state) {
+ case HOME_STATE_ALIVE:
+ state = "alive";
+ break;
+
+ case HOME_STATE_ZOMBIE:
+ state = "zombie";
+ break;
+
+ case HOME_STATE_IS_DEAD:
+ state = "dead";
+ break;
+
+ case HOME_STATE_CONNECTION_FAIL:
+ state = "fail";
+ break;
+
+ case HOME_STATE_ADMIN_DOWN:
+ state = "down";
+ break;
+
+ default:
+ state = "unknown";
+ break;
+ }
+
+ strlcpy(out, state, outlen);
+ return strlen(out);
+ }
+
+ return xlat_cs(request->home_server->cs, fmt, out, outlen);
+}
+
+
+/*
+ * Xlat for %{home_server_pool:foo}
+ */
+static ssize_t xlat_server_pool(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ if (!request->home_pool) {
+ RWDEBUG("No home_pool associated with this request");
+
+ *out = '\0';
+ return 0;
+ }
+
+ if (!fmt) {
+ RWDEBUG("No configuration item requested. Ignoring.");
+
+ *out = '\0';
+ return 0;
+ }
+
+ if (strcmp(fmt, "state") == 0) {
+ char const *state;
+
+ if (request->home_pool->in_fallback) {
+ state = "fallback";
+
+ } else {
+ state = "alive";
+ }
+
+ strlcpy(out, state, outlen);
+ return strlen(out);
+ }
+
+ return xlat_cs(request->home_pool->cs, fmt, out, outlen);
+}
+
+
+/*
+ * Xlat for %{home_server_dynamic:foo}
+ */
+static ssize_t xlat_home_server_dynamic(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ int type;
+ char const *p, *name;
+ home_server_t *home;
+ char buffer[1024];
+
+ if (outlen < 2) return 0;
+
+ switch (request->packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ type = HOME_TYPE_AUTH;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ type = HOME_TYPE_ACCT;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ type = HOME_TYPE_COA;
+ break;
+#endif
+
+ default:
+ *out = '\0';
+ return 0;
+ }
+
+ p = fmt;
+ while (isspace((uint8_t) *p)) p++;
+
+ /*
+ * Allow for dynamic strings as arguments.
+ */
+ if (*p == '&') {
+ VALUE_PAIR *vp;
+
+ if ((radius_get_vp(&vp, request, p) < 0) || !vp ||
+ (vp->da->type != PW_TYPE_STRING)) {
+ return -1;
+ }
+ name = vp->vp_strvalue;
+
+ } else if (*p == '%') {
+ if (radius_xlat(buffer, sizeof(buffer), request, p, NULL, NULL) < 0) {
+ return -1;
+ }
+ name = buffer;
+
+ } else {
+ name = p;
+ }
+
+ home = home_server_byname(name, type);
+ if (!home) {
+ *out = '\0';
+ return 0;
+ }
+
+ /*
+ * 1 for dynamic, 0 for static
+ */
+ out[0] = '0' + home->dynamic;
+ out[1] = '\0';
+
+ return 1;
+}
+#endif
+
+void realms_free(void)
+{
+#ifdef WITH_PROXY
+# ifdef WITH_STATS
+ rbtree_free(home_servers_bynumber);
+ home_servers_bynumber = NULL;
+# endif
+
+ rbtree_free(home_servers_byname);
+ home_servers_byname = NULL;
+
+ rbtree_free(home_servers_byaddr);
+ home_servers_byaddr = NULL;
+
+ rbtree_free(home_pools_byname);
+ home_pools_byname = NULL;
+#endif
+
+ rbtree_free(realms_byname);
+ realms_byname = NULL;
+
+ realm_pool_free(NULL);
+
+ talloc_free(realm_config);
+ realm_config = NULL;
+}
+
+
+#ifdef WITH_PROXY
+static CONF_PARSER limit_config[] = {
+ { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_connections), "16" },
+ { "max_requests", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.max_requests), "0" },
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.lifetime), "0" },
+ { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, limit.idle_timeout), "0" },
+ CONF_PARSER_TERMINATOR
+};
+
+#ifdef WITH_COA
+static CONF_PARSER home_server_coa[] = {
+ { "irt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_irt), STRINGIFY(2) },
+ { "mrt", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrt), STRINGIFY(16) },
+ { "mrc", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrc), STRINGIFY(5) },
+ { "mrd", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, coa_mrd), STRINGIFY(30) },
+ CONF_PARSER_TERMINATOR
+};
+
+
+
+#ifdef WITH_COA_TUNNEL
+static CONF_PARSER home_server_recv_coa[] = {
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, recv_coa_server), NULL },
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+#endif
+
+static CONF_PARSER home_server_config[] = {
+ { "nonblock", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, home_server_t, nonblock), "no" },
+ { "ipaddr", FR_CONF_OFFSET(PW_TYPE_COMBO_IP_ADDR, home_server_t, ipaddr), NULL },
+ { "ipv4addr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, home_server_t, ipaddr), NULL },
+ { "ipv6addr", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, home_server_t, ipaddr), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, virtual_server), NULL },
+
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, home_server_t, port), "0" },
+
+ { "type", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, type_str), NULL },
+
+#ifdef WITH_TCP
+ { "proto", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, proto_str), NULL },
+#endif
+
+ { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, home_server_t, secret), NULL },
+
+ { "src_ipaddr", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, src_ipaddr_str), NULL },
+
+ { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, home_server_t, response_window), "30" },
+ { "response_timeouts", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_response_timeouts), "1" },
+ { "max_outstanding", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, max_outstanding), "65536" },
+
+ { "zombie_period", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, zombie_period), "40" },
+
+ { "status_check", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), "none" },
+ { "ping_check", FR_CONF_OFFSET(PW_TYPE_STRING, home_server_t, ping_check_str), NULL },
+
+ { "ping_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), "30" },
+ { "check_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_interval), NULL },
+
+ { "check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), "4" },
+ { "status_check_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ping_timeout), NULL },
+
+ { "num_answers_to_alive", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, num_pings_to_alive), "3" },
+ { "revive_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, revive_interval), "300" },
+
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_name), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_password), NULL },
+
+#ifdef WITH_STATS
+ { "historic_average_window", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ema.window), NULL },
+#endif
+
+ { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
+
+#ifdef WITH_COA
+ { "coa", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) home_server_coa },
+#ifdef WITH_COA_TUNNEL
+ { "recv_coa", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) home_server_recv_coa },
+#endif
+#endif
+
+ CONF_PARSER_TERMINATOR
+};
+
+
+static void null_free(UNUSED void *data)
+{
+}
+
+/*
+ * Ensure that all of the parameters in the home server are OK.
+ */
+void realm_home_server_sanitize(home_server_t *home, CONF_SECTION *cs)
+{
+ CONF_SECTION *parent = NULL;
+
+ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, >=, 8);
+ FR_INTEGER_BOUND_CHECK("max_outstanding", home->max_outstanding, <=, 65536*16);
+
+ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, >=, 6);
+ FR_INTEGER_BOUND_CHECK("ping_interval", home->ping_interval, <=, 120);
+
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, >=, 0, 1000);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=,
+ main_config.max_request_time, 0);
+ FR_TIMEVAL_BOUND_CHECK("response_window", &home->response_window, <=, 60, 0);
+
+ FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, >=, 1);
+ FR_INTEGER_BOUND_CHECK("response_timeouts", home->max_response_timeouts, <=, 1000);
+
+ /*
+ * Track the minimum response window, so that we can
+ * correctly set the timers in process.c
+ */
+ if (timercmp(&main_config.init_delay, &home->response_window, >)) {
+ main_config.init_delay = home->response_window;
+ }
+
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, 1);
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, <=, 120);
+ FR_INTEGER_BOUND_CHECK("zombie_period", home->zombie_period, >=, (uint32_t) home->response_window.tv_sec);
+
+ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, >=, 3);
+ FR_INTEGER_BOUND_CHECK("num_pings_to_alive", home->num_pings_to_alive, <=, 10);
+
+ FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, >=, 1);
+ FR_INTEGER_BOUND_CHECK("check_timeout", home->ping_timeout, <=, 10);
+
+ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, >=, 10);
+ FR_INTEGER_BOUND_CHECK("revive_interval", home->revive_interval, <=, 3600);
+
+#ifdef WITH_COA
+ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, >=, 1);
+ FR_INTEGER_BOUND_CHECK("coa_irt", home->coa_irt, <=, 5);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrc", home->coa_mrc, <=, 20);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrt", home->coa_mrt, <=, 30);
+
+ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, >=, 5);
+ FR_INTEGER_BOUND_CHECK("coa_mrd", home->coa_mrd, <=, 60);
+#endif
+
+ FR_INTEGER_BOUND_CHECK("max_connections", home->limit.max_connections, <=, 1024);
+
+#ifdef WITH_TCP
+ /*
+ * UDP sockets can't be connection limited.
+ */
+ if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
+#endif
+
+ if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
+ home->limit.idle_timeout = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
+ home->limit.lifetime = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
+ home->limit.idle_timeout = 0;
+
+ /*
+ * Make sure that this is set.
+ */
+ if (home->src_ipaddr.af == AF_UNSPEC) {
+ home->src_ipaddr.af = home->ipaddr.af;
+ }
+
+ parent = cf_item_parent(cf_section_to_item(cs));
+ if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
+ home->parent_server = cf_section_name2(parent);
+ }
+}
+
+/** Insert a new home server into the various internal lookup trees
+ *
+ * @param home server to add.
+ * @param cs That defined the home server.
+ * @return true on success else false.
+ */
+static bool home_server_insert(home_server_t *home, CONF_SECTION *cs)
+{
+ if (home->name && !rbtree_insert(home_servers_byname, home)) {
+ cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ return false;
+ }
+
+ if (!home->virtual_server && !rbtree_insert(home_servers_byaddr, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ return false;
+ }
+
+#ifdef WITH_STATS
+ home->number = home_server_max_number++;
+ if (!rbtree_insert(home_servers_bynumber, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ if (home->ipaddr.af != AF_UNSPEC) {
+ rbtree_deletebydata(home_servers_byname, home);
+ }
+ cf_log_err_cs(cs, "Internal error %d adding home server %s", __LINE__, home->log_name);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+/** Add an already allocate home_server_t to the various trees
+ *
+ * @param home server to add.
+ * @return true on success, else false on error.
+ */
+bool realm_home_server_add(home_server_t *home)
+{
+ /*
+ * The structs aren't mutex protected. Refuse to destroy
+ * the server.
+ */
+ if (event_loop_started && !realm_config->dynamic) {
+ ERROR("Failed to add dynamic home server, \"dynamic = yes\" must be set in proxy.conf");
+ return false;
+ }
+
+ if (home->name && (rbtree_finddata(home_servers_byname, home) != NULL)) {
+ cf_log_err_cs(home->cs, "Duplicate home server name %s", home->name);
+ return false;
+ }
+
+ if (!home->virtual_server && (rbtree_finddata(home_servers_byaddr, home) != NULL)) {
+ char buffer[INET6_ADDRSTRLEN + 3];
+
+ inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr, buffer, sizeof(buffer));
+
+ cf_log_err_cs(home->cs, "Duplicate home server address%s%s%s: %s:%s%s/%i",
+ home->name ? " (already in use by " : "",
+ home->name ? home->name : "",
+ home->name ? ")" : "",
+ buffer,
+ fr_int2str(home_proto, home->proto, "<INVALID>"),
+#ifdef WITH_TLS
+ home->tls ? "+tls" : "",
+#else
+ "",
+#endif
+ home->port);
+
+ return false;
+ }
+
+ if (!home_server_insert(home, home->cs)) return false;
+
+ /*
+ * Dual home servers cause us to auto-create an
+ * accounting server for UDP sockets, and leave
+ * everything alone for TLS sockets.
+ */
+ if (home->dual
+#ifdef WITH_TLS
+ && !home->tls
+#endif
+) {
+ home_server_t *home2 = talloc(talloc_parent(home), home_server_t);
+
+ memcpy(home2, home, sizeof(*home2));
+
+ home2->type = HOME_TYPE_ACCT;
+ home2->dual = true;
+ home2->port++;
+
+ home2->ping_user_password = NULL;
+ home2->cs = home->cs;
+ home2->parent_server = home->parent_server;
+
+ if (!home_server_insert(home2, home->cs)) {
+ talloc_free(home2);
+ return false;
+ }
+ }
+
+#ifdef WITH_COA_TUNNEL
+ if (home->recv_coa) {
+ if (!home->tls) {
+ ERROR("TLS is required in order to accept CoA requests from a home server");
+ return false;
+ }
+
+ if (!home->recv_coa_server) {
+ ERROR("A 'virtual_server' configuration is required in order to accept CoA requests from a home server");
+ return false;
+ }
+ }
+#endif
+
+ /*
+ * Mark it as already processed
+ */
+ cf_data_add(home->cs, "home_server", (void *)null_free, null_free);
+
+ return true;
+}
+
+#ifdef WITH_TLS
+/*
+ * The listeners are always different. And we always look them up by *known* listener. And not "find me some random thing".
+ */
+static int listener_cmp(void const *one, void const *two)
+{
+ if (one < two) return -1;
+ if (one > two) return +1;
+
+ return 0;
+}
+#endif
+
+/** Alloc a new home server defined by a CONF_SECTION
+ *
+ * @param ctx to allocate home_server_t in.
+ * @param rc Realm config, may be NULL in which case the global realm_config will be used.
+ * @param cs Configuration section containing home server parameters.
+ * @return a new home_server_t alloced in the context of the realm_config, or NULL on error.
+ */
+home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SECTION *cs)
+{
+ home_server_t *home;
+ CONF_SECTION *tls;
+
+ if (!rc) rc = realm_config; /* Use the global config */
+
+ home = talloc_zero(ctx, home_server_t);
+ home->name = cf_section_name2(cs);
+ home->log_name = talloc_typed_strdup(home, home->name);
+ home->cs = cs;
+ home->state = HOME_STATE_UNKNOWN;
+ home->proto = IPPROTO_UDP;
+
+ /*
+ * Parse the configuration into the home server
+ * struct.
+ */
+ if (cf_section_parse(cs, home, home_server_config) < 0) goto error;
+
+ /*
+ * It has an IP address, it must be a remote server.
+ */
+ if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
+ if (fr_inaddr_any(&home->ipaddr) == 1) {
+ cf_log_err_cs(cs, "Wildcard '*' addresses are not permitted for home servers");
+ goto error;
+ }
+
+ if (!home->log_name) {
+ char buffer[INET6_ADDRSTRLEN + 3];
+
+ fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
+
+ home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
+ }
+ /*
+ * If it has a 'virtual_Server' config item, it's
+ * a loopback into a virtual server.
+ */
+ } else if (cf_pair_find(cs, "virtual_server") != NULL) {
+ home->ipaddr.af = AF_UNSPEC; /* mark ipaddr as unused */
+
+ if (!home->virtual_server) {
+ cf_log_err_cs(cs, "Invalid value for virtual_server");
+ goto error;
+ }
+
+ /*
+ * Try and find a "server" section off the root of
+ * the config with a name that matches the
+ * virtual_server.
+ */
+ if (!rc) goto error;
+
+ if (!cf_section_sub_find_name2(rc->cs, "server", home->virtual_server)) {
+ cf_log_err_cs(cs, "No such server %s", home->virtual_server);
+ goto error;
+ }
+
+ home->secret = "";
+ home->log_name = talloc_typed_strdup(home, home->virtual_server);
+ /*
+ * Otherwise it's an invalid config section and we
+ * raise an error.
+ */
+ } else {
+ cf_log_err_cs(cs, "No ipaddr, ipv4addr, ipv6addr, or virtual_server defined "
+ "for home server");
+ error:
+ talloc_free(home);
+ return false;
+ }
+
+ {
+ home_type_t type = HOME_TYPE_AUTH_ACCT;
+
+ if (home->type_str) type = fr_str2int(home_server_types, home->type_str, HOME_TYPE_INVALID);
+
+ home->type = type;
+
+ switch (type) {
+ case HOME_TYPE_AUTH_ACCT:
+ home->dual = true;
+ break;
+
+ case HOME_TYPE_AUTH:
+ case HOME_TYPE_ACCT:
+ break;
+
+#ifdef WITH_COA
+ case HOME_TYPE_COA:
+ if (home->virtual_server != NULL) {
+ cf_log_err_cs(cs, "Home servers of type \"coa\" cannot point to a virtual server");
+ goto error;
+ }
+ break;
+
+#ifdef WITH_COA_TUNNEL
+ case HOME_TYPE_AUTH_ACCT_COA:
+ home->dual = true;
+ home->recv_coa = true;
+ break;
+
+ case HOME_TYPE_AUTH_COA:
+ home->recv_coa = true;
+ break;
+#endif
+#endif
+
+ case HOME_TYPE_INVALID:
+ cf_log_err_cs(cs, "Invalid type \"%s\" for home server %s", home->type_str, home->log_name);
+ goto error;
+ }
+ }
+
+ {
+ home_ping_check_t type = HOME_PING_CHECK_NONE;
+
+ if (home->ping_check_str) type = fr_str2int(home_ping_check, home->ping_check_str,
+ HOME_PING_CHECK_INVALID);
+
+ switch (type) {
+ case HOME_PING_CHECK_STATUS_SERVER:
+ case HOME_PING_CHECK_NONE:
+ break;
+
+ case HOME_PING_CHECK_REQUEST:
+ if (!home->ping_user_name) {
+ cf_log_err_cs(cs, "You must supply a 'username' to enable status_check=request");
+ goto error;
+ }
+
+ if (((home->type == HOME_TYPE_AUTH) ||
+#ifdef WITH_COA_TUNNEL
+ (home->type == HOME_TYPE_AUTH_COA) ||
+ (home->type == HOME_TYPE_AUTH_ACCT_COA) ||
+#endif
+ (home->type == HOME_TYPE_AUTH_ACCT)) && !home->ping_user_password) {
+ cf_log_err_cs(cs, "You must supply a 'password' to enable status_check=request");
+ goto error;
+ }
+
+ break;
+
+ case HOME_PING_CHECK_INVALID:
+ cf_log_err_cs(cs, "Invalid status_check \"%s\" for home server %s",
+ home->ping_check_str, home->log_name);
+ goto error;
+ }
+
+ home->ping_check = type;
+ }
+
+ {
+ int proto = IPPROTO_UDP;
+
+ if (home->proto_str) proto = fr_str2int(home_proto, home->proto_str, -1);
+
+ switch (proto) {
+ case IPPROTO_UDP:
+#ifdef WITH_TCP
+ home_servers_udp = true;
+#endif
+ break;
+
+ case IPPROTO_TCP:
+#ifndef WITH_TCP
+ cf_log_err_cs(cs, "Server not built with support for RADIUS over TCP");
+ goto error;
+#endif
+ if ((home->ping_check != HOME_PING_CHECK_NONE) &&
+ (home->ping_check != HOME_PING_CHECK_STATUS_SERVER)) {
+ cf_log_err_cs(cs, "Only 'status_check = status-server' is allowed for home "
+ "servers with 'proto = tcp'");
+ goto error;
+ }
+ break;
+
+ default:
+ cf_log_err_cs(cs, "Unknown proto \"%s\"", home->proto_str);
+ goto error;
+ }
+
+ home->proto = proto;
+ }
+
+ if (!home->virtual_server && rbtree_finddata(home_servers_byaddr, home)) {
+ cf_log_err_cs(cs, "Duplicate home server");
+ goto error;
+ }
+
+ /*
+ * Check the TLS configuration.
+ */
+ tls = cf_section_sub_find(cs, "tls");
+#ifndef WITH_TLS
+ if (tls) {
+ cf_log_err_cs(cs, "TLS transport is not available in this executable");
+ goto error;
+ }
+#endif
+
+ /*
+ * Check the reverse CoA configuration.
+ */
+#ifdef WITH_COA_TUNNEL
+ if (home->recv_coa) {
+ if (!tls) {
+ ERROR("TLS is required in order to accept CoA requests from a home server");
+ goto error;
+ }
+
+ if (!home->recv_coa_server) {
+ ERROR("A 'virtual_server' configuration is required in order to accept CoA requests from a home server");
+ goto error;
+ }
+
+ /*
+ * Try and find a 'server' section off the root of
+ * the config with a name that matches the coa
+ * virtual_server.
+ */
+ if (!rc) {
+ ERROR("Dynamic home servers cannot accept CoA requests");
+ goto error;
+ }
+
+ if (!cf_section_sub_find_name2(rc->cs, "server", home->recv_coa_server)) {
+ cf_log_err_cs(cs, "No such coa server %s", home->recv_coa_server);
+ goto error;
+ }
+ }
+#endif
+
+ /*
+ * If were doing RADSEC (tls+tcp) the secret should default
+ * to radsec, else a secret must be set.
+ */
+ if (!home->secret) {
+#ifdef WITH_TLS
+ if (tls && (home->proto == IPPROTO_TCP)) {
+ home->secret = "radsec";
+ } else
+#endif
+ {
+ cf_log_err_cs(cs, "No shared secret defined for home server %s", home->log_name);
+ goto error;
+ }
+ }
+
+ /*
+ * Virtual servers have some TLS restrictions.
+ */
+ if (home->virtual_server) {
+ if (tls) {
+ cf_log_err_cs(cs, "Virtual home_servers cannot have a \"tls\" subsection");
+ goto error;
+ }
+ } else {
+ /*
+ * If the home is not a virtual server, guess the port
+ * and look up the source ip address.
+ */
+ rad_assert(home->ipaddr.af != AF_UNSPEC);
+
+#ifdef WITH_TLS
+ if (tls && (home->proto != IPPROTO_TCP)) {
+ cf_log_err_cs(cs, "TLS transport is not available for UDP sockets");
+ goto error;
+ }
+#endif
+
+ /*
+ * Set the default port if necessary.
+ */
+ if (home->port == 0) {
+ char buffer[INET6_ADDRSTRLEN + 3];
+
+ /*
+ * For RADSEC we use the special RADIUS over TCP/TLS port
+ * for both accounting and authentication, but for some
+ * bizarre reason for RADIUS over plain TCP we use separate
+ * ports 1812 and 1813.
+ */
+#ifdef WITH_TLS
+ if (tls) {
+ home->port = PW_RADIUS_TLS_PORT;
+ } else
+#endif
+ switch (home->type) {
+ default:
+ rad_assert(0);
+ /* FALL-THROUGH */
+
+ /*
+ * One is added to get the accounting port
+ * for home->dual.
+ */
+ case HOME_TYPE_AUTH_ACCT:
+ case HOME_TYPE_AUTH:
+ home->port = PW_AUTH_UDP_PORT;
+ break;
+
+ case HOME_TYPE_ACCT:
+ home->port = PW_ACCT_UDP_PORT;
+ break;
+
+ case HOME_TYPE_COA:
+ home->port = PW_COA_UDP_PORT;
+ break;
+ }
+
+ /*
+ * Now that we have a real port, use that.
+ */
+ rad_const_free(home->log_name);
+
+ fr_ntop(buffer, sizeof(buffer), &home->ipaddr);
+
+ home->log_name = talloc_asprintf(home, "%s:%i", buffer, home->port);
+ }
+
+ /*
+ * If we have a src_ipaddr_str resolve it to
+ * the same address family as the destination
+ * IP.
+ */
+ if (home->src_ipaddr_str) {
+ if (ip_hton(&home->src_ipaddr, home->ipaddr.af, home->src_ipaddr_str, false) < 0) {
+ cf_log_err_cs(cs, "Failed parsing src_ipaddr");
+ goto error;
+ }
+ /*
+ * Source isn't specified, set it to the
+ * correct address family, but leave it as
+ * zeroes.
+ */
+ } else {
+ home->src_ipaddr.af = home->ipaddr.af;
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Parse the SSL client configuration.
+ */
+ if (tls) {
+ int rcode;
+
+ home->tls = tls_client_conf_parse(tls);
+ if (!home->tls) {
+ goto error;
+ }
+
+ /*
+ * Connection timeouts for outgoing TLS connections.
+ */
+
+ rcode = cf_item_parse(tls, "connect_timeout", FR_ITEM_POINTER(PW_TYPE_INTEGER, &home->connect_timeout), NULL);
+ if (rcode < 0) goto error;
+
+ if (!home->connect_timeout || (home->connect_timeout > 30)) home->connect_timeout = 30;
+
+ home->listeners = rbtree_create(home, listener_cmp, NULL, RBTREE_FLAG_LOCK);
+ if (!home->listeners) goto error;
+
+#ifdef WITH_RADIUSV11
+ if (home->tls->radiusv11_name) {
+ rcode = fr_str2int(radiusv11_types, home->tls->radiusv11_name, -1);
+ if (rcode < 0) {
+ cf_log_err_cs(cs, "Invalid value for 'radiusv11'");
+ goto error;
+ }
+
+ home->tls->radiusv11 = rcode;
+
+ if (fr_radiusv11_client_init(home->tls) < 0) {
+ cf_log_err_cs(cs, "Failed setting OpenSSL callbacks for radiusv11");
+ goto error;
+ }
+ }
+#endif
+
+ }
+#endif
+ } /* end of parse home server */
+
+ realm_home_server_sanitize(home, cs);
+
+ return home;
+}
+
+/** Fixup a client configuration section to specify a home server
+ *
+ * This is used to create the equivalent CoA home server entry for a client,
+ * so that the server can originate CoA messages.
+ *
+ * The server section automatically inherits the following fields from the client:
+ * - ipaddr/ipv4addr/ipv6addr
+ * - secret
+ * - src_ipaddr
+ *
+ * @note new CONF_SECTION will be allocated in the context of the client, but the client
+ * CONF_SECTION will not be modified.
+ *
+ * @param client CONF_SECTION to inherit values from.
+ * @return a new server CONF_SCTION, or a pointer to the existing CONF_SECTION in the client.
+ */
+CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
+{
+ CONF_SECTION *server, *cs;
+ CONF_PAIR *cp;
+
+ /*
+ * Alloc a plain home server for both cases
+ *
+ * There's no way these can be referenced by a pool,
+ * and they may conflict with home servers in proxy.conf
+ * so it's easier to not set a name.
+ */
+
+ /*
+ *
+ * Duplicate the server section, so we don't mangle
+ * the client CONF_SECTION we were passed.
+ */
+ cs = cf_section_sub_find(client, "coa_server");
+ if (cs) {
+ server = cf_section_dup(client, cs, "home_server", NULL, true);
+ } else {
+ server = cf_section_alloc(client, "home_server", cf_section_name2(client));
+ }
+
+ if (!cs || (!cf_pair_find(cs, "ipaddr") && !cf_pair_find(cs, "ipv4addr") && !cf_pair_find(cs, "ipv6addr"))) {
+ cp = cf_pair_find(client, "ipaddr");
+ if (!cp) cp = cf_pair_find(client, "ipv4addr");
+ if (!cp) cp = cf_pair_find(client, "ipv6addr");
+
+ cf_pair_add(server, cf_pair_dup(server, cp));
+ }
+
+ if (!cs || !cf_pair_find(cs, "secret")) {
+ cp = cf_pair_find(client, "secret");
+ if (cp) cf_pair_add(server, cp);
+ }
+
+ if (!cs || !cf_pair_find(cs, "src_ipaddr")) {
+ cp = cf_pair_find(client, "src_ipaddr");
+ if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
+ }
+
+ if (!cs || !(cp = cf_pair_find(cs, "type"))) {
+ cp = cf_pair_alloc(server, "type", "coa", T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
+ } else if (strcmp(cf_pair_value(cp), "coa") != 0) {
+ talloc_free(server);
+ cf_log_err_cs(server, "server.type must be \"coa\"");
+ return NULL;
+ }
+
+ return server;
+}
+
+static home_pool_t *server_pool_alloc(char const *name, home_pool_type_t type,
+ home_type_t server_type, int num_home_servers)
+{
+ home_pool_t *pool;
+
+ pool = rad_malloc(sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
+ if (!pool) return NULL; /* just for pairanoia */
+
+ memset(pool, 0, sizeof(*pool) + (sizeof(pool->servers[0]) * num_home_servers));
+
+ pool->name = name;
+ pool->type = type;
+ pool->server_type = server_type;
+ pool->num_home_servers = num_home_servers;
+
+ return pool;
+}
+
+/*
+ * Ensure any home_server clauses in a home_server_pool section reference
+ * defined home servers, which should already have been created, regardless
+ * of where they appear in the configuration.
+ */
+static int pool_check_home_server(UNUSED realm_config_t *rc, CONF_PAIR *cp,
+ char const *name, home_type_t server_type,
+ home_server_t **phome)
+{
+ home_server_t myhome, *home;
+
+ if (!name) {
+ cf_log_err_cp(cp,
+ "No value given for home_server");
+ return 0;
+ }
+
+ myhome.name = name;
+ myhome.type = server_type;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ if (home) {
+ *phome = home;
+ return 1;
+ }
+
+ switch (server_type) {
+ case HOME_TYPE_AUTH:
+ case HOME_TYPE_ACCT:
+ myhome.type = HOME_TYPE_AUTH_ACCT;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+#ifdef WITH_COA_TUNNEL
+ if (!home) {
+ myhome.type = HOME_TYPE_AUTH_COA;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ if(!home) {
+ myhome.type = HOME_TYPE_AUTH_ACCT_COA;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ }
+ }
+#endif
+ if (home) {
+ *phome = home;
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ cf_log_err_cp(cp, "Unknown home_server \"%s\".", name);
+ return 0;
+}
+
+
+#ifndef HAVE_PTHREAD_H
+void realm_pool_free(home_pool_t *pool)
+{
+ if (!event_loop_started) return;
+ if (!realm_config->dynamic) return;
+
+ talloc_free(pool);
+}
+#else /* HAVE_PTHREAD_H */
+typedef struct pool_list_t pool_list_t;
+
+struct pool_list_t {
+ pool_list_t *next;
+ home_pool_t *pool;
+ time_t when;
+};
+
+static bool pool_free_init = false;
+static pthread_mutex_t pool_free_mutex;
+static pool_list_t *pool_list = NULL;
+
+void realm_pool_free(home_pool_t *pool)
+{
+ int i;
+ time_t now;
+ pool_list_t *this, **last;
+
+ if (!event_loop_started) return;
+ if (!realm_config->dynamic) return;
+
+ if (pool) {
+ /*
+ * Double-check that the realm wasn't loaded from the
+ * configuration files.
+ */
+ for (i = 0; i < pool->num_home_servers; i++) {
+ if (pool->servers[i]->cs) {
+ rad_assert(0 == 1);
+ return;
+ }
+ }
+ }
+
+ if (!pool_free_init) {
+ pthread_mutex_init(&pool_free_mutex, NULL);
+ pool_free_init = true;
+ }
+
+ /*
+ * Ensure only one caller at a time is freeing a pool.
+ */
+ pthread_mutex_lock(&pool_free_mutex);
+
+ /*
+ * Free all of the pools.
+ */
+ if (!pool) {
+ while ((this = pool_list) != NULL) {
+ pool_list = this->next;
+ talloc_free(this->pool);
+ talloc_free(this);
+ }
+ pthread_mutex_unlock(&pool_free_mutex);
+ return;
+ }
+
+ now = time(NULL);
+
+ /*
+ * Free the oldest pool(s)
+ */
+ while ((this = pool_list) != NULL) {
+ if (this->when > now) break;
+
+ pool_list = this->next;
+ talloc_free(this->pool);
+ talloc_free(this);
+ }
+
+ /*
+ * Add this pool to the end of the list.
+ */
+ for (last = &pool_list;
+ *last != NULL;
+ last = &((*last))->next) {
+ /* do nothing */
+ }
+
+ *last = this = talloc(NULL, pool_list_t);
+ if (!this) {
+ talloc_free(pool); /* hope for the best */
+ pthread_mutex_unlock(&pool_free_mutex);
+ return;
+ }
+
+ this->next = NULL;
+ this->when = now + 300;
+ this->pool = pool;
+ pthread_mutex_unlock(&pool_free_mutex);
+}
+#endif /* HAVE_PTHREAD_H */
+
+int realm_pool_add(home_pool_t *pool, CONF_SECTION *cs)
+{
+ home_pool_t *old;
+
+ old = rbtree_finddata(home_pools_byname, pool);
+ if (old) {
+ cf_log_err_cs(cs, "Cannot add duplicate home server %s, original is at %s[%d]", pool->name,
+ cf_section_filename(old->cs), cf_section_lineno(old->cs));
+ return 0;
+ }
+
+ /*
+ * The structs aren't mutex protected. Refuse to destroy
+ * the server.
+ */
+ if (event_loop_started && !realm_config->dynamic) {
+ DEBUG("Must set \"dynamic = true\" in proxy.conf");
+ return 0;
+ }
+
+ if (!rbtree_insert(home_pools_byname, pool)) {
+ rad_assert("Internal sanity check failed" == NULL);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int server_pool_add(realm_config_t *rc,
+ CONF_SECTION *cs, home_type_t server_type, bool do_print)
+{
+ char const *name2;
+ home_pool_t *pool = NULL;
+ char const *value;
+ CONF_PAIR *cp;
+ int num_home_servers;
+ home_server_t *home;
+
+ name2 = cf_section_name1(cs);
+ if (!name2 || ((strcasecmp(name2, "server_pool") != 0) &&
+ (strcasecmp(name2, "home_server_pool") != 0))) {
+ cf_log_err_cs(cs,
+ "Section is not a home_server_pool");
+ return 0;
+ }
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err_cs(cs,
+ "Server pool section is missing a name");
+ return 0;
+ }
+
+ /*
+ * Count the home servers and initalize them.
+ */
+ num_home_servers = 0;
+ for (cp = cf_pair_find(cs, "home_server");
+ cp != NULL;
+ cp = cf_pair_find_next(cs, cp, "home_server")) {
+ num_home_servers++;
+
+ if (!pool_check_home_server(rc, cp, cf_pair_value(cp),
+ server_type, &home)) {
+ return 0;
+ }
+ }
+
+ if (num_home_servers == 0) {
+ cf_log_err_cs(cs,
+ "No home servers defined in pool %s",
+ name2);
+ goto error;
+ }
+
+ pool = server_pool_alloc(name2, HOME_POOL_FAIL_OVER, server_type,
+ num_home_servers);
+ if (!pool) {
+ cf_log_err_cs(cs, "Failed allocating memory for pool");
+ goto error;
+ }
+ pool->cs = cs;
+
+
+ /*
+ * Fallback servers must be defined, and must be
+ * virtual servers.
+ */
+ cp = cf_pair_find(cs, "fallback");
+ if (cp) {
+#ifdef WITH_COA
+ if (server_type == HOME_TYPE_COA) {
+ cf_log_err_cs(cs, "Home server pools of type \"coa\" cannot have a fallback virtual server");
+ goto error;
+ }
+#endif
+
+ if (!pool_check_home_server(rc, cp, cf_pair_value(cp), server_type, &pool->fallback)) {
+ goto error;
+ }
+
+ if (!pool->fallback->virtual_server) {
+ cf_log_err_cs(cs, "Fallback home_server %s does NOT contain a virtual_server directive",
+ pool->fallback->log_name);
+ goto error;
+ }
+ }
+
+ if (do_print) cf_log_info(cs, " home_server_pool %s {", name2);
+
+ cp = cf_pair_find(cs, "type");
+ if (cp) {
+ static FR_NAME_NUMBER pool_types[] = {
+ { "load-balance", HOME_POOL_LOAD_BALANCE },
+
+ { "fail-over", HOME_POOL_FAIL_OVER },
+ { "fail_over", HOME_POOL_FAIL_OVER },
+
+ { "round-robin", HOME_POOL_LOAD_BALANCE },
+ { "round_robin", HOME_POOL_LOAD_BALANCE },
+
+ { "client-balance", HOME_POOL_CLIENT_BALANCE },
+ { "client-port-balance", HOME_POOL_CLIENT_PORT_BALANCE },
+ { "keyed-balance", HOME_POOL_KEYED_BALANCE },
+ { NULL, 0 }
+ };
+
+ value = cf_pair_value(cp);
+ if (!value) {
+ cf_log_err_cp(cp,
+ "No value given for type");
+ goto error;
+ }
+
+ pool->type = fr_str2int(pool_types, value, 0);
+ if (!pool->type) {
+ cf_log_err_cp(cp,
+ "Unknown type \"%s\".",
+ value);
+ goto error;
+ }
+
+ if (do_print) cf_log_info(cs, "\ttype = %s", value);
+ }
+
+ cp = cf_pair_find(cs, "virtual_server");
+ if (cp) {
+ pool->virtual_server = cf_pair_value(cp);
+ if (!pool->virtual_server) {
+ cf_log_err_cp(cp, "No value given for virtual_server");
+ goto error;
+ }
+
+ if (do_print) {
+ cf_log_info(cs, "\tvirtual_server = %s", pool->virtual_server);
+ }
+
+ if (!cf_section_sub_find_name2(rc->cs, "server", pool->virtual_server)) {
+ cf_log_err_cp(cp, "No such server %s", pool->virtual_server);
+ goto error;
+ }
+
+ }
+
+ num_home_servers = 0;
+ for (cp = cf_pair_find(cs, "home_server");
+ cp != NULL;
+ cp = cf_pair_find_next(cs, cp, "home_server")) {
+ home_server_t myhome;
+
+ value = cf_pair_value(cp);
+
+ memset(&myhome, 0, sizeof(myhome));
+ myhome.name = value;
+ myhome.type = server_type;
+
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ if (!home) {
+ switch (server_type) {
+ case HOME_TYPE_AUTH:
+ case HOME_TYPE_ACCT:
+ myhome.type = HOME_TYPE_AUTH_ACCT;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+#ifdef WITH_COA_TUNNEL
+ if (!home) {
+ myhome.type = HOME_TYPE_AUTH_COA;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ if (!home) {
+ myhome.type = HOME_TYPE_AUTH_ACCT_COA;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ }
+ }
+#endif
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!home) {
+ ERROR("Failed to find home server %s", value);
+ goto error;
+ }
+
+ if (do_print) cf_log_info(cs, "\thome_server = %s", home->name);
+ pool->servers[num_home_servers++] = home;
+ } /* loop over home_server's */
+
+ if (pool->fallback && do_print) {
+ cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
+ }
+
+ if (!realm_pool_add(pool, cs)) goto error;
+
+ if (do_print) cf_log_info(cs, " }");
+
+ cf_data_add(cs, "home_server_pool", pool, free);
+
+ rad_assert(pool->server_type != 0);
+
+ return 1;
+
+ error:
+ if (do_print) cf_log_info(cs, " }");
+ free(pool);
+ return 0;
+}
+#endif
+
+static int old_server_add(realm_config_t *rc, CONF_SECTION *cs,
+ char const *realm,
+ char const *name, char const *secret,
+ home_pool_type_t ldflag, home_pool_t **pool_p,
+ home_type_t type, char const *server)
+{
+#ifdef WITH_PROXY
+ int i, insert_point, num_home_servers;
+ home_server_t myhome, *home;
+ home_pool_t mypool, *pool;
+ CONF_SECTION *subcs;
+#else
+ (void) rc; /* -Wunused */
+ (void) realm;
+ (void) secret;
+ (void) ldflag;
+ (void) type;
+ (void) server;
+#endif
+
+ /*
+ * LOCAL realms get sanity checked, and nothing else happens.
+ */
+ if (strcmp(name, "LOCAL") == 0) {
+ if (*pool_p) {
+ cf_log_err_cs(cs, "Realm \"%s\" cannot be both LOCAL and remote", name);
+ return 0;
+ }
+ return 1;
+ }
+
+#ifndef WITH_PROXY
+ return 0; /* Not proxying. Can't do non-LOCAL realms */
+
+#else
+ mypool.name = realm;
+ mypool.server_type = type;
+ pool = rbtree_finddata(home_pools_byname, &mypool);
+ if (pool) {
+ if (pool->type != ldflag) {
+ cf_log_err_cs(cs, "Inconsistent ldflag for server pool \"%s\"", name);
+ return 0;
+ }
+
+ if (pool->server_type != type) {
+ cf_log_err_cs(cs, "Inconsistent home server type for server pool \"%s\"", name);
+ return 0;
+ }
+ }
+
+ myhome.name = name;
+ myhome.type = type;
+ home = rbtree_finddata(home_servers_byname, &myhome);
+ if (home) {
+ WARN("Please use pools instead of authhost and accthost");
+
+ if (secret && (strcmp(home->secret, secret) != 0)) {
+ cf_log_err_cs(cs, "Inconsistent shared secret for home server \"%s\"", name);
+ return 0;
+ }
+
+ if (home->type != type) {
+ cf_log_err_cs(cs, "Inconsistent type for home server \"%s\"", name);
+ return 0;
+ }
+
+ /*
+ * Don't check for duplicate home servers. If
+ * the user specifies that, well, they can do it.
+ *
+ * Allowing duplicates means that all of the
+ * realm->server[] entries are filled, which is
+ * what the rest of the code assumes.
+ */
+ }
+
+ /*
+ * If we do have a pool, check that there is room to
+ * insert the home server we've found, or the one that we
+ * create here.
+ *
+ * Note that we insert it into the LAST available
+ * position, in order to maintain the same order as in
+ * the configuration files.
+ */
+ insert_point = -1;
+ if (pool) {
+ for (i = pool->num_home_servers - 1; i >= 0; i--) {
+ if (pool->servers[i]) break;
+
+ if (!pool->servers[i]) {
+ insert_point = i;
+ }
+ }
+
+ if (insert_point < 0) {
+ cf_log_err_cs(cs, "No room in pool to add home server \"%s\". Please update the realm configuration to use the new-style home servers and server pools.", name);
+ return 0;
+ }
+ }
+
+ /*
+ * No home server, allocate one.
+ */
+ if (!home) {
+ char const *p;
+ char *q;
+
+ home = talloc_zero(rc, home_server_t);
+ home->name = name;
+ home->type = type;
+ home->secret = secret;
+ home->cs = cs;
+ home->proto = IPPROTO_UDP;
+
+ p = strchr(name, ':');
+ if (!p) {
+ if (type == HOME_TYPE_AUTH) {
+ home->port = PW_AUTH_UDP_PORT;
+ } else {
+ home->port = PW_ACCT_UDP_PORT;
+ }
+
+ p = name;
+ q = NULL;
+
+ } else if (p == name) {
+ cf_log_err_cs(cs, "Invalid hostname %s", name);
+ talloc_free(home);
+ return 0;
+ } else {
+ unsigned long port = strtoul(p + 1, NULL, 0);
+ if ((port == 0) || (port > 65535)) {
+ cf_log_err_cs(cs, "Invalid port %s", p + 1);
+ talloc_free(home);
+ return 0;
+ }
+
+ home->port = (uint16_t)port;
+ q = talloc_array(home, char, (p - name) + 1);
+ memcpy(q, name, (p - name));
+ q[p - name] = '\0';
+ p = q;
+ }
+
+ if (!server) {
+ if (ip_hton(&home->ipaddr, AF_UNSPEC, p, false) < 0) {
+ cf_log_err_cs(cs,
+ "Failed looking up hostname %s.",
+ p);
+ talloc_free(home);
+ talloc_free(q);
+ return 0;
+ }
+ home->src_ipaddr.af = home->ipaddr.af;
+ } else {
+ home->ipaddr.af = AF_UNSPEC;
+ home->virtual_server = server;
+ }
+ talloc_free(q);
+
+ /*
+ * Use the old-style configuration.
+ */
+ home->max_outstanding = 65535*16;
+ home->zombie_period = rc->retry_delay * rc->retry_count;
+ if (home->zombie_period < 2) home->zombie_period = 30;
+ home->response_window.tv_sec = home->zombie_period - 1;
+ home->response_window.tv_usec = 0;
+
+ home->ping_check = HOME_PING_CHECK_NONE;
+
+ home->revive_interval = rc->dead_time;
+
+ if (rbtree_finddata(home_servers_byaddr, home)) {
+ cf_log_err_cs(cs, "Home server %s has the same IP address and/or port as another home server.", name);
+ talloc_free(home);
+ return 0;
+ }
+
+ if (!rbtree_insert(home_servers_byname, home)) {
+ cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
+ talloc_free(home);
+ return 0;
+ }
+
+ if (!rbtree_insert(home_servers_byaddr, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ cf_log_err_cs(cs, "Internal error %d adding home server %s.", __LINE__, name);
+ talloc_free(home);
+ return 0;
+ }
+
+#ifdef WITH_STATS
+ home->number = home_server_max_number++;
+ if (!rbtree_insert(home_servers_bynumber, home)) {
+ rbtree_deletebydata(home_servers_byname, home);
+ if (home->ipaddr.af != AF_UNSPEC) {
+ rbtree_deletebydata(home_servers_byname, home);
+ }
+ cf_log_err_cs(cs,
+ "Internal error %d adding home server %s.",
+ __LINE__, name);
+ talloc_free(home);
+ return 0;
+ }
+#endif
+ }
+
+ /*
+ * We now have a home server, see if we can insert it
+ * into pre-existing pool.
+ */
+ if (insert_point >= 0) {
+ rad_assert(pool != NULL);
+ pool->servers[insert_point] = home;
+ return 1;
+ }
+
+ rad_assert(pool == NULL);
+ rad_assert(home != NULL);
+
+ /*
+ * Count the old-style realms of this name.
+ */
+ num_home_servers = 0;
+ for (subcs = cf_section_find_next(cs, NULL, "realm");
+ subcs != NULL;
+ subcs = cf_section_find_next(cs, subcs, "realm")) {
+ char const *this = cf_section_name2(subcs);
+
+ if (!this || (strcmp(this, realm) != 0)) continue;
+ num_home_servers++;
+ }
+
+ if (num_home_servers == 0) {
+ cf_log_err_cs(cs, "Internal error counting pools for home server %s.", name);
+ talloc_free(home);
+ return 0;
+ }
+
+ pool = server_pool_alloc(realm, ldflag, type, num_home_servers);
+ if (!pool) {
+ cf_log_err_cs(cs, "Out of memory");
+ return 0;
+ }
+
+ pool->cs = cs;
+
+ pool->servers[0] = home;
+
+ if (!rbtree_insert(home_pools_byname, pool)) {
+ rad_assert("Internal sanity check failed" == NULL);
+ return 0;
+ }
+
+ *pool_p = pool;
+
+ return 1;
+#endif
+}
+
+static int old_realm_config(realm_config_t *rc, CONF_SECTION *cs, REALM *r)
+{
+ char const *host;
+ char const *secret = NULL;
+ home_pool_type_t ldflag;
+ CONF_PAIR *cp;
+
+ cp = cf_pair_find(cs, "ldflag");
+ ldflag = HOME_POOL_FAIL_OVER;
+ if (cp) {
+ host = cf_pair_value(cp);
+ if (!host) {
+ cf_log_err_cp(cp, "No value specified for ldflag");
+ return 0;
+ }
+
+ if (strcasecmp(host, "fail_over") == 0) {
+ cf_log_info(cs, "\tldflag = fail_over");
+
+ } else if (strcasecmp(host, "round_robin") == 0) {
+ ldflag = HOME_POOL_LOAD_BALANCE;
+ cf_log_info(cs, "\tldflag = round_robin");
+
+ } else {
+ cf_log_err_cs(cs, "Unknown value \"%s\" for ldflag", host);
+ return 0;
+ }
+ } /* else don't print it. */
+
+ /*
+ * Allow old-style if it doesn't exist, or if it exists and
+ * it's LOCAL.
+ */
+ cp = cf_pair_find(cs, "authhost");
+ if (cp) {
+ host = cf_pair_value(cp);
+ if (!host) {
+ cf_log_err_cp(cp, "No value specified for authhost");
+ return 0;
+ }
+
+ if (strcmp(host, "LOCAL") != 0) {
+ cp = cf_pair_find(cs, "secret");
+ if (!cp) {
+ cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
+ return 0;
+ }
+
+ secret = cf_pair_value(cp);
+ if (!secret) {
+ cf_log_err_cp(cp, "No value specified for secret");
+ return 0;
+ }
+ }
+
+ cf_log_info(cs, "\tauthhost = %s", host);
+
+ if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
+ &r->auth_pool, HOME_TYPE_AUTH, NULL)) {
+ return 0;
+ }
+ }
+
+ cp = cf_pair_find(cs, "accthost");
+ if (cp) {
+ host = cf_pair_value(cp);
+ if (!host) {
+ cf_log_err_cp(cp, "No value specified for accthost");
+ return 0;
+ }
+
+ /*
+ * Don't look for a secret again if it was found
+ * above.
+ */
+ if ((strcmp(host, "LOCAL") != 0) && !secret) {
+ cp = cf_pair_find(cs, "secret");
+ if (!cp) {
+ cf_log_err_cs(cs, "No shared secret supplied for realm: %s", r->name);
+ return 0;
+ }
+
+ secret = cf_pair_value(cp);
+ if (!secret) {
+ cf_log_err_cp(cp, "No value specified for secret");
+ return 0;
+ }
+ }
+
+ cf_log_info(cs, "\taccthost = %s", host);
+
+ if (!old_server_add(rc, cs, r->name, host, secret, ldflag,
+ &r->acct_pool, HOME_TYPE_ACCT, NULL)) {
+ return 0;
+ }
+ }
+
+ cp = cf_pair_find(cs, "virtual_server");
+ if (cp) {
+ host = cf_pair_value(cp);
+ if (!host) {
+ cf_log_err_cp(cp, "No value specified for virtual_server");
+ return 0;
+ }
+
+ cf_log_info(cs, "\tvirtual_server = %s", host);
+
+ if (!old_server_add(rc, cs, r->name, host, "", ldflag,
+ &r->auth_pool, HOME_TYPE_AUTH, host)) {
+ return 0;
+ }
+ if (!old_server_add(rc, cs, r->name, host, "", ldflag,
+ &r->acct_pool, HOME_TYPE_ACCT, host)) {
+ return 0;
+ }
+ }
+
+ if (secret) {
+ if (rad_debug_lvl <= 2) {
+ cf_log_info(cs, "\tsecret = <<< secret >>>");
+ } else {
+ cf_log_info(cs, "\tsecret = %s", secret);
+ }
+ }
+
+ return 1;
+
+}
+
+
+#ifdef WITH_PROXY
+static int add_pool_to_realm(realm_config_t *rc, CONF_SECTION *cs,
+ char const *name, home_pool_t **dest,
+ home_type_t server_type, bool do_print)
+{
+ home_pool_t mypool, *pool;
+
+ mypool.name = name;
+ mypool.server_type = server_type;
+
+ pool = rbtree_finddata(home_pools_byname, &mypool);
+ if (!pool) {
+ CONF_SECTION *pool_cs;
+
+ pool_cs = cf_section_sub_find_name2(rc->cs,
+ "home_server_pool",
+ name);
+ if (!pool_cs) {
+ pool_cs = cf_section_sub_find_name2(rc->cs,
+ "server_pool",
+ name);
+ }
+ if (!pool_cs) {
+ cf_log_err_cs(cs, "Failed to find home_server_pool \"%s\"", name);
+ return 0;
+ }
+
+ if (!server_pool_add(rc, pool_cs, server_type, do_print)) {
+ return 0;
+ }
+
+ pool = rbtree_finddata(home_pools_byname, &mypool);
+ if (!pool) {
+ ERROR("Internal sanity check failed in add_pool_to_realm");
+ return 0;
+ }
+ }
+
+ if (pool->server_type != server_type) {
+ cf_log_err_cs(cs, "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name);
+ return 0;
+ }
+
+ *dest = pool;
+
+ return 1;
+}
+#endif
+
+
+static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
+{
+ char const *name2;
+ REALM *r = NULL;
+ CONF_PAIR *cp;
+#ifdef WITH_PROXY
+ home_pool_t *auth_pool, *acct_pool;
+ char const *auth_pool_name, *acct_pool_name;
+#ifdef WITH_COA
+ char const *coa_pool_name;
+ home_pool_t *coa_pool;
+#endif
+#endif
+
+ name2 = cf_section_name1(cs);
+ if (!name2 || (strcasecmp(name2, "realm") != 0)) {
+ cf_log_err_cs(cs, "Section is not a realm");
+ return 0;
+ }
+
+ name2 = cf_section_name2(cs);
+ if (!name2) {
+ cf_log_err_cs(cs, "Realm section is missing the realm name");
+ return 0;
+ }
+
+#ifdef WITH_PROXY
+ auth_pool = acct_pool = NULL;
+ auth_pool_name = acct_pool_name = NULL;
+#ifdef WITH_COA
+ coa_pool = NULL;
+ coa_pool_name = NULL;
+#endif
+
+ /*
+ * Prefer new configuration to old one.
+ */
+ cp = cf_pair_find(cs, "pool");
+ if (!cp) cp = cf_pair_find(cs, "home_server_pool");
+ if (cp) auth_pool_name = cf_pair_value(cp);
+ if (cp && auth_pool_name) {
+ acct_pool_name = auth_pool_name;
+ if (!add_pool_to_realm(rc, cs,
+ auth_pool_name, &auth_pool,
+ HOME_TYPE_AUTH, 1)) {
+ return 0;
+ }
+ if (!add_pool_to_realm(rc, cs,
+ auth_pool_name, &acct_pool,
+ HOME_TYPE_ACCT, 0)) {
+ return 0;
+ }
+ }
+
+ cp = cf_pair_find(cs, "auth_pool");
+ if (cp) auth_pool_name = cf_pair_value(cp);
+ if (cp && auth_pool_name) {
+ if (auth_pool) {
+ cf_log_err_cs(cs, "Cannot use \"pool\" and \"auth_pool\" at the same time");
+ return 0;
+ }
+ if (!add_pool_to_realm(rc, cs,
+ auth_pool_name, &auth_pool,
+ HOME_TYPE_AUTH, 1)) {
+ return 0;
+ }
+ }
+
+ cp = cf_pair_find(cs, "acct_pool");
+ if (cp) acct_pool_name = cf_pair_value(cp);
+ if (cp && acct_pool_name) {
+ bool do_print = true;
+
+ if (acct_pool) {
+ cf_log_err_cs(cs, "Cannot use \"pool\" and \"acct_pool\" at the same time");
+ return 0;
+ }
+
+ if (!auth_pool ||
+ (auth_pool_name &&
+ (strcmp(auth_pool_name, acct_pool_name) != 0))) {
+ do_print = true;
+ }
+
+ if (!add_pool_to_realm(rc, cs,
+ acct_pool_name, &acct_pool,
+ HOME_TYPE_ACCT, do_print)) {
+ return 0;
+ }
+ }
+
+#ifdef WITH_COA
+ cp = cf_pair_find(cs, "coa_pool");
+ if (cp) coa_pool_name = cf_pair_value(cp);
+ if (cp && coa_pool_name) {
+ bool do_print = true;
+
+ if (!add_pool_to_realm(rc, cs,
+ coa_pool_name, &coa_pool,
+ HOME_TYPE_COA, do_print)) {
+ return 0;
+ }
+ }
+#endif
+#endif
+
+ cf_log_info(cs, " realm %s {", name2);
+
+#ifdef WITH_PROXY
+ /*
+ * The realm MAY already exist if it's an old-style realm.
+ * In that case, merge the old-style realm with this one.
+ */
+ r = realm_find2(name2);
+ if (r && (strcmp(r->name, name2) == 0)) {
+ if (cf_pair_find(cs, "auth_pool") ||
+ cf_pair_find(cs, "acct_pool")) {
+ cf_log_err_cs(cs, "Duplicate realm \"%s\"", name2);
+ goto error;
+ }
+
+ if (!old_realm_config(rc, cs, r)) {
+ goto error;
+ }
+
+ cf_log_info(cs, " } # realm %s", name2);
+ return 1;
+ }
+#endif
+
+ r = talloc_zero(rc, REALM);
+ r->name = name2;
+ r->strip_realm = true;
+#ifdef WITH_PROXY
+ r->auth_pool = auth_pool;
+ r->acct_pool = acct_pool;
+#ifdef WITH_COA
+ r->coa_pool = coa_pool;
+#endif
+
+ if (auth_pool_name &&
+ (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */
+ cf_log_info(cs, "\tpool = %s", auth_pool_name);
+ } else {
+ if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name);
+ if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name);
+#ifdef WITH_COA
+ if (coa_pool_name) cf_log_info(cs, "\tcoa_pool = %s", coa_pool_name);
+#endif
+ }
+#endif
+
+ cp = cf_pair_find(cs, "nostrip");
+ if (cp && (cf_pair_value(cp) == NULL)) {
+ r->strip_realm = false;
+ cf_log_info(cs, "\tnostrip");
+ }
+
+ /*
+ * We're a new-style realm. Complain if we see the old
+ * directives.
+ */
+ if (r->auth_pool || r->acct_pool) {
+ if (((cp = cf_pair_find(cs, "authhost")) != NULL) ||
+ ((cp = cf_pair_find(cs, "accthost")) != NULL) ||
+ ((cp = cf_pair_find(cs, "secret")) != NULL) ||
+ ((cp = cf_pair_find(cs, "ldflag")) != NULL)) {
+ WARN("Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name);
+ }
+
+
+ /*
+ * The realm MAY be an old-style realm, as there
+ * was no auth_pool or acct_pool. Double-check
+ * it, just to be safe.
+ */
+ } else if (!old_realm_config(rc, cs, r)) {
+ goto error;
+ }
+
+ if (!realm_realm_add(r, cs)) {
+ goto error;
+ }
+
+ cf_log_info(cs, " }");
+
+ return 1;
+
+ error:
+ cf_log_info(cs, " } # realm %s", name2);
+ return 0;
+}
+
+#ifdef HAVE_REGEX
+int realm_realm_add(REALM *r, CONF_SECTION *cs)
+#else
+int realm_realm_add(REALM *r, UNUSED CONF_SECTION *cs)
+#endif
+{
+ /*
+ * The structs aren't mutex protected. Refuse to destroy
+ * the server.
+ */
+ if (event_loop_started && !realm_config->dynamic) {
+ DEBUG("Must set \"dynamic = true\" in proxy.conf");
+ return 0;
+ }
+
+#ifdef HAVE_REGEX
+ /*
+ * It's a regex. Sanity check it, and add it to a
+ * separate list.
+ */
+ if (r->name[0] == '~') {
+ ssize_t slen;
+ realm_regex_t *rr, **last;
+
+ rr = talloc(r, realm_regex_t);
+
+ /*
+ * Include substring matches.
+ */
+ slen = regex_compile(rr, &rr->preg, r->name + 1, strlen(r->name) - 1, true, false, false, false);
+ if (slen <= 0) {
+ char *spaces, *text;
+
+ fr_canonicalize_error(r, &spaces, &text, slen, r->name + 1);
+
+ cf_log_err_cs(cs, "Invalid regular expression:");
+ cf_log_err_cs(cs, "%s", text);
+ cf_log_err_cs(cs, "%s^ %s", spaces, fr_strerror());
+
+ talloc_free(spaces);
+ talloc_free(text);
+ talloc_free(rr);
+
+ return 0;
+ }
+
+ last = &realms_regex;
+ while (*last) last = &((*last)->next); /* O(N^2)... sue me. */
+
+ rr->realm = r;
+ rr->next = NULL;
+
+ *last = rr;
+ return 1;
+ }
+#endif
+
+ if (!rbtree_insert(realms_byname, r)) {
+ rad_assert("Internal sanity check failed" == NULL);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef WITH_COA
+
+static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
+{
+ int home;
+ char const *name, *type;
+ CONF_PAIR *cp;
+ CONF_SECTION *server_cs;
+
+ cp = cf_pair_find(cs, "home_server");
+ if (!cp) {
+ cf_log_err_cs(cs, "Pool does not contain a \"home_server\" entry");
+ return HOME_TYPE_INVALID;
+ }
+
+ name = cf_pair_value(cp);
+ if (!name) {
+ cf_log_err_cp(cp, "home_server entry does not reference a home server");
+ return HOME_TYPE_INVALID;
+ }
+
+ server_cs = cf_section_sub_find_name2(config, "home_server", name);
+ if (!server_cs) {
+ cf_log_err_cp(cp, "home_server \"%s\" does not exist", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ cp = cf_pair_find(server_cs, "type");
+ if (!cp) {
+ cf_log_err_cs(server_cs, "home_server %s does not contain a \"type\" entry", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ type = cf_pair_value(cp);
+ if (!type) {
+ cf_log_err_cs(server_cs, "home_server %s contains an empty \"type\" entry", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
+ if (home == HOME_TYPE_INVALID) {
+ cf_log_err_cs(server_cs, "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
+ return HOME_TYPE_INVALID;
+ }
+
+ return home; /* 'cause we miss it so much */
+}
+#endif
+
+int realms_init(CONF_SECTION *config)
+{
+ CONF_SECTION *cs;
+ int flags = 0;
+#ifdef WITH_PROXY
+ CONF_SECTION *server_cs;
+#endif
+ realm_config_t *rc;
+
+ if (event_loop_started) return 1;
+
+ rc = talloc_zero(NULL, realm_config_t);
+ rc->cs = config;
+
+#ifdef WITH_PROXY
+ cs = cf_subsection_find_next(config, NULL, "proxy");
+ if (cs) {
+ if (cf_section_parse(cs, rc, proxy_config) < 0) {
+ ERROR("Failed parsing proxy section");
+ goto error;
+ }
+ } else {
+ rc->dead_time = DEAD_TIME;
+ rc->retry_count = RETRY_COUNT;
+ rc->retry_delay = RETRY_DELAY;
+ rc->fallback = false;
+ rc->dynamic = false;
+ rc->wake_all_if_all_dead= 0;
+ }
+
+ if (rc->dynamic) {
+ flags = RBTREE_FLAG_LOCK;
+ }
+
+ home_servers_byaddr = rbtree_create(NULL, home_server_addr_cmp, home_server_free, flags);
+ if (!home_servers_byaddr) goto error;
+
+ home_servers_byname = rbtree_create(NULL, home_server_name_cmp, NULL, flags);
+ if (!home_servers_byname) goto error;
+
+#ifdef WITH_STATS
+ home_servers_bynumber = rbtree_create(NULL, home_server_number_cmp, NULL, flags);
+ if (!home_servers_bynumber) goto error;
+#endif
+
+ home_pools_byname = rbtree_create(NULL, home_pool_name_cmp, NULL, flags);
+ if (!home_pools_byname) goto error;
+
+ for (cs = cf_subsection_find_next(config, NULL, "home_server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "home_server")) {
+ home_server_t *home;
+
+ home = home_server_afrom_cs(rc, rc, cs);
+ if (!home) goto error;
+ if (!realm_home_server_add(home)) goto error;
+ }
+
+ /*
+ * Loop over virtual servers to find home servers which
+ * are defined in them.
+ */
+ for (server_cs = cf_subsection_find_next(config, NULL, "server");
+ server_cs != NULL;
+ server_cs = cf_subsection_find_next(config, server_cs, "server")) {
+ for (cs = cf_subsection_find_next(server_cs, NULL, "home_server");
+ cs != NULL;
+ cs = cf_subsection_find_next(server_cs, cs, "home_server")) {
+ home_server_t *home;
+
+ home = home_server_afrom_cs(rc, rc, cs);
+ if (!home) goto error;
+ if (!realm_home_server_add(home)) goto error;
+ }
+ }
+#endif
+
+ /*
+ * Now create the realms, which point to the home servers
+ * and home server pools.
+ */
+ realms_byname = rbtree_create(NULL, realm_name_cmp, NULL, flags);
+ if (!realms_byname) goto error;
+
+ for (cs = cf_subsection_find_next(config, NULL, "realm");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "realm")) {
+ if (!realm_add(rc, cs)) {
+ error:
+ realms_free();
+ /*
+ * Must be called after realms_free as home_servers
+ * parented by rc are in trees freed by realms_free()
+ */
+ talloc_free(rc);
+ return 0;
+ }
+ }
+
+#ifdef WITH_COA
+ /*
+ * CoA pools aren't necessarily tied to realms.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
+ int type;
+
+ /*
+ * Pool was already loaded.
+ */
+ if (cf_data_find(cs, "home_server_pool")) continue;
+
+ type = pool_peek_type(config, cs);
+ if (type == HOME_TYPE_INVALID) goto error;
+ if (!server_pool_add(rc, cs, type, true)) goto error;
+ }
+#endif
+
+#ifdef WITH_PROXY
+ xlat_register("home_server", xlat_home_server, NULL, NULL);
+ xlat_register("home_server_pool", xlat_server_pool, NULL, NULL);
+ xlat_register("home_server_dynamic", xlat_home_server_dynamic, NULL, NULL);
+#endif
+
+ realm_config = rc;
+
+#ifdef HAVE_DIRENT_H
+ if (!rc->dynamic) {
+ if (rc->directory) {
+ WARN("Ignoring 'directory' as dynamic home servers were not configured.");
+ }
+ } else {
+ DIR *dir;
+ struct dirent *dp;
+
+ if (!rc->directory) {
+ WARN("Ignoring \"dynamic = true\" due to not set \"directory\" in proxy.conf");
+ return 1;
+ }
+
+ DEBUG2("including files in directory %s", rc->directory);
+
+ dir = opendir(rc->directory);
+ if (!dir) {
+ cf_log_err_cs(config, "Error reading directory %s: %s",
+ rc->directory, fr_syserror(errno));
+ goto error;
+ }
+
+ /*
+ * Read the directory, ignoring "." files.
+ */
+ while ((dp = readdir(dir)) != NULL) {
+ char const *p;
+ char conf_file[PATH_MAX];
+
+ if (dp->d_name[0] == '.') continue;
+
+ /*
+ * Skip the TLS configuration.
+ */
+ if (strcmp(dp->d_name, "tls.conf") == 0) continue;
+
+ /*
+ * Check for valid characters
+ */
+ for (p = dp->d_name; *p != '\0'; p++) {
+ if (isalpha((uint8_t)*p) ||
+ isdigit((uint8_t)*p) ||
+ (*p == '-') ||
+ (*p == '_') ||
+ (*p == '.')) continue;
+ break;
+ }
+ if (*p != '\0') continue;
+
+ snprintf(conf_file, sizeof(conf_file), "%s/%s", rc->directory, dp->d_name);
+ if (home_server_afrom_file(conf_file) < 0) {
+ ERROR("Failed reading home_server from %s - %s",
+ conf_file, fr_strerror());
+ closedir(dir);
+ goto error;
+ }
+ }
+ closedir(dir);
+ }
+#endif
+
+ return 1;
+}
+
+/*
+ * Find a realm where "name" might be the regex.
+ */
+REALM *realm_find2(char const *name)
+{
+ REALM myrealm;
+ REALM *realm;
+
+ if (!name) name = "NULL";
+
+ myrealm.name = name;
+ realm = rbtree_finddata(realms_byname, &myrealm);
+ if (realm) return realm;
+
+#ifdef HAVE_REGEX
+ if (realms_regex) {
+ realm_regex_t *this;
+
+ for (this = realms_regex; this != NULL; this = this->next) {
+ if (strcmp(this->realm->name, name) == 0) {
+ return this->realm;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Couldn't find a realm. Look for DEFAULT.
+ */
+ myrealm.name = "DEFAULT";
+ return rbtree_finddata(realms_byname, &myrealm);
+}
+
+
+/*
+ * Find a realm in the REALM list.
+ */
+REALM *realm_find(char const *name)
+{
+ REALM myrealm;
+ REALM *realm;
+
+ if (!name) name = "NULL";
+
+ myrealm.name = name;
+ realm = rbtree_finddata(realms_byname, &myrealm);
+ if (realm) return realm;
+
+#ifdef HAVE_REGEX
+ if (realms_regex) {
+ realm_regex_t *this;
+
+ for (this = realms_regex;
+ this != NULL;
+ this = this->next) {
+ int compare;
+
+ compare = regex_exec(this->preg, name, strlen(name), NULL, NULL);
+ if (compare < 0) {
+ ERROR("Failed performing realm comparison: %s", fr_strerror());
+ return NULL;
+ }
+ if (compare == 1) return this->realm;
+ }
+ }
+#endif
+
+ /*
+ * Couldn't find a realm. Look for DEFAULT.
+ */
+ myrealm.name = "DEFAULT";
+ return rbtree_finddata(realms_byname, &myrealm);
+}
+
+
+#ifdef WITH_PROXY
+
+/*
+ * Allocate the proxy list if it doesn't already exist, and copy request
+ * VPs into it. Setup src/dst IP addresses based on home server, and
+ * calculate and add the message-authenticator.
+ *
+ * This is a distinct function from home_server_ldb, as not all home_server_t
+ * lookups result in the *CURRENT* request being proxied,
+ * as in rlm_replicate, and this may trigger asserts elsewhere in the
+ * server.
+ */
+void home_server_update_request(home_server_t *home, REQUEST *request)
+{
+
+ /*
+ * Allocate the proxy packet, only if it wasn't
+ * already allocated by a module. This check is
+ * mainly to support the proxying of EAP-TTLS and
+ * EAP-PEAP tunneled requests.
+ *
+ * In those cases, the EAP module creates a
+ * "fake" request, and recursively passes it
+ * through the authentication stage of the
+ * server. The module then checks if the request
+ * was supposed to be proxied, and if so, creates
+ * a proxy packet from the TUNNELED request, and
+ * not from the EAP request outside of the
+ * tunnel.
+ *
+ * The proxy then works like normal, except that
+ * the response packet is "eaten" by the EAP
+ * module, and encapsulated into an EAP packet.
+ */
+ if (!request->proxy) {
+ request->proxy = rad_alloc(request, true);
+ if (!request->proxy) {
+ ERROR("no memory");
+ fr_exit(1);
+ }
+
+ /*
+ * Copy the request, then look up name
+ * and plain-text password in the copy.
+ *
+ * Note that the User-Name attribute is
+ * the *original* as sent over by the
+ * client. The Stripped-User-Name
+ * attribute is the one hacked through
+ * the 'hints' file.
+ */
+ request->proxy->vps = fr_pair_list_copy(request->proxy,
+ request->packet->vps);
+ }
+
+ /*
+ * Update the various fields as appropriate.
+ */
+ request->proxy->src_ipaddr = home->src_ipaddr;
+ request->proxy->src_port = 0;
+ request->proxy->dst_ipaddr = home->ipaddr;
+ request->proxy->dst_port = home->port;
+#ifdef WITH_TCP
+ request->proxy->proto = home->proto;
+#endif
+ request->home_server = home;
+
+ /*
+ * Access-Requests have a Message-Authenticator added,
+ * unless one already exists.
+ */
+ if ((request->packet->code == PW_CODE_ACCESS_REQUEST) &&
+#ifdef WITH_RADIUSV11
+ !request->proxy->radiusv11 &&
+#endif
+ !fr_pair_find_by_num(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY)) {
+ fr_pair_make(request->proxy, &request->proxy->vps,
+ "Message-Authenticator", "0x00",
+ T_OP_SET);
+ }
+}
+
+home_server_t *home_server_ldb(char const *realmname,
+ home_pool_t *pool, REQUEST *request)
+{
+ int start;
+ int count;
+ home_server_t *found = NULL;
+ home_server_t *zombie = NULL;
+ VALUE_PAIR *vp;
+ uint32_t hash;
+
+ /*
+ * Determine how to pick choose the home server.
+ */
+ switch (pool->type) {
+
+
+ /*
+ * For load-balancing by client IP address, we
+ * pick a home server by hashing the client IP.
+ *
+ * This isn't as even a load distribution as
+ * tracking the State attribute, but it's better
+ * than nothing.
+ */
+ case HOME_POOL_CLIENT_BALANCE:
+ switch (request->packet->src_ipaddr.af) {
+ case AF_INET:
+ hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
+ sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
+ break;
+
+ case AF_INET6:
+ hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
+ sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
+ break;
+
+ default:
+ hash = 0;
+ break;
+ }
+ start = hash % pool->num_home_servers;
+ break;
+
+ case HOME_POOL_CLIENT_PORT_BALANCE:
+ switch (request->packet->src_ipaddr.af) {
+ case AF_INET:
+ hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr,
+ sizeof(request->packet->src_ipaddr.ipaddr.ip4addr));
+ break;
+
+ case AF_INET6:
+ hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr,
+ sizeof(request->packet->src_ipaddr.ipaddr.ip6addr));
+ break;
+
+ default:
+ hash = 0;
+ break;
+ }
+ hash = fr_hash_update(&request->packet->src_port,
+ sizeof(request->packet->src_port), hash);
+ start = hash % pool->num_home_servers;
+ break;
+
+ case HOME_POOL_KEYED_BALANCE:
+ if ((vp = fr_pair_find_by_num(request->config, PW_LOAD_BALANCE_KEY, 0, TAG_ANY)) != NULL) {
+ hash = fr_hash(vp->vp_strvalue, vp->vp_length);
+ start = hash % pool->num_home_servers;
+ break;
+ }
+ /* FALL-THROUGH */
+
+ case HOME_POOL_LOAD_BALANCE:
+ case HOME_POOL_FAIL_OVER:
+ start = 0;
+ break;
+
+ default: /* this shouldn't happen... */
+ start = 0;
+ break;
+
+ }
+
+ /*
+ * Starting with the home server we chose, loop through
+ * all home servers. If the current one is dead, skip
+ * it. If it is too busy, skip it.
+ *
+ * Otherwise, use it.
+ */
+ for (count = 0; count < pool->num_home_servers; count++) {
+ home_server_t *home = pool->servers[(start + count) % pool->num_home_servers];
+
+ if (!home) continue;
+
+ /*
+ * Skip dead home servers.
+ *
+ * Home servers that are unknown, alive, or zombie
+ * are used for proxying.
+ */
+ if (HOME_SERVER_IS_DEAD(home)) {
+ continue;
+ }
+
+ /*
+ * This home server is too busy. Choose another one.
+ */
+ if (home->currently_outstanding >= home->max_outstanding) {
+ continue;
+ }
+
+#ifdef WITH_DETAIL
+ /*
+ * We read the packet from a detail file, AND it
+ * came from this server. Don't re-proxy it
+ * there.
+ */
+ if (request->listener &&
+ (request->listener->type == RAD_LISTEN_DETAIL) &&
+ (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
+ (fr_ipaddr_cmp(&home->ipaddr, &request->packet->src_ipaddr) == 0)) {
+ continue;
+ }
+#endif
+
+ /*
+ * Default virtual: ignore homes tied to a
+ * virtual.
+ */
+ if (!request->server && home->parent_server) {
+ continue;
+ }
+
+ /*
+ * A virtual AND home is tied to virtual,
+ * ignore ones which don't match.
+ */
+ if (request->server && home->parent_server &&
+ strcmp(request->server, home->parent_server) != 0) {
+ continue;
+ }
+
+ /*
+ * Allow request->server && !home->parent_server
+ *
+ * i.e. virtuals can proxy to globally defined
+ * homes.
+ */
+
+ /*
+ * It's zombie, so we remember the first zombie
+ * we find, but we don't mark it as a "live"
+ * server.
+ */
+ if (home->state == HOME_STATE_ZOMBIE) {
+ if (!zombie) zombie = home;
+ continue;
+ }
+
+ /*
+ * We've found the first "live" one. Use that.
+ */
+ if (pool->type != HOME_POOL_LOAD_BALANCE) {
+ found = home;
+ break;
+ }
+
+ /*
+ * Otherwise we're doing some kind of load balancing.
+ * If we haven't found one yet, pick this one.
+ */
+ if (!found) {
+ found = home;
+ continue;
+ }
+
+ RDEBUG3("PROXY %s %d\t%s %d",
+ found->log_name, found->currently_outstanding,
+ home->log_name, home->currently_outstanding);
+
+ /*
+ * Prefer this server if it's less busy than the
+ * one we had previously found.
+ */
+ if (home->currently_outstanding < found->currently_outstanding) {
+ RDEBUG3("PROXY Choosing %s: It's less busy than %s",
+ home->log_name, found->log_name);
+ found = home;
+ continue;
+ }
+
+ /*
+ * Ignore servers which are busier than the one
+ * we found.
+ */
+ if (home->currently_outstanding > found->currently_outstanding) {
+ RDEBUG3("PROXY Skipping %s: It's busier than %s",
+ home->log_name, found->log_name);
+ continue;
+ }
+
+ /*
+ * From the list of servers which have the same
+ * load, choose one at random.
+ */
+ if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
+ found = home;
+ }
+ } /* loop over the home servers */
+
+ /*
+ * We have no live servers, BUT we have a zombie. Use
+ * the zombie as a last resort.
+ */
+ if (!found && zombie) {
+ found = zombie;
+ zombie = NULL;
+ }
+
+ /*
+ * There's a fallback if they're all dead.
+ */
+ if (!found && pool->fallback) {
+ found = pool->fallback;
+
+ WARN("Home server pool %s failing over to fallback %s",
+ pool->name, found->virtual_server);
+ if (pool->in_fallback) goto update_and_return;
+
+ pool->in_fallback = true;
+
+ /*
+ * Run the trigger once an hour saying that
+ * they're all dead.
+ */
+ if ((pool->time_all_dead + 3600) < request->timestamp) {
+ pool->time_all_dead = request->timestamp;
+ exec_trigger(request, pool->cs, "home_server_pool.fallback", false);
+ }
+ }
+
+ if (found) {
+ update_and_return:
+ if ((found != pool->fallback) && pool->in_fallback) {
+ pool->in_fallback = false;
+ exec_trigger(request, pool->cs, "home_server_pool.normal", false);
+ }
+
+ return found;
+ }
+
+ /*
+ * No live match found, and no fallback to the "DEFAULT"
+ * realm. We fix this by blindly marking all servers as
+ * "live". But only do it for ones that don't support
+ * "pings", as they will be marked live when they
+ * actually are live.
+ */
+ if (!realm_config->fallback &&
+ realm_config->wake_all_if_all_dead) {
+ for (count = 0; count < pool->num_home_servers; count++) {
+ home_server_t *home = pool->servers[count];
+
+ if (!home) continue;
+
+ if (HOME_SERVER_IS_DEAD(home) &&
+ (home->ping_check == HOME_PING_CHECK_NONE)) {
+ home->state = HOME_STATE_ALIVE;
+ home->response_timeouts = 0;
+ if (!found) found = home;
+ }
+ }
+
+ if (found) goto update_and_return;
+ }
+
+ /*
+ * Still nothing. Look up the DEFAULT realm, but only
+ * if we weren't looking up the NULL or DEFAULT realms.
+ */
+ if (realm_config->fallback &&
+ realmname &&
+ (strcmp(realmname, "NULL") != 0) &&
+ (strcmp(realmname, "DEFAULT") != 0)) {
+ REALM *rd = realm_find("DEFAULT");
+
+ if (!rd) return NULL;
+
+ pool = NULL;
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ pool = rd->auth_pool;
+
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ pool = rd->acct_pool;
+ }
+ if (!pool) return NULL;
+
+ RDEBUG2("PROXY - realm %s has no live home servers. Falling back to the DEFAULT realm.", realmname);
+ return home_server_ldb(rd->name, pool, request);
+ }
+
+ /*
+ * Still haven't found anything. Oh well.
+ */
+ return NULL;
+}
+
+
+home_server_t *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port,
+#ifndef WITH_TCP
+ UNUSED
+#endif
+ int proto)
+{
+ home_server_t myhome;
+
+ memset(&myhome, 0, sizeof(myhome));
+ myhome.ipaddr = *ipaddr;
+ myhome.src_ipaddr.af = ipaddr->af;
+ myhome.port = port;
+#ifdef WITH_TCP
+ myhome.proto = proto;
+#else
+ myhome.proto = IPPROTO_UDP;
+#endif
+ myhome.virtual_server = NULL; /* we're not called for internal proxying */
+
+ return rbtree_finddata(home_servers_byaddr, &myhome);
+}
+
+home_server_t *home_server_find_bysrc(fr_ipaddr_t *ipaddr, uint16_t port,
+ int proto,
+ fr_ipaddr_t *src_ipaddr)
+{
+ home_server_t myhome;
+
+ if (!src_ipaddr) return home_server_find(ipaddr, port, proto);
+
+ if (src_ipaddr->af != ipaddr->af) return NULL;
+
+ memset(&myhome, 0, sizeof(myhome));
+ myhome.ipaddr = *ipaddr;
+ myhome.src_ipaddr = *src_ipaddr;
+ myhome.port = port;
+#ifdef WITH_TCP
+ myhome.proto = proto;
+#else
+ myhome.proto = IPPROTO_UDP;
+#endif
+ myhome.virtual_server = NULL; /* we're not called for internal proxying */
+
+ return rbtree_finddata(home_servers_byaddr, &myhome);
+}
+
+#ifdef WITH_COA
+home_server_t *home_server_byname(char const *name, int type)
+{
+ home_server_t myhome;
+
+ memset(&myhome, 0, sizeof(myhome));
+ myhome.type = type;
+ myhome.name = name;
+
+ return rbtree_finddata(home_servers_byname, &myhome);
+}
+#endif
+
+#ifdef WITH_STATS
+home_server_t *home_server_bynumber(int number)
+{
+ home_server_t myhome;
+
+ memset(&myhome, 0, sizeof(myhome));
+ myhome.number = number;
+ myhome.virtual_server = NULL; /* we're not called for internal proxying */
+
+ return rbtree_finddata(home_servers_bynumber, &myhome);
+}
+#endif
+
+home_pool_t *home_pool_byname(char const *name, int type)
+{
+ home_pool_t mypool;
+
+ memset(&mypool, 0, sizeof(mypool));
+ mypool.name = name;
+ mypool.server_type = type;
+ return rbtree_finddata(home_pools_byname, &mypool);
+}
+
+int home_server_afrom_file(char const *filename)
+{
+ CONF_SECTION *cs, *subcs;
+ char const *p;
+ home_server_t *home;
+
+ if (!realm_config->dynamic) {
+ fr_strerror_printf("Must set \"dynamic = true\" in proxy.conf for dynamic home servers to work");
+ return -1;
+ }
+
+ cs = cf_section_alloc(NULL, "home", filename);
+ if (!cs) {
+ fr_strerror_printf("Failed allocating memory");
+ return -1;
+ }
+
+ if (cf_file_read(cs, filename) < 0) {
+ fr_strerror_printf("Failed reading file %s", filename);
+ error:
+ talloc_free(cs);
+ return -1;
+ }
+
+ p = strrchr(filename, '/');
+ if (p) {
+ p++;
+ } else {
+ p = filename;
+ }
+
+ subcs = cf_section_sub_find_name2(cs, "home_server", p);
+ if (!subcs) {
+ fr_strerror_printf("No 'home_server %s' definition in the file.", p);
+ goto error;
+ }
+
+ home = home_server_afrom_cs(realm_config, realm_config, subcs);
+ if (!home) {
+ fr_strerror_printf("Failed parsing configuration to a home_server structure");
+ goto error;
+ }
+
+ home->dynamic = true;
+
+ if (home->virtual_server) {
+ fr_strerror_printf("Dynamic home_server '%s' cannot have 'server = %s' configuration item", p, home->virtual_server);
+ talloc_free(home);
+ goto error;
+ }
+
+ if (home->dual) {
+ fr_strerror_printf("Dynamic home_server '%s' is missing 'type', or it is set to 'auth+acct'. Please specify 'type = auth' or 'type = acct', etc.", p);
+ talloc_free(home);
+ goto error;
+ }
+
+#ifdef COA_TUNNEL
+ if (home->recv_coa) {
+ fr_strerror_printf("Dynamic home_server '%s' cannot receive CoA requests'", p);
+ talloc_free(home);
+ goto error;
+ }
+#endif
+
+ if (!realm_home_server_add(home)) {
+ fr_strerror_printf("Failed adding home_server to the internal data structures");
+ talloc_free(home);
+ goto error;
+ }
+
+ return 0;
+}
+
+int home_server_delete(char const *name, char const *type_name)
+{
+ home_server_t *home;
+ int type;
+ char const *p;
+
+ if (!realm_config->dynamic) {
+ fr_strerror_printf("Must set 'dynamic' in proxy.conf for dynamic home servers to work");
+ return -1;
+ }
+
+ type = fr_str2int(home_server_types, type_name, HOME_TYPE_INVALID);
+ if (type == HOME_TYPE_INVALID) {
+ fr_strerror_printf("Unknown home_server type '%s'", type_name);
+ return -1;
+ }
+
+ p = strrchr(name, '/');
+ if (p) {
+ p++;
+ } else {
+ p = name;
+ }
+
+ home = home_server_byname(p, type);
+ if (!home) {
+ fr_strerror_printf("Failed to find home_server %s", p);
+ return -1;
+ }
+
+ if (!home->dynamic) {
+ fr_strerror_printf("Cannot delete static home_server %s", p);
+ return -1;
+ }
+
+ (void) rbtree_deletebydata(home_servers_byname, home);
+ (void) rbtree_deletebydata(home_servers_byaddr, home);
+#ifdef WITH_STATS
+ (void) rbtree_deletebydata(home_servers_bynumber, home);
+#endif
+
+ /*
+ * Leak home, and home->cs. Oh well.
+ */
+ return 0;
+}
+#endif
diff --git a/src/main/regex.c b/src/main/regex.c
new file mode 100644
index 0000000..f66414c
--- /dev/null
+++ b/src/main/regex.c
@@ -0,0 +1,279 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * $Id$
+ *
+ * @file main/regex.c
+ * @brief Regular expression functions used by the server library.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_REGEX
+
+#define REQUEST_DATA_REGEX (0xadbeef00)
+
+typedef struct regcapture {
+#ifdef HAVE_PCRE
+ regex_t *preg; //!< Compiled pattern.
+#endif
+ char const *value; //!< Original string.
+ regmatch_t *rxmatch; //!< Match vectors.
+ size_t nmatch; //!< Number of match vectors.
+} regcapture_t;
+
+/** Adds subcapture values to request data
+ *
+ * Allows use of %{n} expansions.
+ *
+ * @note After calling regex_sub_to_request *preg may no longer be valid and
+ * should be passed to talloc_free.
+ *
+ * @param request Current request.
+ * @param preg Compiled pattern. May be set to NULL if reparented to the regcapture struct.
+ * @param value The original value.
+ * @param rxmatch Pointers into value.
+ * @param nmatch Sizeof rxmatch.
+ */
+void regex_sub_to_request(REQUEST *request, regex_t **preg, char const *value, size_t len,
+ regmatch_t rxmatch[], size_t nmatch)
+{
+ regcapture_t *old_sc, *new_sc; /* lldb doesn't like new *sigh* */
+ char *p;
+
+ /*
+ * Clear out old_sc matches
+ */
+ old_sc = request_data_get(request, request, REQUEST_DATA_REGEX);
+ if (old_sc) {
+ DEBUG4("Clearing %zu old matches", old_sc->nmatch);
+ talloc_free(old_sc);
+ } else {
+ DEBUG4("No old matches");
+ }
+
+ if (nmatch == 0) return;
+
+ rad_assert(preg && *preg);
+ rad_assert(rxmatch);
+
+ DEBUG4("Adding %zu matches", nmatch);
+
+ /*
+ * Add new_sc matches
+ */
+ MEM(new_sc = talloc(request, regcapture_t));
+
+ MEM(new_sc->rxmatch = talloc_memdup(new_sc, rxmatch, sizeof(rxmatch[0]) * nmatch));
+ talloc_set_type(new_sc->rxmatch, regmatch_t[]);
+
+ MEM(p = talloc_array(new_sc, char, len + 1));
+ memcpy(p, value, len);
+ p[len] = '\0';
+ new_sc->value = p;
+ new_sc->nmatch = nmatch;
+
+#ifdef HAVE_PCRE
+ if (!(*preg)->precompiled) {
+ new_sc->preg = talloc_steal(new_sc, *preg);
+ *preg = NULL;
+ } else {
+ new_sc->preg = *preg;
+ }
+#endif
+
+ request_data_add(request, request, REQUEST_DATA_REGEX, new_sc, true);
+}
+
+# ifdef HAVE_PCRE
+/** Extract a subcapture value from the request
+ *
+ * @note This is the PCRE variant of the function.
+ *
+ * @param ctx To allocate subcapture buffer in.
+ * @param out Where to write the subcapture string.
+ * @param request to extract.
+ * @param num Subcapture index (0 for entire match).
+ * @return 0 on success, -1 on notfound.
+ */
+int regex_request_to_sub(TALLOC_CTX *ctx, char **out, REQUEST *request, uint32_t num)
+{
+ regcapture_t *cap;
+ char const *p;
+ int ret;
+
+ cap = request_data_reference(request, request, REQUEST_DATA_REGEX);
+ if (!cap) {
+ RDEBUG4("No subcapture data found");
+ *out = NULL;
+ return -1;
+ }
+
+ ret = pcre_get_substring(cap->value, (int *)cap->rxmatch, (int)cap->nmatch, num, &p);
+ switch (ret) {
+ case PCRE_ERROR_NOMEMORY:
+ MEM(NULL);
+ /* FALL-THROUGH */
+
+ /*
+ * Not finding a substring is fine
+ */
+ case PCRE_ERROR_NOSUBSTRING:
+ RDEBUG4("%i/%zu Not found", num, cap->nmatch);
+ *out = NULL;
+ return -1;
+
+ default:
+ if (ret < 0) {
+ *out = NULL;
+ return -1;
+ }
+
+ /*
+ * Check libpcre really is using our overloaded
+ * malloc/free talloc wrappers.
+ */
+ p = (char *)talloc_get_type_abort(p, uint8_t);
+ talloc_set_type(p, char *);
+ talloc_steal(ctx, p);
+ memcpy(out, &p, sizeof(*out));
+
+ RDEBUG4("%i/%zu Found: %s (%zu)", num, cap->nmatch, p, talloc_array_length(p));
+
+ return 0;
+ }
+}
+
+/** Extract a named subcapture value from the request
+ *
+ * @note This is the PCRE variant of the function.
+ *
+ * @param ctx To allocate subcapture buffer in.
+ * @param out Where to write the subcapture string.
+ * @param request to extract.
+ * @param name of subcapture.
+ * @return 0 on success, -1 on notfound.
+ */
+int regex_request_to_sub_named(TALLOC_CTX *ctx, char **out, REQUEST *request, char const *name)
+{
+ regcapture_t *cap;
+ char const *p;
+ int ret;
+
+ cap = request_data_reference(request, request, REQUEST_DATA_REGEX);
+ if (!cap) {
+ RDEBUG4("No subcapture data found");
+ *out = NULL;
+ return -1;
+ }
+
+ ret = pcre_get_named_substring(cap->preg->compiled, cap->value,
+ (int *)cap->rxmatch, (int)cap->nmatch, name, &p);
+ switch (ret) {
+ case PCRE_ERROR_NOMEMORY:
+ MEM(NULL);
+ /* FALL-THROUGH */
+
+ /*
+ * Not finding a substring is fine
+ */
+ case PCRE_ERROR_NOSUBSTRING:
+ RDEBUG4("No named capture group \"%s\"", name);
+ *out = NULL;
+ return -1;
+
+ default:
+ if (ret < 0) {
+ *out = NULL;
+ return -1;
+ }
+
+ /*
+ * Check libpcre really is using our overloaded
+ * malloc/free talloc wrappers.
+ */
+ p = (char *)talloc_get_type_abort(p, uint8_t);
+ talloc_set_type(p, char *);
+ talloc_steal(ctx, p);
+ memcpy(out, &p, sizeof(*out));
+
+ RDEBUG4("Found \"%s\": %s (%zu)", name, p, talloc_array_length(p));
+
+ return 0;
+ }
+}
+# else
+/** Extract a subcapture value from the request
+ *
+ * @note This is the POSIX variant of the function.
+ *
+ * @param ctx To allocate subcapture buffer in.
+ * @param out Where to write the subcapture string.
+ * @param request to extract.
+ * @param num Subcapture index (0 for entire match).
+ * @return 0 on success, -1 on notfound.
+ */
+int regex_request_to_sub(TALLOC_CTX *ctx, char **out, REQUEST *request, uint32_t num)
+{
+ regcapture_t *cap;
+ char *p;
+ char const *start;
+ size_t len;
+
+ cap = request_data_reference(request, request, REQUEST_DATA_REGEX);
+ if (!cap) {
+ RDEBUG4("No subcapture data found");
+ *out = NULL;
+ return -1;
+ }
+
+ /*
+ * Greater than our capture array
+ *
+ * -1 means no value in this capture group.
+ */
+ if ((num >= cap->nmatch) || (cap->rxmatch[num].rm_eo == -1) || (cap->rxmatch[num].rm_so == -1)) {
+ RDEBUG4("%i/%zu Not found", num, cap->nmatch);
+ *out = NULL;
+ return -1;
+ }
+
+ /*
+ * Sanity checks on the offsets
+ */
+ rad_assert(cap->rxmatch[num].rm_eo <= (regoff_t)talloc_array_length(cap->value));
+ rad_assert(cap->rxmatch[num].rm_so <= (regoff_t)talloc_array_length(cap->value));
+
+ start = cap->value + cap->rxmatch[num].rm_so;
+ len = cap->rxmatch[num].rm_eo - cap->rxmatch[num].rm_so;
+
+ RDEBUG4("%i/%zu Found: %.*s (%zu)", num, cap->nmatch, (int)len, start, len);
+ MEM(p = talloc_array(ctx, char, len + 1));
+ memcpy(p, start, len);
+ p[len] = '\0';
+
+ *out = p;
+
+ return 0;
+}
+# endif
+#endif
diff --git a/src/main/session.c b/src/main/session.c
new file mode 100644
index 0000000..ddec8ff
--- /dev/null
+++ b/src/main/session.c
@@ -0,0 +1,262 @@
+/*
+ * session.c session management
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * End a session by faking a Stop packet to all accounting modules.
+ */
+int session_zap(REQUEST *request, fr_ipaddr_t const *nasaddr, uint32_t nas_port,
+ char const *nas_port_id, char const *user,
+ char const *sessionid, uint32_t cliaddr, char proto,
+ int session_time)
+{
+ REQUEST *stopreq;
+ VALUE_PAIR *vp;
+ int ret;
+
+ stopreq = request_alloc_fake(request);
+ rad_assert(stopreq != NULL);
+ rad_assert(stopreq->packet != NULL);
+ stopreq->packet->code = PW_CODE_ACCOUNTING_REQUEST; /* just to be safe */
+ stopreq->listener = request->listener;
+
+ /* Hold your breath */
+#define PAIR(n,v,e) do { \
+ if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) { \
+ talloc_free(stopreq); \
+ ERROR("no memory"); \
+ return 0; \
+ } \
+ vp->e = v; \
+ fr_pair_add(&(stopreq->packet->vps), vp); \
+ } while(0)
+
+#define INTPAIR(n,v) PAIR(n,v,vp_integer)
+
+#define IPPAIR(n,v) PAIR(n,v,vp_ipaddr)
+
+#define IPV6PAIR(n,v) PAIR(n,v,vp_ipv6addr)
+
+#define STRINGPAIR(n,v) do { \
+ if(!(vp = fr_pair_afrom_num(stopreq->packet,n, 0))) { \
+ talloc_free(stopreq); \
+ ERROR("no memory"); \
+ return 0; \
+ } \
+ fr_pair_value_strcpy(vp, v); \
+ fr_pair_add(&(stopreq->packet->vps), vp); \
+ } while(0)
+
+ INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
+
+ if (nasaddr->af == AF_INET) {
+ IPPAIR(PW_NAS_IP_ADDRESS, nasaddr->ipaddr.ip4addr.s_addr);
+ } else {
+ IPV6PAIR(PW_NAS_IPV6_ADDRESS, nasaddr->ipaddr.ip6addr);
+ }
+
+ INTPAIR(PW_EVENT_TIMESTAMP, 0);
+ vp->vp_date = time(NULL);
+ INTPAIR(PW_ACCT_DELAY_TIME, 0);
+
+ STRINGPAIR(PW_USER_NAME, user);
+ stopreq->username = vp;
+
+ if (!nas_port_id) {
+ INTPAIR(PW_NAS_PORT, nas_port);
+ } else {
+ STRINGPAIR(PW_NAS_PORT_ID, nas_port_id);
+ }
+ STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
+ if(proto == 'P') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
+ } else if(proto == 'S') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
+ } else {
+ INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
+ }
+ if(cliaddr != 0)
+ IPPAIR(PW_FRAMED_IP_ADDRESS, cliaddr);
+ INTPAIR(PW_ACCT_SESSION_TIME, session_time);
+ INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
+
+ stopreq->password = NULL;
+
+ RDEBUG("Running Accounting section for automatically created accounting 'stop'");
+ rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL);
+ ret = rad_accounting(stopreq);
+
+ /*
+ * We've got to clean it up by hand, because no one else will.
+ */
+ talloc_free(stopreq);
+
+ return ret;
+}
+
+#ifndef __MINGW32__
+
+/*
+ * Check one terminal server to see if a user is logged in.
+ *
+ * Return values:
+ * 0 The user is off-line.
+ * 1 The user is logged in.
+ * 2 Some error occured.
+ */
+int rad_check_ts(fr_ipaddr_t const *nasaddr, uint32_t nas_port, char const *nas_port_id, char const *user,
+ char const *session_id)
+{
+ pid_t pid, child_pid;
+ int status;
+ char address[64];
+ char port[11];
+ RADCLIENT *cl;
+
+ /*
+ * Find NAS type.
+ */
+ cl = client_find_old(nasaddr);
+ if (!cl) {
+ /*
+ * Unknown NAS, so trusting radutmp.
+ */
+ DEBUG2("checkrad: Unknown NAS %s, not checking",
+ inet_ntop(nasaddr->af, &(nasaddr->ipaddr), address, sizeof(address)));
+ return 1;
+ }
+
+ /*
+ * No nas_type, or nas type 'other', trust radutmp.
+ */
+ if (!cl->nas_type || (cl->nas_type[0] == '\0') ||
+ (strcmp(cl->nas_type, "other") == 0)) {
+ DEBUG2("checkrad: No NAS type, or type \"other\" not checking");
+ return 1;
+ }
+
+ /*
+ * Fork.
+ */
+ if ((pid = rad_fork()) < 0) { /* do wait for the fork'd result */
+ ERROR("Accounting: Failed in fork(): Cannot run checkrad\n");
+ return 2;
+ }
+
+ if (pid > 0) {
+ child_pid = rad_waitpid(pid, &status);
+
+ /*
+ * It's taking too long. Stop waiting for it.
+ *
+ * Don't bother to kill it, as we don't care what
+ * happens to it now.
+ */
+ if (child_pid == 0) {
+ ERROR("Check-TS: timeout waiting for checkrad");
+ return 2;
+ }
+
+ if (child_pid < 0) {
+ ERROR("Check-TS: unknown error in waitpid()");
+ return 2;
+ }
+
+ return WEXITSTATUS(status);
+ }
+
+ /*
+ * We don't close fd's 0, 1, and 2. If we're in debugging mode,
+ * then they should go to stdout (etc), along with the other
+ * server log messages.
+ *
+ * If we're not in debugging mode, then the code in radiusd.c
+ * takes care of connecting fd's 0, 1, and 2 to /dev/null.
+ */
+ closefrom(3);
+
+ inet_ntop(nasaddr->af, &(nasaddr->ipaddr), address, sizeof(address));
+
+ if (!nas_port_id) {
+ snprintf(port, sizeof(port), "%u", nas_port);
+ nas_port_id = port;
+ }
+
+#ifdef __EMX__
+ /* OS/2 can't directly execute scripts then we call the command
+ processor to execute checkrad
+ */
+ execl(getenv("COMSPEC"), "", "/C","checkrad", cl->nas_type, address, nas_port_id,
+ user, session_id, NULL);
+#else
+ execl(main_config.checkrad, "checkrad", cl->nas_type, address, nas_port_id,
+ user, session_id, NULL);
+#endif
+ ERROR("Check-TS: exec %s: %s", main_config.checkrad, fr_syserror(errno));
+
+ /*
+ * Exit - 2 means "some error occured".
+ */
+ exit(2);
+}
+#else
+int rad_check_ts(fr_ipaddr_t const *nasaddr, UNUSED unsigned int nas_port,
+ UNUSED char const *user, UNUSED char const *session_id)
+{
+ ERROR("Simultaneous-Use is not supported");
+ return 2;
+}
+#endif
+
+#else
+/* WITH_SESSION_MGMT */
+
+int session_zap(UNUSED REQUEST *request, fr_ipaddr_t const *nasaddr, UNUSED uint32_t nas_port,
+ UNUSED char const *nas_port_id, UNUSED char const *user,
+ UNUSED char const *sessionid, UNUSED uint32_t cliaddr, UNUSED char proto,
+ UNUSED int session_time)
+{
+ return RLM_MODULE_FAIL;
+}
+
+int rad_check_ts(fr_ipaddr_t const *nasaddr, UNUSED unsigned int nas_port,
+ UNUSED char const *nas_port_id, UNUSED char const *user, UNUSED char const *session_id)
+{
+ ERROR("Simultaneous-Use is not supported");
+ return 2;
+}
+#endif
diff --git a/src/main/soh.c b/src/main/soh.c
new file mode 100644
index 0000000..754ad84
--- /dev/null
+++ b/src/main/soh.c
@@ -0,0 +1,675 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file soh.c
+ * @brief Implements the MS-SOH parsing code. This is called from rlm_eap_peap
+ *
+ * @copyright 2010 Phil Mayers <p.mayers@imperial.ac.uk>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/soh.h>
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * This code implements parsing of MS-SOH data into FreeRadius AVPs
+ * allowing for FreeRadius MS-NAP policies
+ */
+
+/**
+ * EAP-SOH packet
+ */
+typedef struct {
+ uint16_t tlv_type; /**< ==7 for EAP-SOH */
+ uint16_t tlv_len;
+ uint32_t tlv_vendor;
+
+ /**
+ * @name soh-payload
+ * @brief either an soh request or response */
+ uint16_t soh_type; /**< ==2 for request, 1 for response */
+ uint16_t soh_len;
+
+ /* an soh-response may now follow... */
+} eap_soh;
+
+/**
+ * SOH response payload
+ * Send by client to server
+ */
+typedef struct {
+ uint16_t outer_type;
+ uint16_t outer_len;
+ uint32_t vendor;
+ uint16_t inner_type;
+ uint16_t inner_len;
+} soh_response;
+
+/**
+ * SOH mode subheader
+ * Typical microsoft binary blob nonsense
+ */
+typedef struct {
+ uint16_t outer_type;
+ uint16_t outer_len;
+ uint32_t vendor;
+ uint8_t corrid[24];
+ uint8_t intent;
+ uint8_t content_type;
+} soh_mode_subheader;
+
+/**
+ * SOH type-length-value header
+ */
+typedef struct {
+ uint16_t tlv_type;
+ uint16_t tlv_len;
+} soh_tlv;
+
+/** Read big-endian 2-byte unsigned from p
+ *
+ * caller must ensure enough data exists at "p"
+ */
+uint16_t soh_pull_be_16(uint8_t const *p) {
+ uint16_t r;
+
+ r = *p++ << 8;
+ r += *p++;
+
+ return r;
+}
+
+/** Read big-endian 3-byte unsigned from p
+ *
+ * caller must ensure enough data exists at "p"
+ */
+uint32_t soh_pull_be_24(uint8_t const *p) {
+ uint32_t r;
+
+ r = *p++ << 16;
+ r += *p++ << 8;
+ r += *p++;
+
+ return r;
+}
+
+/** Read big-endian 4-byte unsigned from p
+ *
+ * caller must ensure enough data exists at "p"
+ */
+uint32_t soh_pull_be_32(uint8_t const *p) {
+ uint32_t r;
+
+ r = *p++ << 24;
+ r += *p++ << 16;
+ r += *p++ << 8;
+ r += *p++;
+
+ return r;
+}
+
+static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len) CC_HINT(nonnull);
+
+/** Parses the MS-SOH type/value (note: NOT type/length/value) data and update the sohvp list
+ *
+ * See section 2.2.4 of MS-SOH. Because there's no "length" field we CANNOT just skip
+ * unknown types; we need to know their length ahead of time. Therefore, we abort
+ * if we find an unknown type. Note that sohvp may still have been modified in the
+ * failure case.
+ *
+ * @param request Current request
+ * @param p binary blob
+ * @param data_len length of blob
+ * @return 1 on success, 0 on failure
+ */
+static int eapsoh_mstlv(REQUEST *request, uint8_t const *p, unsigned int data_len)
+{
+ VALUE_PAIR *vp;
+ uint8_t c;
+ int t;
+
+ while (data_len > 0) {
+ c = *p++;
+ data_len--;
+
+ switch (c) {
+ case 1:
+ /* MS-Machine-Inventory-Packet
+ * MS-SOH section 2.2.4.1
+ */
+ if (data_len < 18) {
+ RDEBUG("insufficient data for MS-Machine-Inventory-Packet");
+ return 0;
+ }
+ data_len -= 18;
+
+ vp = pair_make_request("SoH-MS-Machine-OS-vendor", "Microsoft", T_OP_EQ);
+ if (!vp) return 0;
+
+ vp = pair_make_request("SoH-MS-Machine-OS-version", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_32(p); p+=4;
+
+ vp = pair_make_request("SoH-MS-Machine-OS-release", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_32(p); p+=4;
+
+ vp = pair_make_request("SoH-MS-Machine-OS-build", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_32(p); p+=4;
+
+ vp = pair_make_request("SoH-MS-Machine-SP-version", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_16(p); p+=2;
+
+ vp = pair_make_request("SoH-MS-Machine-SP-release", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_16(p); p+=2;
+
+ vp = pair_make_request("SoH-MS-Machine-Processor", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = soh_pull_be_16(p); p+=2;
+ break;
+
+ case 2:
+ /* MS-Quarantine-State - FIXME: currently unhandled
+ * MS-SOH 2.2.4.1
+ *
+ * 1 byte reserved
+ * 1 byte flags
+ * 8 bytes NT Time field (100-nanosec since 1 Jan 1601)
+ * 2 byte urilen
+ * N bytes uri
+ */
+ p += 10;
+ t = soh_pull_be_16(p); /* t == uri len */
+ p += 2;
+ p += t;
+ data_len -= 12 + t;
+ break;
+
+ case 3:
+ /* MS-Packet-Info
+ * MS-SOH 2.2.4.3
+ */
+ RDEBUG3("SoH MS-Packet-Info %s vers=%i", *p & 0x10 ? "request" : "response", *p & 0xf);
+ p++;
+ data_len--;
+ break;
+
+ case 4:
+ /* MS-SystemGenerated-Ids - FIXME: currently unhandled
+ * MS-SOH 2.2.4.4
+ *
+ * 2 byte length
+ * N bytes (3 bytes IANA enterprise# + 1 byte component id#)
+ */
+ t = soh_pull_be_16(p);
+ p += 2;
+ p += t;
+ data_len -= 2 + t;
+ break;
+
+ case 5:
+ /* MS-MachineName
+ * MS-SOH 2.2.4.5
+ *
+ * 1 byte namelen
+ * N bytes name
+ */
+ t = soh_pull_be_16(p);
+ p += 2;
+
+ vp = pair_make_request("SoH-MS-Machine-Name", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ fr_pair_value_bstrncpy(vp, p, t);
+
+ p += t;
+ data_len -= 2 + t;
+ break;
+
+ case 6:
+ /* MS-CorrelationId
+ * MS-SOH 2.2.4.6
+ *
+ * 24 bytes opaque binary which we might, in future, have
+ * to echo back to the client in a final SoHR
+ */
+ vp = pair_make_request("SoH-MS-Correlation-Id", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ fr_pair_value_memcpy(vp, p, 24);
+ p += 24;
+ data_len -= 24;
+ break;
+
+ case 7:
+ /* MS-Installed-Shvs - FIXME: currently unhandled
+ * MS-SOH 2.2.4.7
+ *
+ * 2 bytes length
+ * N bytes (3 bytes IANA enterprise# + 1 byte component id#)
+ */
+ t = soh_pull_be_16(p);
+ p += 2;
+ p += t;
+ data_len -= 2 + t;
+ break;
+
+ case 8:
+ /* MS-Machine-Inventory-Ex
+ * MS-SOH 2.2.4.8
+ *
+ * 4 bytes reserved
+ * 1 byte product type (client=1 domain_controller=2 server=3)
+ */
+ p += 4;
+ vp = pair_make_request("SoH-MS-Machine-Role", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ vp->vp_integer = *p;
+ p++;
+ data_len -= 5;
+ break;
+
+ default:
+ RDEBUG("SoH Unknown MS TV %i stopping", c);
+ return 0;
+ }
+ }
+ return 1;
+}
+/** Convert windows Health Class status into human-readable string
+ *
+ * Tedious, really, really tedious...
+ */
+static char const* clientstatus2str(uint32_t hcstatus) {
+ switch (hcstatus) {
+ /* this lot should all just be for windows updates */
+ case 0xff0005:
+ return "wua-ok";
+
+ case 0xff0006:
+ return "wua-missing";
+
+ case 0xff0008:
+ return "wua-not-started";
+
+ case 0xc0ff000c:
+ return "wua-no-wsus-server";
+
+ case 0xc0ff000d:
+ return "wua-no-wsus-clientid";
+
+ case 0xc0ff000e:
+ return "wua-disabled";
+
+ case 0xc0ff000f:
+ return "wua-comm-failure";
+
+ /* these next 3 are for all health-classes */
+ case 0xc0ff0002:
+ return "not-installed";
+
+ case 0xc0ff0003:
+ return "down";
+
+ case 0xc0ff0018:
+ return "not-started";
+ }
+ return NULL;
+}
+
+/** Convert a Health Class into a string
+ *
+ */
+static char const* healthclass2str(uint8_t hc) {
+ switch (hc) {
+ case 0:
+ return "firewall";
+
+ case 1:
+ return "antivirus";
+
+ case 2:
+ return "antispyware";
+
+ case 3:
+ return "updates";
+
+ case 4:
+ return "security-updates";
+ }
+ return NULL;
+}
+
+/** Parse the MS-SOH response in data and update sohvp
+ *
+ * Note that sohvp might still have been updated in event of a failure.
+ *
+ * @param request Current request
+ * @param data MS-SOH blob
+ * @param data_len length of MS-SOH blob
+ *
+ * @return 0 on success, -1 on failure
+ *
+ */
+int soh_verify(REQUEST *request, uint8_t const *data, unsigned int data_len) {
+
+ VALUE_PAIR *vp;
+ eap_soh hdr;
+ soh_response resp;
+ soh_mode_subheader mode;
+ soh_tlv tlv;
+ int curr_shid=-1, curr_shid_c=-1, curr_hc=-1;
+
+ rad_assert(request->packet != NULL);
+
+ hdr.tlv_type = soh_pull_be_16(data); data += 2;
+ hdr.tlv_len = soh_pull_be_16(data); data += 2;
+ hdr.tlv_vendor = soh_pull_be_32(data); data += 4;
+
+ if (hdr.tlv_type != 7 || hdr.tlv_vendor != 0x137) {
+ RDEBUG("SoH payload is %i %08x not a ms-vendor packet", hdr.tlv_type, hdr.tlv_vendor);
+ return -1;
+ }
+
+ hdr.soh_type = soh_pull_be_16(data); data += 2;
+ hdr.soh_len = soh_pull_be_16(data); data += 2;
+ if (hdr.soh_type != 1) {
+ RDEBUG("SoH tlv %04x is not a response", hdr.soh_type);
+ return -1;
+ }
+
+ /* FIXME: check for sufficient data */
+ resp.outer_type = soh_pull_be_16(data); data += 2;
+ resp.outer_len = soh_pull_be_16(data); data += 2;
+ resp.vendor = soh_pull_be_32(data); data += 4;
+ resp.inner_type = soh_pull_be_16(data); data += 2;
+ resp.inner_len = soh_pull_be_16(data); data += 2;
+
+
+ if (resp.outer_type!=7 || resp.vendor != 0x137) {
+ RDEBUG("SoH response outer type %i/vendor %08x not recognised", resp.outer_type, resp.vendor);
+ return -1;
+ }
+ switch (resp.inner_type) {
+ case 1:
+ /* no mode sub-header */
+ RDEBUG("SoH without mode subheader");
+ break;
+
+ case 2:
+ mode.outer_type = soh_pull_be_16(data); data += 2;
+ mode.outer_len = soh_pull_be_16(data); data += 2;
+ mode.vendor = soh_pull_be_32(data); data += 4;
+ memcpy(mode.corrid, data, 24); data += 24;
+ mode.intent = data[0];
+ mode.content_type = data[1];
+ data += 2;
+
+ if (mode.outer_type != 7 || mode.vendor != 0x137 || mode.content_type != 0) {
+ RDEBUG3("SoH mode subheader outer type %i/vendor %08x/content type %i invalid", mode.outer_type, mode.vendor, mode.content_type);
+ return -1;
+ }
+ RDEBUG3("SoH with mode subheader");
+ break;
+
+ default:
+ RDEBUG("SoH invalid inner type %i", resp.inner_type);
+ return -1;
+ }
+
+ /* subtract off the relevant amount of data */
+ if (resp.inner_type==2) {
+ data_len = resp.inner_len - 34;
+ } else {
+ data_len = resp.inner_len;
+ }
+
+ /* TLV
+ * MS-SOH 2.2.1
+ * See also 2.2.3
+ *
+ * 1 bit mandatory
+ * 1 bit reserved
+ * 14 bits tlv type
+ * 2 bytes tlv length
+ * N bytes payload
+ *
+ */
+ while (data_len >= 4) {
+ tlv.tlv_type = soh_pull_be_16(data); data += 2;
+ tlv.tlv_len = soh_pull_be_16(data); data += 2;
+
+ data_len -= 4;
+
+ switch (tlv.tlv_type) {
+ case 2:
+ /* System-Health-Id TLV
+ * MS-SOH 2.2.3.1
+ *
+ * 3 bytes IANA/SMI vendor code
+ * 1 byte component (i.e. within vendor, which SoH component
+ */
+ curr_shid = soh_pull_be_24(data);
+ curr_shid_c = data[3];
+ RDEBUG2("SoH System-Health-ID vendor %08x component=%i", curr_shid, curr_shid_c);
+ break;
+
+ case 7:
+ /* Vendor-Specific packet
+ * MS-SOH 2.2.3.3
+ *
+ * 4 bytes vendor, supposedly ignored by NAP
+ * N bytes payload; for Microsoft component#0 this is the MS TV stuff
+ */
+ if (curr_shid==0x137 && curr_shid_c==0) {
+ RDEBUG2("SoH MS type-value payload");
+ eapsoh_mstlv(request, data + 4, tlv.tlv_len - 4);
+ } else {
+ RDEBUG2("SoH unhandled vendor-specific TLV %08x/component=%i %i bytes payload",
+ curr_shid, curr_shid_c, tlv.tlv_len);
+ }
+ break;
+
+ case 8:
+ /* Health-Class
+ * MS-SOH 2.2.3.5.6
+ *
+ * 1 byte integer
+ */
+ RDEBUG2("SoH Health-Class %i", data[0]);
+ curr_hc = data[0];
+ break;
+
+ case 9:
+ /* Software-Version
+ * MS-SOH 2.2.3.5.7
+ *
+ * 1 byte integer
+ */
+ RDEBUG2("SoH Software-Version %i", data[0]);
+ break;
+
+ case 11:
+ /* Health-Class status
+ * MS-SOH 2.2.3.5.9
+ *
+ * variable data; for the MS System Health vendor, these are 4-byte
+ * integers which are a really, really dumb format:
+ *
+ * 28 bits ignore
+ * 1 bit - 1==product snoozed
+ * 1 bit - 1==microsoft product
+ * 1 bit - 1==product up-to-date
+ * 1 bit - 1==product enabled
+ */
+ RDEBUG2("SoH Health-Class-Status - current shid=%08x component=%i", curr_shid, curr_shid_c);
+
+ if (curr_shid == 0x137 && curr_shid_c == 128) {
+ char const *s, *t;
+ uint32_t hcstatus = soh_pull_be_32(data);
+
+ RDEBUG2("SoH Health-Class-Status microsoft DWORD=%08x", hcstatus);
+
+ vp = pair_make_request("SoH-MS-Windows-Health-Status", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ switch (curr_hc) {
+ case 4:
+ /* security updates */
+ s = "security-updates";
+ switch (hcstatus) {
+ case 0xff0005:
+ fr_pair_value_sprintf(vp, "%s ok all-installed", s);
+ break;
+
+ case 0xff0006:
+ fr_pair_value_sprintf(vp, "%s warn some-missing", s);
+ break;
+
+ case 0xff0008:
+ fr_pair_value_sprintf(vp, "%s warn never-started", s);
+ break;
+
+ case 0xc0ff000c:
+ fr_pair_value_sprintf(vp, "%s error no-wsus-srv", s);
+ break;
+
+ case 0xc0ff000d:
+ fr_pair_value_sprintf(vp, "%s error no-wsus-clid", s);
+ break;
+
+ case 0xc0ff000e:
+ fr_pair_value_sprintf(vp, "%s warn wsus-disabled", s);
+ break;
+
+ case 0xc0ff000f:
+ fr_pair_value_sprintf(vp, "%s error comm-failure", s);
+ break;
+
+ case 0xc0ff0010:
+ fr_pair_value_sprintf(vp, "%s warn needs-reboot", s);
+ break;
+
+ default:
+ fr_pair_value_sprintf(vp, "%s error %08x", s, hcstatus);
+ break;
+ }
+ break;
+
+ case 3:
+ /* auto updates */
+ s = "auto-updates";
+ switch (hcstatus) {
+ case 1:
+ fr_pair_value_sprintf(vp, "%s warn disabled", s);
+ break;
+
+ case 2:
+ fr_pair_value_sprintf(vp, "%s ok action=check-only", s);
+ break;
+
+ case 3:
+ fr_pair_value_sprintf(vp, "%s ok action=download", s);
+ break;
+
+ case 4:
+ fr_pair_value_sprintf(vp, "%s ok action=install", s);
+ break;
+
+ case 5:
+ fr_pair_value_sprintf(vp, "%s warn unconfigured", s);
+ break;
+
+ case 0xc0ff0003:
+ fr_pair_value_sprintf(vp, "%s warn service-down", s);
+ break;
+
+ case 0xc0ff0018:
+ fr_pair_value_sprintf(vp, "%s warn never-started", s);
+ break;
+
+ default:
+ fr_pair_value_sprintf(vp, "%s error %08x", s, hcstatus);
+ break;
+ }
+ break;
+
+ default:
+ /* other - firewall, antivirus, antispyware */
+ s = healthclass2str(curr_hc);
+ if (s) {
+ /* bah. this is vile. stupid microsoft
+ */
+ if (hcstatus & 0xff000000) {
+ /* top octet non-zero means an error
+ * FIXME: is this always correct? MS-WSH 2.2.8 is unclear
+ */
+ t = clientstatus2str(hcstatus);
+ if (t) {
+ fr_pair_value_sprintf(vp, "%s error %s", s, t);
+ } else {
+ fr_pair_value_sprintf(vp, "%s error %08x", s, hcstatus);
+ }
+ } else {
+ fr_pair_value_sprintf(vp,
+ "%s ok snoozed=%i microsoft=%i up2date=%i enabled=%i",
+ s,
+ hcstatus & 0x8 ? 1 : 0,
+ hcstatus & 0x4 ? 1 : 0,
+ hcstatus & 0x2 ? 1 : 0,
+ hcstatus & 0x1 ? 1 : 0
+ );
+ }
+ } else {
+ fr_pair_value_sprintf(vp, "%i unknown %08x", curr_hc, hcstatus);
+ }
+ break;
+ }
+ } else {
+ vp = pair_make_request("SoH-MS-Health-Other", NULL, T_OP_EQ);
+ if (!vp) return 0;
+
+ /* FIXME: what to do with the payload? */
+ fr_pair_value_sprintf(vp, "%08x/%i ?", curr_shid, curr_shid_c);
+ }
+ break;
+
+ default:
+ RDEBUG("SoH Unknown TLV %i len=%i", tlv.tlv_type, tlv.tlv_len);
+ break;
+ }
+
+ data += tlv.tlv_len;
+ data_len -= tlv.tlv_len;
+ }
+
+ return 0;
+}
diff --git a/src/main/state.c b/src/main/state.c
new file mode 100644
index 0000000..3700062
--- /dev/null
+++ b/src/main/state.c
@@ -0,0 +1,713 @@
+/*
+ * 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 Multi-packet state handling
+ * @file main/state.c
+ *
+ * @ingroup AVP
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/state.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/process.h>
+
+typedef struct state_entry_t {
+ uint8_t state[AUTH_VECTOR_LEN];
+
+ time_t cleanup;
+ struct state_entry_t *prev;
+ struct state_entry_t *next;
+
+ int tries;
+
+ TALLOC_CTX *ctx;
+ VALUE_PAIR *vps;
+
+ char *server;
+ unsigned int request_number;
+ RADCLIENT *request_client;
+ main_config_t *request_root;
+
+ void *opaque;
+ void (*free_opaque)(void *opaque);
+} state_entry_t;
+
+struct fr_state_t {
+ rbtree_t *tree;
+
+ state_entry_t *head, *tail;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex;
+#endif
+};
+
+static fr_state_t global_state;
+
+#define STATE_FREE(_x) if (_x != &global_state) talloc_free(_x)
+
+#ifdef HAVE_PTHREAD_H
+
+#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+
+#else
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+
+#endif
+
+/*
+ * rbtree callback.
+ */
+static int state_entry_cmp(void const *one, void const *two)
+{
+ state_entry_t const *a = one;
+ state_entry_t const *b = two;
+
+ return memcmp(a->state, b->state, sizeof(a->state));
+}
+
+static bool state_entry_link(fr_state_t *state, state_entry_t *entry)
+{
+ if (!rbtree_insert(state->tree, entry)) {
+ return false;
+ }
+
+ /*
+ * Link it to the end of the list, which is implicitely
+ * ordered by cleanup time.
+ */
+ if (!state->head) {
+ entry->prev = entry->next = NULL;
+ state->head = state->tail = entry;
+ } else {
+ rad_assert(state->tail != NULL);
+
+ entry->prev = state->tail;
+ state->tail->next = entry;
+
+ entry->next = NULL;
+ state->tail = entry;
+ }
+
+ return true;
+}
+
+static void state_entry_unlink(fr_state_t *state, state_entry_t *entry)
+{
+ state_entry_t *prev, *next;
+
+ prev = entry->prev;
+ next = entry->next;
+
+ if (prev) {
+ rad_assert(state->head != entry);
+ prev->next = next;
+ } else if (state->head) {
+ rad_assert(state->head == entry);
+ state->head = next;
+ }
+
+ if (next) {
+ rad_assert(state->tail != entry);
+ next->prev = prev;
+ } else if (state->tail) {
+ rad_assert(state->tail == entry);
+ state->tail = prev;
+ }
+
+ rbtree_deletebydata(state->tree, entry);
+}
+
+/*
+ * When an entry is free'd, it's removed from the linked list of
+ * cleanup timers.
+ */
+static void state_entry_free(fr_state_t *state, state_entry_t *entry)
+{
+ /*
+ * If we're deleting the whole tree, don't bother doing
+ * all of the fixups.
+ */
+ if (!state || !state->tree) return;
+
+ state_entry_unlink(state, entry);
+
+ if (entry->opaque) {
+ entry->free_opaque(entry->opaque);
+ }
+
+#ifdef WITH_VERIFY_PTR
+ (void) talloc_get_type_abort(entry, state_entry_t);
+#endif
+ if (entry->ctx) talloc_free(entry->ctx);
+
+ talloc_free(entry);
+}
+
+fr_state_t *fr_state_init(TALLOC_CTX *ctx)
+{
+ fr_state_t *state;
+
+ if (!ctx) {
+ state = &global_state;
+ if (state->tree) return state;
+ } else {
+ state = talloc_zero(ctx, fr_state_t);
+ if (!state) return 0;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&state->mutex, NULL) != 0) {
+ STATE_FREE(state);
+ return NULL;
+ }
+#endif
+
+ state->tree = rbtree_create(NULL, state_entry_cmp, NULL, 0);
+ if (!state->tree) {
+ STATE_FREE(state);
+ return NULL;
+ }
+
+ return state;
+}
+
+void fr_state_delete(fr_state_t *state)
+{
+ rbtree_t *my_tree;
+
+ if (!state) return;
+
+ PTHREAD_MUTEX_LOCK(&state->mutex);
+
+ /*
+ * Tell the talloc callback to NOT delete the entry from
+ * the tree. We're deleting the entire tree.
+ */
+ my_tree = state->tree;
+ state->tree = NULL;
+
+ rbtree_free(my_tree);
+ PTHREAD_MUTEX_UNLOCK(&state->mutex);
+
+ STATE_FREE(state);
+}
+
+/*
+ * Create a fake request, based on what we know about the
+ * session that has expired, and inject it into the server to
+ * allow final logging or cleaning up.
+ */
+static REQUEST *fr_state_cleanup_request(state_entry_t *entry)
+{
+ REQUEST *request;
+ RADIUS_PACKET *packet = NULL;
+ RADIUS_PACKET *reply_packet = NULL;
+ VALUE_PAIR *vp;
+
+ /*
+ * Allocate a new fake request with enough to keep
+ * the rest of the server happy.
+ */
+ request = request_alloc(NULL);
+ if (unlikely(!request)) return NULL;
+
+ packet = rad_alloc(request, false);
+ if (unlikely(!packet)) {
+ error:
+ TALLOC_FREE(reply_packet);
+ TALLOC_FREE(packet);
+ TALLOC_FREE(request);
+ return NULL;
+ }
+
+ reply_packet = rad_alloc(request, false);
+ if (unlikely(!reply_packet)) goto error;
+
+ /*
+ * Move the server from the state entry over to the
+ * request. Clearing it in the state means this
+ * function will never be called again.
+ */
+ request->server = talloc_steal(request, entry->server);
+ entry->server = NULL;
+
+ /*
+ * Build the fake request with the limited
+ * information we have from the state.
+ */
+ request->packet = packet;
+ request->reply = reply_packet;
+ request->number = entry->request_number;
+ request->client = entry->request_client;
+ request->root = entry->request_root;
+ request->handle = rad_postauth;
+
+ /*
+ * Move session-state VPS over, after first freeing the
+ * separately-parented state_ctx that was allocated along with the
+ * fake request.
+ */
+ talloc_free(request->state_ctx);
+ request->state_ctx = entry->ctx;
+ request->state = entry->vps;
+
+ entry->ctx = NULL;
+ entry->vps = NULL;
+
+ /*
+ * Set correct Post-Auth-Type section
+ */
+ fr_pair_delete_by_num(&request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+ vp = pair_make_config("Post-Auth-Type", "Client-Lost", T_OP_SET);
+ if (unlikely(!vp)) goto error;
+
+ VERIFY_REQUEST(request);
+ return request;
+}
+
+/*
+ * Check state for old entries that need to be cleaned up. If
+ * they are old enough then move them from the global state
+ * list to a list of entries to clean up (outside the mutex).
+ * Called with the mutex held.
+ */
+static state_entry_t *fr_state_cleanup_find(fr_state_t *state)
+{
+ time_t now = time(NULL);
+ state_entry_t *entry, *next;
+ state_entry_t *head = NULL, **tail = &head;
+
+ for (entry = state->head; entry != NULL; entry = next) {
+ next = entry->next;
+
+ /*
+ * Unused. We can delete it, even if now isn't
+ * the time to clean it up.
+ */
+ if (!entry->ctx && !entry->opaque) {
+ state_entry_free(state, entry);
+ continue;
+ }
+
+ /*
+ * Not yet time to clean it up.
+ */
+ if (entry->cleanup > now) {
+ continue;
+ }
+
+ /*
+ * We're not running the "client lost" section.
+ * Just nuke the entry now.
+ */
+ if (!main_config.postauth_client_lost) {
+ state_entry_free(state, entry);
+ continue;
+ }
+
+ /*
+ * Old enough that the request has been removed.
+ * We can add it to the cleanup list.
+ */
+ state_entry_unlink(state, entry);
+ entry->prev = entry->next = NULL;
+ (*tail) = entry;
+ tail = &entry->next;
+ }
+
+ return head;
+}
+
+/*
+ * Inject all requests in cleanup list for cleanup post-auth
+ */
+static void fr_state_cleanup(state_entry_t *head)
+{
+ state_entry_t *entry, *next;
+
+ if (!head) return;
+
+ for (entry = head; entry != NULL; entry = next) {
+ REQUEST *request;
+
+ next = entry->next;
+
+ request = fr_state_cleanup_request(entry);
+ if (request) {
+ RDEBUG2("No response from client, cleaning up expired state");
+ RDEBUG2("Restoring &session-state");
+
+ /*
+ * @todo - print out message
+ * saying where the handler was
+ * in the process? i.e. "sent
+ * server cert", etc. This will
+ * require updating the EAP code
+ * to put a new attribute into
+ * the session state list.
+ */
+
+ rdebug_pair_list(L_DBG_LVL_2, request, request->state, "&session-state:");
+
+ request_inject(request);
+ }
+
+ talloc_free(entry);
+ }
+}
+
+
+/*
+ * Create a new entry. Called with the mutex held.
+ */
+static state_entry_t *fr_state_entry_create(fr_state_t *state, REQUEST *request, RADIUS_PACKET *packet, state_entry_t *old)
+{
+ size_t i;
+ uint32_t x;
+ time_t now = time(NULL);
+ VALUE_PAIR *vp;
+ state_entry_t *entry;
+
+ /*
+ * Limit the size of the cache based on how many requests
+ * we can handle at the same time.
+ */
+ if (rbtree_num_elements(state->tree) >= main_config.max_requests * 2) {
+ return NULL;
+ }
+
+ /*
+ * Allocate a new one.
+ */
+ entry = talloc_zero(state->tree, state_entry_t);
+ if (!entry) return NULL;
+
+ /*
+ * Limit the lifetime of this entry based on how long the
+ * server takes to process a request. Doing it this way
+ * isn't perfect, but it's reasonable, and it's one less
+ * thing for an administrator to configure.
+ */
+ entry->cleanup = now + main_config.max_request_time * 2;
+
+ /*
+ * Hacks for EAP, until we convert EAP to using the state API.
+ *
+ * The EAP module creates it's own State attribute, so we
+ * want to use that one in preference to one we create.
+ */
+ vp = fr_pair_find_by_num(packet->vps, PW_STATE, 0, TAG_ANY);
+
+ /*
+ * If possible, base the new one off of the old one.
+ */
+ if (old) {
+ entry->tries = old->tries + 1;
+
+ /*
+ * Track State
+ */
+ if (!vp) {
+ memcpy(entry->state, old->state, sizeof(entry->state));
+
+ entry->state[1] = entry->state[0] ^ entry->tries;
+ entry->state[8] = entry->state[2] ^ ((((uint32_t) HEXIFY(RADIUSD_VERSION)) >> 16) & 0xff);
+ entry->state[10] = entry->state[2] ^ ((((uint32_t) HEXIFY(RADIUSD_VERSION)) >> 8) & 0xff);
+ entry->state[12] = entry->state[2] ^ (((uint32_t) HEXIFY(RADIUSD_VERSION)) & 0xff);
+ }
+
+ /*
+ * The old one isn't used any more, so we can free it.
+ */
+ if (!old->opaque) state_entry_free(state, old);
+
+ } else if (!vp) {
+ /*
+ * 16 octets of randomness should be enough to
+ * have a globally unique state.
+ */
+ for (i = 0; i < sizeof(entry->state) / sizeof(x); i++) {
+ x = fr_rand();
+ memcpy(entry->state + (i * 4), &x, sizeof(x));
+ }
+ }
+
+ /*
+ * If EAP created a State, use that. Otherwise, use the
+ * one we created above.
+ */
+ if (vp) {
+ /*
+ * Assume our own State first.
+ */
+ if (vp->vp_length == sizeof(entry->state)) {
+ memcpy(entry->state, vp->vp_octets, sizeof(entry->state));
+
+ /*
+ * Too big? Get the MD5 hash, in order
+ * to depend on the entire contents of State.
+ */
+ } else if (vp->vp_length > sizeof(entry->state)) {
+ fr_md5_calc(entry->state, vp->vp_octets, vp->vp_length);
+
+ /*
+ * Too small? Use the whole thing, and
+ * set the rest of entry->state to zero.
+ */
+ } else {
+ memcpy(entry->state, vp->vp_octets, vp->vp_length);
+ memset(&entry->state[vp->vp_length], 0, sizeof(entry->state) - vp->vp_length);
+ }
+ } else {
+ vp = fr_pair_afrom_num(packet, PW_STATE, 0);
+ fr_pair_value_memcpy(vp, entry->state, sizeof(entry->state));
+ fr_pair_add(&packet->vps, vp);
+ }
+
+ /* Make unique for different virtual servers handling same request
+ */
+ if (request->server) {
+ /*
+ * Make unique for different virtual servers handling same request
+ */
+ *((uint32_t *)(&entry->state[4])) ^= fr_hash_string(request->server);
+
+ /*
+ * Copy server to state in case it's needed for cleanup
+ */
+ entry->server = talloc_strdup(entry, request->server);
+ entry->request_number = request->number;
+ entry->request_client = request->client;
+ entry->request_root = request->root;
+ }
+
+ if (!state_entry_link(state, entry)) {
+ talloc_free(entry);
+ return NULL;
+ }
+
+ return entry;
+}
+
+
+/*
+ * Find the entry, based on the State attribute.
+ */
+static state_entry_t *fr_state_find(fr_state_t *state, const char *server, RADIUS_PACKET *packet)
+{
+ VALUE_PAIR *vp;
+ state_entry_t *entry, my_entry;
+
+ vp = fr_pair_find_by_num(packet->vps, PW_STATE, 0, TAG_ANY);
+ if (!vp) return NULL;
+
+ /*
+ * Assume our own State first.
+ */
+ if (vp->vp_length == sizeof(my_entry.state)) {
+ memcpy(my_entry.state, vp->vp_octets, sizeof(my_entry.state));
+
+ /*
+ * Too big? Get the MD5 hash, in order
+ * to depend on the entire contents of State.
+ */
+ } else if (vp->vp_length > sizeof(my_entry.state)) {
+ fr_md5_calc(my_entry.state, vp->vp_octets, vp->vp_length);
+
+ /*
+ * Too small? Use the whole thing, and
+ * set the rest of my_entry.state to zero.
+ */
+ } else {
+ memcpy(my_entry.state, vp->vp_octets, vp->vp_length);
+ memset(&my_entry.state[vp->vp_length], 0, sizeof(my_entry.state) - vp->vp_length);
+ }
+
+ /* Make unique for different virtual servers handling same request
+ */
+ if (server) *((uint32_t *)(&my_entry.state[4])) ^= fr_hash_string(server);
+
+ entry = rbtree_finddata(state->tree, &my_entry);
+
+#ifdef WITH_VERIFY_PTR
+ if (entry) (void) talloc_get_type_abort(entry, state_entry_t);
+#endif
+
+ return entry;
+}
+
+/*
+ * Called when sending Access-Accept or Access-Reject, so
+ * that all State is discarded.
+ */
+void fr_state_discard(REQUEST *request, RADIUS_PACKET *original)
+{
+ state_entry_t *entry;
+ fr_state_t *state = &global_state;
+
+ fr_pair_list_free(&request->state);
+ request->state = NULL;
+
+ PTHREAD_MUTEX_LOCK(&state->mutex);
+ entry = fr_state_find(state, request->server, original);
+ if (entry) state_entry_free(state, entry);
+ PTHREAD_MUTEX_UNLOCK(&state->mutex);
+}
+
+/*
+ * Get the VPS from the state.
+ */
+void fr_state_get_vps(REQUEST *request, RADIUS_PACKET *packet)
+{
+ state_entry_t *entry;
+ fr_state_t *state = &global_state;
+ TALLOC_CTX *old_ctx = NULL;
+
+ /*
+ * No State, don't do anything.
+ */
+ if (!fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY)) {
+ RDEBUG3("session-state: No State attribute");
+ return;
+ }
+
+ rad_assert(request->state == NULL);
+
+ PTHREAD_MUTEX_LOCK(&state->mutex);
+ entry = fr_state_find(state, request->server, packet);
+
+ /*
+ * This has to be done in a mutex lock, because talloc
+ * isn't thread-safe.
+ */
+ if (entry) {
+ RDEBUG2("Restoring &session-state");
+
+ if (request->state_ctx) old_ctx = request->state_ctx;
+
+ request->state_ctx = entry->ctx;
+ request->state = entry->vps;
+
+ entry->ctx = NULL;
+ entry->vps = NULL;
+
+ rdebug_pair_list(L_DBG_LVL_2, request, request->state, "&session-state:");
+
+ } else {
+ RDEBUG2("session-state: No cached attributes");
+ }
+
+ PTHREAD_MUTEX_UNLOCK(&state->mutex);
+
+ /*
+ * Free this outside of the mutex for less contention.
+ */
+ if (old_ctx) talloc_free(old_ctx);
+
+ VERIFY_REQUEST(request);
+ return;
+}
+
+
+/*
+ * Put request->state into the State attribute. Put the State
+ * attribute into the vps list. Delete the original entry, if it
+ * exists.
+ */
+bool fr_state_put_vps(REQUEST *request, RADIUS_PACKET *original, RADIUS_PACKET *packet)
+{
+ state_entry_t *entry, *old;
+ fr_state_t *state = &global_state;
+ state_entry_t *cleanup_list;
+
+ if (!request->state) {
+ size_t i;
+ uint32_t x;
+ VALUE_PAIR *vp;
+ uint8_t buffer[16];
+
+ RDEBUG3("session-state: Nothing to cache");
+
+ if (packet->code != PW_CODE_ACCESS_CHALLENGE) return true;
+
+ vp = fr_pair_find_by_num(packet->vps, PW_STATE, 0, TAG_ANY);
+ if (vp) return true;
+
+ /*
+ *
+ */
+ for (i = 0; i < sizeof(buffer) / sizeof(x); i++) {
+ x = fr_rand();
+ memcpy(buffer + (i * 4), &x, sizeof(x));
+ }
+
+ vp = fr_pair_afrom_num(packet, PW_STATE, 0);
+ fr_pair_value_memcpy(vp, buffer, sizeof(buffer));
+ fr_pair_add(&packet->vps, vp);
+
+ return true;
+ }
+
+ RDEBUG2("session-state: Saving cached attributes");
+ rdebug_pair_list(L_DBG_LVL_1, request, request->state, NULL);
+
+ PTHREAD_MUTEX_LOCK(&state->mutex);
+
+ cleanup_list = fr_state_cleanup_find(state);
+
+ if (original) {
+ old = fr_state_find(state, request->server, original);
+ } else {
+ old = NULL;
+ }
+
+ /*
+ * Create a new entry and add it to the list.
+ */
+ entry = fr_state_entry_create(state, request, packet, old);
+ if (!entry) {
+ PTHREAD_MUTEX_UNLOCK(&state->mutex);
+ fr_state_cleanup(cleanup_list);
+ return false;
+ }
+
+ rad_assert(entry->ctx == NULL);
+ entry->ctx = request->state_ctx;
+ entry->vps = request->state;
+
+ request->state_ctx = NULL;
+ request->state = NULL;
+
+ PTHREAD_MUTEX_UNLOCK(&state->mutex);
+ fr_state_cleanup(cleanup_list);
+
+ VERIFY_REQUEST(request);
+ return true;
+}
diff --git a/src/main/stats.c b/src/main/stats.c
new file mode 100644
index 0000000..a5c672e
--- /dev/null
+++ b/src/main/stats.c
@@ -0,0 +1,1028 @@
+/*
+ * stats.c Internal statistics handling.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef WITH_STATS
+
+#define USEC (1000000)
+#define EMA_SCALE (100)
+#define F_EMA_SCALE (1000000)
+
+static struct timeval start_time;
+static struct timeval hup_time;
+
+#define FR_STATS_INIT { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ { 0, 0, 0, 0, 0, 0, 0, 0 }}
+
+fr_stats_t radius_auth_stats = FR_STATS_INIT;
+#ifdef WITH_ACCOUNTING
+fr_stats_t radius_acct_stats = FR_STATS_INIT;
+#endif
+#ifdef WITH_COA
+fr_stats_t radius_coa_stats = FR_STATS_INIT;
+fr_stats_t radius_dsc_stats = FR_STATS_INIT;
+#endif
+
+#ifdef WITH_PROXY
+fr_stats_t proxy_auth_stats = FR_STATS_INIT;
+#ifdef WITH_ACCOUNTING
+fr_stats_t proxy_acct_stats = FR_STATS_INIT;
+#endif
+#ifdef WITH_COA
+fr_stats_t proxy_coa_stats = FR_STATS_INIT;
+fr_stats_t proxy_dsc_stats = FR_STATS_INIT;
+#endif
+#endif
+
+static void stats_time(fr_stats_t *stats, struct timeval *start,
+ struct timeval *end)
+{
+ struct timeval diff;
+ uint32_t delay;
+
+ if ((start->tv_sec == 0) || (end->tv_sec == 0) ||
+ (end->tv_sec < start->tv_sec)) return;
+
+ rad_tv_sub(end, start, &diff);
+
+ if (diff.tv_sec >= 10) {
+ stats->elapsed[7]++;
+ } else {
+ int i;
+ uint32_t cmp;
+
+ delay = (diff.tv_sec * USEC) + diff.tv_usec;
+
+ cmp = 10;
+ for (i = 0; i < 7; i++) {
+ if (delay < cmp) {
+ stats->elapsed[i]++;
+ break;
+ }
+ cmp *= 10;
+ }
+ }
+}
+
+void request_stats_final(REQUEST *request)
+{
+ rad_listen_t *listener;
+
+ if (request->master_state == REQUEST_COUNTED) return;
+
+ if (!request->listener) return;
+ if (!request->client) return;
+
+ if ((request->listener->type != RAD_LISTEN_NONE) &&
+#ifdef WITH_ACCOUNTING
+ (request->listener->type != RAD_LISTEN_ACCT) &&
+#endif
+#ifdef WITH_COA
+ (request->listener->type != RAD_LISTEN_COA) &&
+#endif
+ (request->listener->type != RAD_LISTEN_AUTH)) return;
+
+ /* don't count statistic requests */
+ if (request->packet->code == PW_CODE_STATUS_SERVER)
+ return;
+
+ /*
+ * Deal with TCP / TLS issues. The statistics are kept in the parent socket.
+ */
+ listener = request->listener;
+ if (listener->parent) listener = listener->parent;
+
+#undef INC_AUTH
+#define INC_AUTH(_x) radius_auth_stats._x++;listener->stats._x++;request->client->auth._x++;
+
+#undef INC_ACCT
+#ifdef WITH_ACCOUNTING
+#define INC_ACCT(_x) radius_acct_stats._x++;listener->stats._x++;request->client->acct._x++
+#else
+#define INC_ACCT(_x)
+#endif
+
+#undef INC_COA
+#ifdef WITH_COA
+#define INC_COA(_x) radius_coa_stats._x++;listener->stats._x++;request->client->coa._x++
+#else
+#define INC_COA(_x)
+#endif
+
+#undef INC_DSC
+#ifdef WITH_DSC
+#define INC_DSC(_x) radius_dsc_stats._x++;listener->stats._x++;request->client->dsc._x++
+#else
+#define INC_DSC(_x)
+#endif
+
+ /*
+ * Update the statistics.
+ *
+ * Note that we do NOT do this in a child thread.
+ * Instead, we update the stats when a request is
+ * deleted, because only the main server thread calls
+ * this function, which makes it thread-safe.
+ */
+ if (request->reply && (request->packet->code != PW_CODE_STATUS_SERVER)) switch (request->reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ INC_AUTH(total_access_accepts);
+
+ auth_stats:
+ INC_AUTH(total_responses);
+
+ /*
+ * FIXME: Do the time calculations once...
+ */
+ stats_time(&radius_auth_stats,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ stats_time(&request->client->auth,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ stats_time(&listener->stats,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ break;
+
+ case PW_CODE_ACCESS_REJECT:
+ INC_AUTH(total_access_rejects);
+ goto auth_stats;
+
+ case PW_CODE_ACCESS_CHALLENGE:
+ INC_AUTH(total_access_challenges);
+ goto auth_stats;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ INC_ACCT(total_responses);
+ stats_time(&radius_acct_stats,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ stats_time(&request->client->acct,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_ACK:
+ INC_COA(total_access_accepts);
+ coa_stats:
+ INC_COA(total_responses);
+ stats_time(&request->client->coa,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ break;
+
+ case PW_CODE_COA_NAK:
+ INC_COA(total_access_rejects);
+ goto coa_stats;
+
+ case PW_CODE_DISCONNECT_ACK:
+ INC_DSC(total_access_accepts);
+ dsc_stats:
+ INC_DSC(total_responses);
+ stats_time(&request->client->dsc,
+ &request->packet->timestamp,
+ &request->reply->timestamp);
+ break;
+
+ case PW_CODE_DISCONNECT_NAK:
+ INC_DSC(total_access_rejects);
+ goto dsc_stats;
+#endif
+
+ /*
+ * No response, it must have been a bad
+ * authenticator.
+ */
+ case 0:
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ if (request->reply->offset == -2) {
+ INC_AUTH(total_bad_authenticators);
+ } else {
+ INC_AUTH(total_packets_dropped);
+ }
+ } else if (request->packet->code == PW_CODE_ACCOUNTING_REQUEST) {
+ if (request->reply->offset == -2) {
+ INC_ACCT(total_bad_authenticators);
+ } else {
+ INC_ACCT(total_packets_dropped);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+#ifdef WITH_PROXY
+ if (!request->proxy || !request->home_server) goto done; /* simplifies formatting */
+
+ switch (request->proxy->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ proxy_auth_stats.total_requests += request->num_proxied_requests;
+ request->home_server->stats.total_requests += request->num_proxied_requests;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ proxy_acct_stats.total_requests += request->num_proxied_requests;
+ request->home_server->stats.total_requests += request->num_proxied_requests;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ proxy_coa_stats.total_requests += request->num_proxied_requests;
+ request->home_server->stats.total_requests += request->num_proxied_requests;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ proxy_dsc_stats.total_requests += request->num_proxied_requests;
+ request->home_server->stats.total_requests += request->num_proxied_requests;
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ if (!request->proxy_reply) goto done; /* simplifies formatting */
+
+#undef INC
+#define INC(_x) proxy_auth_stats._x += request->num_proxied_responses; request->home_server->stats._x += request->num_proxied_responses;
+
+ switch (request->proxy_reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ INC(total_access_accepts);
+ proxy_stats:
+ INC(total_responses);
+ stats_time(&proxy_auth_stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ stats_time(&request->home_server->stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ break;
+
+ case PW_CODE_ACCESS_REJECT:
+ INC(total_access_rejects);
+ goto proxy_stats;
+
+ case PW_CODE_ACCESS_CHALLENGE:
+ INC(total_access_challenges);
+ goto proxy_stats;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ proxy_acct_stats.total_responses++;
+ request->home_server->stats.total_responses++;
+ stats_time(&proxy_acct_stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ stats_time(&request->home_server->stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ proxy_coa_stats.total_responses++;
+ request->home_server->stats.total_responses++;
+ stats_time(&proxy_coa_stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ stats_time(&request->home_server->stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ break;
+
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ proxy_dsc_stats.total_responses++;
+ request->home_server->stats.total_responses++;
+ stats_time(&proxy_dsc_stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ stats_time(&request->home_server->stats,
+ &request->proxy->timestamp,
+ &request->proxy_reply->timestamp);
+ break;
+#endif
+
+ default:
+ proxy_auth_stats.total_unknown_types++;
+ request->home_server->stats.total_unknown_types++;
+ break;
+ }
+
+ done:
+#endif /* WITH_PROXY */
+
+
+ if (request->max_time) {
+ RADCLIENT *client = request->client;
+
+ switch (request->packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ FR_STATS_INC(auth, unresponsive_child);
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ FR_STATS_INC(acct, unresponsive_child);
+ break;
+#endif
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ FR_STATS_INC(coa, unresponsive_child);
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ FR_STATS_INC(dsc, unresponsive_child);
+ break;
+#endif
+
+ default:
+ break;
+ }
+ }
+
+ request->master_state = REQUEST_COUNTED;
+}
+
+typedef struct fr_stats2vp {
+ int attribute;
+ size_t offset;
+} fr_stats2vp;
+
+/*
+ * Authentication
+ */
+static fr_stats2vp authvp[] = {
+ { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+ { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+ { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+ { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { PW_FREERADIUS_TOTAL_AUTH_CONFLICTS, offsetof(fr_stats_t, total_conflicts) },
+ { 0, 0 }
+};
+
+
+#ifdef WITH_PROXY
+/*
+ * Proxied authentication requests.
+ */
+static fr_stats2vp proxy_authvp[] = {
+ { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_PROXY_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { 0, 0 }
+};
+#endif
+
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Accounting
+ */
+static fr_stats2vp acctvp[] = {
+ { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { PW_FREERADIUS_TOTAL_ACCT_CONFLICTS, offsetof(fr_stats_t, total_conflicts) },
+ { 0, 0 }
+};
+
+#ifdef WITH_PROXY
+static fr_stats2vp proxy_acctvp[] = {
+ { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_PROXY_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { 0, 0 }
+};
+#endif
+#endif
+
+static fr_stats2vp client_authvp[] = {
+ { PW_FREERADIUS_TOTAL_ACCESS_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_ACCESS_ACCEPTS, offsetof(fr_stats_t, total_access_accepts) },
+ { PW_FREERADIUS_TOTAL_ACCESS_REJECTS, offsetof(fr_stats_t, total_access_rejects) },
+ { PW_FREERADIUS_TOTAL_ACCESS_CHALLENGES, offsetof(fr_stats_t, total_access_challenges) },
+ { PW_FREERADIUS_TOTAL_AUTH_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_AUTH_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_AUTH_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_AUTH_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_AUTH_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_AUTH_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { 0, 0 }
+};
+
+#ifdef WITH_ACCOUNTING
+static fr_stats2vp client_acctvp[] = {
+ { PW_FREERADIUS_TOTAL_ACCOUNTING_REQUESTS, offsetof(fr_stats_t, total_requests) },
+ { PW_FREERADIUS_TOTAL_ACCOUNTING_RESPONSES, offsetof(fr_stats_t, total_responses) },
+ { PW_FREERADIUS_TOTAL_ACCT_DUPLICATE_REQUESTS, offsetof(fr_stats_t, total_dup_requests) },
+ { PW_FREERADIUS_TOTAL_ACCT_MALFORMED_REQUESTS, offsetof(fr_stats_t, total_malformed_requests) },
+ { PW_FREERADIUS_TOTAL_ACCT_INVALID_REQUESTS, offsetof(fr_stats_t, total_bad_authenticators) },
+ { PW_FREERADIUS_TOTAL_ACCT_DROPPED_REQUESTS, offsetof(fr_stats_t, total_packets_dropped) },
+ { PW_FREERADIUS_TOTAL_ACCT_UNKNOWN_TYPES, offsetof(fr_stats_t, total_unknown_types) },
+ { 0, 0 }
+};
+#endif
+
+static void request_stats_addvp(REQUEST *request,
+ fr_stats2vp *table, fr_stats_t *stats)
+{
+ int i;
+ uint64_t counter;
+ VALUE_PAIR *vp;
+
+ for (i = 0; table[i].attribute != 0; i++) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ table[i].attribute, VENDORPEC_FREERADIUS);
+ if (!vp) continue;
+
+ counter = *(uint64_t *) (((uint8_t *) stats) + table[i].offset);
+ vp->vp_integer = counter;
+ }
+}
+
+static void stats_error(REQUEST *request, char const *msg)
+{
+ VALUE_PAIR *vp;
+
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_ERROR, VENDORPEC_FREERADIUS);
+ if (!vp) return;
+
+ fr_pair_value_strcpy(vp, msg);
+}
+
+
+void request_stats_reply(REQUEST *request)
+{
+ VALUE_PAIR *flag, *vp;
+
+ /*
+ * Statistics are available ONLY on a "status" port.
+ */
+ rad_assert(request->packet->code == PW_CODE_STATUS_SERVER);
+ rad_assert(request->listener->type == RAD_LISTEN_NONE);
+
+ flag = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATISTICS_TYPE, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (!flag || (flag->vp_integer == 0)) return;
+
+ /*
+ * Authentication.
+ */
+ if (((flag->vp_integer & 0x01) != 0) &&
+ ((flag->vp_integer & 0xc0) == 0)) {
+ request_stats_addvp(request, authvp, &radius_auth_stats);
+ }
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Accounting
+ */
+ if (((flag->vp_integer & 0x02) != 0) &&
+ ((flag->vp_integer & 0xc0) == 0)) {
+ request_stats_addvp(request, acctvp, &radius_acct_stats);
+ }
+#endif
+
+#ifdef WITH_PROXY
+ /*
+ * Proxied authentication requests.
+ */
+ if (((flag->vp_integer & 0x04) != 0) &&
+ ((flag->vp_integer & 0x20) == 0)) {
+ request_stats_addvp(request, proxy_authvp, &proxy_auth_stats);
+ }
+
+#ifdef WITH_ACCOUNTING
+ /*
+ * Proxied accounting requests.
+ */
+ if (((flag->vp_integer & 0x08) != 0) &&
+ ((flag->vp_integer & 0x20) == 0)) {
+ request_stats_addvp(request, proxy_acctvp, &proxy_acct_stats);
+ }
+#endif
+#endif
+
+ /*
+ * Internal server statistics
+ */
+ if ((flag->vp_integer & 0x10) != 0) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_START_TIME, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = start_time.tv_sec;
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_HUP_TIME, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = hup_time.tv_sec;
+
+#ifdef HAVE_PTHREAD_H
+ int i, array[RAD_LISTEN_MAX], stats[3];
+
+ thread_pool_queue_stats(array, stats);
+
+ for (i = 0; i <= 4; i++) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_QUEUE_LEN_INTERNAL + i, VENDORPEC_FREERADIUS);
+
+ if (!vp) continue;
+ vp->vp_integer = array[i];
+ }
+
+ for (i = 0; i < 2; i++) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_QUEUE_PPS_IN + i, VENDORPEC_FREERADIUS);
+
+ if (!vp) continue;
+ vp->vp_integer = stats[i];
+ }
+
+ thread_pool_thread_stats(stats);
+
+ for (i = 0; i < 3; i++) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_THREADS_ACTIVE + i, VENDORPEC_FREERADIUS);
+
+ if (!vp) continue;
+ vp->vp_integer = stats[i];
+ }
+#endif
+ }
+
+ /*
+ * For a particular client.
+ */
+ if ((flag->vp_integer & 0x20) != 0) {
+ fr_ipaddr_t ipaddr;
+ VALUE_PAIR *server_ip, *server_port = NULL;
+ RADCLIENT *client = NULL;
+ RADCLIENT_LIST *cl = NULL;
+
+ /*
+ * See if we need to look up the client by server
+ * socket.
+ */
+ server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (server_ip) {
+ server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
+
+ if (server_port) {
+ ipaddr.af = AF_INET;
+ ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
+ cl = listener_find_client_list(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
+
+ /*
+ * Not found: don't do anything
+ */
+ if (!cl) return;
+ }
+#ifdef AF_INET6
+ } else {
+ server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IPV6_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (server_ip) {
+ server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (server_port) {
+ ipaddr.af = AF_INET6;
+ ipaddr.ipaddr.ip6addr = server_ip->vp_ipv6addr;
+ cl = listener_find_client_list(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
+
+ /*
+ * Not found: don't do anything
+ */
+ if (!cl) return;
+ }
+ }
+#endif /* AF_INET6 */
+ }
+
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (vp) {
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ ipaddr.af = AF_INET;
+ ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ client = client_find(cl, &ipaddr, IPPROTO_UDP);
+#ifdef WITH_TCP
+ if (!client) {
+ client = client_find(cl, &ipaddr, IPPROTO_TCP);
+ }
+#endif
+
+#ifdef AF_INET6
+ } else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_IPV6_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
+ memset(&ipaddr, 0, sizeof(ipaddr));
+ ipaddr.af = AF_INET6;
+ ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ client = client_find(cl, &ipaddr, IPPROTO_UDP);
+#ifdef WITH_TCP
+ if (!client) {
+ client = client_find(cl, &ipaddr, IPPROTO_TCP);
+ }
+#endif
+#endif /* AF_INET6 */
+
+ /*
+ * Else look it up by number.
+ */
+ } else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_CLIENT_NUMBER, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
+ client = client_findbynumber(cl, vp->vp_integer);
+ }
+
+ if (client) {
+ /*
+ * If found, echo it back, along with
+ * the requested statistics.
+ */
+ fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
+
+ /*
+ * When retrieving client by number, also
+ * echo back it's IP address.
+ */
+ if (vp->da->type == PW_TYPE_INTEGER) {
+ if (client->ipaddr.af == AF_INET) {
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_STATS_CLIENT_IP_ADDRESS, VENDORPEC_FREERADIUS);
+ if (vp) {
+ vp->vp_ipaddr = client->ipaddr.ipaddr.ip4addr.s_addr;
+ }
+
+ if (client->ipaddr.prefix != 32) {
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_STATS_CLIENT_NETMASK, VENDORPEC_FREERADIUS);
+ if (vp) {
+ vp->vp_integer = client->ipaddr.prefix;
+ }
+ }
+ }
+
+#ifdef AF_INET6
+ if (client->ipaddr.af == AF_INET6) {
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_STATS_CLIENT_IPV6_ADDRESS, VENDORPEC_FREERADIUS);
+ if (vp) {
+ vp->vp_ipv6addr = client->ipaddr.ipaddr.ip6addr;
+ }
+
+ if (client->ipaddr.prefix != 128) {
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_STATS_CLIENT_NETMASK, VENDORPEC_FREERADIUS);
+ if (vp) {
+ vp->vp_integer = client->ipaddr.prefix;
+ }
+ }
+ }
+#endif /* AF_INET6 */
+ }
+
+ if (server_ip) {
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_ip));
+ }
+ if (server_port) {
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_port));
+ }
+
+ if ((flag->vp_integer & 0x01) != 0) {
+ request_stats_addvp(request, client_authvp,
+ &client->auth);
+ }
+#ifdef WITH_ACCOUNTING
+ if ((flag->vp_integer & 0x02) != 0) {
+ request_stats_addvp(request, client_acctvp,
+ &client->acct);
+ }
+#endif
+ } else {
+ /*
+ * No such client.
+ */
+ stats_error(request, "No such client");
+ }
+ }
+
+ /*
+ * For a particular "listen" socket.
+ */
+ if (((flag->vp_integer & 0x40) != 0) &&
+ ((flag->vp_integer & 0x03) != 0)) {
+ rad_listen_t *this;
+ VALUE_PAIR *server_ip, *server_port;
+ fr_ipaddr_t ipaddr;
+
+ /*
+ * See if we need to look up the server by socket
+ * socket.
+ */
+ server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (!server_port) return;
+
+ server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (server_ip) {
+ ipaddr.af = AF_INET;
+ ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
+#ifdef AF_INET6
+ } else if ((server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IPV6_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
+ ipaddr.af = AF_INET6;
+ ipaddr.ipaddr.ip6addr = server_ip->vp_ipv6addr;
+#endif /* AF_INET6 */
+ } else {
+ stats_error(request, "No listener IP address supplied");
+ }
+
+ /*
+ * Not found: don't do anything
+ */
+ this = listener_find_byipaddr(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
+#ifdef WITH_TCP
+ if (!this) this = listener_find_byipaddr(&ipaddr, server_port->vp_integer, IPPROTO_TCP);
+#endif
+ if (!this) {
+ stats_error(request, "No such listener");
+ return;
+ }
+
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_ip));
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_port));
+
+ if ((flag->vp_integer & 0x01) != 0) {
+ if ((request->listener->type == RAD_LISTEN_AUTH) ||
+ (request->listener->type == RAD_LISTEN_NONE)) {
+ request_stats_addvp(request, authvp, &this->stats);
+ } else {
+ stats_error(request, "Listener is not auth");
+ }
+ }
+
+#ifdef WITH_ACCOUNTING
+ if ((flag->vp_integer & 0x02) != 0) {
+ if ((request->listener->type == RAD_LISTEN_ACCT) ||
+ (request->listener->type == RAD_LISTEN_NONE)) {
+ request_stats_addvp(request, acctvp, &this->stats);
+ } else {
+ stats_error(request, "Listener is not acct");
+ }
+ }
+#endif
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * Home servers.
+ */
+ if (((flag->vp_integer & 0x80) != 0) &&
+ ((flag->vp_integer & 0x03) != 0)) {
+ home_server_t *home;
+ VALUE_PAIR *server_ip, *server_port;
+ fr_ipaddr_t ipaddr;
+
+ server_port = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_PORT, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (!server_port) {
+ stats_error(request, "No home server port supplied");
+ return;
+ }
+
+#ifndef NDEBUG
+ memset(&ipaddr, 0, sizeof(ipaddr));
+#endif
+
+ /*
+ * See if we need to look up the server by socket
+ * socket.
+ */
+ server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IP_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY);
+ if (server_ip) {
+ ipaddr.af = AF_INET;
+ ipaddr.prefix = 32;
+ ipaddr.ipaddr.ip4addr.s_addr = server_ip->vp_ipaddr;
+#ifdef AF_INET6
+ } else if ((server_ip = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_STATS_SERVER_IPV6_ADDRESS, VENDORPEC_FREERADIUS, TAG_ANY)) != NULL) {
+ ipaddr.af = AF_INET6;
+ ipaddr.ipaddr.ip6addr = server_ip->vp_ipv6addr;
+#endif /* AF_INET6 */
+ } else {
+ stats_error(request, "No home server IP supplied");
+ return;
+ }
+
+ /*
+ * Not found: don't do anything
+ */
+ home = home_server_find(&ipaddr, server_port->vp_integer, IPPROTO_UDP);
+#ifdef WITH_TCP
+ if (!home) home = home_server_find(&ipaddr, server_port->vp_integer, IPPROTO_TCP);
+#endif
+ if (!home) {
+ stats_error(request, "Failed to find home server IP");
+ return;
+ }
+
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_ip));
+ fr_pair_add(&request->reply->vps,
+ fr_pair_copy(request->reply, server_port));
+
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_SERVER_OUTSTANDING_REQUESTS, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = home->currently_outstanding;
+
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_SERVER_STATE, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = home->state;
+
+ if ((home->state == HOME_STATE_ALIVE) &&
+ (home->revive_time.tv_sec != 0)) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_SERVER_TIME_OF_LIFE, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = home->revive_time.tv_sec;
+ }
+
+ if ((home->state == HOME_STATE_ALIVE) &&
+ (home->ema.window > 0)) {
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_SERVER_EMA_WINDOW, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = home->ema.window;
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_1, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = home->ema.ema1 / EMA_SCALE;
+ vp = radius_pair_create(request->reply,
+ &request->reply->vps,
+ PW_FREERADIUS_SERVER_EMA_USEC_WINDOW_10, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = home->ema.ema10 / EMA_SCALE;
+
+ }
+
+ if (home->state == HOME_STATE_IS_DEAD) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_SERVER_TIME_OF_DEATH, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = home->zombie_period_start.tv_sec + home->zombie_period;
+ }
+
+ /*
+ * Show more information...
+ *
+ * FIXME: do this for clients, too!
+ */
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_LAST_PACKET_RECV, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = home->last_packet_recv;
+
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_FREERADIUS_STATS_LAST_PACKET_SENT, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_date = home->last_packet_sent;
+
+ if ((flag->vp_integer & 0x01) != 0) {
+ if (home->type == HOME_TYPE_AUTH) {
+ request_stats_addvp(request, proxy_authvp,
+ &home->stats);
+ } else {
+ stats_error(request, "Home server is not auth");
+ }
+ }
+
+#ifdef WITH_ACCOUNTING
+ if ((flag->vp_integer & 0x02) != 0) {
+ if (home->type == HOME_TYPE_ACCT) {
+ request_stats_addvp(request, proxy_acctvp,
+ &home->stats);
+ } else {
+ stats_error(request, "Home server is not acct");
+ }
+ }
+#endif
+ }
+#endif /* WITH_PROXY */
+}
+
+void radius_stats_init(int flag)
+{
+ if (!flag) {
+ gettimeofday(&start_time, NULL);
+ hup_time = start_time; /* it's just nicer this way */
+ } else {
+ gettimeofday(&hup_time, NULL);
+ }
+}
+
+void radius_stats_ema(fr_stats_ema_t *ema,
+ struct timeval *start, struct timeval *end)
+{
+ int micro;
+ time_t tdiff;
+#ifdef WITH_STATS_DEBUG
+ static int n = 0;
+#endif
+ if (ema->window == 0) return;
+
+ rad_assert(start->tv_sec <= end->tv_sec);
+
+ /*
+ * Initialize it.
+ */
+ if (ema->f1 == 0) {
+ if (ema->window > 10000) ema->window = 10000;
+
+ ema->f1 = (2 * F_EMA_SCALE) / (ema->window + 1);
+ ema->f10 = (2 * F_EMA_SCALE) / ((10 * ema->window) + 1);
+ }
+
+
+ tdiff = start->tv_sec;
+ tdiff -= end->tv_sec;
+
+ micro = (int) tdiff;
+ if (micro > 40) micro = 40; /* don't overflow 32-bit ints */
+ micro *= USEC;
+ micro += start->tv_usec;
+ micro -= end->tv_usec;
+
+ micro *= EMA_SCALE;
+
+ if (ema->ema1 == 0) {
+ ema->ema1 = micro;
+ ema->ema10 = micro;
+ } else {
+ int diff;
+
+ diff = ema->f1 * (micro - ema->ema1);
+ ema->ema1 += (diff / 1000000);
+
+ diff = ema->f10 * (micro - ema->ema10);
+ ema->ema10 += (diff / 1000000);
+ }
+
+
+#ifdef WITH_STATS_DEBUG
+ DEBUG("time %d %d.%06d\t%d.%06d\t%d.%06d\n",
+ n, micro / PREC, (micro / EMA_SCALE) % USEC,
+ ema->ema1 / PREC, (ema->ema1 / EMA_SCALE) % USEC,
+ ema->ema10 / PREC, (ema->ema10 / EMA_SCALE) % USEC);
+ n++;
+#endif
+}
+
+#endif /* WITH_STATS */
diff --git a/src/main/threads.c b/src/main/threads.c
new file mode 100644
index 0000000..a187106
--- /dev/null
+++ b/src/main/threads.c
@@ -0,0 +1,1697 @@
+/*
+ * threads.c request threading support
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/process.h>
+
+#ifdef HAVE_STDATOMIC_H
+#include <freeradius-devel/atomic_queue.h>
+#endif
+
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * Other OS's have sem_init, OS X doesn't.
+ */
+#ifdef HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#ifdef __APPLE__
+#ifdef WITH_GCD
+#include <dispatch/dispatch.h>
+#endif
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <mach/semaphore.h>
+
+#ifndef WITH_GCD
+#undef sem_t
+#define sem_t semaphore_t
+#undef sem_init
+#define sem_init(s,p,c) semaphore_create(mach_task_self(),s,SYNC_POLICY_FIFO,c)
+#undef sem_wait
+#define sem_wait(s) semaphore_wait(*s)
+#undef sem_post
+#define sem_post(s) semaphore_signal(*s)
+#endif /* WITH_GCD */
+#endif /* __APPLE__ */
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+
+#ifdef HAVE_OPENSSL_CRYPTO_H
+#include <openssl/crypto.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+#ifdef HAVE_OPENSSL_EVP_H
+#include <openssl/evp.h>
+#endif
+
+#ifndef WITH_GCD
+#define SEMAPHORE_LOCKED (0)
+
+#define THREAD_RUNNING (1)
+#define THREAD_CANCELLED (2)
+#define THREAD_EXITED (3)
+
+#define NUM_FIFOS RAD_LISTEN_MAX
+
+#ifndef HAVE_STDALIGN_H
+#undef HAVE_STDATOMIC_H
+#endif
+
+#ifdef HAVE_STDATOMIC_H
+#define CAS_INCR(_x) do { uint32_t num; \
+ num = load(_x); \
+ if (cas_incr(_x, num)) break; \
+ } while (true)
+
+#define CAS_DECR(_x) do { uint32_t num; \
+ num = load(_x); \
+ if (cas_decr(_x, num)) break; \
+ } while (true)
+#endif
+
+/*
+ * A data structure which contains the information about
+ * the current thread.
+ */
+typedef struct THREAD_HANDLE {
+ struct THREAD_HANDLE *prev; //!< Previous thread handle (in the linked list).
+ struct THREAD_HANDLE *next; //!< Next thread handle (int the linked list).
+ pthread_t pthread_id; //!< pthread_id.
+ int thread_num; //!< Server thread number, 1...number of threads.
+ int status; //!< Is the thread running or exited?
+ unsigned int request_count; //!< The number of requests that this thread has handled.
+ time_t timestamp; //!< When the thread started executing.
+ REQUEST *request;
+} THREAD_HANDLE;
+
+#endif /* WITH_GCD */
+
+#ifdef WNOHANG
+typedef struct thread_fork_t {
+ pid_t pid;
+ int status;
+ int exited;
+} thread_fork_t;
+#endif
+
+
+#ifdef WITH_STATS
+typedef struct fr_pps_t {
+ uint32_t pps_old;
+ uint32_t pps_now;
+ uint32_t pps;
+ time_t time_old;
+} fr_pps_t;
+#endif
+
+
+/*
+ * A data structure to manage the thread pool. There's no real
+ * need for a data structure, but it makes things conceptually
+ * easier.
+ */
+typedef struct THREAD_POOL {
+#ifndef WITH_GCD
+ THREAD_HANDLE *head;
+ THREAD_HANDLE *tail;
+
+ uint32_t total_threads;
+
+ uint32_t max_thread_num;
+ uint32_t start_threads;
+ uint32_t max_threads;
+ uint32_t min_spare_threads;
+ uint32_t max_spare_threads;
+ uint32_t max_requests_per_thread;
+ uint32_t request_count;
+ time_t time_last_spawned;
+ uint32_t cleanup_delay;
+ bool stop_flag;
+#endif /* WITH_GCD */
+ bool spawn_flag;
+
+#ifdef WNOHANG
+ pthread_mutex_t wait_mutex;
+ fr_hash_table_t *waiters;
+#endif
+
+#ifdef WITH_GCD
+ dispatch_queue_t queue;
+#else
+
+#ifdef WITH_STATS
+ fr_pps_t pps_in, pps_out;
+#ifdef WITH_ACCOUNTING
+ bool auto_limit_acct;
+#endif
+#endif
+
+ /*
+ * All threads wait on this semaphore, for requests
+ * to enter the queue.
+ */
+ sem_t semaphore;
+
+ uint32_t max_queue_size;
+
+#ifndef HAVE_STDATOMIC_H
+ /*
+ * To ensure only one thread at a time touches the queue.
+ */
+ pthread_mutex_t queue_mutex;
+
+ uint32_t active_threads; /* protected by queue_mutex */
+ uint32_t exited_threads;
+ uint32_t num_queued;
+ fr_fifo_t *fifo[NUM_FIFOS];
+#else
+ atomic_uint32_t active_threads;
+ atomic_uint32_t exited_threads;
+ fr_atomic_queue_t *queue[NUM_FIFOS];
+#endif /* STDATOMIC */
+#endif /* WITH_GCD */
+} THREAD_POOL;
+
+static THREAD_POOL thread_pool;
+static bool pool_initialized = false;
+
+#ifndef WITH_GCD
+static time_t last_cleaned = 0;
+
+static void thread_pool_manage(time_t now);
+#endif
+
+#ifndef WITH_GCD
+/*
+ * A mapping of configuration file names to internal integers
+ */
+static const CONF_PARSER thread_config[] = {
+ { "start_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.start_threads), "5" },
+ { "max_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_threads), "32" },
+ { "min_spare_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.min_spare_threads), "3" },
+ { "max_spare_servers", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_spare_threads), "10" },
+ { "max_requests_per_server", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_requests_per_thread), "0" },
+ { "cleanup_delay", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.cleanup_delay), "5" },
+ { "max_queue_size", FR_CONF_POINTER(PW_TYPE_INTEGER, &thread_pool.max_queue_size), "65536" },
+#ifdef WITH_STATS
+#ifdef WITH_ACCOUNTING
+ { "auto_limit_acct", FR_CONF_POINTER(PW_TYPE_BOOLEAN, &thread_pool.auto_limit_acct), NULL },
+#endif
+#endif
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+#if defined(HAVE_OPENSSL_CRYPTO_H) && defined(HAVE_CRYPTO_SET_LOCKING_CALLBACK)
+
+/*
+ * If we're linking against OpenSSL, then it is the
+ * duty of the application, if it is multithreaded,
+ * to provide OpenSSL with appropriate thread id
+ * and mutex locking functions
+ *
+ * Note: this only implements static callbacks.
+ * OpenSSL does not use dynamic locking callbacks
+ * right now, but may in the future, so we will have
+ * to add them at some point.
+ */
+static pthread_mutex_t *ssl_mutexes = NULL;
+
+static void ssl_locking_function(int mode, int n, UNUSED char const *file, UNUSED int line)
+{
+ rad_assert(&ssl_mutexes[n] != NULL);
+
+ if (mode & CRYPTO_LOCK) {
+ pthread_mutex_lock(&ssl_mutexes[n]);
+ } else {
+ pthread_mutex_unlock(&ssl_mutexes[n]);
+ }
+}
+
+/*
+ * Create the TLS mutexes.
+ */
+int tls_mutexes_init(void)
+{
+ int i, num;
+
+ rad_assert(ssl_mutexes == NULL);
+
+ num = CRYPTO_num_locks();
+
+ ssl_mutexes = rad_malloc(num * sizeof(pthread_mutex_t));
+ if (!ssl_mutexes) {
+ ERROR("Error allocating memory for SSL mutexes!");
+ return -1;
+ }
+
+ for (i = 0; i < num; i++) {
+ pthread_mutex_init(&ssl_mutexes[i], NULL);
+ }
+
+ CRYPTO_set_locking_callback(ssl_locking_function);
+
+ return 0;
+}
+
+static void tls_mutexes_destroy(void)
+{
+#ifdef HAVE_CRYPTO_SET_LOCKING_CALLBACK
+ int i, num;
+
+ rad_assert(ssl_mutex != NULL);
+
+ num = CRYPTO_num_locks();
+
+ for (i = 0; i < num; i++) {
+ pthread_mutex_destroy(&ssl_mutexes[i]);
+ }
+ free(ssl_mutexes);
+
+ CRYPTO_set_locking_callback(NULL);
+#endif
+}
+#else
+#define tls_mutexes_destroy()
+#endif
+
+#ifdef WNOHANG
+/*
+ * We don't want to catch SIGCHLD for a host of reasons.
+ *
+ * - exec_wait means that someone, somewhere, somewhen, will
+ * call waitpid(), and catch the child.
+ *
+ * - SIGCHLD is delivered to a random thread, not the one that
+ * forked.
+ *
+ * - if another thread catches the child, we have to coordinate
+ * with the thread doing the waiting.
+ *
+ * - if we don't waitpid() for non-wait children, they'll be zombies,
+ * and will hang around forever.
+ *
+ */
+static void reap_children(void)
+{
+ pid_t pid;
+ int status;
+ thread_fork_t mytf, *tf;
+
+
+ pthread_mutex_lock(&thread_pool.wait_mutex);
+
+ do {
+ retry:
+ pid = waitpid(0, &status, WNOHANG);
+ if (pid <= 0) break;
+
+ mytf.pid = pid;
+ tf = fr_hash_table_finddata(thread_pool.waiters, &mytf);
+ if (!tf) goto retry;
+
+ tf->status = status;
+ tf->exited = 1;
+ } while (fr_hash_table_num_elements(thread_pool.waiters) > 0);
+
+ pthread_mutex_unlock(&thread_pool.wait_mutex);
+}
+#else
+#define reap_children()
+#endif /* WNOHANG */
+
+#ifndef WITH_GCD
+/*
+ * Add a request to the list of waiting requests.
+ * This function gets called ONLY from the main handler thread...
+ *
+ * This function should never fail.
+ */
+int request_enqueue(REQUEST *request)
+{
+ bool managed = false;
+
+ rad_assert(pool_initialized == true);
+
+ /*
+ * If we haven't checked the number of child threads
+ * in a while, OR if the thread pool appears to be full,
+ * go manage it.
+ */
+ if (last_cleaned < request->timestamp) {
+ thread_pool_manage(request->timestamp);
+ managed = true;
+ }
+
+#ifdef HAVE_STDATOMIC_H
+ if (!managed) {
+ uint32_t num;
+
+ num = load(thread_pool.active_threads);
+ if (num == thread_pool.total_threads) {
+ thread_pool_manage(request->timestamp);
+ managed = true;
+ }
+
+ if (!managed) {
+ num = load(thread_pool.exited_threads);
+ if (num > 0) {
+ thread_pool_manage(request->timestamp);
+ }
+ }
+ }
+
+ /*
+ * Use atomic queues where possible. They're substantially faster than mutexes.
+ */
+ request->component = "<core>";
+ request->module = "<queue>";
+ request->child_state = REQUEST_QUEUED;
+
+ /*
+ * Push the request onto the appropriate fifo for that
+ */
+ if (!fr_atomic_queue_push(thread_pool.queue[request->priority], request)) {
+ ERROR("!!! ERROR !!! Failed inserting request %d into the queue", request->number);
+ return 0;
+ }
+
+#else /* no atomic queues */
+
+ if (!managed &&
+ ((thread_pool.active_threads == thread_pool.total_threads) ||
+ (thread_pool.exited_threads > 0))) {
+ thread_pool_manage(request->timestamp);
+ }
+
+ pthread_mutex_lock(&thread_pool.queue_mutex);
+
+#ifdef WITH_STATS
+#ifdef WITH_ACCOUNTING
+ if (thread_pool.auto_limit_acct) {
+ struct timeval now;
+
+ /*
+ * Throw away accounting requests if we're too
+ * busy. The NAS should retransmit these, and no
+ * one should notice.
+ *
+ * In contrast, we always try to process
+ * authentication requests. Those are more time
+ * critical, and it's harder to determine which
+ * we can throw away, and which we can keep.
+ *
+ * We allow the queue to get half full before we
+ * start worrying. Even then, we still require
+ * that the rate of input packets is higher than
+ * the rate of outgoing packets. i.e. the queue
+ * is growing.
+ *
+ * Once that happens, we roll a dice to see where
+ * the barrier is for "keep" versus "toss". If
+ * the queue is smaller than the barrier, we
+ * allow it. If the queue is larger than the
+ * barrier, we throw the packet away. Otherwise,
+ * we keep it.
+ *
+ * i.e. the probability of throwing the packet
+ * away increases from 0 (queue is half full), to
+ * 100 percent (queue is completely full).
+ *
+ * A probabilistic approach allows us to process
+ * SOME of the new accounting packets.
+ */
+ if ((request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
+ (thread_pool.num_queued > (thread_pool.max_queue_size / 2)) &&
+ (thread_pool.pps_in.pps_now > thread_pool.pps_out.pps_now)) {
+ uint32_t prob;
+ uint32_t keep;
+
+ /*
+ * Take a random value of how full we
+ * want the queue to be. It's OK to be
+ * half full, but we get excited over
+ * anything more than that.
+ */
+ keep = (thread_pool.max_queue_size / 2);
+ prob = fr_rand() & ((1 << 10) - 1);
+ keep *= prob;
+ keep >>= 10;
+ keep += (thread_pool.max_queue_size / 2);
+
+ /*
+ * If the queue is larger than our dice
+ * roll, we throw the packet away.
+ */
+ if (thread_pool.num_queued > keep) {
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+ return 0;
+ }
+ }
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Calculate the instantaneous arrival rate into
+ * the queue.
+ */
+ thread_pool.pps_in.pps = rad_pps(&thread_pool.pps_in.pps_old,
+ &thread_pool.pps_in.pps_now,
+ &thread_pool.pps_in.time_old,
+ &now);
+
+ thread_pool.pps_in.pps_now++;
+ }
+#endif /* WITH_ACCOUNTING */
+#endif
+
+ thread_pool.request_count++;
+
+ if (thread_pool.num_queued >= thread_pool.max_queue_size) {
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+
+ /*
+ * Mark the request as done.
+ */
+ RATE_LIMIT(ERROR("Something is blocking the server. There are %d packets in the queue, "
+ "waiting to be processed. Ignoring the new request.", thread_pool.num_queued));
+ return 0;
+ }
+
+ request->component = "<core>";
+ request->module = "<queue>";
+ request->child_state = REQUEST_QUEUED;
+
+ /*
+ * Push the request onto the appropriate fifo for that
+ */
+ if (!fr_fifo_push(thread_pool.fifo[request->priority], request)) {
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+ ERROR("!!! ERROR !!! Failed inserting request %d into the queue", request->number);
+ return 0;
+ }
+
+ thread_pool.num_queued++;
+
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+#endif
+
+ /*
+ * There's one more request in the queue.
+ *
+ * Note that we're not touching the queue any more, so
+ * the semaphore post is outside of the mutex. This also
+ * means that when the thread wakes up and tries to lock
+ * the mutex, it will be unlocked, and there won't be
+ * contention.
+ */
+ sem_post(&thread_pool.semaphore);
+
+ return 1;
+}
+
+/*
+ * Remove a request from the queue.
+ */
+static int request_dequeue(REQUEST **prequest)
+{
+ time_t blocked;
+ static time_t last_complained = 0;
+ static time_t total_blocked = 0;
+ int num_blocked = 0;
+#ifndef HAVE_STDATOMIC_H
+ RAD_LISTEN_TYPE start;
+#endif
+ RAD_LISTEN_TYPE i;
+ REQUEST *request = NULL;
+ reap_children();
+
+ rad_assert(pool_initialized == true);
+
+#ifdef HAVE_STDATOMIC_H
+retry:
+ for (i = 0; i < NUM_FIFOS; i++) {
+ if (!fr_atomic_queue_pop(thread_pool.queue[i], (void **) &request)) continue;
+
+ rad_assert(request != NULL);
+
+ VERIFY_REQUEST(request);
+
+ if (request->master_state != REQUEST_STOP_PROCESSING) {
+ break;
+ }
+
+ /*
+ * This entry was marked to be stopped. Acknowledge it.
+ */
+ request->child_state = REQUEST_DONE;
+ }
+
+ /*
+ * Popping might fail. If so, return.
+ */
+ if (!request) return 0;
+
+#else
+ pthread_mutex_lock(&thread_pool.queue_mutex);
+
+#ifdef WITH_STATS
+#ifdef WITH_ACCOUNTING
+ if (thread_pool.auto_limit_acct) {
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ /*
+ * Calculate the instantaneous departure rate
+ * from the queue.
+ */
+ thread_pool.pps_out.pps = rad_pps(&thread_pool.pps_out.pps_old,
+ &thread_pool.pps_out.pps_now,
+ &thread_pool.pps_out.time_old,
+ &now);
+ thread_pool.pps_out.pps_now++;
+ }
+#endif
+#endif
+
+ /*
+ * Clear old requests from all queues.
+ *
+ * We only do one pass over the queue, in order to
+ * amortize the work across the child threads. Since we
+ * do N checks for one request de-queued, the old
+ * requests will be quickly cleared.
+ */
+ for (i = 0; i < NUM_FIFOS; i++) {
+ request = fr_fifo_peek(thread_pool.fifo[i]);
+ if (!request) continue;
+
+ VERIFY_REQUEST(request);
+
+ if (request->master_state != REQUEST_STOP_PROCESSING) {
+ continue;
+ }
+
+ /*
+ * This entry was marked to be stopped. Acknowledge it.
+ */
+ request = fr_fifo_pop(thread_pool.fifo[i]);
+ rad_assert(request != NULL);
+ VERIFY_REQUEST(request);
+ request->child_state = REQUEST_DONE;
+ thread_pool.num_queued--;
+ }
+
+ start = 0;
+ retry:
+ /*
+ * Pop results from the top of the queue
+ */
+ for (i = start; i < NUM_FIFOS; i++) {
+ request = fr_fifo_pop(thread_pool.fifo[i]);
+ if (request) {
+ VERIFY_REQUEST(request);
+ start = i;
+ break;
+ }
+ }
+
+ if (!request) {
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+ *prequest = NULL;
+ return 0;
+ }
+
+ rad_assert(thread_pool.num_queued > 0);
+ thread_pool.num_queued--;
+#endif /* HAVE_STD_ATOMIC_H */
+
+ *prequest = request;
+
+ rad_assert(*prequest != NULL);
+ rad_assert(request->magic == REQUEST_MAGIC);
+
+ request->component = "<core>";
+ request->module = "";
+ request->child_state = REQUEST_RUNNING;
+
+ /*
+ * If the request has sat in the queue for too long,
+ * kill it.
+ *
+ * The main clean-up code can't delete the request from
+ * the queue, and therefore won't clean it up until we
+ * have acknowledged it as "done".
+ */
+ if (request->master_state == REQUEST_STOP_PROCESSING) {
+ request->module = "<done>";
+ request->child_state = REQUEST_DONE;
+ goto retry;
+ }
+
+ /*
+ * The thread is currently processing a request.
+ */
+#ifdef HAVE_STDATOMIC_H
+ CAS_INCR(thread_pool.active_threads);
+#else
+ thread_pool.active_threads++;
+#endif
+
+ blocked = time(NULL);
+ if (!request->proxy && (blocked - request->timestamp) > 5) {
+ total_blocked++;
+ if (last_complained < blocked) {
+ last_complained = blocked;
+ blocked -= request->timestamp;
+ num_blocked = total_blocked;
+ } else {
+ blocked = 0;
+ }
+ } else {
+ total_blocked = 0;
+ blocked = 0;
+ }
+
+#ifndef HAVE_STDATOMIC_H
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+#endif
+
+ if (blocked) {
+ ERROR("%d requests have been waiting in the processing queue for %d seconds. Check that all databases are running properly!",
+ num_blocked, (int) blocked);
+ }
+
+ return 1;
+}
+
+
+/*
+ * The main thread handler for requests.
+ *
+ * Wait on the semaphore until we have it, and process the request.
+ */
+static void *request_handler_thread(void *arg)
+{
+ THREAD_HANDLE *self = (THREAD_HANDLE *) arg;
+
+ /*
+ * Loop forever, until told to exit.
+ */
+ do {
+ /*
+ * Wait to be signalled.
+ */
+ DEBUG2("Thread %d waiting to be assigned a request",
+ self->thread_num);
+ re_wait:
+ if (sem_wait(&thread_pool.semaphore) != 0) {
+ /*
+ * Interrupted system call. Go back to
+ * waiting, but DON'T print out any more
+ * text.
+ */
+ if ((errno == EINTR) || (errno == EAGAIN)) {
+ DEBUG2("Re-wait %d", self->thread_num);
+ goto re_wait;
+ }
+ ERROR("Thread %d failed waiting for semaphore: %s: Exiting\n",
+ self->thread_num, fr_syserror(errno));
+ break;
+ }
+
+ DEBUG2("Thread %d got semaphore", self->thread_num);
+
+#ifdef HAVE_OPENSSL_ERR_H
+ /*
+ * Clear the error queue for the current thread.
+ */
+ ERR_clear_error();
+#endif
+
+ /*
+ * The server is exiting. Don't dequeue any
+ * requests.
+ */
+ if (thread_pool.stop_flag) break;
+
+ /*
+ * Try to grab a request from the queue.
+ *
+ * It may be empty, in which case we fail
+ * gracefully.
+ */
+ if (!request_dequeue(&self->request)) continue;
+
+ self->request->child_pid = self->pthread_id;
+ self->request_count++;
+
+ DEBUG2("Thread %d handling request %d, (%d handled so far)",
+ self->thread_num, self->request->number,
+ self->request_count);
+
+#ifndef HAVE_STDATOMIC_H
+#ifdef WITH_ACCOUNTING
+ if ((self->request->packet->code == PW_CODE_ACCOUNTING_REQUEST) &&
+ thread_pool.auto_limit_acct) {
+ VALUE_PAIR *vp;
+ REQUEST *request = self->request;
+
+ vp = radius_pair_create(request, &request->config,
+ 181, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = thread_pool.pps_in.pps;
+
+ vp = radius_pair_create(request, &request->config,
+ 182, VENDORPEC_FREERADIUS);
+ if (vp) vp->vp_integer = thread_pool.pps_in.pps;
+
+ vp = radius_pair_create(request, &request->config,
+ 183, VENDORPEC_FREERADIUS);
+ if (vp) {
+ vp->vp_integer = thread_pool.max_queue_size - thread_pool.num_queued;
+ vp->vp_integer *= 100;
+ vp->vp_integer /= thread_pool.max_queue_size;
+ }
+ }
+#endif
+#endif
+
+ self->request->process(self->request, FR_ACTION_RUN);
+ self->request = NULL;
+
+#ifdef HAVE_STDATOMIC_H
+ CAS_DECR(thread_pool.active_threads);
+#else
+ /*
+ * Update the active threads.
+ */
+ pthread_mutex_lock(&thread_pool.queue_mutex);
+ rad_assert(thread_pool.active_threads > 0);
+ thread_pool.active_threads--;
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+#endif
+
+ /*
+ * If the thread has handled too many requests, then make it
+ * exit.
+ */
+ if ((thread_pool.max_requests_per_thread > 0) &&
+ (self->request_count >= thread_pool.max_requests_per_thread)) {
+ DEBUG2("Thread %d handled too many requests",
+ self->thread_num);
+ break;
+ }
+ } while (self->status != THREAD_CANCELLED);
+
+ DEBUG2("Thread %d exiting...", self->thread_num);
+
+#ifdef HAVE_OPENSSL_ERR_H
+ /*
+ * If we linked with OpenSSL, the application
+ * must remove the thread's error queue before
+ * exiting to prevent memory leaks.
+ */
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ ERR_remove_state(0);
+#elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ ERR_remove_thread_state(NULL);
+#endif
+#endif
+
+#ifdef HAVE_STDATOMIC_H
+ CAS_INCR(thread_pool.exited_threads);
+#else
+ pthread_mutex_lock(&thread_pool.queue_mutex);
+ thread_pool.exited_threads++;
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+#endif
+
+ /*
+ * Do this as the LAST thing before exiting.
+ */
+ self->request = NULL;
+ self->status = THREAD_EXITED;
+ exec_trigger(NULL, NULL, "server.thread.stop", true);
+
+ return NULL;
+}
+
+/*
+ * Take a THREAD_HANDLE, delete it from the thread pool and
+ * free its resources.
+ *
+ * This function is called ONLY from the main server thread,
+ * ONLY after the thread has exited.
+ */
+static void delete_thread(THREAD_HANDLE *handle)
+{
+ THREAD_HANDLE *prev;
+ THREAD_HANDLE *next;
+
+ rad_assert(handle->request == NULL);
+
+ DEBUG2("Deleting thread %d", handle->thread_num);
+
+ prev = handle->prev;
+ next = handle->next;
+ rad_assert(thread_pool.total_threads > 0);
+ thread_pool.total_threads--;
+
+ /*
+ * Remove the handle from the list.
+ */
+ if (prev == NULL) {
+ rad_assert(thread_pool.head == handle);
+ thread_pool.head = next;
+ } else {
+ prev->next = next;
+ }
+
+ if (next == NULL) {
+ rad_assert(thread_pool.tail == handle);
+ thread_pool.tail = prev;
+ } else {
+ next->prev = prev;
+ }
+
+ /*
+ * Free the handle, now that it's no longer referencable.
+ */
+ free(handle);
+}
+
+
+/*
+ * Spawn a new thread, and place it in the thread pool.
+ *
+ * The thread is started initially in the blocked state, waiting
+ * for the semaphore.
+ */
+static THREAD_HANDLE *spawn_thread(time_t now, int do_trigger)
+{
+ int rcode;
+ THREAD_HANDLE *handle;
+
+ /*
+ * Ensure that we don't spawn too many threads.
+ */
+ if (thread_pool.total_threads >= thread_pool.max_threads) {
+ DEBUG2("Thread spawn failed. Maximum number of threads (%d) already running.", thread_pool.max_threads);
+ return NULL;
+ }
+
+ /*
+ * Allocate a new thread handle.
+ */
+ handle = (THREAD_HANDLE *) rad_malloc(sizeof(THREAD_HANDLE));
+ memset(handle, 0, sizeof(THREAD_HANDLE));
+ handle->prev = NULL;
+ handle->next = NULL;
+ handle->thread_num = thread_pool.max_thread_num++;
+ handle->request_count = 0;
+ handle->status = THREAD_RUNNING;
+ handle->timestamp = time(NULL);
+
+ /*
+ * Create the thread joinable, so that it can be cleaned up
+ * using pthread_join().
+ *
+ * Note that the function returns non-zero on error, NOT
+ * -1. The return code is the error, and errno isn't set.
+ */
+ rcode = pthread_create(&handle->pthread_id, 0, request_handler_thread, handle);
+ if (rcode != 0) {
+ free(handle);
+ ERROR("Thread create failed: %s",
+ fr_syserror(rcode));
+ return NULL;
+ }
+
+ /*
+ * One more thread to go into the list.
+ */
+ thread_pool.total_threads++;
+ DEBUG2("Thread spawned new child %d. Total threads in pool: %d",
+ handle->thread_num, thread_pool.total_threads);
+ if (do_trigger) exec_trigger(NULL, NULL, "server.thread.start", true);
+
+ /*
+ * Add the thread handle to the tail of the thread pool list.
+ */
+ if (thread_pool.tail) {
+ thread_pool.tail->next = handle;
+ handle->prev = thread_pool.tail;
+ thread_pool.tail = handle;
+ } else {
+ rad_assert(thread_pool.head == NULL);
+ thread_pool.head = thread_pool.tail = handle;
+ }
+
+ /*
+ * Update the time we last spawned a thread.
+ */
+ thread_pool.time_last_spawned = now;
+
+ /*
+ * Fire trigger if maximum number of threads reached
+ */
+ if (thread_pool.total_threads >= thread_pool.max_threads)
+ exec_trigger(NULL, NULL, "server.thread.max_threads", true);
+
+ /*
+ * And return the new handle to the caller.
+ */
+ return handle;
+}
+#endif /* WITH_GCD */
+
+
+#ifdef WNOHANG
+static uint32_t pid_hash(void const *data)
+{
+ thread_fork_t const *tf = data;
+
+ return fr_hash(&tf->pid, sizeof(tf->pid));
+}
+
+static int pid_cmp(void const *one, void const *two)
+{
+ thread_fork_t const *a = one;
+ thread_fork_t const *b = two;
+
+ return (a->pid - b->pid);
+}
+#endif
+
+/*
+ * Allocate the thread pool, and seed it with an initial number
+ * of threads.
+ *
+ * FIXME: What to do on a SIGHUP???
+ */
+DIAG_OFF(deprecated-declarations)
+int thread_pool_init(CONF_SECTION *cs, bool *spawn_flag)
+{
+#ifndef WITH_GCD
+ uint32_t i;
+ int rcode;
+#endif
+ CONF_SECTION *pool_cf;
+ time_t now;
+#ifdef HAVE_STDATOMIC_H
+ int num;
+ TALLOC_CTX *autofree;
+
+ autofree = talloc_autofree_context();
+#endif
+
+ now = time(NULL);
+
+ rad_assert(spawn_flag != NULL);
+ rad_assert(*spawn_flag == true);
+ rad_assert(pool_initialized == false); /* not called on HUP */
+
+ pool_cf = cf_subsection_find_next(cs, NULL, "thread");
+#ifdef WITH_GCD
+ if (pool_cf) WARN("Built with Grand Central Dispatch. Ignoring 'thread' subsection");
+#else
+ if (!pool_cf) *spawn_flag = false;
+#endif
+
+ /*
+ * Initialize the thread pool to some reasonable values.
+ */
+ memset(&thread_pool, 0, sizeof(THREAD_POOL));
+#ifndef WITH_GCD
+ thread_pool.head = NULL;
+ thread_pool.tail = NULL;
+ thread_pool.total_threads = 0;
+ thread_pool.max_thread_num = 1;
+ thread_pool.cleanup_delay = 5;
+ thread_pool.stop_flag = false;
+#endif
+ thread_pool.spawn_flag = *spawn_flag;
+
+ /*
+ * Don't bother initializing the mutexes or
+ * creating the hash tables. They won't be used.
+ */
+ if (!*spawn_flag) return 0;
+
+#ifdef WNOHANG
+ if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) {
+ ERROR("FATAL: Failed to initialize wait mutex: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Create the hash table of child PID's
+ */
+ thread_pool.waiters = fr_hash_table_create(pid_hash,
+ pid_cmp,
+ free);
+ if (!thread_pool.waiters) {
+ ERROR("FATAL: Failed to set up wait hash");
+ return -1;
+ }
+#endif
+
+#ifndef WITH_GCD
+ if (cf_section_parse(pool_cf, NULL, thread_config) < 0) {
+ return -1;
+ }
+
+ /*
+ * Catch corner cases.
+ */
+ if (thread_pool.min_spare_threads < 1)
+ thread_pool.min_spare_threads = 1;
+ if (thread_pool.max_spare_threads < 1)
+ thread_pool.max_spare_threads = 1;
+ if (thread_pool.max_spare_threads < thread_pool.min_spare_threads)
+ thread_pool.max_spare_threads = thread_pool.min_spare_threads;
+ if (thread_pool.max_threads == 0)
+ thread_pool.max_threads = 256;
+ if ((thread_pool.max_queue_size < 2) || (thread_pool.max_queue_size > 1024*1024)) {
+ ERROR("FATAL: max_queue_size value must be in range 2-1048576");
+ return -1;
+ }
+
+ if (thread_pool.start_threads > thread_pool.max_threads) {
+ ERROR("FATAL: start_servers (%i) must be <= max_servers (%i)",
+ thread_pool.start_threads, thread_pool.max_threads);
+ return -1;
+ }
+#endif /* WITH_GCD */
+
+ /*
+ * The pool has already been initialized. Don't spawn
+ * new threads, and don't forget about forked children.
+ */
+ if (pool_initialized) {
+ return 0;
+ }
+
+#ifndef WITH_GCD
+ /*
+ * Initialize the queue of requests.
+ */
+ memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore));
+ rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED);
+ if (rcode != 0) {
+ ERROR("FATAL: Failed to initialize semaphore: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+
+#ifndef HAVE_STDATOMIC_H
+ rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL);
+ if (rcode != 0) {
+ ERROR("FATAL: Failed to initialize queue mutex: %s",
+ fr_syserror(errno));
+ return -1;
+ }
+#else
+ num = 0;
+ store(thread_pool.active_threads, num);
+ store(thread_pool.exited_threads, num);
+#endif
+
+ /*
+ * Allocate multiple fifos.
+ */
+ for (i = 0; i < NUM_FIFOS; i++) {
+#ifdef HAVE_STDATOMIC_H
+ thread_pool.queue[i] = fr_atomic_queue_alloc(autofree, thread_pool.max_queue_size);
+ if (!thread_pool.queue[i]) {
+ ERROR("FATAL: Failed to set up request fifo");
+ return -1;
+ }
+#else
+ thread_pool.fifo[i] = fr_fifo_create(NULL, thread_pool.max_queue_size, NULL);
+ if (!thread_pool.fifo[i]) {
+ ERROR("FATAL: Failed to set up request fifo");
+ return -1;
+ }
+#endif
+ }
+#endif
+
+#ifndef WITH_GCD
+ /*
+ * Create a number of waiting threads.
+ *
+ * If we fail while creating them, do something intelligent.
+ */
+ for (i = 0; i < thread_pool.start_threads; i++) {
+ if (spawn_thread(now, 0) == NULL) {
+ return -1;
+ }
+ }
+#else
+ thread_pool.queue = dispatch_queue_create("org.freeradius.threads", NULL);
+ if (!thread_pool.queue) {
+ ERROR("Failed creating dispatch queue: %s", fr_syserror(errno));
+ fr_exit(1);
+ }
+#endif
+
+ DEBUG2("Thread pool initialized");
+ pool_initialized = true;
+ return 0;
+}
+DIAG_ON(deprecated-declarations)
+
+/*
+ * Stop all threads in the pool.
+ */
+void thread_pool_stop(void)
+{
+#ifndef WITH_GCD
+ int i;
+ int total_threads;
+ THREAD_HANDLE *handle;
+ THREAD_HANDLE *next;
+
+ if (!pool_initialized) return;
+
+ /*
+ * Set pool stop flag.
+ */
+ thread_pool.stop_flag = true;
+
+ /*
+ * Wakeup all threads to make them see stop flag.
+ */
+ total_threads = thread_pool.total_threads;
+ for (i = 0; i != total_threads; i++) {
+ sem_post(&thread_pool.semaphore);
+ }
+
+ /*
+ * Join and free all threads.
+ */
+ for (handle = thread_pool.head; handle; handle = next) {
+ next = handle->next;
+ pthread_join(handle->pthread_id, NULL);
+ delete_thread(handle);
+ }
+
+ for (i = 0; i < NUM_FIFOS; i++) {
+#ifdef HAVE_STDATOMIC_H
+ fr_atomic_queue_free(&thread_pool.queue[i]);
+#else
+ fr_fifo_free(thread_pool.fifo[i]);
+#endif
+ }
+
+#ifdef WNOHANG
+ fr_hash_table_free(thread_pool.waiters);
+#endif
+
+ /*
+ * We're no longer threaded. Remove the mutexes and free
+ * the memory.
+ */
+ tls_mutexes_destroy();
+#endif
+}
+
+
+#ifdef WITH_GCD
+int request_enqueue(REQUEST *request)
+{
+ dispatch_block_t block;
+
+ block = ^{
+ request->process(request, FR_ACTION_RUN);
+ };
+
+ dispatch_async(thread_pool.queue, block);
+
+ return 1;
+}
+#endif
+
+#ifndef WITH_GCD
+/*
+ * Check the min_spare_threads and max_spare_threads.
+ *
+ * If there are too many or too few threads waiting, then we
+ * either create some more, or delete some.
+ */
+static void thread_pool_manage(time_t now)
+{
+ uint32_t spare;
+ int i, total;
+ THREAD_HANDLE *handle, *next;
+ uint32_t active_threads;
+
+ /*
+ * Loop over the thread pool, deleting exited threads.
+ */
+ for (handle = thread_pool.head; handle; handle = next) {
+ next = handle->next;
+
+ /*
+ * Maybe we've asked the thread to exit, and it
+ * has agreed.
+ */
+ if (handle->status == THREAD_EXITED) {
+ pthread_join(handle->pthread_id, NULL);
+ delete_thread(handle);
+
+#ifdef HAVE_STDATOMIC_H
+ CAS_DECR(thread_pool.exited_threads);
+#else
+ pthread_mutex_lock(&thread_pool.queue_mutex);
+ thread_pool.exited_threads--;
+ pthread_mutex_unlock(&thread_pool.queue_mutex);
+#endif
+ }
+ }
+
+ /*
+ * We don't need a mutex lock here, as we're reading
+ * active_threads, and not modifying it. We want a close
+ * approximation of the number of active threads, and this
+ * is good enough.
+ */
+#ifdef HAVE_STDATOMIC_H
+ active_threads = load(thread_pool.active_threads);
+#else
+ active_threads = thread_pool.active_threads;
+#endif
+ spare = thread_pool.total_threads - active_threads;
+ if (rad_debug_lvl) {
+ static uint32_t old_total = 0;
+ static uint32_t old_active = 0;
+
+ if ((old_total != thread_pool.total_threads) || (old_active != active_threads)) {
+ DEBUG2("Threads: total/active/spare threads = %d/%d/%d",
+ thread_pool.total_threads, active_threads, spare);
+ old_total = thread_pool.total_threads;
+ old_active = active_threads;
+ }
+ }
+
+ /*
+ * If there are too few spare threads. Go create some more.
+ */
+ if ((thread_pool.total_threads < thread_pool.max_threads) &&
+ (spare < thread_pool.min_spare_threads)) {
+ total = thread_pool.min_spare_threads - spare;
+
+ if ((total + thread_pool.total_threads) > thread_pool.max_threads) {
+ total = thread_pool.max_threads - thread_pool.total_threads;
+ }
+
+ DEBUG2("Threads: Spawning %d spares", total);
+
+ /*
+ * Create a number of spare threads.
+ */
+ for (i = 0; i < total; i++) {
+ handle = spawn_thread(now, 1);
+ if (handle == NULL) {
+ return;
+ }
+ }
+
+ return; /* there aren't too many spare threads */
+ }
+
+ /*
+ * Only delete spare threads if we haven't already done
+ * so this second.
+ */
+ if (now == last_cleaned) {
+ return;
+ }
+ last_cleaned = now;
+
+ /*
+ * Only delete the spare threads if sufficient time has
+ * passed since we last created one. This helps to minimize
+ * the amount of create/delete cycles.
+ */
+ if ((now - thread_pool.time_last_spawned) < (int)thread_pool.cleanup_delay) {
+ return;
+ }
+
+ /*
+ * If there are too many spare threads, delete one.
+ *
+ * Note that we only delete ONE at a time, instead of
+ * wiping out many. This allows the excess servers to
+ * be slowly reaped, just in case the load spike comes again.
+ */
+ if (spare > thread_pool.max_spare_threads) {
+
+ spare -= thread_pool.max_spare_threads;
+
+ DEBUG2("Threads: deleting 1 spare out of %d spares", spare);
+
+ /*
+ * Walk through the thread pool, deleting the
+ * first idle thread we come across.
+ */
+ for (handle = thread_pool.head; (handle != NULL) && (spare > 0) ; handle = next) {
+ next = handle->next;
+
+ /*
+ * If the thread is not handling a
+ * request, but still live, then tell it
+ * to exit.
+ *
+ * It will eventually wake up, and realize
+ * it's been told to commit suicide.
+ */
+ if ((handle->request == NULL) &&
+ (handle->status == THREAD_RUNNING)) {
+ handle->status = THREAD_CANCELLED;
+ /*
+ * Post an extra semaphore, as a
+ * signal to wake up, and exit.
+ */
+ sem_post(&thread_pool.semaphore);
+ spare--;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Otherwise everything's kosher. There are not too few,
+ * or too many spare threads. Exit happily.
+ */
+ return;
+}
+#endif /* WITH_GCD */
+
+#ifdef WNOHANG
+/*
+ * Thread wrapper for fork().
+ */
+pid_t rad_fork(void)
+{
+ pid_t child_pid;
+
+ if (!pool_initialized) return fork();
+
+ reap_children(); /* be nice to non-wait thingies */
+
+ if (fr_hash_table_num_elements(thread_pool.waiters) >= 1024) {
+ return -1;
+ }
+
+ /*
+ * Fork & save the PID for later reaping.
+ */
+ child_pid = fork();
+ if (child_pid > 0) {
+ int rcode;
+ thread_fork_t *tf;
+
+ tf = rad_malloc(sizeof(*tf));
+ memset(tf, 0, sizeof(*tf));
+
+ tf->pid = child_pid;
+
+ pthread_mutex_lock(&thread_pool.wait_mutex);
+ rcode = fr_hash_table_insert(thread_pool.waiters, tf);
+ pthread_mutex_unlock(&thread_pool.wait_mutex);
+
+ if (!rcode) {
+ ERROR("Failed to store PID, creating what will be a zombie process %d",
+ (int) child_pid);
+ free(tf);
+ }
+ }
+
+ /*
+ * Return whatever we were told.
+ */
+ return child_pid;
+}
+
+
+/*
+ * Wait 10 seconds at most for a child to exit, then give up.
+ */
+pid_t rad_waitpid(pid_t pid, int *status)
+{
+ int i;
+ thread_fork_t mytf, *tf;
+
+ if (!pool_initialized) return waitpid(pid, status, 0);
+
+ if (pid <= 0) return -1;
+
+ mytf.pid = pid;
+
+ pthread_mutex_lock(&thread_pool.wait_mutex);
+ tf = fr_hash_table_finddata(thread_pool.waiters, &mytf);
+ pthread_mutex_unlock(&thread_pool.wait_mutex);
+
+ if (!tf) return -1;
+
+ for (i = 0; i < 100; i++) {
+ reap_children();
+
+ if (tf->exited) {
+ *status = tf->status;
+
+ pthread_mutex_lock(&thread_pool.wait_mutex);
+ fr_hash_table_delete(thread_pool.waiters, &mytf);
+ pthread_mutex_unlock(&thread_pool.wait_mutex);
+ return pid;
+ }
+ usleep(100000); /* sleep for 1/10 of a second */
+ }
+
+ /*
+ * 10 seconds have passed, give up on the child.
+ */
+ pthread_mutex_lock(&thread_pool.wait_mutex);
+ fr_hash_table_delete(thread_pool.waiters, &mytf);
+ pthread_mutex_unlock(&thread_pool.wait_mutex);
+
+ return 0;
+}
+#else
+/*
+ * No rad_fork or rad_waitpid
+ */
+#endif
+
+void thread_pool_queue_stats(int array[RAD_LISTEN_MAX], int pps[2])
+{
+ int i;
+
+#ifndef WITH_GCD
+ if (pool_initialized) {
+ struct timeval now;
+
+ for (i = 0; i < RAD_LISTEN_MAX; i++) {
+#ifndef HAVE_STDATOMIC_H
+ array[i] = fr_fifo_num_elements(thread_pool.fifo[i]);
+#else
+ array[i] = 0;
+#endif
+ }
+
+ gettimeofday(&now, NULL);
+
+ pps[0] = rad_pps(&thread_pool.pps_in.pps_old,
+ &thread_pool.pps_in.pps_now,
+ &thread_pool.pps_in.time_old,
+ &now);
+ pps[1] = rad_pps(&thread_pool.pps_out.pps_old,
+ &thread_pool.pps_out.pps_now,
+ &thread_pool.pps_out.time_old,
+ &now);
+
+ } else
+#endif /* WITH_GCD */
+ {
+ for (i = 0; i < RAD_LISTEN_MAX; i++) {
+ array[i] = 0;
+ }
+
+ pps[0] = pps[1] = 0;
+ }
+}
+
+void thread_pool_thread_stats(int stats[3])
+{
+#ifndef WITH_GCD
+ if (pool_initialized) {
+ /*
+ * We don't need a mutex lock here as we only want to
+ * read a close approximation of the number of active
+ * threads, and not modify it.
+ */
+#ifdef HAVE_STDATOMIC_H
+ stats[0] = load(thread_pool.active_threads);
+#else
+ stats[0] = thread_pool.active_threads;
+#endif
+ stats[1] = thread_pool.total_threads;
+ stats[2] = thread_pool.max_threads;
+ } else
+#endif /* WITH_GCD */
+ {
+ stats[0] = stats[1] = stats[2] = 0;
+ }
+}
+#endif /* HAVE_PTHREAD_H */
+
+static void time_free(void *data)
+{
+ free(data);
+}
+
+void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, int quench)
+{
+ CONF_SECTION *subcs;
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+ char const *attr;
+ char const *value;
+ VALUE_PAIR *vp;
+ bool alloc = false;
+
+ /*
+ * Use global "trigger" section if no local config is given.
+ */
+ if (!cs) {
+ cs = main_config.config;
+ attr = name;
+ } else {
+ /*
+ * Try to use pair name, rather than reference.
+ */
+ attr = strrchr(name, '.');
+ if (attr) {
+ attr++;
+ } else {
+ attr = name;
+ }
+ }
+
+ /*
+ * Find local "trigger" subsection. If it isn't found,
+ * try using the global "trigger" section, and reset the
+ * reference to the full path, rather than the sub-path.
+ */
+ subcs = cf_section_sub_find(cs, "trigger");
+ if (!subcs && (cs != main_config.config)) {
+ subcs = cf_section_sub_find(main_config.config, "trigger");
+ attr = name;
+ }
+
+ if (!subcs) return;
+
+ ci = cf_reference_item(subcs, main_config.config, attr);
+ if (!ci) {
+ ERROR("No such item in trigger section: %s", attr);
+ return;
+ }
+
+ if (!cf_item_is_pair(ci)) {
+ ERROR("Trigger is not a configuration variable: %s", attr);
+ return;
+ }
+
+ cp = cf_item_to_pair(ci);
+ if (!cp) return;
+
+ value = cf_pair_value(cp);
+ if (!value) {
+ ERROR("Trigger has no value: %s", name);
+ return;
+ }
+
+ /*
+ * May be called for Status-Server packets.
+ */
+ vp = NULL;
+ if (request && request->packet) vp = request->packet->vps;
+
+ /*
+ * Perform periodic quenching.
+ */
+ if (quench) {
+ time_t *last_time;
+
+ last_time = cf_data_find(cs, value);
+ if (!last_time) {
+ last_time = rad_malloc(sizeof(*last_time));
+ *last_time = 0;
+
+ if (cf_data_add(cs, value, last_time, time_free) < 0) {
+ free(last_time);
+ last_time = NULL;
+ }
+ }
+
+ /*
+ * Send the quenched traps at most once per second.
+ */
+ if (last_time) {
+ time_t now = time(NULL);
+ if (*last_time == now) return;
+
+ *last_time = now;
+ }
+ }
+
+ /*
+ * radius_exec_program always needs a request.
+ */
+ if (!request) {
+ request = request_alloc(NULL);
+ alloc = true;
+ }
+
+ DEBUG("Trigger %s -> %s", name, value);
+
+ radius_exec_program(request, NULL, 0, NULL, request, value, vp, false, true, 0);
+
+ if (alloc) talloc_free(request);
+}
diff --git a/src/main/tls.c b/src/main/tls.c
new file mode 100644
index 0000000..c8cae3b
--- /dev/null
+++ b/src/main/tls.c
@@ -0,0 +1,5420 @@
+/*
+ * tls.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#include <ctype.h>
+
+#ifdef WITH_TLS
+# ifdef HAVE_OPENSSL_RAND_H
+# include <openssl/rand.h>
+# endif
+
+# ifdef HAVE_OPENSSL_OCSP_H
+# include <openssl/ocsp.h>
+# endif
+
+# ifdef HAVE_OPENSSL_EVP_H
+# include <openssl/evp.h>
+# endif
+# include <openssl/ssl.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/provider.h>
+
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+#endif
+
+#define LOG_PREFIX "tls"
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#define ERR_get_error_line(_file, _line) ERR_get_error_all(_file, _line, NULL, NULL, NULL)
+
+#define FIPS_mode(_x) EVP_default_properties_is_fips_enabled(NULL)
+#define PEM_read_bio_DHparams(_bio, _x, _y, _z) PEM_read_bio_Parameters(_bio, &dh)
+#define SSL_CTX_set0_tmp_dh_pkey(_ctx, _dh) SSL_CTX_set_tmp_dh(_ctx, _dh)
+#define DH EVP_PKEY
+#define DH_free(_dh)
+#endif
+
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+typedef struct libssl_defect {
+ uint64_t high;
+ uint64_t low;
+
+ char const *id;
+ char const *name;
+ char const *comment;
+} libssl_defect_t;
+
+/* Record critical defects in libssl here, new versions of OpenSSL to older versions of OpenSSL. */
+static libssl_defect_t libssl_defects[] =
+{
+ {
+ .low = 0x01010001f, /* 1.1.0a */
+ .high = 0x01010001f, /* 1.1.0a */
+ .id = "CVE-2016-6309",
+ .name = "OCSP status request extension",
+ .comment = "For more information see https://www.openssl.org/news/secadv/20160926.txt"
+ },
+ {
+ .low = 0x01010000f, /* 1.1.0 */
+ .high = 0x01010000f, /* 1.1.0 */
+ .id = "CVE-2016-6304",
+ .name = "OCSP status request extension",
+ .comment = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+ },
+ {
+ .low = 0x01000209f, /* 1.0.2i */
+ .high = 0x01000209f, /* 1.0.2i */
+ .id = "CVE-2016-7052",
+ .name = "OCSP status request extension",
+ .comment = "For more information see https://www.openssl.org/news/secadv/20160926.txt"
+ },
+ {
+ .low = 0x01000200f, /* 1.0.2 */
+ .high = 0x01000208f, /* 1.0.2h */
+ .id = "CVE-2016-6304",
+ .name = "OCSP status request extension",
+ .comment = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+ },
+ {
+ .low = 0x01000100f, /* 1.0.1 */
+ .high = 0x01000114f, /* 1.0.1t */
+ .id = "CVE-2016-6304",
+ .name = "OCSP status request extension",
+ .comment = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+ },
+ {
+ .low = 0x010001000, /* 1.0.1 */
+ .high = 0x01000106f, /* 1.0.1f */
+ .id = "CVE-2014-0160",
+ .name = "Heartbleed",
+ .comment = "For more information see http://heartbleed.com"
+ },
+};
+#endif /* ENABLE_OPENSSL_VERSION_CHECK */
+
+FR_NAME_NUMBER const fr_tls_status_table[] = {
+ { "invalid", FR_TLS_INVALID },
+ { "request", FR_TLS_REQUEST },
+ { "response", FR_TLS_RESPONSE },
+ { "success", FR_TLS_SUCCESS },
+ { "fail", FR_TLS_FAIL },
+ { "noop", FR_TLS_NOOP },
+
+ { "start", FR_TLS_START },
+ { "ok", FR_TLS_OK },
+ { "ack", FR_TLS_ACK },
+ { "first fragment", FR_TLS_FIRST_FRAGMENT },
+ { "more fragments", FR_TLS_MORE_FRAGMENTS },
+ { "length included", FR_TLS_LENGTH_INCLUDED },
+ { "more fragments with length", FR_TLS_MORE_FRAGMENTS_WITH_LENGTH },
+ { "handled", FR_TLS_HANDLED },
+ { NULL , -1},
+};
+
+/* index we use to store cached session VPs
+ * needs to be dynamic so we can supply a "free" function
+ */
+int fr_tls_ex_index_vps = -1;
+int fr_tls_ex_index_certs = -1;
+
+/* Session */
+static void session_close(tls_session_t *ssn);
+static void session_init(tls_session_t *ssn);
+
+/* record */
+static void record_init(record_t *buf);
+static void record_close(record_t *buf);
+static unsigned int record_plus(record_t *buf, void const *ptr,
+ unsigned int size);
+static unsigned int record_minus(record_t *buf, void *ptr,
+ unsigned int size);
+
+typedef struct {
+ char const *name;
+ SSL_CTX *ctx;
+} fr_realm_ctx_t;
+
+DIAG_OFF(format-nonliteral)
+/** Print errors in the TLS thread local error stack
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors.
+ *
+ * @param[in] request The current request (may be NULL).
+ * @param[in] msg Error message describing the operation being attempted.
+ * @param[in] ap Arguments for msg.
+ * @return the number of errors drained from the stack.
+ */
+static int tls_verror_log(REQUEST *request, char const *msg, va_list ap)
+{
+ unsigned long error;
+ char *p;
+ int in_stack = 0;
+ char buffer[256];
+
+ int line;
+ char const *file;
+
+ /*
+ * Pop the first error, so ERR_peek_error()
+ * can be used to determine if there are
+ * multiple errors.
+ */
+ error = ERR_get_error_line(&file, &line);
+
+ if (msg) {
+ p = talloc_vasprintf(request, msg, ap);
+
+ /*
+ * Single line mode (there's only one error)
+ */
+ if (error && !ERR_peek_error()) {
+ ERR_error_string_n(error, buffer, sizeof(buffer));
+
+ /* Extra verbose */
+ if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) %s: %s[%i]:%s", p, file, line, buffer);
+ } else {
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) %s: %s", p, buffer);
+ }
+
+ talloc_free(p);
+
+ return 1;
+ }
+
+ /*
+ * Print the error we were given, irrespective
+ * of whether there were any OpenSSL errors.
+ */
+ ROPTIONAL(RERROR, ERROR, "(TLS) %s", p);
+ talloc_free(p);
+ }
+
+ /*
+ * Stack mode (there are multiple errors)
+ */
+ if (!error) return 0;
+ do {
+ ERR_error_string_n(error, buffer, sizeof(buffer));
+ /* Extra verbose */
+ if ((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) {
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) %s[%i]:%s", file, line, buffer);
+ } else {
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) %s", buffer);
+ }
+ in_stack++;
+ } while ((error = ERR_get_error_line(&file, &line)));
+
+ return in_stack;
+}
+DIAG_ON(format-nonliteral)
+
+/** Print errors in the TLS thread local error stack
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors.
+ *
+ * @param[in] request The current request (may be NULL).
+ * @param[in] msg Error message describing the operation being attempted.
+ * @param[in] ... Arguments for msg.
+ * @return the number of errors drained from the stack.
+ */
+int tls_error_log(REQUEST *request, char const *msg, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, msg);
+ ret = tls_verror_log(request, msg, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/** Print errors raised by OpenSSL I/O functions
+ *
+ * Drains the thread local OpenSSL error queue, and prints out errors
+ * based on the SSL handle and the return code of the I/O function.
+ *
+ * OpenSSL lists I/O functions to be:
+ * - SSL_connect
+ * - SSL_accept
+ * - SSL_do_handshake
+ * - SSL_read
+ * - SSL_peek
+ * - SSL_write
+ *
+ * @param request The current request (may be NULL).
+ * @param session The current tls_session.
+ * @param ret from the I/O operation.
+ * @param msg Error message describing the operation being attempted.
+ * @param ... Arguments for msg.
+ * @return
+ * - 0 TLS session cannot continue.
+ * - 1 TLS session may still be viable.
+ */
+int tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char const *msg, ...)
+{
+ int error;
+ va_list ap;
+
+ if (ERR_peek_error()) {
+ va_start(ap, msg);
+ tls_verror_log(request, msg, ap);
+ va_end(ap);
+ }
+
+ error = SSL_get_error(session->ssl, ret);
+ switch (error) {
+ /*
+ * These seem to be harmless and already "dealt
+ * with" by our non-blocking environment. NB:
+ * "ZERO_RETURN" is the clean "error"
+ * indicating a successfully closed SSL
+ * tunnel. We let this happen because our IO
+ * loop should not appear to have broken on
+ * this condition - and outside the IO loop, the
+ * "shutdown" state is checked.
+ *
+ * Don't print anything if we ignore the error.
+ */
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_ZERO_RETURN:
+ break;
+
+ /*
+ * These seem to be indications of a genuine
+ * error that should result in the SSL tunnel
+ * being regarded as "dead".
+ */
+ case SSL_ERROR_SYSCALL:
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) System call (I/O) error (%i)", ret);
+ return 0;
+
+ case SSL_ERROR_SSL:
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) Protocol error (%i)", ret);
+ return 0;
+
+ /*
+ * For any other errors that (a) exist, and (b)
+ * crop up - we need to interpret what to do with
+ * them - so "politely inform" the caller that
+ * the code needs updating here.
+ */
+ default:
+ ROPTIONAL(REDEBUG, ERROR, "(TLS) Session error %i (%i)", error, ret);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef PSK_MAX_IDENTITY_LEN
+static bool identity_is_safe(const char *identity)
+{
+ char c;
+
+ if (!identity) return true;
+
+ while ((c = *(identity++)) != '\0') {
+ if (isalpha((uint8_t) c) || isdigit((uint8_t) c) || isspace((uint8_t) c) ||
+ (c == '@') || (c == '-') || (c == '_') || (c == '.')) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * When a client uses TLS-PSK to talk to a server, this callback
+ * is used by the server to determine the PSK to use.
+ */
+static unsigned int psk_server_callback(SSL *ssl, const char *identity,
+ unsigned char *psk,
+ unsigned int max_psk_len)
+{
+ unsigned int psk_len = 0;
+ fr_tls_server_conf_t *conf;
+ REQUEST *request;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl,
+ FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 0;
+
+ request = (REQUEST *)SSL_get_ex_data(ssl,
+ FR_TLS_EX_INDEX_REQUEST);
+ if (request && conf->psk_query) {
+ size_t hex_len;
+ VALUE_PAIR *vp, **certs;
+ TALLOC_CTX *talloc_ctx;
+ char buffer[2 * PSK_MAX_PSK_LEN + 4]; /* allow for too-long keys */
+
+ /*
+ * The passed identity is weird. Deny it.
+ */
+ if (!identity_is_safe(identity)) {
+ RWDEBUG("(TLS) Invalid characters in PSK identity %s", identity);
+ return 0;
+ }
+
+ vp = pair_make_request("TLS-PSK-Identity", identity, T_OP_SET);
+ if (!vp) return 0;
+
+ certs = (VALUE_PAIR **)SSL_get_ex_data(ssl, fr_tls_ex_index_certs);
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
+ fr_assert(certs != NULL); /* pointer to sock->certs */
+ fr_assert(talloc_ctx != NULL); /* sock */
+
+ fr_pair_add(certs, fr_pair_copy(talloc_ctx, vp));
+
+ hex_len = radius_xlat(buffer, sizeof(buffer), request, conf->psk_query,
+ NULL, NULL);
+ if (!hex_len) {
+ RWDEBUG("(TLS) PSK expansion returned an empty string.");
+ return 0;
+ }
+
+ /*
+ * The returned key is truncated at MORE than
+ * OpenSSL can handle. That way we can detect
+ * the truncation, and complain about it.
+ */
+ if (hex_len > (2 * max_psk_len)) {
+ RWDEBUG("(TLS) Returned PSK is too long (%u > %u)",
+ (unsigned int) hex_len, 2 * max_psk_len);
+ return 0;
+ }
+
+ /*
+ * Leave the TLS-PSK-Identity in the request, and
+ * convert the expansion from printable string
+ * back to hex.
+ */
+ return fr_hex2bin(psk, max_psk_len, buffer, hex_len);
+ }
+
+ if (!conf->psk_identity) {
+ DEBUG("No static PSK identity set. Rejecting the user");
+ return 0;
+ }
+
+ /*
+ * No REQUEST, or no dynamic query. Just look for a
+ * static identity.
+ */
+ if (strcmp(identity, conf->psk_identity) != 0) {
+ ERROR("(TKS) Supplied PSK identity %s does not match configuration. Rejecting.",
+ identity);
+ return 0;
+ }
+
+ psk_len = strlen(conf->psk_password);
+ if (psk_len > (2 * max_psk_len)) return 0;
+
+ return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
+}
+
+static unsigned int psk_client_callback(SSL *ssl, UNUSED char const *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ unsigned int psk_len;
+ fr_tls_server_conf_t *conf;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl,
+ FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 0;
+
+ psk_len = strlen(conf->psk_password);
+ if (psk_len > (2 * max_psk_len)) return 0;
+
+ strlcpy(identity, conf->psk_identity, max_identity_len);
+
+ return fr_hex2bin(psk, max_psk_len, conf->psk_password, psk_len);
+}
+
+#endif
+
+#define MAX_SESSION_SIZE (256)
+
+
+void tls_session_id(SSL_SESSION *ssn, char *buffer, size_t bufsize)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+ size_t size;
+
+ size = ssn->session_id_length;
+ if (size > bufsize) size = bufsize;
+
+ fr_bin2hex(buffer, ssn->session_id, size);
+#else
+ unsigned int size;
+ uint8_t const *p;
+
+ p = SSL_SESSION_get_id(ssn, &size);
+ if (size > bufsize) size = bufsize;
+
+ fr_bin2hex(buffer, p, size);
+
+#endif
+}
+
+static int _tls_session_free(tls_session_t *ssn)
+{
+ /*
+ * Free any opaque TTLS or PEAP data.
+ */
+ if ((ssn->opaque) && (ssn->free_opaque)) {
+ ssn->free_opaque(ssn->opaque);
+ ssn->opaque = NULL;
+ }
+
+ session_close(ssn);
+
+ return 0;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * By setting the environment variable SSLKEYLOGFILE to a filename keying
+ * material will be exported that you may use with Wireshark to decode any
+ * TLS flows. Please see the following for more details:
+ *
+ * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
+ *
+ * An example logging session is (you should delete the file on each run):
+ *
+ * rm -f /tmp/sslkey.log; env SSLKEYLOGFILE=/tmp/sslkey.log freeradius -X | tee /tmp/debug
+ */
+static void tls_keylog_cb(UNUSED const SSL *ssl, const char *line)
+{
+ int fd;
+ size_t len;
+ const char *filename;
+ // less than _POSIX_PIPE_BUF (512) guarantees writes are atomic for O_APPEND
+ char buffer[64 + 2*SSL3_RANDOM_SIZE + 2*SSL_MAX_MASTER_KEY_LENGTH];
+
+ filename = getenv("SSLKEYLOGFILE");
+ if (!filename) return;
+
+ len = strlen(line);
+ if ((len + 1) > sizeof(buffer)) {
+ DEBUG("SSLKEYLOGFILE buffer not large enough, max %lu, required %lu", sizeof(buffer), len + 1);
+ return;
+ }
+
+ memcpy(buffer, line, len);
+ buffer[len] = '\n';
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ fr_strerror_printf("Failed to open file %s: %s", filename, strerror(errno));
+ return;
+ }
+
+ if (write(fd, buffer, len + 1) == -1) {
+ DEBUG("Failed to write to file %s: %s", filename, strerror(errno));
+ }
+
+ close(fd);
+}
+#endif
+
+tls_session_t *tls_new_client_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, int fd, VALUE_PAIR **certs)
+{
+ int ret;
+ int verify_mode;
+ tls_session_t *ssn = NULL;
+ REQUEST *request;
+
+ ssn = talloc_zero(ctx, tls_session_t);
+ if (!ssn) return NULL;
+
+ talloc_set_destructor(ssn, _tls_session_free);
+
+ ssn->ctx = conf->ctx;
+ ssn->mtu = conf->fragment_size;
+ ssn->conf = conf;
+
+ SSL_CTX_set_mode(ssn->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
+
+ ssn->ssl = SSL_new(ssn->ctx);
+ if (!ssn->ssl) {
+ talloc_free(ssn);
+ return NULL;
+ }
+
+ request = request_alloc(ssn);
+ request->packet = rad_alloc(request, false);
+ request->reply = rad_alloc(request, false);
+
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);
+
+ if (conf->fix_cert_order) {
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_FIX_CERT_ORDER, (void *) &conf->fix_cert_order);
+ }
+
+ /*
+ * Add the message callback to identify what type of
+ * message/handshake is passed
+ */
+ SSL_set_msg_callback(ssn->ssl, cbtls_msg);
+ SSL_set_msg_callback_arg(ssn->ssl, ssn);
+ SSL_set_info_callback(ssn->ssl, cbtls_info);
+
+ /*
+ * Always verify the peer certificate.
+ */
+ DEBUG2("Requiring Server certificate");
+ verify_mode = SSL_VERIFY_PEER;
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ SSL_set_verify(ssn->ssl, verify_mode, cbtls_verify);
+
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn);
+ if (certs) SSL_set_ex_data(ssn->ssl, fr_tls_ex_index_certs, (void *)certs);
+
+ SSL_set_fd(ssn->ssl, fd);
+
+ ret = SSL_connect(ssn->ssl);
+ if (ret < 0) {
+ switch (SSL_get_error(ssn->ssl, ret)) {
+ default:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ ssn->connected = false;
+ return ssn;
+
+ case SSL_ERROR_WANT_WRITE:
+ ssn->connected = false;
+ return ssn;
+ }
+ }
+
+ if (ret <= 0) {
+ tls_error_io_log(NULL, ssn, ret, "Failed in connecting TLS session.");
+ talloc_free(ssn);
+
+ return NULL;
+ }
+
+ ssn->connected = true;
+ return ssn;
+}
+
+
+/** Create a new TLS session
+ *
+ * Configures a new TLS session, configuring options, setting callbacks etc...
+ *
+ * @param ctx to alloc session data in. Should usually be NULL unless the lifetime of the
+ * session is tied to another talloc'd object.
+ * @param conf to use to configure the tls session.
+ * @param request The current #REQUEST.
+ * @param client_cert Whether to require a client_cert.
+ * @param allow_tls13 Whether to allow or forbid TLS 1.3.
+ * @return a new session on success, or NULL on error.
+ */
+tls_session_t *tls_new_session(TALLOC_CTX *ctx, fr_tls_server_conf_t *conf, REQUEST *request, bool client_cert,
+#ifndef TLS1_3_VERSION
+ UNUSED
+#endif
+ bool allow_tls13)
+{
+ tls_session_t *state = NULL;
+ SSL *new_tls = NULL;
+ int verify_mode = 0;
+ VALUE_PAIR *vp;
+ X509_STORE *new_cert_store;
+
+ rad_assert(request != NULL);
+
+ RDEBUG2("(TLS) Initiating new session");
+
+ /*
+ * Replace X509 store if it is time to update CRLs/certs in ca_path
+ */
+ if (conf->ca_path_reload_interval > 0 && conf->ca_path_last_reload + conf->ca_path_reload_interval <= request->timestamp) {
+ pthread_mutex_lock(&conf->mutex);
+ /* recheck conf->ca_path_last_reload because it may be inaccurate without mutex */
+ if (conf->ca_path_last_reload + conf->ca_path_reload_interval <= request->timestamp) {
+ RDEBUG2("Flushing X509 store to re-read data from ca_path dir");
+
+ if ((new_cert_store = fr_init_x509_store(conf)) == NULL) {
+ RERROR("(TLS) Error replacing X509 store, out of memory (?)");
+ } else {
+ if (conf->old_x509_store) X509_STORE_free(conf->old_x509_store);
+ /*
+ * Swap empty store with the old one.
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ conf->old_x509_store = SSL_CTX_get_cert_store(conf->ctx);
+ /* Bump refcnt so the store is kept allocated till next store replacement */
+ X509_STORE_up_ref(conf->old_x509_store);
+ SSL_CTX_set_cert_store(conf->ctx, new_cert_store);
+#else
+ /*
+ * We do not use SSL_CTX_set_cert_store() call here because
+ * we are not sure that old X509 store is not in the use by some
+ * thread (i.e. cert check in progress).
+ * Keep it allocated till next store replacement.
+ */
+ conf->old_x509_store = conf->ctx->cert_store;
+ conf->ctx->cert_store = new_cert_store;
+#endif
+ conf->ca_path_last_reload = request->timestamp;
+ }
+ }
+ pthread_mutex_unlock(&conf->mutex);
+ }
+
+ new_tls = SSL_new(conf->ctx);
+ if (new_tls == NULL) {
+ tls_error_log(request, "Error creating new TLS session");
+ return NULL;
+ }
+
+#ifdef TLS1_3_VERSION
+ /*
+ * Disallow TLS 1.3 for FAST.
+ *
+ * We need another magic configuration option to allow
+ * it.
+ */
+ if (!allow_tls13 && (conf->max_version == TLS1_3_VERSION)) {
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! FORCING MAXIMUM TLS VERSION TO TLS 1.2 !!");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! There is no standard for using this EAP method with TLS 1.3");
+ WARN("!! Please set tls_max_version = \"1.2\"");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+
+ if (SSL_set_max_proto_version(new_tls, TLS1_2_VERSION) == 0) {
+ tls_error_log(request, "Failed limiting maximum version to TLS 1.2");
+ return NULL;
+ }
+ }
+#endif
+
+ /* We use the SSL's "app_data" to indicate a call-back */
+ SSL_set_app_data(new_tls, NULL);
+
+ if ((state = talloc_zero(ctx, tls_session_t)) == NULL) {
+ RERROR("(TLS) Error allocating memory for SSL state");
+ return NULL;
+ }
+ session_init(state);
+ talloc_set_destructor(state, _tls_session_free);
+
+ state->ctx = conf->ctx;
+ state->ssl = new_tls;
+ state->conf = conf;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * Set the keylog file if the admin requested it.
+ */
+ if (getenv("SSLKEYLOGFILE") != NULL) SSL_CTX_set_keylog_callback(state->ctx, tls_keylog_cb);
+#endif
+
+ /*
+ * Initialize callbacks
+ */
+ state->record_init = record_init;
+ state->record_close = record_close;
+ state->record_plus = record_plus;
+ state->record_minus = record_minus;
+
+ /*
+ * Create & hook the BIOs to handle the dirty side of the
+ * SSL. This is *very important* as we want to handle
+ * the transmission part. Now the only IO interface
+ * that SSL is aware of, is our defined BIO buffers.
+ *
+ * This means that all SSL IO is done to/from memory,
+ * and we can update those BIOs from the packets we've
+ * received.
+ */
+ state->into_ssl = BIO_new(BIO_s_mem());
+ state->from_ssl = BIO_new(BIO_s_mem());
+ SSL_set_bio(state->ssl, state->into_ssl, state->from_ssl);
+
+ /*
+ * Add the message callback to identify what type of
+ * message/handshake is passed
+ */
+ SSL_set_msg_callback(new_tls, cbtls_msg);
+ SSL_set_msg_callback_arg(new_tls, state);
+ SSL_set_info_callback(new_tls, cbtls_info);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ /*
+ * Allow policies to load context-specific certificate chains.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_TLS_SESSION_CERT_FILE, 0, TAG_ANY);
+ if (vp) {
+ VALUE_PAIR *key = fr_pair_find_by_num(request->config, PW_TLS_SESSION_CERT_PRIVATE_KEY_FILE, 0, TAG_ANY);
+ if (!key) key = vp;
+
+ RDEBUG2("(TLS) Loading session certificate file \"%s\"", vp->vp_strvalue);
+
+ if (conf->realms) {
+ fr_realm_ctx_t my_r, *r;
+
+ /*
+ * Use a pre-existing SSL CTX, if
+ * available. Note that due to OpenSSL
+ * issues, this really changes only the
+ * certificate files, and leaves all
+ * other fields alone. e.g. you can't
+ * select a different TLS version.
+ *
+ * This is fine for our purposes in v3.
+ * Due to how we build them, the various
+ * additional SSL_CTXs are identical to
+ * the main one, except for certs.
+ */
+ my_r.name = vp->vp_strvalue;
+ r = fr_hash_table_finddata(conf->realms, &my_r);
+ if (r) {
+ (void) SSL_set_SSL_CTX(state->ssl, r->ctx);
+ goto after_chain;
+ }
+
+ /*
+ * Else fall through to trying to dynamically load the certs.
+ */
+ }
+
+ if (conf->file_type) {
+ if (SSL_use_certificate_chain_file(state->ssl, vp->vp_strvalue) != 1) {
+ tls_error_log(request, "Failed loading TLS session certificate \"%s\"",
+ vp->vp_strvalue);
+ error:
+ talloc_free(state);
+ return NULL;
+ }
+ } else {
+ if (SSL_use_certificate_file(state->ssl, vp->vp_strvalue, SSL_FILETYPE_ASN1) != 1) {
+ tls_error_log(request, "Failed loading TLS session certificate \"%s\"",
+ vp->vp_strvalue);
+ goto error;
+ }
+ }
+
+ /*
+ * Note that there is either no password, or it
+ * has to be the same as what's in the
+ * configuration.
+ *
+ * There is just no additional security to
+ * putting a password into the same file system
+ * as the private key.
+ */
+ if (SSL_use_PrivateKey_file(state->ssl, key->vp_strvalue, SSL_FILETYPE_PEM) != 1) {
+ tls_error_log(request, "Failed loading TLS session certificate \"%s\"",
+ key->vp_strvalue);
+ goto error;
+ }
+
+ if (SSL_check_private_key(state->ssl) != 1) {
+ tls_error_log(request, "Failed validating TLS session certificate \"%s\"",
+ vp->vp_strvalue);
+ goto error;
+ }
+ }
+after_chain:
+#endif
+
+ /*
+ * In Server mode we only accept.
+ */
+ SSL_set_accept_state(state->ssl);
+
+ /*
+ * Verify the peer certificate, if asked.
+ */
+ if (client_cert) {
+ RDEBUG2("(TLS) Setting verify mode to require certificate from client");
+ verify_mode = SSL_VERIFY_PEER;
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ verify_mode |= SSL_VERIFY_CLIENT_ONCE;
+ }
+ SSL_set_verify(state->ssl, verify_mode, cbtls_verify);
+
+ SSL_set_ex_data(state->ssl, FR_TLS_EX_INDEX_CONF, (void *)conf);
+ SSL_set_ex_data(state->ssl, FR_TLS_EX_INDEX_SSN, (void *)state);
+ state->length_flag = conf->include_length;
+
+ /*
+ * We use default fragment size, unless the Framed-MTU
+ * tells us it's too big. Note that we do NOT account
+ * for the EAP-TLS headers if conf->fragment_size is
+ * large, because that config item looks to be confusing.
+ *
+ * i.e. it should REALLY be called MTU, and the code here
+ * should figure out what that means for TLS fragment size.
+ * asking the administrator to know the internal details
+ * of EAP-TLS in order to calculate fragment sizes is
+ * just too much.
+ */
+ state->mtu = conf->fragment_size;
+#define EAP_TLS_MAGIC_OVERHEAD (63)
+
+ /*
+ * If the packet contains an MTU, then use that. We
+ * trust the admin!
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY);
+ if (vp) {
+ if ((vp->vp_integer > 100) && (vp->vp_integer < state->mtu)) {
+ state->mtu = vp->vp_integer;
+ }
+
+ } else if (request->parent) {
+ /*
+ * If there's a parent request, we look for what
+ * MTU was set there. Then, we use an MTU which
+ * accounts for the extra overhead of nesting EAP
+ * + TLS inside of EAP + TLS.
+ */
+ vp = fr_pair_find_by_num(request->parent->state, PW_FRAMED_MTU, 0, TAG_ANY);
+ if (vp && (vp->vp_integer > (100 + EAP_TLS_MAGIC_OVERHEAD)) && (vp->vp_integer <= state->mtu)) {
+ state->mtu = vp->vp_integer - EAP_TLS_MAGIC_OVERHEAD;
+ }
+ }
+
+ /*
+ * Cache / update the Framed-MTU in the session-state
+ * list.
+ */
+ vp = fr_pair_find_by_num(request->state, PW_FRAMED_MTU, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(request->state_ctx, PW_FRAMED_MTU, 0);
+ fr_pair_add(&request->state, vp);
+ }
+ if (vp) vp->vp_integer = state->mtu;
+
+ if (conf->session_cache_enable) state->allow_session_resumption = true; /* otherwise it's false */
+
+ return state;
+}
+
+/*
+ * We are the server, we always get the dirty data
+ * (Handshake data is also considered as dirty data)
+ * During handshake, since SSL API handles itself,
+ * After clean-up, dirty_out will be filled with
+ * the data required for handshaking. So we check
+ * if dirty_out is empty then we simply send it back.
+ * As of now, if handshake is successful, then we keep going,
+ * otherwise we fail.
+ *
+ * Fill the Bio with the dirty data to clean it
+ * Get the cleaned data from SSL, if it is not Handshake data
+ */
+int tls_handshake_recv(REQUEST *request, tls_session_t *ssn)
+{
+ int err;
+
+ if (ssn->invalid_hb_used) {
+ REDEBUG("(TLS) OpenSSL Heartbeat attack detected. Closing connection");
+ return 0;
+ }
+
+ if (ssn->dirty_in.used > 0) {
+ err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used);
+ if (err != (int) ssn->dirty_in.used) {
+ REDEBUG("(TLS) Failed writing %zd bytes to SSL BIO: %d", ssn->dirty_in.used, err);
+ record_init(&ssn->dirty_in);
+ return 0;
+ }
+ record_init(&ssn->dirty_in);
+ }
+
+ err = SSL_read(ssn->ssl, ssn->clean_out.data + ssn->clean_out.used,
+ sizeof(ssn->clean_out.data) - ssn->clean_out.used);
+ if (err > 0) {
+ ssn->clean_out.used += err;
+ return 1;
+ }
+
+ if (!tls_error_io_log(request, ssn, err, "Failed reading from OpenSSL")) return 0;
+
+ /* Some Extra STATE information for easy debugging */
+ if (!ssn->is_init_finished && SSL_is_init_finished(ssn->ssl)) {
+ VALUE_PAIR *vp;
+ char const *str_version;
+
+ RDEBUG2("(TLS) Connection Established");
+ ssn->is_init_finished = true;
+
+ vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_SESSION_CIPHER_SUITE, 0);
+ if (vp) {
+ fr_pair_value_strcpy(vp, SSL_CIPHER_get_name(SSL_get_current_cipher(ssn->ssl)));
+ fr_pair_add(&request->state, vp);
+ RINDENT();
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ REXDENT();
+ }
+
+ switch (SSL_version(ssn->ssl)) {
+ case SSL2_VERSION:
+ str_version = "SSL 2.0";
+ break;
+ case SSL3_VERSION:
+ str_version = "SSL 3.0";
+ break;
+ case TLS1_VERSION:
+ str_version = "TLS 1.0";
+ break;
+#ifdef TLS1_1_VERSION
+ case TLS1_1_VERSION:
+ str_version = "TLS 1.1";
+ break;
+#endif
+#ifdef TLS1_2_VERSION
+ case TLS1_2_VERSION:
+ str_version = "TLS 1.2";
+ break;
+#endif
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ str_version = "TLS 1.3";
+ break;
+#endif
+ default:
+ str_version = "UNKNOWN";
+ break;
+ }
+
+ vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_SESSION_VERSION, 0);
+ if (vp) {
+ fr_pair_value_strcpy(vp, str_version);
+ fr_pair_add(&request->state, vp);
+ RINDENT();
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ REXDENT();
+ }
+ }
+ else if (SSL_in_init(ssn->ssl)) { RDEBUG2("(TLS) In Handshake Phase"); }
+ else if (SSL_in_before(ssn->ssl)) { RDEBUG2("(TLS) Before Handshake Phase"); }
+ else if (SSL_in_accept_init(ssn->ssl)) { RDEBUG2("(TLS) In Accept mode"); }
+ else if (SSL_in_connect_init(ssn->ssl)) { RDEBUG2("(TLS) In Connect mode"); }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ /*
+ * Cache the SSL_SESSION pointer.
+ */
+ if (!ssn->ssl_session) {
+ ssn->ssl_session = SSL_get_session(ssn->ssl);
+
+ /*
+ * Some versions of OpenSSL don't allow you to
+ * get the session before the init is finished.
+ * In that case, this error is a soft fail.
+ *
+ * If the session init is finished, then failure
+ * to get the session is a hard fail.
+ */
+ if (!ssn->ssl_session && ssn->is_init_finished) {
+ RDEBUG("(TLS) Failed getting session");
+ return 0;
+ }
+ }
+
+#else
+#error You must use a newer version of OpenSSL
+#endif
+
+ err = BIO_ctrl_pending(ssn->from_ssl);
+ if (err > 0) {
+ err = BIO_read(ssn->from_ssl, ssn->dirty_out.data,
+ sizeof(ssn->dirty_out.data));
+ if (err > 0) {
+ RDEBUG3("(TLS) got %d bytes of data", err);
+ ssn->dirty_out.used = err;
+
+ } else if (BIO_should_retry(ssn->from_ssl)) {
+ record_init(&ssn->dirty_in);
+ RDEBUG2("(TLS) Asking for more data in tunnel.");
+ return 1;
+
+ } else {
+ tls_error_log(NULL, "Error reading from OpenSSL");
+ record_init(&ssn->dirty_in);
+ return 0;
+ }
+ } else {
+ RDEBUG2("(TLS) Application data.");
+ /* Its clean application data, leave whatever is in the buffer */
+#if 0
+ record_init(&ssn->clean_out);
+#endif
+ }
+
+ /* We are done with dirty_in, reinitialize it */
+ record_init(&ssn->dirty_in);
+ return 1;
+}
+
+/*
+ * Take cleartext user data, and encrypt it into the output buffer,
+ * to send to the client at the other end of the SSL connection.
+ */
+int tls_handshake_send(REQUEST *request, tls_session_t *ssn)
+{
+ int err;
+
+ /*
+ * If there's un-encrypted data in 'clean_in', then write
+ * that data to the SSL session, and then call the BIO function
+ * to get that encrypted data from the SSL session, into
+ * a buffer which we can then package into an EAP packet.
+ *
+ * Based on Server's logic this clean_in is expected to
+ * contain the data to send to the client.
+ */
+ if (ssn->clean_in.used > 0) {
+ int written;
+
+ written = SSL_write(ssn->ssl, ssn->clean_in.data, ssn->clean_in.used);
+ record_minus(&ssn->clean_in, NULL, written);
+
+ /* Get the dirty data from Bio to send it */
+ err = BIO_read(ssn->from_ssl, ssn->dirty_out.data + ssn->dirty_out.used,
+ sizeof(ssn->dirty_out.data) - ssn->dirty_out.used);
+ if (err > 0) {
+ ssn->dirty_out.used += err;
+ } else {
+ if (!tls_error_io_log(request, ssn, err, "Failed writing to OpenSSL")) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void session_init(tls_session_t *ssn)
+{
+ ssn->ssl = NULL;
+ ssn->into_ssl = ssn->from_ssl = NULL;
+ record_init(&ssn->clean_in);
+ record_init(&ssn->clean_out);
+ record_init(&ssn->dirty_in);
+ record_init(&ssn->dirty_out);
+
+ memset(&ssn->info, 0, sizeof(ssn->info));
+
+ ssn->mtu = 0;
+ ssn->fragment = false;
+ ssn->tls_msg_len = 0;
+ ssn->length_flag = false;
+ ssn->opaque = NULL;
+ ssn->free_opaque = NULL;
+}
+
+static void session_close(tls_session_t *ssn)
+{
+ if (ssn->ssl) {
+ SSL_set_quiet_shutdown(ssn->ssl, 1);
+ SSL_shutdown(ssn->ssl);
+
+ SSL_free(ssn->ssl);
+ ssn->ssl = NULL;
+ }
+
+ record_close(&ssn->clean_in);
+ record_close(&ssn->clean_out);
+ record_close(&ssn->dirty_in);
+ record_close(&ssn->dirty_out);
+ session_init(ssn);
+}
+
+static void record_init(record_t *rec)
+{
+ rec->used = 0;
+}
+
+static void record_close(record_t *rec)
+{
+ rec->used = 0;
+}
+
+
+/*
+ * Copy data to the intermediate buffer, before we send
+ * it somewhere.
+ */
+static unsigned int record_plus(record_t *rec, void const *ptr,
+ unsigned int size)
+{
+ unsigned int added = MAX_RECORD_SIZE - rec->used;
+
+ if(added > size)
+ added = size;
+ if(added == 0)
+ return 0;
+ memcpy(rec->data + rec->used, ptr, added);
+ rec->used += added;
+ return added;
+}
+
+/*
+ * Take data from the buffer, and give it to the caller.
+ */
+static unsigned int record_minus(record_t *rec, void *ptr,
+ unsigned int size)
+{
+ unsigned int taken = rec->used;
+
+ if(taken > size)
+ taken = size;
+ if(taken == 0)
+ return 0;
+ if(ptr)
+ memcpy(ptr, rec->data, taken);
+ rec->used -= taken;
+
+ /*
+ * This is pretty bad...
+ */
+ if (rec->used > 0) memmove(rec->data, rec->data + taken, rec->used);
+
+ return taken;
+}
+
+void tls_session_information(tls_session_t *tls_session)
+{
+ char const *str_write_p, *str_version, *str_content_type = "";
+ char const *str_details1 = "", *str_details2= "";
+ char const *details = NULL;
+ REQUEST *request;
+ VALUE_PAIR *vp;
+ char content_type[16], alert_buf[16];
+ char buffer[32];
+
+ /*
+ * Don't print this out in the normal course of
+ * operations.
+ */
+ if (rad_debug_lvl == 0) return;
+
+ /*
+ * OpenSSL calls this function with 'pseudo' content
+ * types. The user doesn't care about them, so suppress them.
+ */
+ if (tls_session->info.content_type > UINT8_MAX) return;
+
+ request = SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST);
+ if (!request) return;
+
+ str_write_p = tls_session->info.origin ? "(TLS) send" : "(TLS) recv";
+
+#define FROM_CLIENT (tls_session->info.origin == 0)
+
+ switch (SSL_version(tls_session->ssl)) {
+ case SSL2_VERSION:
+ str_version = "SSL 2.0 ";
+ break;
+ case SSL3_VERSION:
+ str_version = "SSL 3.0 ";
+ break;
+ case TLS1_VERSION:
+ str_version = "TLS 1.0 ";
+ break;
+#ifdef TLS1_1_VERSION
+ case TLS1_1_VERSION:
+ str_version = "TLS 1.1 ";
+ break;
+#endif
+#ifdef TLS1_2_VERSION
+ case TLS1_2_VERSION:
+ str_version = "TLS 1.2 ";
+ break;
+#endif
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ str_version = "TLS 1.3 ";
+ break;
+#endif
+
+ default:
+ sprintf(buffer, "UNKNOWN TLS VERSION '%04X'", SSL_version(tls_session->ssl));
+ str_version = buffer;
+ break;
+ }
+
+ if (1) {
+ switch (tls_session->info.content_type) {
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ str_content_type = "ChangeCipherSpec";
+ break;
+
+ case SSL3_RT_ALERT:
+ str_content_type = "Alert";
+ break;
+
+ case SSL3_RT_HANDSHAKE:
+ str_content_type = "Handshake";
+ break;
+
+ case SSL3_RT_APPLICATION_DATA:
+ str_content_type = "ApplicationData";
+ break;
+
+ default:
+ snprintf(content_type, sizeof(content_type), "content=%d", tls_session->info.content_type);
+ str_content_type = content_type;
+ break;
+ }
+
+ if (tls_session->info.content_type == SSL3_RT_ALERT) {
+ str_details1 = ", ???";
+
+ if (tls_session->info.record_len == 2) {
+
+ switch (tls_session->info.alert_level) {
+ case SSL3_AL_WARNING:
+ str_details1 = ", warning";
+ break;
+ case SSL3_AL_FATAL:
+ str_details1 = ", fatal";
+ break;
+ }
+
+ str_details2 = " ???";
+ details = "there is a failure inside the TLS protocol exchange";
+
+ switch (tls_session->info.alert_description) {
+ case SSL3_AD_CLOSE_NOTIFY:
+ str_details2 = " close_notify";
+ details = "the connection has been closed, and no further TLS exchanges will take place";
+ break;
+
+ case SSL3_AD_UNEXPECTED_MESSAGE:
+ str_details2 = " unexpected_message";
+ break;
+
+ case SSL3_AD_BAD_RECORD_MAC:
+ str_details2 = " bad_record_mac";
+ break;
+
+ case TLS1_AD_DECRYPTION_FAILED:
+ str_details2 = " decryption_failed";
+ break;
+
+ case TLS1_AD_RECORD_OVERFLOW:
+ str_details2 = " record_overflow";
+ break;
+
+ case SSL3_AD_DECOMPRESSION_FAILURE:
+ str_details2 = " decompression_failure";
+ break;
+
+ case SSL3_AD_HANDSHAKE_FAILURE:
+ str_details2 = " handshake_failure";
+ break;
+
+ case SSL3_AD_NO_CERTIFICATE:
+ str_details2 = " no_certificate";
+ details = "the server did not present a certificate to the client";
+ break;
+
+ case SSL3_AD_BAD_CERTIFICATE:
+ str_details2 = " bad_certificate";
+ details = "it believes the server certificate is invalid or malformed";
+ break;
+
+ case SSL3_AD_UNSUPPORTED_CERTIFICATE:
+ str_details2 = " unsupported_certificate";
+ details = "it does not understand the certificate presented by the server";
+ break;
+
+ case SSL3_AD_CERTIFICATE_REVOKED:
+ str_details2 = " certificate_revoked";
+ details = "it believes that the server certificate has been revoked";
+ break;
+
+ case SSL3_AD_CERTIFICATE_EXPIRED:
+ str_details2 = " certificate_expired";
+ details = "it believes that the server certificate has expired. Either renew the server certificate, or check the time on the client";
+ break;
+
+ case SSL3_AD_CERTIFICATE_UNKNOWN:
+ str_details2 = " certificate_unknown";
+ details = "it does not recognize the server certificate";
+ break;
+
+ case SSL3_AD_ILLEGAL_PARAMETER:
+ str_details2 = " illegal_parameter";
+ break;
+
+ case TLS1_AD_UNKNOWN_CA:
+ str_details2 = " unknown_ca";
+ details = "it does not recognize the CA used to issue the server certificate. Please update the client so that it knows about the CA";
+ break;
+
+ case TLS1_AD_ACCESS_DENIED:
+ str_details2 = " access_denied";
+ break;
+
+ case TLS1_AD_DECODE_ERROR:
+ str_details2 = " decode_error";
+ break;
+
+ case TLS1_AD_DECRYPT_ERROR:
+ str_details2 = " decrypt_error";
+ break;
+
+ case TLS1_AD_EXPORT_RESTRICTION:
+ str_details2 = " export_restriction";
+ break;
+
+ case TLS1_AD_PROTOCOL_VERSION:
+ str_details2 = " protocol_version";
+ details = "the client does not accept the version of TLS negotiated by the server";
+
+#ifdef TLS1_3_VERSION
+ /*
+ * Complain about OpenSSL bugs.
+ */
+ if ((SSL_version(tls_session->ssl) > tls_session->conf->max_version) &&
+ (rad_debug_lvl > 0)) {
+ WARN("TLS 1.3 has been negotiated even though it was disabled. This is an OpenSSL Bug.");
+ WARN("Please set: cipher_list = \"DEFAULT@SECLEVEL=1\" in the tls {...} section.");
+ }
+#endif
+ break;
+
+ case TLS1_AD_INSUFFICIENT_SECURITY:
+ str_details2 = " insufficient_security";
+ break;
+
+ case TLS1_AD_INTERNAL_ERROR:
+ str_details2 = " internal_error";
+ break;
+
+ case TLS1_AD_USER_CANCELLED:
+ str_details2 = " user_canceled";
+ break;
+
+ case TLS1_AD_NO_RENEGOTIATION:
+ str_details2 = " no_renegotiation";
+ break;
+
+#ifdef TLS13_AD_MISSING_EXTENSIONS
+ case TLS13_AD_MISSING_EXTENSIONS:
+ str_details2 = " missing_extensions";
+ details = "the server did not present a TLS extension which the client expected to be present. Please check the TLS libraries on the client and server for compatibility";
+ break;
+#endif
+
+#ifdef TLS13_AD_CERTIFICATE_REQUIRED
+ case TLS13_AD_CERTIFICATE_REQUIRED:
+ str_details2 = " certificate_required";
+ details = "the server did not present a certificate";
+ break;
+#endif
+
+#ifdef TLS1_AD_UNSUPPORTED_EXTENSION
+ case TLS1_AD_UNSUPPORTED_EXTENSION:
+ str_details2 = " unsupported_extension";
+ details = "the server has sent a TLS message which the client does not recognize. Please check the TLS libraries on the client and server for compatibility";
+ break;
+#endif
+
+#ifdef TLS1_AD_CERTIFICATE_UNOBTAINABLE
+ case TLS1_AD_CERTIFICATE_UNOBTAINABLE:
+ str_details2 = " certificate_unobtainable";
+ break;
+#endif
+
+#ifdef TLS1_AD_UNRECOGNIZED_NAME
+ case TLS1_AD_UNRECOGNIZED_NAME:
+ str_details2 = " unrecognized_name";
+ break;
+#endif
+
+#ifdef TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE
+ case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+ str_details2 = " bad_certificate_status_response";
+ break;
+#endif
+
+#ifdef TLS1_AD_BAD_CERTIFICATE_HASH_VALUE
+ case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE:
+ str_details2 = " bad_certificate_hash_value";
+ break;
+#endif
+
+#ifdef TLS1_AD_UNKNOWN_PSK_IDENTITY
+ case TLS1_AD_UNKNOWN_PSK_IDENTITY:
+ str_details2 = " unknown_psk_identity";
+ break;
+#endif
+
+#ifdef TLS1_AD_NO_APPLICATION_PROTOCOL
+ case TLS1_AD_NO_APPLICATION_PROTOCOL:
+ str_details2 = " no_application_protocol";
+ break;
+#endif
+ }
+ }
+ }
+
+ if (tls_session->info.content_type == SSL3_RT_HANDSHAKE) {
+ str_details1 = "";
+
+ if (tls_session->info.record_len > 0) switch (tls_session->info.handshake_type) {
+ case SSL3_MT_HELLO_REQUEST:
+ str_details1 = ", HelloRequest";
+ break;
+
+ case SSL3_MT_CLIENT_HELLO:
+ str_details1 = ", ClientHello";
+ break;
+
+ case SSL3_MT_SERVER_HELLO:
+ str_details1 = ", ServerHello";
+ break;
+
+#ifdef SSL3_MT_NEWSESSION_TICKET
+ case SSL3_MT_NEWSESSION_TICKET:
+ str_details1 = ", NewSessionTicket";
+ break;
+#endif
+
+#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS
+ case SSL3_MT_ENCRYPTED_EXTENSIONS:
+ str_details1 = ", EncryptedExtensions";
+ break;
+#endif
+
+ case SSL3_MT_CERTIFICATE:
+ str_details1 = ", Certificate";
+ break;
+
+ case SSL3_MT_SERVER_KEY_EXCHANGE:
+ str_details1 = ", ServerKeyExchange";
+ break;
+
+ case SSL3_MT_CERTIFICATE_REQUEST:
+ str_details1 = ", CertificateRequest";
+ break;
+
+ case SSL3_MT_SERVER_DONE:
+ str_details1 = ", ServerHelloDone";
+ break;
+
+ case SSL3_MT_CERTIFICATE_VERIFY:
+ str_details1 = ", CertificateVerify";
+ break;
+
+ case SSL3_MT_CLIENT_KEY_EXCHANGE:
+ str_details1 = ", ClientKeyExchange";
+ break;
+
+ case SSL3_MT_FINISHED:
+ str_details1 = ", Finished";
+ break;
+
+#ifdef SSL3_MT_KEY_UPDATE
+ case SSL3_MT_KEY_UPDATE:
+ str_content_type = "KeyUpdate";
+ break;
+#endif
+
+ default:
+ snprintf(alert_buf, sizeof(alert_buf), ", type=%d", tls_session->info.handshake_type);
+ str_details1 = alert_buf;
+ break;
+ }
+ }
+ }
+
+ snprintf(tls_session->info.info_description,
+ sizeof(tls_session->info.info_description),
+ "%s %s%s%s%s",
+ str_write_p, str_version, str_content_type,
+ str_details1, str_details2);
+
+ /*
+ * Cache the TLS session information in the session-state
+ * list, so it can be accessed by Post-Auth-Type
+ * Client-Lost { ... }
+ */
+ vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_SESSION_INFORMATION, 0);
+ if (vp) {
+ fr_pair_value_strcpy(vp, tls_session->info.info_description);
+ fr_pair_add(&request->state, vp);
+ }
+
+ RDEBUG2("%s", tls_session->info.info_description);
+
+ if (FROM_CLIENT && details) RDEBUG2("(TLS) The client is informing us that %s.", details);
+}
+
+static CONF_PARSER cache_config[] = {
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, session_cache_enable), "no" },
+
+ { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_lifetime), "24" },
+ { "name", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_id_name), NULL },
+
+ { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, session_cache_size), "255" },
+ { "persist_dir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_cache_path), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, session_cache_server), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER verify_config[] = {
+ { "skip_if_ocsp_ok", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, verify_skip_if_ocsp_ok), "no" },
+ { "tmpdir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_tmp_dir), NULL },
+ { "client", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, verify_client_cert_cmd), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+#ifdef HAVE_OPENSSL_OCSP_H
+static CONF_PARSER ocsp_config[] = {
+ { "enable", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_enable), "no" },
+ { "override_cert_url", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_override_url), "no" },
+ { "url", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ocsp_url), NULL },
+ { "use_nonce", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_use_nonce), "yes" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, ocsp_timeout), "yes" },
+ { "softfail", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, ocsp_softfail), "no" },
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+static CONF_PARSER tls_server_config[] = {
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "CA_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_path), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "CA_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, fr_tls_server_conf_t, ca_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
+#ifdef PSK_MAX_IDENTITY_LEN
+ { "psk_identity", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_identity), NULL },
+ { "psk_hexphrase", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, psk_password), NULL },
+ { "psk_query", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, psk_query), NULL },
+#endif
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "auto_chain", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, auto_chain), "yes" },
+ { "disable_single_dh_use", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_single_dh_use), NULL },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+#ifdef X509_V_FLAG_CRL_CHECK_ALL
+ { "check_all_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_all_crl), "no" },
+#endif
+ { "ca_path_reload_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, ca_path_reload_interval), "0" },
+ { "allow_expired_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, allow_expired_crl), NULL },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "cipher_server_preference", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, cipher_server_preference), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, require_client_cert), NULL },
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ { "sigalgs_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, sigalgs_list), NULL },
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ { "reject_unknown_intermediate_ca", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disallow_untrusted), .dflt = "no", },
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
+#endif
+#endif
+
+#ifdef SSL_OP_NO_TLSv1
+ { "disable_tlsv1", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1), NULL },
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_1
+ { "disable_tlsv1_1", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1_1), NULL },
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_2
+ { "disable_tlsv1_2", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1_2), NULL },
+#endif
+
+ { "tls_max_version", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, tls_max_version), NULL },
+
+ { "tls_min_version", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, tls_min_version),
+#if defined(TLS1_2_VERSION)
+ "1.2"
+#elif defined(TLS1_1_VERSION)
+ "1.1"
+#else
+ "1.0"
+#endif
+ },
+
+#ifdef WITH_RADIUSV11
+ { "radiusv1_1", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, radiusv11_name), NULL },
+#endif
+
+ { "realm_dir", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, realm_dir), NULL },
+
+ { "cache", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) cache_config },
+
+ { "verify", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) verify_config },
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ { "ocsp", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) ocsp_config },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+
+static CONF_PARSER tls_client_config[] = {
+ { "verify_depth", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, verify_depth), "0" },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_path), NULL },
+ { "pem_file_type", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, file_type), "yes" },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, private_key_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, certificate_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, fr_tls_server_conf_t, ca_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, fr_tls_server_conf_t, private_key_password), NULL },
+ { "dh_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, dh_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, random_file), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, fragment_size), "1024" },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, include_length), "yes" },
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, check_crl), "no" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_cn), NULL },
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, cipher_list), NULL },
+ { "check_cert_issuer", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, check_cert_issuer), NULL },
+ { "ca_path_reload_interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, fr_tls_server_conf_t, ca_path_reload_interval), "0" },
+
+ { "fix_cert_order", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, fix_cert_order), NULL },
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ { "ecdh_curve", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, ecdh_curve), "prime256v1" },
+#endif
+#endif
+
+#ifdef SSL_OP_NO_TLSv1
+ { "disable_tlsv1", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1), NULL },
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_1
+ { "disable_tlsv1_1", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1_1), NULL },
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_2
+ { "disable_tlsv1_2", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, fr_tls_server_conf_t, disable_tlsv1_2), NULL },
+#endif
+
+ { "tls_max_version", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, tls_max_version), NULL },
+
+ { "tls_min_version", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, tls_min_version),
+#if defined(TLS1_2_VERSION)
+ "1.2"
+#elif defined(TLS1_1_VERSION)
+ "1.1"
+#else
+ "1.0"
+#endif
+ },
+
+#ifdef WITH_RADIUSV11
+ { "radiusv1_1", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, radiusv11_name), NULL },
+#endif
+
+ { "hostname", FR_CONF_OFFSET(PW_TYPE_STRING, fr_tls_server_conf_t, client_hostname), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * TODO: Check for the type of key exchange * like conf->dh_key
+ */
+static int load_dh_params(SSL_CTX *ctx, char *file)
+{
+ DH *dh = NULL;
+ BIO *bio;
+
+ /*
+ * Prior to trying to load the file, check what OpenSSL will do with it.
+ *
+ * Certain downstreams (such as RHEL) will ignore user-provided dhparams
+ * in FIPS mode, unless the specified parameters are FIPS-approved.
+ * However, since OpenSSL >= 1.1.1 will automatically select parameters
+ * anyways, there's no point in attempting to load them.
+ *
+ * Change suggested by @t8m
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ if (FIPS_mode() > 0) {
+ WARN(LOG_PREFIX ": Ignoring user-selected DH parameters in FIPS mode. Using defaults.");
+ file = NULL;
+ }
+
+ /*
+ * No dh file, set auto context.
+ */
+ if (!file) {
+ if (!SSL_CTX_set_dh_auto(ctx, 1)) {
+ ERROR(LOG_PREFIX ": Unable to set DH parameters");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ WARN(LOG_PREFIX ": Setting DH parameters from %s - this is no longer necessary.", file);
+ WARN(LOG_PREFIX ": You should comment out the 'dh_file' configuration item.");
+
+#else
+ if (!file) {
+ WARN(LOG_PREFIX ": Cannot set DH parameters. DH cipher suites may not work.");
+ return 0;
+ }
+#endif
+
+
+ if ((bio = BIO_new_file(file, "r")) == NULL) {
+ ERROR(LOG_PREFIX ": Unable to open DH file - %s", file);
+ return -1;
+ }
+
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (!dh) {
+ WARN(LOG_PREFIX ": Unable to set DH parameters. DH cipher suites may not work!");
+ WARN(LOG_PREFIX ": Fix this by running the OpenSSL command listed in eap.conf");
+ return 0;
+ }
+
+ if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) {
+ ERROR(LOG_PREFIX ": Unable to set DH parameters");
+ DH_free(dh);
+ return -1;
+ }
+
+ DH_free(dh);
+ return 0;
+}
+
+
+/*
+ * Print debugging messages, and free data.
+ */
+static void cbtls_remove_session(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+ fr_tls_server_conf_t *conf;
+
+ tls_session_id(sess, buffer, MAX_SESSION_SIZE);
+
+ conf = (fr_tls_server_conf_t *)SSL_CTX_get_app_data(ctx);
+ if (!conf) {
+ DEBUG(LOG_PREFIX ": Failed to find TLS configuration in session");
+ return;
+ }
+
+ {
+ int rv;
+ char filename[3 * MAX_SESSION_SIZE + 1];
+
+ DEBUG2(LOG_PREFIX ": Removing session %s from the cache", buffer);
+
+ /* remove session and any cached VPs */
+ snprintf(filename, sizeof(filename), "%s%c%s.asn1",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ rv = unlink(filename);
+ if (rv != 0) {
+ DEBUG2(LOG_PREFIX ": Could not remove persisted session file %s: %s",
+ filename, fr_syserror(errno));
+ }
+ /* VPs might be absent; might not have been written to disk yet */
+ snprintf(filename, sizeof(filename), "%s%c%s.vps",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ unlink(filename);
+ }
+
+ return;
+}
+
+static int cbtls_new_session(SSL *ssl, SSL_SESSION *sess)
+{
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+ fr_tls_server_conf_t *conf;
+ unsigned char *sess_blob = NULL;
+
+ REQUEST *request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) {
+ RWDEBUG("(TLS) Failed to find TLS configuration in session");
+ return 0;
+ }
+
+ tls_session_id(sess, buffer, MAX_SESSION_SIZE);
+
+ {
+ int fd, rv, todo, blob_len;
+ char filename[3 * MAX_SESSION_SIZE + 1];
+ unsigned char *p;
+
+ RDEBUG2("Serialising session %s, and storing in cache", buffer);
+
+ /* find out what length data we need */
+ blob_len = i2d_SSL_SESSION(sess, NULL);
+ if (blob_len < 1) {
+ /* something went wrong */
+ if (request) RWDEBUG("(TLS) Session serialisation failed, could not determine required buffer length");
+ return 0;
+ }
+
+ /* Do not convert to TALLOC - Thread safety */
+ /* alloc and convert to ASN.1 */
+ sess_blob = malloc(blob_len);
+ if (!sess_blob) {
+ RWDEBUG("(TLS) Session serialisation failed, couldn't allocate buffer (%d bytes)", blob_len);
+ return 0;
+ }
+ /* openssl mutates &p */
+ p = sess_blob;
+ rv = i2d_SSL_SESSION(sess, &p);
+ if (rv != blob_len) {
+ if (request) RWDEBUG("(TLS) Session serialisation failed");
+ goto error;
+ }
+
+ /* open output file */
+ snprintf(filename, sizeof(filename), "%s%c%s.asn1",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ fd = open(filename, O_RDWR|O_CREAT|O_EXCL, S_IWUSR);
+ if (fd < 0) {
+ if (request) RERROR("(TLS) Session serialisation failed, failed opening session file %s: %s",
+ filename, fr_syserror(errno));
+ goto error;
+ }
+
+ /*
+ * Set the filename to be temporarily write-only.
+ */
+ if (request) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_CACHE_FILENAME, 0);
+ if (vp) {
+ fr_pair_value_strcpy(vp, filename);
+ fr_pair_add(&request->state, vp);
+ }
+ }
+
+ todo = blob_len;
+ p = sess_blob;
+ while (todo > 0) {
+ rv = write(fd, p, todo);
+ if (rv < 1) {
+ if (request) RWDEBUG("(TLS) Failed writing session: %s", fr_syserror(errno));
+ close(fd);
+ goto error;
+ }
+ p += rv;
+ todo -= rv;
+ }
+ close(fd);
+ if (request) RWDEBUG("(TLS) Wrote session %s to %s (%d bytes)", buffer, filename, blob_len);
+ }
+
+error:
+ free(sess_blob);
+
+ return 0;
+}
+
+/** Convert OpenSSL's ASN1_TIME to an epoch time
+ *
+ * @param[out] out Where to write the time_t.
+ * @param[in] asn1 The ASN1_TIME to convert.
+ * @return
+ * - 0 success.
+ * - -1 on failure.
+ */
+static int ocsp_asn1time_to_epoch(time_t *out, char const *asn1)
+{
+ struct tm t;
+ char const *p = asn1, *end = p + strlen(p);
+
+ memset(&t, 0, sizeof(t));
+
+ if ((end - p) <= 13) {
+ if ((end - p) < 2) {
+ fr_strerror_printf("ASN1 date string too short, expected 2 additional bytes, got %zu bytes",
+ end - p);
+ return -1;
+ }
+
+ t.tm_year = (*(p++) - '0') * 10;
+ t.tm_year += (*(p++) - '0');
+ if (t.tm_year < 70) t.tm_year += 100;
+ } else {
+ t.tm_year = (*(p++) - '0') * 1000;
+ t.tm_year += (*(p++) - '0') * 100;
+ t.tm_year += (*(p++) - '0') * 10;
+ t.tm_year += (*(p++) - '0');
+ t.tm_year -= 1900;
+ }
+
+ if ((end - p) < 4) {
+ fr_strerror_printf("ASN1 string too short, expected 10 additional bytes, got %zu bytes",
+ end - p);
+ return -1;
+ }
+
+ t.tm_mon = (*(p++) - '0') * 10;
+ t.tm_mon += (*(p++) - '0') - 1; // -1 since January is 0 not 1.
+ t.tm_mday = (*(p++) - '0') * 10;
+ t.tm_mday += (*(p++) - '0');
+
+ if ((end - p) < 2) goto done;
+ t.tm_hour = (*(p++) - '0') * 10;
+ t.tm_hour += (*(p++) - '0');
+
+ if ((end - p) < 2) goto done;
+ t.tm_min = (*(p++) - '0') * 10;
+ t.tm_min += (*(p++) - '0');
+
+ if ((end - p) < 2) goto done;
+ t.tm_sec = (*(p++) - '0') * 10;
+ t.tm_sec += (*(p++) - '0');
+
+ /* Apparently OpenSSL converts all timestamps to UTC? Maybe? */
+done:
+ *out = timegm(&t);
+ return 0;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+static SSL_SESSION *cbtls_get_session(SSL *ssl, unsigned char *data, int len, int *copy)
+#else
+static SSL_SESSION *cbtls_get_session(SSL *ssl, const unsigned char *data, int len, int *copy)
+#endif
+{
+ size_t size;
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+ fr_tls_server_conf_t *conf;
+ TALLOC_CTX *talloc_ctx;
+
+ SSL_SESSION *sess = NULL;
+ unsigned char *sess_data = NULL;
+ PAIR_LIST *pairlist = NULL;
+
+ REQUEST *request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+
+ rad_assert(request != NULL);
+
+ size = len;
+ if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
+
+ fr_bin2hex(buffer, data, size);
+
+ RDEBUG2("Peer requested cached session: %s", buffer);
+
+ *copy = 0;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) {
+ RWDEBUG("(TLS) Failed to find TLS configuration in session");
+ return NULL;
+ }
+
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
+
+ {
+ int rv, fd, todo;
+ char filename[3 * MAX_SESSION_SIZE + 1];
+
+ unsigned char const **o;
+ unsigned char **p;
+ uint8_t *q;
+
+ struct stat st;
+ VALUE_PAIR *vps = NULL;
+ VALUE_PAIR *vp;
+
+ /* load the actual SSL session */
+ snprintf(filename, sizeof(filename), "%s%c%s.asn1", conf->session_cache_path, FR_DIR_SEP, buffer);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ RWDEBUG("(TLS) No persisted session file %s: %s", filename, fr_syserror(errno));
+ goto error;
+ }
+
+ rv = fstat(fd, &st);
+ if (rv < 0) {
+ RWDEBUG("(TLS) Failed stating persisted session file %s: %s", filename, fr_syserror(errno));
+ close(fd);
+ goto error;
+ }
+
+ sess_data = talloc_array(NULL, unsigned char, st.st_size);
+ if (!sess_data) {
+ RWDEBUG("(TLS) Failed allocating buffer for persisted session (%d bytes)", (int) st.st_size);
+ close(fd);
+ goto error;
+ }
+
+ q = sess_data;
+ todo = st.st_size;
+ while (todo > 0) {
+ rv = read(fd, q, todo);
+ if (rv < 1) {
+ RWDEBUG("(TLS) Failed reading persisted session: %s", fr_syserror(errno));
+ close(fd);
+ goto error;
+ }
+ todo -= rv;
+ q += rv;
+ }
+ close(fd);
+
+ /*
+ * OpenSSL mutates what's passed in, so we assign sess_data to q,
+ * so the value of q gets mutated, and not the value of sess_data.
+ *
+ * We then need a pointer to hold &q, but it can't be const, because
+ * clang complains about lack of consting in nested pointer types.
+ *
+ * So we memcpy the value of that pointer, to one that
+ * does have a const, which we then pass into d2i_SSL_SESSION *sigh*.
+ */
+ q = sess_data;
+ p = &q;
+ memcpy(&o, &p, sizeof(o));
+ sess = d2i_SSL_SESSION(NULL, o, st.st_size);
+ if (!sess) {
+ RWDEBUG("(TLS) Failed loading persisted session: %s", ERR_error_string(ERR_get_error(), NULL));
+ goto error;
+ }
+
+ /* read in the cached VPs from the .vps file */
+ snprintf(filename, sizeof(filename), "%s%c%s.vps",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ rv = pairlist_read(talloc_ctx, filename, &pairlist, 1);
+ if (rv < 0) {
+ /* not safe to un-persist a session w/o VPs */
+ RWDEBUG("(TLS) Failed loading persisted VPs for session %s", buffer);
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ goto error;
+ }
+
+ /*
+ * Enforce client certificate expiration.
+ */
+ vp = fr_pair_find_by_num(pairlist->reply, PW_TLS_CLIENT_CERT_EXPIRATION, 0, TAG_ANY);
+ if (vp) {
+ time_t expires;
+
+ if (ocsp_asn1time_to_epoch(&expires, vp->vp_strvalue) < 0) {
+ RDEBUG2("Failed getting certificate expiration, removing cache entry for session %s - %s", buffer, fr_strerror());
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ goto error;
+ }
+
+ if (expires <= request->timestamp) {
+ RDEBUG2("Certificate has expired, removing cache entry for session %s", buffer);
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ goto error;
+ }
+
+ /*
+ * Account for Session-Timeout, if it's available.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (vp) {
+ if ((request->timestamp + vp->vp_integer) > expires) {
+ vp->vp_integer = expires - request->timestamp;
+ RWDEBUG2("(TLS) Updating Session-Timeout to %u, due to impending certificate expiration",
+ vp->vp_integer);
+ }
+ }
+ }
+
+ /*
+ * Resumption MUST use the same EAP type as from
+ * the original packet.
+ */
+ vp = fr_pair_find_by_num(pairlist->reply, PW_EAP_TYPE, 0, TAG_ANY);
+ if (vp) {
+ VALUE_PAIR *type = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY);
+
+ if (type && (type->vp_integer != vp->vp_integer)) {
+ REDEBUG("Resumption has changed EAP types for session %s", buffer);
+ REDEBUG("Rejecting session due to protocol violations");
+ goto error;
+ }
+ }
+
+ /* move the cached VPs into the session */
+ fr_pair_list_mcopy_by_num(talloc_ctx, &vps, &pairlist->reply, 0, 0, TAG_ANY);
+
+ SSL_SESSION_set_ex_data(sess, fr_tls_ex_index_vps, vps);
+ RDEBUG("Successfully restored session %s", buffer);
+ rdebug_pair_list(L_DBG_LVL_2, request, vps, "reply:");
+
+ /*
+ * The "restore VPs from OpenSSL cache" code is
+ * now in eaptls_process()
+ */
+ }
+error:
+ if (sess_data) talloc_free(sess_data);
+ if (pairlist) pairlist_free(&pairlist);
+
+ return sess;
+}
+
+static size_t tls_session_id_binary(SSL_SESSION *ssn, uint8_t *buffer, size_t bufsize)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+ size_t size;
+
+ size = ssn->session_id_length;
+ if (size > bufsize) size = bufsize;
+
+ memcpy(buffer, ssn->session_id, size);
+ return size;
+#else
+ unsigned int size;
+ uint8_t const *p;
+
+ p = SSL_SESSION_get_id(ssn, &size);
+ if (size > bufsize) size = bufsize;
+
+ memcpy(buffer, p, size);
+ return size;
+#endif
+}
+
+/*
+ * From TLS-Cache-Method
+ *
+ * All of the save / clear / load callbacks are done with any
+ * OpenSSL locks *unlocked*. So says the OpenSSL code.
+ */
+#define CACHE_SAVE (1)
+#define CACHE_LOAD (2)
+#define CACHE_CLEAR (3)
+#define CACHE_REFRESH (4)
+
+static REQUEST *cache_init_fake_request(fr_tls_server_conf_t const *conf, SSL_SESSION *sess, SSL *ssl,
+ uint8_t const *data, size_t size)
+{
+ VALUE_PAIR *vp;
+ REQUEST *fake, *request = NULL;
+ uint8_t buffer[MAX_SESSION_SIZE];
+
+ if (sess) {
+ size = tls_session_id_binary(sess, buffer, sizeof(buffer));
+ data = buffer;
+ }
+
+ /*
+ * We get called essentially at random by OpenSSL, with
+ * no information other than the session ID. As a
+ * result, we have to manually set up our own request.
+ */
+ if (ssl) request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+
+ if (request) {
+ fake = request_alloc_fake(request);
+ } else {
+ fake = request_alloc(NULL);
+ fake->packet = rad_alloc(fake, false);
+ fake->reply = rad_alloc(fake, false);
+ }
+
+ vp = fr_pair_afrom_num(fake->packet, PW_TLS_SESSION_ID, 0);
+ if (!vp) {
+ talloc_free(fake);
+ return NULL;
+ }
+
+ fr_pair_value_memcpy(vp, data, size);
+ fr_pair_add(&fake->packet->vps, vp);
+
+ fake->server = conf->session_cache_server;
+
+ return fake;
+}
+
+/*
+ * Clear cached data
+ */
+static void cbtls_cache_clear(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ fr_tls_server_conf_t *conf;
+ REQUEST *fake;
+
+ conf = (fr_tls_server_conf_t *)SSL_CTX_get_app_data(ctx);
+ if (!conf) {
+ DEBUG(LOG_PREFIX ": Failed to find TLS configuration in session");
+ return;
+ }
+
+ /*
+ * Find the SSL ID from the session, and delete it.
+ *
+ * Don't bother with any parent request. We're in a
+ * timer callback, and there is no request available.
+ */
+ fake = cache_init_fake_request(conf, sess, NULL, NULL, 0);
+ if (!fake) return;
+
+ /*
+ * Use &request:TLS-Session-Id to clear the cache entry.
+ */
+ (void) process_post_auth(CACHE_CLEAR, fake);
+ talloc_free(fake);
+ return;
+}
+
+/*
+ * OpenSSL calls this function in order to save the session
+ * BEFORE it has sent the final TLS success. So our process here
+ * is to say "yes, we saved it", and then do the *actual* saving
+ * after the TLS success has been sent.
+ */
+static int cbtls_cache_save(UNUSED SSL *ssl, UNUSED SSL_SESSION *sess)
+{
+ return 0;
+}
+
+static int cbtls_cache_save_vps(SSL *ssl, SSL_SESSION *sess, VALUE_PAIR *vps)
+{
+ fr_tls_server_conf_t *conf;
+ VALUE_PAIR *vp;
+ REQUEST *fake = NULL;
+ size_t size, rv;
+ uint8_t *p, *sess_blob = NULL;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 0;
+
+ /*
+ * Find the SSL ID from the session, and save it.
+ *
+ * Save anything from the parent request.
+ */
+ fake = cache_init_fake_request(conf, sess, ssl, NULL, 0);
+ if (!fake) return 0;
+
+ /* find out what length data we need */
+ size = i2d_SSL_SESSION(sess, NULL);
+ if (size < 1) return 0;
+
+ /* Do not convert to TALLOC - it's passed to OpenSSL */
+ /* alloc and convert to ASN.1 */
+ MEM(sess_blob = malloc(size));
+
+ /* openssl mutates &p */
+ p = sess_blob;
+ rv = i2d_SSL_SESSION(sess, &p);
+ if (rv != size) goto error;
+
+ vp = fr_pair_afrom_num(fake->state_ctx, PW_TLS_SESSION_DATA, 0);
+ if (!vp) goto error;
+
+ fr_pair_value_memcpy(vp, sess_blob, size);
+ fr_pair_add(&fake->state, vp);
+
+ if (vps) fr_pair_add(&fake->reply->vps, fr_pair_list_copy(fake->reply, vps));
+
+ /*
+ * Use &request:TLS-Session-Id to save the
+ * &session-state:TLS-Session-Data values.
+ *
+ * The current &reply: list is the list of VPs which
+ * should be cached.
+ *
+ * Any other attributes which need to be saved can be
+ * read from the &outer.reply: list.
+ */
+ (void) process_post_auth(CACHE_SAVE, fake);
+
+error:
+ if (fake) talloc_free(fake);
+ free(sess_blob);
+
+ return 0;
+}
+
+static int cbtls_cache_refresh(SSL *ssl, SSL_SESSION *sess)
+{
+ fr_tls_server_conf_t *conf;
+ REQUEST *fake = NULL;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 0;
+
+ /*
+ * Find the SSL ID from the session, and save it.
+ *
+ * Save anything from the parent request.
+ */
+ fake = cache_init_fake_request(conf, sess, ssl, NULL, 0);
+ if (!fake) return 0;
+ /*
+ * Use &request:TLS-Session-Id to update the cache
+ * entry so that it doesn't not expire.
+ */
+ (void) process_post_auth(CACHE_REFRESH, fake);
+
+ talloc_free(fake);
+
+ return 0;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+static SSL_SESSION *cbtls_cache_load(SSL *ssl, unsigned char *data, int len, int *copy)
+#else
+static SSL_SESSION *cbtls_cache_load(SSL *ssl, const unsigned char *data, int len, int *copy)
+#endif
+{
+ fr_tls_server_conf_t *conf;
+ size_t size;
+ uint8_t const *p;
+ VALUE_PAIR *vp, *vps;
+ TALLOC_CTX *talloc_ctx;
+ SSL_SESSION *sess = NULL;
+ REQUEST *fake = NULL;
+ REQUEST *request = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) return NULL;
+
+ rad_assert(request);
+
+ size = len;
+ if (size > MAX_SESSION_SIZE) size = MAX_SESSION_SIZE;
+
+ if (fr_debug_lvl > 1) {
+ fr_bin2hex(buffer, data, size);
+ RDEBUG2("Peer requested cached session: %s", buffer);
+ }
+
+ *copy = 0;
+
+ /*
+ * Take the given SSL ID, and create a fake request.
+ *
+ * Don't bother parenting it from another request. We do
+ * this for a number of reasons.
+ *
+ * One is that rest of the code expects that the VPs will
+ * be added to fr_tls_ex_index_vps. So we don't want to
+ * be poking the request directly, as that will result in
+ * a change of behavior.
+ *
+ * The larger reason is that we do _not_ want to actually
+ * update the reply, until such time as we know that the
+ * user has been authenticated.
+ */
+ fake = cache_init_fake_request(conf, NULL, NULL, data, size);
+ if (!fake) return 0;
+
+ /*
+ * Use &request:TLS-Session-Id to load the cached
+ * session.
+ *
+ * The "cache load { ...}" section should put the reply
+ * attributes into the &reply: list, and the
+ * &session-state:TLS-Session-Data attribute.
+ *
+ * Why? Because v4 does it that way, and there aren't
+ * really good reasons for doing it differently.
+ */
+ (void) process_post_auth(CACHE_LOAD, fake);
+
+ /*
+ * Enforce client certificate expiration.
+ */
+ vp = fr_pair_find_by_num(fake->reply->vps, PW_TLS_CLIENT_CERT_EXPIRATION, 0, TAG_ANY);
+ if (vp) {
+ time_t expires;
+
+ if (ocsp_asn1time_to_epoch(&expires, vp->vp_strvalue) < 0) {
+ RDEBUG2("Failed getting certificate expiration, removing cache entry for session %s - %s", buffer, fr_strerror());
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ goto error;
+ }
+
+ if (expires <= request->timestamp) {
+ RDEBUG2("Certificate has expired, removing cache entry for session %s", buffer);
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ goto error;
+ }
+
+ /*
+ * Account for Session-Timeout, if it's available.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (vp) {
+ if ((request->timestamp + vp->vp_integer) > expires) {
+ vp->vp_integer = expires - request->timestamp;
+ RWDEBUG2("(TLS) Updating Session-Timeout to %u, due to impending certificate expiration",
+ vp->vp_integer);
+ }
+ }
+ }
+
+ /*
+ * Try to de-serialize the session data.
+ */
+ vp = fr_pair_find_by_num(fake->state, PW_TLS_SESSION_DATA, 0, TAG_ANY);
+ if (!vp) {
+ RWDEBUG("(TLS) Failed to find TLS-Session-Data in 'session-state' list for session %s", buffer);
+ goto error;
+ }
+
+ /*
+ * OpenSSL mutates what's passed in, so we assign sess_data to q,
+ * so the value of q gets mutated, and not the value of sess_data.
+ *
+ * We then need a pointer to hold &q, but it can't be const, because
+ * clang complains about lack of consting in nested pointer types.
+ *
+ * So we memcpy the value of that pointer, to one that
+ * does have a const, which we then pass into d2i_SSL_SESSION *sigh*.
+ */
+ p = vp->vp_octets;
+ sess = d2i_SSL_SESSION(NULL, &p, vp->vp_length);
+ if (!sess) {
+ RWDEBUG("(TLS) Failed loading persisted session: %s", ERR_error_string(ERR_get_error(), NULL));
+ goto error;
+ }
+
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
+ vps = NULL;
+
+ /* move the cached VPs into the session */
+ fr_pair_list_mcopy_by_num(talloc_ctx, &vps, &fake->reply->vps, 0, 0, TAG_ANY);
+
+ SSL_SESSION_set_ex_data(sess, fr_tls_ex_index_vps, vps);
+ RDEBUG("Successfully restored session %s", buffer);
+ rdebug_pair_list(L_DBG_LVL_2, request, vps, "reply:");
+
+ /*
+ * The "restore VPs from OpenSSL cache" code is
+ * now in eaptls_process()
+ */
+
+error:
+ if (fake) talloc_free(fake);
+
+ return sess;
+}
+
+#ifdef HAVE_OPENSSL_OCSP_H
+
+/** Extract components of OCSP responser URL from a certificate
+ *
+ * @param[in] cert to extract URL from.
+ * @param[out] host_out Portion of the URL (must be freed with free()).
+ * @param[out] port_out Port portion of the URL (must be freed with free()).
+ * @param[out] path_out Path portion of the URL (must be freed with free()).
+ * @param[out] is_https Whether the responder should be contacted using https.
+ * @return
+ * - 0 if no valid URL is contained in the certificate.
+ * - 1 if a URL was found and parsed.
+ * - -1 if at least one URL was found, but none could be parsed.
+ */
+static int ocsp_parse_cert_url(X509 *cert, char **host_out, char **port_out,
+ char **path_out, int *is_https)
+{
+ int i;
+ bool found_uri = false;
+
+ AUTHORITY_INFO_ACCESS *aia;
+ ACCESS_DESCRIPTION *ad;
+
+ aia = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL);
+
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) {
+ ad = sk_ACCESS_DESCRIPTION_value(aia, i);
+ if (OBJ_obj2nid(ad->method) != NID_ad_OCSP) continue;
+ if (ad->location->type != GEN_URI) continue;
+ found_uri = true;
+
+ if (OCSP_parse_url((char *) ad->location->d.ia5->data, host_out,
+ port_out, path_out, is_https)) return 1;
+ }
+ return found_uri ? -1 : 0;
+}
+
+/*
+ * This function sends a OCSP request to a defined OCSP responder
+ * and checks the OCSP response for correctness.
+ */
+
+/* Maximum leeway in validity period: default 5 minutes */
+#define MAX_VALIDITY_PERIOD (5 * 60)
+
+typedef enum {
+ OCSP_STATUS_FAILED = 0,
+ OCSP_STATUS_OK = 1,
+ OCSP_STATUS_SKIPPED = 2,
+} ocsp_status_t;
+
+static ocsp_status_t ocsp_check(REQUEST *request, X509_STORE *store, X509 *issuer_cert, X509 *client_cert,
+ fr_tls_server_conf_t *conf)
+{
+ OCSP_CERTID *certid;
+ OCSP_REQUEST *req;
+ OCSP_RESPONSE *resp = NULL;
+ OCSP_BASICRESP *bresp = NULL;
+ char *host = NULL;
+ char *port = NULL;
+ char *path = NULL;
+ char hostheader[1024];
+ int use_ssl = -1;
+ long nsec = MAX_VALIDITY_PERIOD, maxage = -1;
+ BIO *cbio, *bio_out;
+ ocsp_status_t ocsp_status = OCSP_STATUS_FAILED;
+ int status;
+ ASN1_GENERALIZEDTIME *rev = NULL, *thisupd, *nextupd;
+ int reason;
+#if OPENSSL_VERSION_NUMBER >= 0x1000003f
+ OCSP_REQ_CTX *ctx;
+ int rc;
+ struct timeval now;
+ struct timeval when;
+#endif
+ VALUE_PAIR *vp;
+
+ if (issuer_cert == NULL) {
+ RWDEBUG("(TLS) Could not get issuer certificate");
+ goto skipped;
+ }
+
+ /*
+ * Create OCSP Request
+ */
+ certid = OCSP_cert_to_id(NULL, client_cert, issuer_cert);
+ req = OCSP_REQUEST_new();
+ OCSP_request_add0_id(req, certid);
+ if (conf->ocsp_use_nonce) OCSP_request_add1_nonce(req, NULL, 8);
+
+ /*
+ * Send OCSP Request and get OCSP Response
+ */
+
+ /* Get OCSP responder URL */
+ if (conf->ocsp_override_url) {
+ char *url;
+
+ use_ocsp_url:
+ memcpy(&url, &conf->ocsp_url, sizeof(url));
+ /* Reading the libssl src, they do a strdup on the URL, so it could of been const *sigh* */
+ OCSP_parse_url(url, &host, &port, &path, &use_ssl);
+ if (!host || !port || !path) {
+ RWDEBUG("(TLS) ocsp: Host or port or path missing from configured URL \"%s\". Not doing OCSP", url);
+ goto skipped;
+ }
+ } else {
+ int ret;
+
+ ret = ocsp_parse_cert_url(client_cert, &host, &port, &path, &use_ssl);
+ switch (ret) {
+ case -1:
+ RWDEBUG("(TLS) ocsp: Invalid URL in certificate. Not doing OCSP");
+ break;
+
+ case 0:
+ if (conf->ocsp_url) {
+ RWDEBUG("(TLS) ocsp: No OCSP URL in certificate, falling back to configured URL");
+ goto use_ocsp_url;
+ }
+ RWDEBUG("(TLS) ocsp: No OCSP URL in certificate. Not doing OCSP");
+ goto skipped;
+
+ case 1:
+ break;
+ }
+ }
+
+ RDEBUG2("ocsp: Using responder URL \"http://%s:%s%s\"", host, port, path);
+
+ /* Check host and port length are sane, then create Host: HTTP header */
+ if ((strlen(host) + strlen(port) + 2) > sizeof(hostheader)) {
+ RWDEBUG("(TLS) ocsp: Host and port too long");
+ goto skipped;
+ }
+ snprintf(hostheader, sizeof(hostheader), "%s:%s", host, port);
+
+ /* Setup BIO socket to OCSP responder */
+ cbio = BIO_new_connect(host);
+
+ bio_out = NULL;
+ if (rad_debug_lvl) {
+ if (default_log.dst == L_DST_STDOUT) {
+ bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
+ } else if (default_log.dst == L_DST_STDERR) {
+ bio_out = BIO_new_fp(stderr, BIO_NOCLOSE);
+ }
+ }
+
+ BIO_set_conn_port(cbio, port);
+#if OPENSSL_VERSION_NUMBER < 0x1000003f
+ BIO_do_connect(cbio);
+
+ /* Send OCSP request and wait for response */
+ resp = OCSP_sendreq_bio(cbio, path, req);
+ if (!resp) {
+ REDEBUG("ocsp: Couldn't get OCSP response");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+#else
+ if (conf->ocsp_timeout)
+ BIO_set_nbio(cbio, 1);
+
+ rc = BIO_do_connect(cbio);
+ if ((rc <= 0) && ((!conf->ocsp_timeout) || !BIO_should_retry(cbio))) {
+ REDEBUG("ocsp: Couldn't connect to OCSP responder");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+
+ ctx = OCSP_sendreq_new(cbio, path, NULL, -1);
+ if (!ctx) {
+ REDEBUG("ocsp: Couldn't create OCSP request");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+
+ if (!OCSP_REQ_CTX_add1_header(ctx, "Host", hostheader)) {
+ REDEBUG("ocsp: Couldn't set Host header");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+
+ if (!OCSP_REQ_CTX_set1_req(ctx, req)) {
+ REDEBUG("ocsp: Couldn't add data to OCSP request");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+
+ gettimeofday(&when, NULL);
+ when.tv_sec += conf->ocsp_timeout;
+
+ do {
+ rc = OCSP_sendreq_nbio(&resp, ctx);
+ if (conf->ocsp_timeout) {
+ gettimeofday(&now, NULL);
+ if (!timercmp(&now, &when, <))
+ break;
+ }
+ } while ((rc == -1) && BIO_should_retry(cbio));
+
+ if (conf->ocsp_timeout && (rc == -1) && BIO_should_retry(cbio)) {
+ REDEBUG("ocsp: Response timed out");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+
+ OCSP_REQ_CTX_free(ctx);
+
+ if (rc == 0) {
+ REDEBUG("ocsp: Couldn't get OCSP response");
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ goto ocsp_end;
+ }
+#endif
+
+ /* Verify OCSP response status */
+ status = OCSP_response_status(resp);
+ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ REDEBUG("ocsp: Response status: %s", OCSP_response_status_str(status));
+ goto ocsp_end;
+ }
+ bresp = OCSP_response_get1_basic(resp);
+ if (!bresp) {
+ RDEBUG("ocsp: Failed parsing response");
+ goto ocsp_end;
+ }
+
+ if (conf->ocsp_use_nonce && OCSP_check_nonce(req, bresp)!=1) {
+ REDEBUG("ocsp: Response has wrong nonce value");
+ goto ocsp_end;
+ }
+ if (OCSP_basic_verify(bresp, NULL, store, 0)!=1){
+ REDEBUG("ocsp: Couldn't verify OCSP basic response");
+ goto ocsp_end;
+ }
+
+ /* Verify OCSP cert status */
+ if (!OCSP_resp_find_status(bresp, certid, &status, &reason, &rev, &thisupd, &nextupd)) {
+ REDEBUG("ocsp: No Status found");
+ goto ocsp_end;
+ }
+
+ if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) {
+ if (bio_out) {
+ BIO_puts(bio_out, "WARNING: Status times invalid.\n");
+ ERR_print_errors(bio_out);
+ }
+ goto ocsp_end;
+ }
+
+ if (bio_out) {
+ BIO_puts(bio_out, "\tThis Update: ");
+ ASN1_GENERALIZEDTIME_print(bio_out, thisupd);
+ BIO_puts(bio_out, "\n");
+ if (nextupd) {
+ BIO_puts(bio_out, "\tNext Update: ");
+ ASN1_GENERALIZEDTIME_print(bio_out, nextupd);
+ BIO_puts(bio_out, "\n");
+ }
+ }
+
+ switch (status) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ RDEBUG2("ocsp: Cert status: good");
+ vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+ vp->vp_integer = 1; /* yes */
+ ocsp_status = OCSP_STATUS_OK;
+ break;
+
+ default:
+ /* REVOKED / UNKNOWN */
+ REDEBUG("ocsp: Cert status: %s", OCSP_cert_status_str(status));
+ if (reason != -1) REDEBUG("ocsp: Reason: %s", OCSP_crl_reason_str(reason));
+
+ if (bio_out && rev) {
+ BIO_puts(bio_out, "\tRevocation Time: ");
+ ASN1_GENERALIZEDTIME_print(bio_out, rev);
+ BIO_puts(bio_out, "\n");
+ }
+ break;
+ }
+
+ocsp_end:
+ /* Free OCSP Stuff */
+ OCSP_REQUEST_free(req);
+ OCSP_RESPONSE_free(resp);
+ free(host);
+ free(port);
+ free(path);
+ BIO_free_all(cbio);
+ if (bio_out) BIO_free(bio_out);
+ OCSP_BASICRESP_free(bresp);
+
+ switch (ocsp_status) {
+ case OCSP_STATUS_OK:
+ RDEBUG2("ocsp: Certificate is valid");
+ break;
+
+ case OCSP_STATUS_SKIPPED:
+ skipped:
+ vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+ vp->vp_integer = 2; /* skipped */
+ if (conf->ocsp_softfail) {
+ RWDEBUG("(TLS) ocsp: Unable to check certificate, assuming it's valid");
+ RWDEBUG("(TLS) ocsp: This may be insecure");
+
+ /* Remove OpenSSL errors from queue or handshake will fail */
+ while (ERR_get_error());
+
+ ocsp_status = OCSP_STATUS_SKIPPED;
+ } else {
+ REDEBUG("(TLS) ocsp: Unable to check certificate, failing");
+ ocsp_status = OCSP_STATUS_FAILED;
+ }
+ break;
+
+ default:
+ vp = pair_make_request("TLS-OCSP-Cert-Valid", NULL, T_OP_SET);
+ vp->vp_integer = 0; /* no */
+ REDEBUG("(TLS) ocsp: Certificate has been expired/revoked");
+ break;
+ }
+
+ return ocsp_status;
+}
+#endif /* HAVE_OPENSSL_OCSP_H */
+
+/*
+ * For creating certificate attributes.
+ */
+static char const *cert_attr_names[9][2] = {
+ { "TLS-Client-Cert-Serial", "TLS-Cert-Serial" },
+ { "TLS-Client-Cert-Expiration", "TLS-Cert-Expiration" },
+ { "TLS-Client-Cert-Subject", "TLS-Cert-Subject" },
+ { "TLS-Client-Cert-Issuer", "TLS-Cert-Issuer" },
+ { "TLS-Client-Cert-Common-Name", "TLS-Cert-Common-Name" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Email", "TLS-Cert-Subject-Alt-Name-Email" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Dns", "TLS-Cert-Subject-Alt-Name-Dns" },
+ { "TLS-Client-Cert-Subject-Alt-Name-Upn", "TLS-Cert-Subject-Alt-Name-Upn" },
+ { "TLS-Client-Cert-Valid-Since", "TLS-Cert-Valid-Since" }
+};
+
+#define FR_TLS_SERIAL (0)
+#define FR_TLS_EXPIRATION (1)
+#define FR_TLS_SUBJECT (2)
+#define FR_TLS_ISSUER (3)
+#define FR_TLS_CN (4)
+#define FR_TLS_SAN_EMAIL (5)
+#define FR_TLS_SAN_DNS (6)
+#define FR_TLS_SAN_UPN (7)
+#define FR_TLS_VALID_SINCE (8)
+
+static const char *cert_names[2] = {
+ "client", "server",
+};
+
+/*
+ * Before trusting a certificate, you must make sure that the
+ * certificate is 'valid'. There are several steps that your
+ * application can take in determining if a certificate is
+ * valid. Commonly used steps are:
+ *
+ * 1.Verifying the certificate's signature, and verifying that
+ * the certificate has been issued by a trusted Certificate
+ * Authority.
+ *
+ * 2.Verifying that the certificate is valid for the present date
+ * (i.e. it is being presented within its validity dates).
+ *
+ * 3.Verifying that the certificate has not been revoked by its
+ * issuing Certificate Authority, by checking with respect to a
+ * Certificate Revocation List (CRL).
+ *
+ * 4.Verifying that the credentials presented by the certificate
+ * fulfill additional requirements specific to the application,
+ * such as with respect to access control lists or with respect
+ * to OCSP (Online Certificate Status Processing).
+ *
+ * NOTE: This callback will be called multiple times based on the
+ * depth of the root certificate chain
+ */
+int cbtls_verify(int ok, X509_STORE_CTX *ctx)
+{
+ char subject[1024]; /* Used for the subject name */
+ char issuer[1024]; /* Used for the issuer name */
+ char attribute[1024];
+ char value[1024];
+ char common_name[1024];
+ char cn_str[1024];
+ char buf[64];
+ X509 *client_cert;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ const STACK_OF(X509_EXTENSION) *ext_list;
+#else
+ STACK_OF(X509_EXTENSION) *ext_list;
+#endif
+ SSL *ssl;
+ int err, depth, lookup, loc;
+ fr_tls_server_conf_t *conf;
+ int my_ok = ok;
+
+ ASN1_INTEGER *sn = NULL;
+ ASN1_TIME *asn_time = NULL;
+ VALUE_PAIR **certs;
+ char **identity;
+#ifdef HAVE_OPENSSL_OCSP_H
+ X509_STORE *ocsp_store = NULL;
+ X509 *issuer_cert;
+ bool do_verify = false;
+#endif
+ VALUE_PAIR *vp;
+ TALLOC_CTX *talloc_ctx;
+
+ REQUEST *request;
+
+ client_cert = X509_STORE_CTX_get_current_cert(ctx);
+ err = X509_STORE_CTX_get_error(ctx);
+ depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ lookup = depth;
+
+ /*
+ * Retrieve the pointer to the SSL of the connection currently treated
+ * and the application specific data stored into the SSL object.
+ */
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+ if (!conf) return 1;
+
+ request = (REQUEST *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_REQUEST);
+ rad_assert(request != NULL);
+ certs = (VALUE_PAIR **)SSL_get_ex_data(ssl, fr_tls_ex_index_certs);
+
+ identity = (char **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_IDENTITY);
+#ifdef HAVE_OPENSSL_OCSP_H
+ ocsp_store = conf->ocsp_store;
+#endif
+
+ talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
+
+ /*
+ * Log client/issuing cert. If there's an error, log
+ * issuing cert.
+ *
+ * Inbound: 0 = client, 1 = server (intermediate CA), 2 = issuing CA
+ * Outbound: 0 = server, 2 = issuing CA.
+ *
+ * Our array of certificates uses 0 for client, and 1 for server. We
+ * also ignore subsequent certs.
+ */
+ if (lookup > 1) {
+ if (!my_ok) lookup = 1;
+
+ } else if (lookup == 0) {
+ /*
+ * This flag is only set for outbound
+ * connections. And then allows us to remap SSL
+ * offset 0 (server) to our offset 1 (also
+ * server).
+ */
+ lookup = (SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_FIX_CERT_ORDER) != NULL);
+ }
+
+ /*
+ * Get the Serial Number
+ */
+ buf[0] = '\0';
+ sn = X509_get_serialNumber(client_cert);
+
+ RDEBUG2("(TLS) Creating attributes from %s certificate", cert_names[lookup ]);
+ RINDENT();
+
+ /*
+ * For this next bit, we create the attributes *only* if
+ * we're at the client or issuing certificate.
+ */
+ if (certs &&
+ (lookup <= 1) && sn && ((size_t) sn->length < (sizeof(buf) / 2))) {
+ char *p = buf;
+ int i;
+
+ for (i = 0; i < sn->length; i++) {
+ sprintf(p, "%02x", (unsigned int)sn->data[i]);
+ p += 2;
+ }
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_SERIAL][lookup], buf, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ /*
+ * Get the Expiration Date
+ */
+ buf[0] = '\0';
+ asn_time = X509_get_notAfter(client_cert);
+ if (certs && (lookup <= 1) && asn_time &&
+ (asn_time->length < (int) sizeof(buf))) {
+ memcpy(buf, (char*) asn_time->data, asn_time->length);
+ buf[asn_time->length] = '\0';
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_EXPIRATION][lookup], buf, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ /*
+ * Get the Valid Since Date
+ */
+ buf[0] = '\0';
+ asn_time = X509_get_notBefore(client_cert);
+ if (certs && (lookup <= 1) && asn_time &&
+ (asn_time->length < (int) sizeof(buf))) {
+ memcpy(buf, (char*) asn_time->data, asn_time->length);
+ buf[asn_time->length] = '\0';
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_VALID_SINCE][lookup], buf, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ /*
+ * Get the Subject & Issuer
+ */
+ subject[0] = issuer[0] = '\0';
+ X509_NAME_oneline(X509_get_subject_name(client_cert), subject,
+ sizeof(subject));
+ subject[sizeof(subject) - 1] = '\0';
+ if (certs && (lookup <= 1) && subject[0]) {
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_SUBJECT][lookup], subject, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ X509_NAME_oneline(X509_get_issuer_name(client_cert), issuer,
+ sizeof(issuer));
+ issuer[sizeof(issuer) - 1] = '\0';
+ if (certs && (lookup <= 1) && issuer[0]) {
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_ISSUER][lookup], issuer, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ /*
+ * Get the Common Name, if there is a subject.
+ */
+ X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert),
+ NID_commonName, common_name, sizeof(common_name));
+ common_name[sizeof(common_name) - 1] = '\0';
+ if (certs && (lookup <= 1) && common_name[0] && subject[0]) {
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_CN][lookup], common_name, T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+
+ /*
+ * Get the RFC822 Subject Alternative Name
+ */
+ loc = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, -1);
+ if (certs && (lookup <= 1) && (loc >= 0)) {
+ X509_EXTENSION *ext = NULL;
+ GENERAL_NAMES *names = NULL;
+ int i;
+
+ if ((ext = X509_get_ext(client_cert, loc)) &&
+ (names = X509V3_EXT_d2i(ext))) {
+ for (i = 0; i < sk_GENERAL_NAME_num(names); i++) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
+
+ switch (name->type) {
+#ifdef GEN_EMAIL
+ case GEN_EMAIL:
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_EMAIL][lookup],
+ (char const *) ASN1_STRING_get0_data(name->d.rfc822Name), T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ break;
+#endif /* GEN_EMAIL */
+#ifdef GEN_DNS
+ case GEN_DNS:
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_DNS][lookup],
+ (char const *) ASN1_STRING_get0_data(name->d.dNSName), T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ break;
+#endif /* GEN_DNS */
+#ifdef GEN_OTHERNAME
+ case GEN_OTHERNAME:
+ /* look for a MS UPN */
+ if (NID_ms_upn == OBJ_obj2nid(name->d.otherName->type_id)) {
+ /* we've got a UPN - Must be ASN1-encoded UTF8 string */
+ if (name->d.otherName->value->type == V_ASN1_UTF8STRING) {
+ vp = fr_pair_make(talloc_ctx, certs, cert_attr_names[FR_TLS_SAN_UPN][lookup],
+ (char const *) ASN1_STRING_get0_data(name->d.otherName->value->value.utf8string), T_OP_SET);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ break;
+ } else {
+ RWARN("Invalid UPN in Subject Alt Name (should be UTF-8)");
+ break;
+ }
+ }
+ break;
+#endif /* GEN_OTHERNAME */
+ default:
+ /* XXX TODO handle other SAN types */
+ break;
+ }
+ }
+ }
+ if (names != NULL)
+ GENERAL_NAMES_free(names);
+ }
+
+ /*
+ * If the CRL has expired, that might still be OK.
+ */
+ if (!my_ok &&
+ (conf->allow_expired_crl) &&
+ (err == X509_V_ERR_CRL_HAS_EXPIRED)) {
+ my_ok = 1;
+ X509_STORE_CTX_set_error( ctx, 0 );
+ }
+
+ if (!my_ok) {
+ char const *p = X509_verify_cert_error_string(err);
+ RERROR("(TLS) OpenSSL says error %d : %s", err, p);
+ REXDENT();
+
+ /*
+ * Copy certs even on failure so that they can be logged.
+ */
+ if (certs && request) fr_pair_add(&request->packet->vps, fr_pair_list_copy(request->packet, *certs));
+
+ return my_ok;
+ }
+
+ if (lookup == 0) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ ext_list = X509_get0_extensions(client_cert);
+#else
+ X509_CINF *client_inf;
+ client_inf = client_cert->cert_info;
+ ext_list = client_inf->extensions;
+#endif
+ } else {
+ ext_list = NULL;
+ }
+
+ /*
+ * Grab the X509 extensions, and create attributes out of them.
+ * For laziness, we re-use the OpenSSL names
+ */
+ if (certs && (sk_X509_EXTENSION_num(ext_list) > 0)) {
+ int i, len;
+ EXTENDED_KEY_USAGE *eku;
+ char *p;
+ BIO *out;
+
+ out = BIO_new(BIO_s_mem());
+ strlcpy(attribute, "TLS-Client-Cert-", sizeof(attribute));
+
+ for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ext;
+
+ ext = sk_X509_EXTENSION_value(ext_list, i);
+
+ obj = X509_EXTENSION_get_object(ext);
+ i2a_ASN1_OBJECT(out, obj);
+ len = BIO_read(out, attribute + 16 , sizeof(attribute) - 16 - 1);
+ if (len <= 0) continue;
+
+ attribute[16 + len] = '\0';
+
+ for (p = attribute + 16; *p != '\0'; p++) {
+ if (*p == ' ') *p = '-';
+ }
+
+ if (X509V3_EXT_get(ext)) { /* Known extension, converting value into plain string */
+ X509V3_EXT_print(out, ext, 0, 0);
+ len = BIO_read(out, value, sizeof(value) - 1);
+ if (len <= 0) continue;
+ value[len] = '\0';
+ } else {
+ /*
+ * An extension not known to OpenSSL, dump it's value as a value of an unknown attribute.
+ */
+ value[0] = '0';
+ value[1] = 'x';
+ const unsigned char *srcp;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ const ASN1_STRING *srcasn1p;
+ srcasn1p = X509_EXTENSION_get_data(ext);
+ srcp = ASN1_STRING_get0_data(srcasn1p);
+#else
+ ASN1_STRING *srcasn1p;
+ srcasn1p = X509_EXTENSION_get_data(ext);
+ srcp = ASN1_STRING_data(srcasn1p);
+#endif
+ int asn1len = ASN1_STRING_length(srcasn1p);
+ /* 3 comes from '0x' + \0 */
+ if ((size_t)(asn1len << 1) >= sizeof(value) - 3) {
+ RDEBUG("Value of '%s' attribute is too long to be stored, it will be truncated", attribute);
+ asn1len = (sizeof(value) - 3) >> 1;
+ }
+ fr_bin2hex(value + 2, srcp, asn1len);
+ }
+
+ vp = fr_pair_make(talloc_ctx, certs, attribute, value, T_OP_ADD);
+ if (!vp) {
+ RDEBUG3("Skipping %s += '%s'. Please check that both the "
+ "attribute and value are defined in the dictionaries",
+ attribute, value);
+ } else {
+ /*
+ * rdebug_pair_list indents (so pre REXDENT())
+ */
+ REXDENT();
+ rdebug_pair_list(L_DBG_LVL_2, request, vp, NULL);
+ RINDENT();
+ }
+ }
+
+ BIO_free_all(out);
+
+ /* Export raw EKU OIDs to allow matching a single OID regardless of its name */
+ eku = X509_get_ext_d2i(client_cert, NID_ext_key_usage, NULL, NULL);
+ if (eku != NULL) {
+ for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
+ len = OBJ_obj2txt(value, sizeof(value), sk_ASN1_OBJECT_value(eku, i), 1);
+ if ((len > 0) && ((unsigned) len < sizeof(value))) {
+ vp = fr_pair_make(talloc_ctx, certs,
+ "TLS-Client-Cert-X509v3-Extended-Key-Usage-OID",
+ value, T_OP_ADD);
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+ else {
+ RDEBUG("Failed to get EKU OID at index %d", i);
+ }
+ }
+ EXTENDED_KEY_USAGE_free(eku);
+ }
+ }
+
+ REXDENT();
+
+ switch (X509_STORE_CTX_get_error(ctx)) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ RERROR("(TLS) unable to get issuer certificate for issuer=%s", issuer);
+ break;
+
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ RERROR("(TLS) Failed with certificate not yet valid.");
+ break;
+
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ RERROR("(TLS) Failed with error in certificate 'not before' field.");
+#if 0
+ ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert));
+#endif
+ break;
+
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ RERROR("(TLS) Failed with certificate has expired.");
+ break;
+
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ RERROR("(TLS) Failed with err in certificate 'no after' field..");
+ break;
+
+#if 0
+ ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert));
+#endif
+ break;
+ }
+
+ /*
+ * If we're at the actual client cert, apply additional
+ * checks.
+ */
+ if (depth == 0) {
+ tls_session_t *ssn = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_SSN);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ STACK_OF(X509)* untrusted = NULL;
+#endif
+
+ rad_assert(ssn != NULL);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ /*
+ * See if there are any untrusted certificates.
+ * If so, complain about them.
+ */
+ untrusted = X509_STORE_CTX_get0_untrusted(ctx);
+ if (untrusted) {
+ if (conf->disallow_untrusted || RDEBUG_ENABLED2) {
+ int i;
+
+ WARN("Certificate chain - %i cert(s) untrusted",
+ X509_STORE_CTX_get_num_untrusted(ctx));
+ for (i = sk_X509_num(untrusted); i > 0 ; i--) {
+ X509 *this_cert = sk_X509_value(untrusted, i - 1);
+
+ X509_NAME_oneline(X509_get_subject_name(this_cert), subject, sizeof(subject));
+ subject[sizeof(subject) - 1] = '\0';
+
+ WARN("(TLS) untrusted certificate with depth [%i] subject name %s",
+ i - 1, subject);
+ }
+ }
+
+ if (conf->disallow_untrusted) {
+ AUTH(LOG_PREFIX ": There are untrusted certificates in the certificate chain. Rejecting.");
+ my_ok = 0;
+ }
+ }
+#endif
+
+ /*
+ * If the conf tells us to, check cert issuer
+ * against the specified value and fail
+ * verification if they don't match.
+ */
+ if (my_ok && conf->check_cert_issuer &&
+ (strcmp(issuer, conf->check_cert_issuer) != 0)) {
+ AUTH(LOG_PREFIX ": Certificate issuer (%s) does not match specified value (%s)!",
+ issuer, conf->check_cert_issuer);
+ my_ok = 0;
+ }
+
+ /*
+ * If the conf tells us to, check the CN in the
+ * cert against xlat'ed value, but only if the
+ * previous checks passed.
+ */
+ if (my_ok && conf->check_cert_cn) {
+ if (radius_xlat(cn_str, sizeof(cn_str), request, conf->check_cert_cn, NULL, NULL) < 0) {
+ /* if this fails, fail the verification */
+ my_ok = 0;
+ } else {
+ RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str);
+ if (strcmp(cn_str, common_name) != 0) {
+ AUTH(LOG_PREFIX ": Certificate CN (%s) does not match specified value (%s)!",
+ common_name, cn_str);
+ my_ok = 0;
+ }
+ }
+ } /* check_cert_cn */
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ if (my_ok) {
+ /*
+ * No OCSP, allow external verification.
+ */
+ if (!conf->ocsp_enable) {
+ do_verify = true;
+
+ } else {
+ RDEBUG2("Starting OCSP Request");
+
+ /*
+ * If we don't have an issuer, then we can't send
+ * and OCSP request, but pass the NULL issuer in
+ * so ocsp_check can decide on the correct
+ * return code.
+ */
+ issuer_cert = X509_STORE_CTX_get0_current_issuer(ctx);
+
+ /*
+ * Do the full OCSP checks.
+ *
+ * If they fail, don't run the external verify. We don't want
+ * to allow admins to force authentication success for bad
+ * certificates.
+ *
+ * If the OCSP checks succeed, check whether we still want to
+ * run the external verification routine. If it's marked as
+ * "skip verify on OK", then we don't do verify.
+ */
+ my_ok = ocsp_check(request, ocsp_store, issuer_cert, client_cert, conf);
+ if (my_ok != OCSP_STATUS_FAILED) {
+ do_verify = !conf->verify_skip_if_ocsp_ok;
+ }
+ }
+ }
+#endif
+
+ if ((my_ok != OCSP_STATUS_FAILED)
+#ifdef HAVE_OPENSSL_OCSP_H
+ && do_verify
+#endif
+ ) while (conf->verify_client_cert_cmd) {
+ char filename[3 * MAX_SESSION_SIZE + 1];
+ int fd;
+ FILE *fp;
+
+ snprintf(filename, sizeof(filename), "%s/%s.client.XXXXXXXX",
+ conf->verify_tmp_dir, main_config.name);
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ RDEBUG("Failed creating file in %s: %s",
+ conf->verify_tmp_dir, fr_syserror(errno));
+ break;
+ }
+
+ fp = fdopen(fd, "w");
+ if (!fp) {
+ close(fd);
+ RDEBUG("Failed opening file %s: %s",
+ filename, fr_syserror(errno));
+ break;
+ }
+
+ if (!PEM_write_X509(fp, client_cert)) {
+ fclose(fp);
+ RDEBUG("Failed writing certificate to file");
+ goto do_unlink;
+ }
+ fclose(fp);
+
+ if (!pair_make_request("TLS-Client-Cert-Filename",
+ filename, T_OP_SET)) {
+ RDEBUG("Failed creating TLS-Client-Cert-Filename");
+
+ goto do_unlink;
+ }
+
+ RDEBUG("Verifying client certificate: %s", conf->verify_client_cert_cmd);
+ if (radius_exec_program(request, NULL, 0, NULL, request, conf->verify_client_cert_cmd,
+ request->packet->vps,
+ true, true, EXEC_TIMEOUT) != 0) {
+ AUTH(LOG_PREFIX ": Certificate CN (%s) fails external verification!", common_name);
+ my_ok = 0;
+
+ } else if (request) {
+ RDEBUG("Client certificate CN %s passed external validation", common_name);
+ }
+
+ do_unlink:
+ unlink(filename);
+ break;
+ }
+
+ /*
+ * Track that we've verified the client certificate.
+ */
+ ssn->client_cert_ok = (my_ok == 1);
+ } /* depth == 0 */
+
+ /*
+ * Copy certs to request even on failure, so that the
+ * user can log them.
+ */
+ if (certs && request && !my_ok) {
+ fr_pair_add(&request->packet->vps, fr_pair_list_copy(request->packet, *certs));
+ }
+
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("(TLS) chain-depth : %d", depth);
+ RDEBUG3("(TLS) error : %d", err);
+
+ if (identity) RDEBUG3("identity : %s", *identity);
+ RDEBUG3("(TLS) common name : %s", common_name);
+ RDEBUG3("(TLS) subject : %s", subject);
+ RDEBUG3("(TLS) issuer : %s", issuer);
+ RDEBUG3("(TLS) verify return : %d", my_ok);
+ }
+
+ return (my_ok != 0);
+}
+
+
+/*
+ * Configure a X509 CA store to verify OCSP or client repsonses
+ *
+ * - Load the trusted CAs
+ * - Load the trusted issuer certificates
+ * - Configure CRLs check if needed
+ */
+X509_STORE *fr_init_x509_store(fr_tls_server_conf_t *conf)
+{
+ X509_STORE *store = X509_STORE_new();
+
+ if (store == NULL) return NULL;
+
+ /* Load the CAs we trust */
+ if (conf->ca_file || conf->ca_path)
+ if (!X509_STORE_load_locations(store, conf->ca_file, conf->ca_path)) {
+ tls_error_log(NULL, "Error reading Trusted root CA list \"%s\"", conf->ca_file);
+ X509_STORE_free(store);
+ return NULL;
+ }
+
+#ifdef X509_V_FLAG_CRL_CHECK
+ if (conf->check_crl)
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
+#endif
+#ifdef X509_V_FLAG_CRL_CHECK_ALL
+ if (conf->check_all_crl)
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK_ALL);
+#endif
+
+#if defined(X509_V_FLAG_PARTIAL_CHAIN)
+ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
+#endif
+
+ return store;
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+static int set_ecdh_curve(SSL_CTX *ctx, char const *ecdh_curve, bool disable_single_dh_use)
+{
+ if (!disable_single_dh_use) {
+ SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
+ }
+
+ if (!ecdh_curve) return 0;
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+ /*
+ * A colon-separated list of curves.
+ */
+ if (*ecdh_curve) {
+ char *list;
+
+ memcpy(&list, &ecdh_curve, sizeof(list)); /* const issues */
+
+ if (SSL_CTX_set1_curves_list(ctx, list) == 0) {
+ ERROR(LOG_PREFIX ": Unknown ecdh_curve \"%s\"", ecdh_curve);
+ return -1;
+ }
+ }
+
+ (void) SSL_CTX_set_ecdh_auto(ctx, 1);
+#else
+ /*
+ * Use APIs for older versions of OpenSSL.
+ */
+ {
+ int nid;
+ EC_KEY *ecdh;
+
+ nid = OBJ_sn2nid(ecdh_curve);
+ if (!nid) {
+ ERROR(LOG_PREFIX ": Unknown ecdh_curve \"%s\"", ecdh_curve);
+ return -1;
+ }
+
+ ecdh = EC_KEY_new_by_curve_name(nid);
+ if (!ecdh) {
+ ERROR(LOG_PREFIX ": Unable to create new curve \"%s\"", ecdh_curve);
+ return -1;
+ }
+
+ SSL_CTX_set_tmp_ecdh(ctx, ecdh);
+
+ EC_KEY_free(ecdh);
+ }
+#endif
+
+ return 0;
+}
+#endif
+#endif
+
+#if defined(HAVE_OPENSSL_CRYPTO_H) && defined(HAVE_CRYPTO_SET_LOCKING_CALLBACK)
+#define TLS_UNUSED
+#else
+#define TLS_UNUSED UNUSED
+#endif
+
+/** Add all the default ciphers and message digests reate our context.
+ *
+ * This should be called exactly once from main, before reading the main config
+ * or initialising any modules.
+ */
+int tls_global_init(TLS_UNUSED bool spawn_flag, TLS_UNUSED bool check)
+{
+ SSL_load_error_strings(); /* readable error messages (examples show call before library_init) */
+ SSL_library_init(); /* initialize library */
+ OpenSSL_add_all_algorithms(); /* required for SHA2 in OpenSSL < 0.9.8o and 1.0.0.a */
+ CONF_modules_load_file(NULL, NULL, 0);
+
+ /*
+ * Initialize the index for the certificates.
+ */
+ fr_tls_ex_index_certs = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+
+#if defined(HAVE_OPENSSL_CRYPTO_H) && defined(HAVE_CRYPTO_SET_LOCKING_CALLBACK)
+ /*
+ * If we're linking with OpenSSL too, then we need
+ * to set up the mutexes and enable the thread callbacks.
+ *
+ * 'check' and not 'check_config' because it's a global,
+ * and we don't want to have tls.c depend on globals.
+ */
+ if (spawn_flag && !check && (tls_mutexes_init() < 0)) {
+ ERROR("(TLS) FATAL: Failed to set up SSL mutexes");
+ return -1;
+ }
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ /*
+ * Load the default provider for most algorithms
+ */
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+ if (!openssl_default_provider) {
+ ERROR("(TLS) Failed loading default provider");
+ return -1;
+ }
+
+ /*
+ * Needed for MD4
+ *
+ * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
+ */
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+ if (!openssl_legacy_provider) {
+ ERROR("(TLS) Failed loading legacy provider");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef ENABLE_OPENSSL_VERSION_CHECK
+/** Check for vulnerable versions of libssl
+ *
+ * @param acknowledged The highest CVE number a user has confirmed is not present in the system's libssl.
+ * @return 0 if the CVE specified by the user matches the most recent CVE we have, else -1.
+ */
+int tls_global_version_check(char const *acknowledged)
+{
+ uint64_t v;
+ bool bad = false;
+ size_t i;
+
+ if (strcmp(acknowledged, "yes") == 0) return 0;
+
+ /* Check for bad versions */
+ v = (uint64_t) SSLeay();
+
+ for (i = 0; i < (sizeof(libssl_defects) / sizeof(*libssl_defects)); i++) {
+ libssl_defect_t *defect = &libssl_defects[i];
+
+ if ((v >= defect->low) && (v <= defect->high)) {
+ /*
+ * If the CVE is acknowledged, allow it.
+ */
+ if (!bad && (strcmp(acknowledged, defect->id) == 0)) return 0;
+
+ ERROR("Refusing to start with libssl version %s (in range %s)",
+ ssl_version(), ssl_version_range(defect->low, defect->high));
+ ERROR("Security advisory %s (%s)", defect->id, defect->name);
+ ERROR("%s", defect->comment);
+
+ /*
+ * Only warn about the first one...
+ */
+ if (!bad) {
+ INFO("Once you have verified libssl has been correctly patched, "
+ "set security.allow_vulnerable_openssl = '%s'", defect->id);
+
+ bad = true;
+ }
+ }
+ }
+
+ if (bad) return -1;
+
+ return 0;
+}
+#endif
+
+/** Free any memory alloced by libssl
+ *
+ */
+void tls_global_cleanup(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+ ERR_remove_state(0);
+#elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ ERR_remove_thread_state(NULL);
+#endif
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_cleanup();
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
+ ERROR("Failed unloading default provider");
+ }
+ openssl_default_provider = NULL;
+
+ if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
+ ERROR("Failed unloading legacy provider");
+ }
+ openssl_legacy_provider = NULL;
+#endif
+
+ CONF_modules_unload(1);
+ ERR_free_strings();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+}
+
+
+/*
+ * Map version strings to OpenSSL macros.
+ */
+static const FR_NAME_NUMBER version2int[] = {
+ { "1.0", TLS1_VERSION },
+#ifdef TLS1_1_VERSION
+ { "1.1", TLS1_1_VERSION },
+#endif
+#ifdef TLS1_2_VERSION
+ { "1.2", TLS1_2_VERSION },
+#endif
+#ifdef TLS1_3_VERSION
+ { "1.3", TLS1_3_VERSION },
+#endif
+ { NULL, 0 }
+};
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#ifdef TLS1_3_VERSION
+#define CHECK_FOR_PSK_CERTS (1)
+#endif
+#endif
+
+/** Create SSL context
+ *
+ * - Load the trusted CAs
+ * - Load the Private key & the certificate
+ * - Set the Context options & Verify options
+ */
+SSL_CTX *tls_init_ctx(fr_tls_server_conf_t *conf, int client, char const *chain_file, char const *private_key_file)
+{
+ SSL_CTX *ctx;
+ X509_STORE *certstore;
+ int verify_mode = SSL_VERIFY_NONE;
+ int ctx_options = 0, ctx_available = 0;
+ int type;
+#ifdef CHECK_FOR_PSK_CERTS
+ bool psk_and_certs = false;
+#endif
+ int min_version;
+ int max_version;
+
+ /*
+ * SHA256 is in all versions of OpenSSL, but isn't
+ * initialized by default. It's needed for WiMAX
+ * certificates.
+ */
+#ifdef HAVE_OPENSSL_EVP_SHA256
+ EVP_add_digest(EVP_sha256());
+#endif
+
+ ctx = SSL_CTX_new(SSLv23_method()); /* which is really "all known SSL / TLS methods". Idiots. */
+ if (!ctx) {
+ tls_error_log(NULL, "Failed creating OpenSSL context");
+ return NULL;
+ }
+
+ /*
+ * Save the config on the context so that callbacks which
+ * only get SSL_CTX* e.g. session persistence, can get it
+ */
+ SSL_CTX_set_app_data(ctx, conf);
+
+ /*
+ * Identify the type of certificates that needs to be loaded
+ */
+ if (conf->file_type) {
+ type = SSL_FILETYPE_PEM;
+ } else {
+ type = SSL_FILETYPE_ASN1;
+ }
+
+ /*
+ * Set the password to load private key
+ */
+ if (conf->private_key_password) {
+#ifdef __APPLE__
+ /*
+ * We don't want to put the private key password in eap.conf, so check
+ * for our special string which indicates we should get the password
+ * programmatically.
+ */
+ char const* special_string = "Apple:UseCertAdmin";
+ if (strncmp(conf->private_key_password, special_string, strlen(special_string)) == 0) {
+ char cmd[256];
+ char *password;
+ long const max_password_len = 128;
+ snprintf(cmd, sizeof(cmd) - 1, "/usr/sbin/certadmin --get-private-key-passphrase \"%s\"",
+ conf->private_key_file);
+
+ DEBUG2(LOG_PREFIX ": Getting private key passphrase using command \"%s\"", cmd);
+
+ FILE* cmd_pipe = popen(cmd, "r");
+ if (!cmd_pipe) {
+ ERROR(LOG_PREFIX ": %s command failed: Unable to get private_key_password", cmd);
+ ERROR(LOG_PREFIX ": Error reading private_key_file %s", conf->private_key_file);
+ return NULL;
+ }
+
+ rad_const_free(conf->private_key_password);
+ password = talloc_array(conf, char, max_password_len);
+ if (!password) {
+ ERROR(LOG_PREFIX ": Can't allocate space for private_key_password");
+ ERROR(LOG_PREFIX ": Error reading private_key_file %s", conf->private_key_file);
+ pclose(cmd_pipe);
+ return NULL;
+ }
+
+ fgets(password, max_password_len, cmd_pipe);
+ pclose(cmd_pipe);
+
+ /* Get rid of newline at end of password. */
+ password[strlen(password) - 1] = '\0';
+
+ DEBUG3(LOG_PREFIX ": Password from command = \"%s\"", password);
+ conf->private_key_password = password;
+ }
+#endif
+
+ {
+ char *password;
+
+ memcpy(&password, &conf->private_key_password, sizeof(password));
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, password);
+ SSL_CTX_set_default_passwd_cb(ctx, cbtls_password);
+ }
+ }
+
+#ifdef PSK_MAX_IDENTITY_LEN
+ /*
+ * A dynamic query exists. There MUST NOT be a
+ * statically configured identity and password.
+ */
+ if (conf->psk_query) {
+ if (!*conf->psk_query) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_query cannot be empty");
+ return NULL;
+ }
+
+ if (conf->psk_identity && *conf->psk_identity) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_identity and psk_query cannot be used at the same time.");
+ return NULL;
+ }
+
+ if (conf->psk_password && *conf->psk_password) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_password and psk_query cannot be used at the same time.");
+ return NULL;
+ }
+
+ if (client) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_query cannot be used for outgoing connections");
+ return NULL;
+ }
+
+ /*
+ * Now check that if PSK is being used, that the config is valid.
+ */
+ } else if (conf->psk_identity) {
+ if (!*conf->psk_identity) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_identity is empty");
+ return NULL;
+ }
+
+
+ if (!conf->psk_password || !*conf->psk_password) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_identity is set, but there is no psk_password");
+ return NULL;
+ }
+
+ } else if (conf->psk_password) {
+ ERROR(LOG_PREFIX ": Invalid PSK Configuration: psk_password is set, but there is no psk_identity");
+ return NULL;
+ }
+
+ /*
+ * Set the server PSK callback if necessary.
+ */
+ if (!client && (conf->psk_identity || conf->psk_query)) {
+ SSL_CTX_set_psk_server_callback(ctx, psk_server_callback);
+ }
+
+ /*
+ * Do more sanity checking if we have a PSK identity. We
+ * check the password, and convert it to it's final form.
+ */
+ if (conf->psk_identity) {
+ size_t psk_len, hex_len;
+ uint8_t buffer[PSK_MAX_PSK_LEN];
+
+ if (client) {
+ SSL_CTX_set_psk_client_callback(ctx,
+ psk_client_callback);
+ }
+
+ if (!conf->psk_password || !*conf->psk_password) {
+ ERROR(LOG_PREFIX ": psk_hexphrase cannot be empty");
+ return NULL;
+ }
+
+ psk_len = strlen(conf->psk_password);
+ if (strlen(conf->psk_password) > (2 * PSK_MAX_PSK_LEN)) {
+ ERROR(LOG_PREFIX ": psk_hexphrase is too long (max %d)", PSK_MAX_PSK_LEN);
+ return NULL;
+ }
+
+ /*
+ * Check the password now, so that we don't have
+ * errors at run-time.
+ */
+ hex_len = fr_hex2bin(buffer, sizeof(buffer), conf->psk_password, psk_len);
+ if (psk_len != (2 * hex_len)) {
+ ERROR(LOG_PREFIX ": psk_hexphrase is not all hex");
+ return NULL;
+ }
+
+#ifdef CHECK_FOR_PSK_CERTS
+ /*
+ * RFC 8446 says:
+ *
+ * When authenticating via a certificate, the server will send the
+ * Certificate (Section 4.4.2) and CertificateVerify (Section 4.4.3)
+ * messages. In TLS 1.3 as defined by this document, either a PSK or
+ * a certificate is always used, but not both. Future documents may
+ * define how to use them together.
+ */
+ if (((conf->psk_identity || conf->psk_password || conf->psk_query)) &&
+ (conf->certificate_file || conf->private_key_password || conf->private_key_file)) {
+ psk_and_certs = true;
+ }
+#endif
+
+ goto post_ca;
+ }
+#else
+ (void) client; /* -Wunused */
+#endif
+
+ /*
+ * Load our keys and certificates
+ *
+ * If certificates are of type PEM then we can make use
+ * of cert chain authentication using openssl api call
+ * SSL_CTX_use_certificate_chain_file. Please see how
+ * the cert chain needs to be given in PEM from
+ * openSSL.org
+ */
+ if (!chain_file) chain_file = conf->certificate_file;
+ if (!chain_file) goto load_ca;
+
+ if (type == SSL_FILETYPE_PEM) {
+ if (!(SSL_CTX_use_certificate_chain_file(ctx, chain_file))) {
+ tls_error_log(NULL, "Failed reading certificate file \"%s\"",
+ chain_file);
+ return NULL;
+ }
+
+ } else if (!(SSL_CTX_use_certificate_file(ctx, chain_file, type))) {
+ tls_error_log(NULL, "Failed reading certificate file \"%s\"",
+ chain_file);
+ return NULL;
+ }
+
+load_ca:
+ /*
+ * Load the CAs we trust and configure CRL checks if needed
+ */
+ if (conf->ca_file || conf->ca_path) {
+ if ((certstore = fr_init_x509_store(conf)) == NULL ) return NULL;
+ SSL_CTX_set_cert_store(ctx, certstore);
+ } else {
+#if defined(X509_V_FLAG_PARTIAL_CHAIN)
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(ctx), X509_V_FLAG_PARTIAL_CHAIN);
+#endif
+ }
+
+ if (conf->ca_file && *conf->ca_file) SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(conf->ca_file));
+
+ conf->ca_path_last_reload = time(NULL);
+ conf->old_x509_store = NULL;
+
+ /*
+ * Disable reloading of cert store if we're not using CA path
+ */
+ if (!conf->ca_path) conf->ca_path_reload_interval = 0;
+
+ if (conf->ca_path_reload_interval > 0 && conf->ca_path_reload_interval < 300) {
+ DEBUG2("ca_path_reload_interval is set too low, reset it to 300");
+ conf->ca_path_reload_interval = 300;
+ }
+
+ /* Load private key */
+ if (!private_key_file) private_key_file = conf->private_key_file;
+ if (private_key_file) {
+ if (!(SSL_CTX_use_PrivateKey_file(ctx, private_key_file, type))) {
+ tls_error_log(NULL, "Failed reading private key file \"%s\"",
+ private_key_file);
+ return NULL;
+ }
+
+ /*
+ * Check if the loaded private key is the right one
+ */
+ if (!SSL_CTX_check_private_key(ctx)) {
+ ERROR(LOG_PREFIX ": Private key does not match the certificate public key");
+ return NULL;
+ }
+ }
+
+#ifdef PSK_MAX_IDENTITY_LEN
+post_ca:
+#endif
+
+ /*
+ * We never want SSLv2 or SSLv3.
+ */
+ ctx_options |= SSL_OP_NO_SSLv2;
+ ctx_options |= SSL_OP_NO_SSLv3;
+
+ /*
+ * If set then dummy Change Cipher Spec (CCS) messages are sent in
+ * TLSv1.3. This has the effect of making TLSv1.3 look more like TLSv1.2
+ * so that middleboxes that do not understand TLSv1.3 will not drop
+ * the connection. This isn't needed for EAP-TLS, so we disable it.
+ *
+ * EAP (hopefully) does not have middlebox deployments
+ */
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ ctx_options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+#endif
+
+ /*
+ * SSL_CTX_set_(min|max)_proto_version was included in OpenSSL 1.1.0
+ *
+ * This version already defines macros for TLS1_2_VERSION and
+ * below, so we don't need to check for them explicitly.
+ *
+ * TLS1_3_VERSION is available in OpenSSL 1.1.1.
+ */
+
+ /*
+ * Get the max version from the configuration files.
+ */
+ if (conf->tls_max_version && *conf->tls_max_version) {
+ max_version = fr_str2int(version2int, conf->tls_max_version, 0);
+ if (!max_version) {
+ ERROR("Invalid value for tls_max_version '%s'", conf->tls_max_version);
+ return NULL;
+ }
+ } else {
+ /*
+ * Pick the maximum version available at compile
+ * time.
+ */
+#if defined(TLS1_3_VERSION)
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUS 1.1 requires TLS 1.3 or later.
+ */
+ if (conf->radiusv11) {
+ max_version = TLS1_3_VERSION;
+ } else
+#endif
+
+
+ max_version = TLS1_2_VERSION; /* yes, we only use TLS 1.3 if it's EXPLICITELY ENABLED */
+#elif defined(TLS1_2_VERSION)
+ max_version = TLS1_2_VERSION;
+#elif defined(TLS1_1_VERSION)
+ max_version = TLS1_1_VERSION;
+#else
+ max_version = TLS1_VERSION;
+#endif
+ }
+
+ /*
+ * Get the min version from the configuration files.
+ */
+ if (conf->tls_min_version && *conf->tls_min_version) {
+ min_version = fr_str2int(version2int, conf->tls_min_version, 0);
+ if (!min_version) {
+ ERROR("Unknown or unsupported value for tls_min_version '%s'", conf->tls_min_version);
+ return NULL;
+ }
+ } else {
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUS 1.1 requires TLS 1.3 or later.
+ */
+ if (conf->radiusv11) {
+ min_version = TLS1_3_VERSION;
+ } else
+#endif
+ /*
+ * Allow TLS 1.0. It is horribly insecure, but
+ * some systems still use it.
+ */
+ min_version = TLS1_VERSION;
+ }
+
+ /*
+ * Compare the two.
+ */
+ if ((min_version > max_version) || (max_version < min_version)) {
+ ERROR("tls_min_version '%s' must be <= tls_max_version '%s'",
+ conf->tls_min_version, conf->tls_max_version);
+ return NULL;
+ }
+
+#ifdef CHECK_FOR_PSK_CERTS
+ /*
+ * Disable TLS 1.3 when using PSKs and certs.
+ * This doesn't work.
+ *
+ * It's best to disable the offending
+ * configuration and warn about it. The
+ * alternative is to have the admin wonder why it
+ * doesn't work.
+ *
+ * Note that the admin can over-ride this by
+ * setting "min_version = max_version = 1.3"
+ */
+ if (psk_and_certs &&
+ (min_version < TLS1_3_VERSION) && (max_version >= TLS1_3_VERSION)) {
+ max_version = TLS1_2_VERSION;
+ radlog(L_DBG | L_WARN, "Disabling TLS 1.3 due to PSK and certificates being configured simultaneously. This is not supported by the standards.");
+ }
+#endif
+
+ /*
+ * No one should be using TLS 1.0 or TLS 1.1 any more
+ *
+ * If TLS1.2 isn't defined by OpenSSL, then we _know_
+ * it's an insecure version of OpenSSL.
+ */
+#ifdef TLS1_2_VERSION
+ if (max_version < TLS1_2_VERSION)
+#endif
+ {
+ if (rad_debug_lvl) {
+ WARN(LOG_PREFIX ": The configuration allows TLS 1.0 and/or TLS 1.1. We STRONGLY recommned using only TLS 1.2 for security");
+ WARN(LOG_PREFIX ": Please set: tls_min_version = '1.2'");
+ }
+ }
+
+#ifdef SSL_OP_NO_TLSv1
+ /*
+ * Check min / max against the old-style "disable" flag.
+ */
+ if (conf->disable_tlsv1) {
+ if (min_version == TLS1_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1' is set, but 'min_version = 1.0'. These cannot both be true.");
+ return NULL;
+ }
+ if (max_version == TLS1_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1' is set, but 'max_version = 1.0'. These cannot both be true.");
+ return NULL;
+ }
+ ctx_options |= SSL_OP_NO_TLSv1;
+ }
+
+ if (min_version > TLS1_VERSION) ctx_options |= SSL_OP_NO_TLSv1;
+
+ ctx_available |= SSL_OP_NO_TLSv1;
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_1
+ /*
+ * Check min / max against the old-style "disable" flag.
+ */
+ if (conf->disable_tlsv1_1) {
+ if (min_version <= TLS1_1_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1_1' is set, but 'min_version <= 1.1'. These cannot both be true.");
+ return NULL;
+ }
+ if (max_version == TLS1_1_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1_1' is set, but 'max_version = 1.1'. These cannot both be true.");
+ return NULL;
+ }
+ ctx_options |= SSL_OP_NO_TLSv1_1;
+ }
+
+ if (min_version > TLS1_1_VERSION) ctx_options |= SSL_OP_NO_TLSv1_1;
+ if (max_version < TLS1_1_VERSION) ctx_options |= SSL_OP_NO_TLSv1_1;
+
+ ctx_available |= SSL_OP_NO_TLSv1_1;
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_2
+ /*
+ * Check min / max against the old-style "disable" flag.
+ */
+ if (conf->disable_tlsv1_2) {
+ if (min_version <= TLS1_2_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1_2' is set, but 'min_version <= 1.2'. These cannot both be true.");
+ return NULL;
+ }
+ if (max_version == TLS1_2_VERSION) {
+ ERROR(LOG_PREFIX ": 'disable_tlsv1_1' is set, but 'max_version = 1.2'. These cannot both be true.");
+ return NULL;
+ }
+ ctx_options |= SSL_OP_NO_TLSv1_2;
+ }
+ ctx_available |= SSL_OP_NO_TLSv1_2;
+
+ if (min_version > TLS1_2_VERSION) ctx_options |= SSL_OP_NO_TLSv1_2;
+ if (max_version < TLS1_2_VERSION) ctx_options |= SSL_OP_NO_TLSv1_2;
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_3
+ ctx_available |= SSL_OP_NO_TLSv1_3;
+ if (min_version > TLS1_3_VERSION) ctx_options |= SSL_OP_NO_TLSv1_3;
+ if (max_version < TLS1_3_VERSION) ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUS 1.1 requires TLS 1.3 or later.
+ */
+ if (conf->radiusv11 && (min_version < TLS1_3_VERSION)) {
+ ERROR(LOG_PREFIX ": Please set 'tls_min_version = 1.2' or greater to use 'radiusv1_1 = true'");
+ return NULL;
+ }
+#endif
+
+ /*
+ * Set the cipher list if we were told to do so. We do
+ * this before setting min/max TLS version. In a sane
+ * world, OpenSSL would error out if we set the max TLS
+ * version to something which was unsupported by the
+ * current security level. However, this is OpenSSL. If
+ * you set conflicting options, it doesn't give an error.
+ * Instead, it just picks something to do.
+ */
+ if (conf->cipher_list) {
+ if (!SSL_CTX_set_cipher_list(ctx, conf->cipher_list)) {
+ tls_error_log(NULL, "Failed setting cipher list");
+ return NULL;
+ }
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ if (conf->sigalgs_list) {
+ char *list;
+
+ memcpy(&list, &(conf->sigalgs_list), sizeof(list)); /* const issues */
+
+ if (SSL_CTX_set1_sigalgs_list(ctx, list) == 0) {
+ tls_error_log(NULL, "Failed setting signature list '%s'", conf->sigalgs_list);
+ return NULL;
+ }
+ }
+#endif
+
+ /*
+ * Tell OpenSSL PRETTY PLEASE MAY WE USE TLS 1.1.
+ *
+ * Because saying "use TLS 1.1" isn't enough. We have to
+ * send it flowers and cake.
+ */
+ if (min_version <= TLS1_1_VERSION) {
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ int seclevel = SSL_CTX_get_security_level(ctx);
+ int required;;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ required = 0;
+#else
+ required = 1;
+#endif
+
+ if (seclevel != required) {
+ WARN(LOG_PREFIX ": In order to use TLS 1.0 and/or TLS 1.1, you likely need to set: cipher_list = \"DEFAULT@SECLEVEL=%d\"", required);
+ }
+
+#else
+ /*
+ * No API to get the security level. Just guess based on the string in the cipher_list.
+ */
+ if (conf->cipher_list &&
+ !strstr(conf->cipher_list, "DEFAULT@SECLEVEL=1")) {
+ WARN(LOG_PREFIX ": In order to use TLS 1.0 and/or TLS 1.1, you likely need to set: cipher_list = \"DEFAULT@SECLEVEL=1\"");
+ }
+#endif
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ if (conf->disable_tlsv1) {
+ WARN(LOG_PREFIX ": Please use 'tls_min_version' and 'tls_max_version' instead of 'disable_tlsv1'");
+ }
+ if (conf->disable_tlsv1_1) {
+ WARN(LOG_PREFIX ": Please use 'tls_min_version' and 'tls_max_version' instead of 'disable_tlsv1_1'");
+ }
+ if (conf->disable_tlsv1_2) {
+ WARN(LOG_PREFIX ": Please use 'tls_min_version' and 'tls_max_version' instead of 'disable_tlsv1_2'");
+ }
+
+ ctx_options &= ~(ctx_available); /* clear these flags, as they're not needed. */
+
+ if (!SSL_CTX_set_max_proto_version(ctx, max_version)) {
+ ERROR("Failed setting TLS maximum version");
+ return NULL;
+ }
+ if (!SSL_CTX_set_min_proto_version(ctx, min_version)) {
+ ERROR("Failed setting TLS minimum version");
+ return NULL;
+ }
+#endif /* OpenSSL version < 1.1.0 */
+
+ if ((ctx_options & ctx_available) == ctx_available) {
+ ERROR(LOG_PREFIX ": You have disabled all available TLS versions. EAP will not work");
+ return NULL;
+ }
+
+ /*
+ * Cache min / max TLS version so that we can
+ * programatically disable TLS 1.3 for TTLS, PEAP, and
+ * FAST.
+ */
+ conf->min_version = min_version;
+ conf->max_version = max_version;
+
+#ifdef SSL_OP_NO_TICKET
+ ctx_options |= SSL_OP_NO_TICKET;
+#endif
+
+ if (!conf->disable_single_dh_use) {
+ /*
+ * SSL_OP_SINGLE_DH_USE must be used in order to prevent
+ * small subgroup attacks and forward secrecy. Always
+ * using SSL_OP_SINGLE_DH_USE has an impact on the
+ * computer time needed during negotiation, but it is not
+ * very large.
+ */
+ ctx_options |= SSL_OP_SINGLE_DH_USE;
+ }
+
+ /*
+ * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS to work around issues
+ * in Windows Vista client.
+ * http://www.openssl.org/~bodo/tls-cbc.txt
+ * http://www.nabble.com/(RADIATOR)-Radiator-Version-3.16-released-t2600070.html
+ */
+ ctx_options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+
+ if (conf->cipher_server_preference) {
+ /*
+ * SSL_OP_CIPHER_SERVER_PREFERENCE to follow best practice
+ * of nowday's TLS: do not allow poorly-selected ciphers from
+ * client to take preference
+ */
+ ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+ }
+
+ SSL_CTX_set_options(ctx, ctx_options);
+
+ /*
+ * TLS 1.3 introduces the concept of early data (also known as zero
+ * round trip data or 0-RTT data). Early data allows a client to send
+ * data to a server in the first round trip of a connection, without
+ * waiting for the TLS handshake to complete if the client has spoken
+ * to the same server recently. This doesn't work for EAP, so we
+ * disable early data.
+ *
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ SSL_CTX_set_max_early_data(ctx, 0);
+#endif
+
+ /*
+ * TODO: Set the RSA & DH
+ * SSL_CTX_set_tmp_rsa_callback(ctx, cbtls_rsa);
+ * SSL_CTX_set_tmp_dh_callback(ctx, cbtls_dh);
+ */
+
+ /*
+ * set the message callback to identify the type of
+ * message. For every new session, there can be a
+ * different callback argument.
+ *
+ * SSL_CTX_set_msg_callback(ctx, cbtls_msg);
+ */
+
+ /*
+ * Set eliptical curve crypto configuration.
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ if (set_ecdh_curve(ctx, conf->ecdh_curve, conf->disable_single_dh_use) < 0) {
+ return NULL;
+ }
+#endif
+#endif
+
+ /*
+ * OpenSSL will automatically create certificate chains,
+ * unless we tell it to not do that. The problem is that
+ * it sometimes gets the chains right from a certificate
+ * signature view, but wrong from the clients view.
+ */
+ if (!conf->auto_chain) {
+ SSL_CTX_set_mode(ctx, SSL_MODE_NO_AUTO_CHAIN);
+ }
+
+ /* Set Info callback */
+ SSL_CTX_set_info_callback(ctx, cbtls_info);
+
+ /*
+ * Callbacks, etc. for session resumption.
+ */
+ if (conf->session_cache_enable) {
+ /*
+ * Cache sessions on disk if requested.
+ */
+ if (conf->session_cache_path && *conf->session_cache_path) {
+ SSL_CTX_sess_set_new_cb(ctx, cbtls_new_session);
+ SSL_CTX_sess_set_get_cb(ctx, cbtls_get_session);
+ SSL_CTX_sess_set_remove_cb(ctx, cbtls_remove_session);
+ }
+
+ /*
+ * Or run the cache through a virtual server.
+ */
+ if (conf->session_cache_server && *conf->session_cache_server) {
+ SSL_CTX_sess_set_new_cb(ctx, cbtls_cache_save);
+ SSL_CTX_sess_set_get_cb(ctx, cbtls_cache_load);
+ SSL_CTX_sess_set_remove_cb(ctx, cbtls_cache_clear);
+ }
+
+ SSL_CTX_set_quiet_shutdown(ctx, 1);
+ if (fr_tls_ex_index_vps < 0)
+ fr_tls_ex_index_vps = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ }
+
+ /*
+ * Check the certificates for revocation.
+ */
+#ifdef X509_V_FLAG_CRL_CHECK
+ if (conf->check_crl) {
+ certstore = SSL_CTX_get_cert_store(ctx);
+ if (certstore == NULL) {
+ tls_error_log(NULL, "Error reading Certificate Store");
+ return NULL;
+ }
+ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK);
+
+#ifdef X509_V_FLAG_USE_DELTAS
+ /*
+ * If set, delta CRLs (if present) are used to
+ * determine certificate status. If not set
+ * deltas are ignored.
+ *
+ * So it's safe to always set this flag.
+ */
+ X509_STORE_set_flags(certstore, X509_V_FLAG_USE_DELTAS);
+#endif
+
+#ifdef X509_V_FLAG_CRL_CHECK_ALL
+ if (conf->check_all_crl)
+ X509_STORE_set_flags(certstore, X509_V_FLAG_CRL_CHECK_ALL);
+#endif
+ }
+#endif
+
+ /*
+ * Set verify modes
+ * Always verify the peer certificate
+ */
+ verify_mode |= SSL_VERIFY_PEER;
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ verify_mode |= SSL_VERIFY_CLIENT_ONCE;
+ SSL_CTX_set_verify(ctx, verify_mode, cbtls_verify);
+
+ if (conf->verify_depth) {
+ SSL_CTX_set_verify_depth(ctx, conf->verify_depth);
+ }
+
+#ifndef LIBRESSL_VERSION_NUMBER
+ /* Load randomness */
+ if (conf->random_file) {
+ if (!(RAND_load_file(conf->random_file, 1024*10))) {
+ tls_error_log(NULL, "Failed loading randomness");
+ return NULL;
+ }
+ }
+#endif
+
+ /*
+ * Setup session caching
+ */
+ if (conf->session_cache_enable) {
+ /*
+ * Create a unique context Id per EAP-TLS configuration.
+ */
+ if (conf->session_id_name) {
+ snprintf(conf->session_context_id, sizeof(conf->session_context_id),
+ "FR eap %s", conf->session_id_name);
+ } else {
+ snprintf(conf->session_context_id, sizeof(conf->session_context_id),
+ "FR eap %p", conf);
+ }
+
+ /*
+ * Cache it, DON'T auto-clear it, and disable the internal OpenSSL session cache.
+ */
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR | SSL_SESS_CACHE_NO_INTERNAL);
+
+ SSL_CTX_set_session_id_context(ctx,
+ (unsigned char *) conf->session_context_id,
+ (unsigned int) strlen(conf->session_context_id));
+
+ /*
+ * Our lifetime is in hours, this is in seconds.
+ */
+ SSL_CTX_set_timeout(ctx, conf->session_lifetime * 3600);
+
+ /*
+ * Set the maximum number of entries in the
+ * session cache.
+ */
+ SSL_CTX_sess_set_cache_size(ctx, conf->session_cache_size);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ SSL_CTX_set_num_tickets(ctx, 1);
+#endif
+
+ } else {
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ /*
+ * This controls the number of stateful or stateless tickets
+ * generated with TLS 1.3. In OpenSSL 1.1.1 it's also
+ * required to disable sending session tickets,
+ * SSL_SESS_CACHE_OFF is not good enough.
+ */
+ SSL_CTX_set_num_tickets(ctx, 0);
+#endif
+ }
+
+ return ctx;
+}
+
+
+/*
+ * Free TLS client/server config
+ * Should not be called outside this code, as a callback is
+ * added to automatically free the data when the CONF_SECTION
+ * is freed.
+ */
+static int _tls_server_conf_free(fr_tls_server_conf_t *conf)
+{
+ if (conf->ctx) SSL_CTX_free(conf->ctx);
+
+ if (conf->cache_ht) fr_hash_table_free(conf->cache_ht);
+
+ pthread_mutex_destroy(&conf->mutex);
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ if (conf->ocsp_store) X509_STORE_free(conf->ocsp_store);
+ conf->ocsp_store = NULL;
+#endif
+
+ if (conf->realms) fr_hash_table_free(conf->realms);
+
+#ifndef NDEBUG
+ memset(conf, 0, sizeof(*conf));
+#endif
+ return 0;
+}
+
+fr_tls_server_conf_t *tls_server_conf_alloc(TALLOC_CTX *ctx)
+{
+ fr_tls_server_conf_t *conf;
+
+ conf = talloc_zero(ctx, fr_tls_server_conf_t);
+ if (!conf) {
+ ERROR(LOG_PREFIX ": Out of memory");
+ return NULL;
+ }
+
+ talloc_set_destructor(conf, _tls_server_conf_free);
+
+ return conf;
+}
+
+static uint32_t store_hash(void const *data)
+{
+ DICT_ATTR const *da = data;
+ return fr_hash(&da, sizeof(da));
+}
+
+static int store_cmp(void const *a, void const *b)
+{
+ DICT_ATTR const *one = a;
+ DICT_ATTR const *two = b;
+
+ return (one < two) - (one > two);
+}
+
+static uint32_t realm_hash(void const *data)
+{
+ fr_realm_ctx_t const *r = data;
+
+ return fr_hash_string(r->name);
+}
+
+static int realm_cmp(void const *a, void const *b)
+{
+ fr_realm_ctx_t const *one = a;
+ fr_realm_ctx_t const *two = b;
+
+ return strcmp(one->name, two->name);
+}
+
+static void realm_free(void *data)
+{
+ fr_realm_ctx_t *r = data;
+
+ SSL_CTX_free(r->ctx);
+}
+
+static int tls_realms_load(fr_tls_server_conf_t *conf)
+{
+ fr_hash_table_t *ht;
+ DIR *dir;
+ struct dirent *dp;
+ char buffer[PATH_MAX];
+ char buffer2[PATH_MAX];
+
+ ht = fr_hash_table_create(realm_hash, realm_cmp, realm_free);
+ if (!ht) return -1;
+
+ dir = opendir(conf->realm_dir);
+ if (!dir) {
+ ERROR("Error reading directory %s: %s", conf->realm_dir, fr_syserror(errno));
+ error:
+ if (dir) closedir(dir);
+ fr_hash_table_free(ht);
+ return -1;
+ }
+
+ /*
+ * Read only the PEM files
+ */
+ while ((dp = readdir(dir)) != NULL) {
+ char *p;
+ struct stat stat_buf;
+ SSL_CTX *ctx;
+ fr_realm_ctx_t *r;
+ char const *private_key_file = buffer;
+
+ if (dp->d_name[0] == '.') continue;
+
+ p = strrchr(dp->d_name, '.');
+ if (!p) continue;
+
+ if (memcmp(p, ".pem", 5) != 0) continue; /* must END in .pem */
+
+ snprintf(buffer, sizeof(buffer), "%s/%s", conf->realm_dir, dp->d_name); /* ignore directories */
+ if ((stat(buffer, &stat_buf) != 0) ||
+ S_ISDIR(stat_buf.st_mode)) continue;
+
+ strcpy(buffer2, buffer);
+ p = strchr(buffer2, '.'); /* which must be there... */
+ if (!p) continue;
+
+ /*
+ * If there's a key file, then use that.
+ * Otherwise assume that the private key is in
+ * the chain file.
+ */
+ strcpy(p, ".key");
+ if (stat(buffer2, &stat_buf) != 0) private_key_file = buffer2;
+
+ ctx = tls_init_ctx(conf, 1, buffer, private_key_file);
+ if (!ctx) goto error;
+
+ r = talloc_zero(conf, fr_realm_ctx_t);
+ if (!r) {
+ SSL_CTX_free(ctx);
+ goto error;
+ }
+
+ r->name = talloc_strdup(r, buffer);
+ r->ctx = ctx;
+
+ if (fr_hash_table_insert(ht, r) < 0) {
+ ERROR("Failed inserting certificate file %s into hash table", buffer);
+ goto error;
+ }
+ }
+
+ conf->realms = ht;
+ closedir(dir);
+
+ return 0;
+}
+
+
+fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs)
+{
+ fr_tls_server_conf_t *conf;
+
+ /*
+ * If cs has already been parsed there should be a cached copy
+ * of conf already stored, so just return that.
+ */
+ conf = cf_data_find(cs, "tls-conf");
+ if (conf) {
+ DEBUG(LOG_PREFIX ": Using cached TLS configuration from previous invocation");
+ return conf;
+ }
+
+ conf = tls_server_conf_alloc(cs);
+
+ if (cf_section_parse(cs, conf, tls_server_config) < 0) {
+ error:
+ talloc_free(conf);
+ return NULL;
+ }
+
+ /*
+ * Save people from their own stupidity.
+ */
+ if (conf->fragment_size < 100) conf->fragment_size = 100;
+
+ /*
+ * Disallow sessions of more than 7 days, as per RFC
+ * 8446.
+ *
+ * Note that we also enforce this on TLS 1.2, etc.
+ * Because there's just no reason to have month-long TLS
+ * sessions.
+ */
+ if (conf->session_lifetime > (7 * 24)) conf->session_lifetime = 7 * 24;
+
+ /*
+ * Only check for certificate things if we don't have a
+ * PSK query.
+ */
+#ifdef PSK_MAX_IDENTITY_LEN
+ if (conf->psk_identity) {
+ if (conf->private_key_file) {
+ WARN(LOG_PREFIX ": Ignoring private key file due to psk_identity being used");
+ }
+
+ if (conf->certificate_file) {
+ WARN(LOG_PREFIX ": Ignoring certificate file due to psk_identity being used");
+ }
+
+ } else
+#endif
+ {
+ if (!conf->private_key_file) {
+ ERROR(LOG_PREFIX ": TLS Server requires a private key file");
+ goto error;
+ }
+
+ if (!conf->certificate_file) {
+ ERROR(LOG_PREFIX ": TLS Server requires a certificate file");
+ goto error;
+ }
+ }
+
+ /*
+ * Initialize configuration mutex
+ */
+ pthread_mutex_init(&conf->mutex, NULL);
+
+ /*
+ * Initialize TLS
+ */
+ conf->ctx = tls_init_ctx(conf, 0, NULL, NULL);
+ if (conf->ctx == NULL) {
+ goto error;
+ }
+
+ if (conf->session_cache_enable) {
+ CONF_SECTION *subcs;
+ CONF_ITEM *ci;
+
+ subcs = cf_section_sub_find(cs, "cache");
+ if (!subcs) goto skip_list;
+ subcs = cf_section_sub_find(subcs, "store");
+ if (!subcs) goto skip_list;
+
+ /*
+ * Largely taken from rlm_detail for laziness.
+ */
+ conf->cache_ht = fr_hash_table_create(store_hash, store_cmp, NULL);
+
+ for (ci = cf_item_find_next(subcs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(subcs, ci)) {
+ char const *attr;
+ DICT_ATTR const *da;
+
+ if (!cf_item_is_pair(ci)) continue;
+
+ attr = cf_pair_attr(cf_item_to_pair(ci));
+ if (!attr) continue; /* pair-anoia */
+
+ da = dict_attrbyname(attr);
+ if (!da) {
+ ERROR(LOG_PREFIX ": TLS Server requires a certificate file");
+ goto error;
+ }
+
+ /*
+ * Be kind to minor mistakes.
+ */
+ if (fr_hash_table_finddata(conf->cache_ht, da)) {
+ WARN(LOG_PREFIX ": Ignoring duplicate entry '%s'", attr);
+ continue;
+ }
+
+
+ if (!fr_hash_table_insert(conf->cache_ht, da)) {
+ ERROR(LOG_PREFIX ": Failed inserting '%s' into cache list", attr);
+ goto error;
+ }
+ }
+
+ /*
+ * If we didn't suppress anything, delete the hash table.
+ */
+ if (fr_hash_table_num_elements(conf->cache_ht) == 0) {
+ fr_hash_table_free(conf->cache_ht);
+ conf->cache_ht = NULL;
+ }
+ }
+
+skip_list:
+
+#ifdef HAVE_OPENSSL_OCSP_H
+ /*
+ * Initialize OCSP Revocation Store
+ */
+ if (conf->ocsp_enable) {
+ conf->ocsp_store = fr_init_x509_store(conf);
+ if (conf->ocsp_store == NULL) goto error;
+ }
+#endif /*HAVE_OPENSSL_OCSP_H*/
+
+ {
+ char *dh_file;
+
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
+ }
+
+ if (conf->verify_tmp_dir) {
+ if (chmod(conf->verify_tmp_dir, S_IRWXU) < 0) {
+ ERROR(LOG_PREFIX ": Failed changing permissions on %s: %s",
+ conf->verify_tmp_dir, fr_syserror(errno));
+ goto error;
+ }
+ }
+
+ if (conf->verify_client_cert_cmd && !conf->verify_tmp_dir) {
+ ERROR(LOG_PREFIX ": You MUST set the 'tmpdir' directory in order to use '%s' cmd", conf->verify_client_cert_cmd);
+ goto error;
+ }
+
+#ifdef SSL_OP_NO_TLSv1_2
+ /*
+ * OpenSSL 1.0.1f and 1.0.1g get the MS-MPPE keys wrong.
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x1010106L) && (OPENSSL_VERSION_NUMBER <= 0x1010107L)
+ conf->disable_tlsv1_2 = true;
+ WARN(LOG_PREFIX ": Disabling TLSv1.2 due to OpenSSL bugs");
+#endif
+#endif
+
+ /*
+ * Load certificates and private keys from the realm directory.
+ */
+ if (conf->realm_dir && (tls_realms_load(conf) < 0)) goto error;
+
+ /*
+ * Cache conf in cs in case we're asked to parse this again.
+ */
+ cf_data_add(cs, "tls-conf", conf, NULL);
+
+ return conf;
+}
+
+fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs)
+{
+ fr_tls_server_conf_t *conf;
+
+ conf = cf_data_find(cs, "tls-conf");
+ if (conf) {
+ DEBUG2(LOG_PREFIX ": Using cached TLS configuration from previous invocation");
+ return conf;
+ }
+
+ conf = tls_server_conf_alloc(cs);
+
+ if (cf_section_parse(cs, conf, tls_client_config) < 0) {
+ error:
+ talloc_free(conf);
+ return NULL;
+ }
+
+ /*
+ * Save people from their own stupidity.
+ */
+ if (conf->fragment_size < 100) conf->fragment_size = 100;
+
+ /*
+ * Initialize TLS
+ */
+ conf->ctx = tls_init_ctx(conf, 1, NULL, NULL);
+ if (conf->ctx == NULL) {
+ goto error;
+ }
+
+ {
+ char *dh_file;
+
+ memcpy(&dh_file, &conf->dh_file, sizeof(dh_file));
+ if (load_dh_params(conf->ctx, dh_file) < 0) {
+ goto error;
+ }
+ }
+
+ cf_data_add(cs, "tls-conf", conf, NULL);
+
+ return conf;
+}
+
+
+int tls_success(tls_session_t *ssn, REQUEST *request)
+{
+ VALUE_PAIR *vp, *vps = NULL;
+ fr_tls_server_conf_t *conf;
+ TALLOC_CTX *talloc_ctx;
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF);
+ rad_assert(conf != NULL);
+
+ talloc_ctx = SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC);
+
+ /*
+ * If there's no session resumption, delete the entry
+ * from the cache. This means either it's disabled
+ * globally for this SSL context, OR we were told to
+ * disable it for this user.
+ *
+ * This also means you can't turn it on just for one
+ * user.
+ */
+ if ((!ssn->allow_session_resumption) ||
+ (((vp = fr_pair_find_by_num(request->config, PW_ALLOW_SESSION_RESUMPTION, 0, TAG_ANY)) != NULL) &&
+ (vp->vp_integer == 0))) {
+ SSL_CTX_remove_session(ssn->ctx,
+ ssn->ssl_session);
+ ssn->allow_session_resumption = false;
+
+ /*
+ * If we're in a resumed session and it's
+ * not allowed,
+ */
+ if (SSL_session_reused(ssn->ssl)) {
+ RDEBUG("(TLS) cache - Forcibly stopping session resumption as it is administratively disabled.");
+ return -1;
+ }
+
+ /*
+ * Else resumption IS allowed, so we store the
+ * user data in the cache.
+ */
+ } else if ((!SSL_session_reused(ssn->ssl)) || ssn->session_not_resumed) {
+ VALUE_PAIR **certs;
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+
+ tls_session_id(ssn->ssl_session, buffer, MAX_SESSION_SIZE);
+
+ RDEBUG("(TLS) cache - Setting up attributes for session resumption");
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->packet->vps, PW_STRIPPED_USER_DOMAIN, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->reply->vps, PW_CHARGEABLE_USER_IDENTITY, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ vp = fr_pair_list_copy_by_num(talloc_ctx, request->reply->vps, PW_CACHED_SESSION_POLICY, 0, TAG_ANY);
+ if (vp) fr_pair_add(&vps, vp);
+
+ if (conf->cache_ht) {
+ vp_cursor_t cursor;
+
+ /* Write each attribute/value to the log file */
+ for (vp = fr_cursor_init(&cursor, &request->reply->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VALUE_PAIR *copy;
+
+ if (!fr_hash_table_finddata(conf->cache_ht, vp->da)) {
+ continue;
+ }
+
+ copy = fr_pair_copy(talloc_ctx, vp);
+ if (copy) fr_pair_add(&vps, copy);
+ }
+ }
+
+ /*
+ * Hmm... the certs should probably be session data.
+ */
+ certs = (VALUE_PAIR **)SSL_get_ex_data(ssn->ssl, fr_tls_ex_index_certs);
+ if (certs) {
+ /*
+ * @todo: some go into reply, others into
+ * request
+ */
+ fr_pair_add(&vps, fr_pair_list_copy(talloc_ctx, *certs));
+
+ vp = fr_pair_find_by_num(vps, PW_TLS_CLIENT_CERT_EXPIRATION, 0, TAG_ANY);
+ if (vp) {
+ time_t expires;
+
+ if (ocsp_asn1time_to_epoch(&expires, vp->vp_strvalue) < 0) {
+ RDEBUG2("Failed getting certificate expiration, removing cache entry for session %s", buffer);
+ SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
+ return -1;
+ }
+
+ if (expires <= request->timestamp) {
+ RDEBUG2("Certificate has expired, removing cache entry for session %s", buffer);
+ SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
+ return -1;
+ }
+
+ /*
+ * Account for Session-Timeout, if it's available.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (vp) {
+ if ((request->timestamp + vp->vp_integer) > expires) {
+ vp->vp_integer = expires - request->timestamp;
+ RWDEBUG2("(TLS) Updating Session-Timeout to %u, due to impending certificate expiration",
+ vp->vp_integer);
+ }
+ }
+ }
+ }
+
+ if (vps) {
+ SSL_SESSION_set_ex_data(ssn->ssl_session, fr_tls_ex_index_vps, vps);
+ rdebug_pair_list(L_DBG_LVL_2, request, vps, " caching ");
+
+ if (conf->session_cache_path) {
+ /* write the VPs to the cache file */
+ char filename[3 * MAX_SESSION_SIZE + 1], buf[1024];
+ FILE *vp_file;
+
+ RDEBUG2("Saving session %s in the disk cache", buffer);
+
+ snprintf(filename, sizeof(filename), "%s%c%s.vps", conf->session_cache_path,
+ FR_DIR_SEP, buffer);
+ vp_file = fopen(filename, "w");
+ if (vp_file == NULL) {
+ RWDEBUG("(TLS) Could not write session VPs to persistent cache: %s",
+ fr_syserror(errno));
+ } else {
+ VALUE_PAIR *prev = NULL;
+ vp_cursor_t cursor;
+ /* generate a dummy user-style entry which is easy to read back */
+ fprintf(vp_file, "# SSL cached session\n");
+ fprintf(vp_file, "%s\n\t", buffer);
+
+ for (vp = fr_cursor_init(&cursor, &vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Terminate the previous line.
+ */
+ if (prev) fprintf(vp_file, ",\n\t");
+
+ /*
+ * Write this one.
+ */
+ vp_prints(buf, sizeof(buf), vp);
+ fputs(buf, vp_file);
+ prev = vp;
+ }
+
+ /*
+ * Terminate the final line.
+ */
+ fprintf(vp_file, "\n");
+ fclose(vp_file);
+ }
+
+ } else if (conf->session_cache_server) {
+ cbtls_cache_save_vps(ssn->ssl, ssn->ssl_session, vps);
+
+ } else {
+ RDEBUG("Failed to find 'persist_dir' in TLS configuration. Session will not be cached on disk.");
+ }
+ } else {
+ RDEBUG2("No information to cache: session caching will be disabled for session %s", buffer);
+ SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
+ }
+
+ /*
+ * Else the session WAS allowed. Copy the cached reply.
+ */
+ } else {
+ RDEBUG("(TLS) cache - Refreshing entry for session resumption");
+
+ /*
+ * The "restore VPs from OpenSSL cache" code is
+ * now in eaptls_process()
+ */
+ if (conf->session_cache_path) {
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+#ifdef TLS1_3_VERSION
+ /*
+ * OpenSSL frees the underlying session out from
+ * under us in TLS 1.3.
+ */
+ if (SSL_version(ssn->ssl) == TLS1_3_VERSION) ssn->ssl_session = SSL_get_session(ssn->ssl);
+#endif
+#endif
+
+ tls_session_id(ssn->ssl_session, buffer, MAX_SESSION_SIZE);
+
+ /* "touch" the cached session/vp file */
+ char filename[3 * MAX_SESSION_SIZE + 1];
+
+ snprintf(filename, sizeof(filename), "%s%c%s.asn1",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ utime(filename, NULL);
+ snprintf(filename, sizeof(filename), "%s%c%s.vps",
+ conf->session_cache_path, FR_DIR_SEP, buffer);
+ utime(filename, NULL);
+ }
+
+ if (conf->session_cache_server) {
+ cbtls_cache_refresh(ssn->ssl, ssn->ssl_session);
+ }
+
+ /*
+ * Mark the request as resumed.
+ */
+ pair_make_request("EAP-Session-Resumed", "1", T_OP_SET);
+ RDEBUG(" &request:EAP-Session-Resumed := 1");
+ }
+
+ return 0;
+}
+
+
+void tls_fail(tls_session_t *ssn)
+{
+ /*
+ * Force the session to NOT be cached.
+ */
+ SSL_CTX_remove_session(ssn->ctx, ssn->ssl_session);
+}
+
+fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request)
+
+{
+ int err;
+ VALUE_PAIR **certs;
+
+ /*
+ * Decrypt the complete record.
+ */
+ if (ssn->dirty_in.used > 0) {
+ err = BIO_write(ssn->into_ssl, ssn->dirty_in.data,
+ ssn->dirty_in.used);
+ if (err != (int) ssn->dirty_in.used) {
+ REDEBUG("(TLS) Failed writing %zd bytes to SSL BIO: %d", ssn->dirty_in.used, err);
+ record_init(&ssn->dirty_in);
+ return FR_TLS_FAIL;
+ }
+
+ record_init(&ssn->dirty_in);
+ }
+
+ /*
+ * tls_handshake_recv() may read application data. So
+ * don't touch clean_out. But only if the BIO_write()
+ * above didn't do anything.
+ */
+ else if (ssn->clean_out.used > 0) {
+ RDEBUG("(TLS) We already have %zd bytes of application data, processing it.",
+ (ssn->clean_out.used));
+ goto add_certs;
+ }
+
+ /*
+ * Read (and decrypt) the tunneled data from the
+ * SSL session, and put it into the decrypted
+ * data buffer.
+ */
+ err = SSL_read(ssn->ssl, ssn->clean_out.data + ssn->clean_out.used,
+ sizeof(ssn->clean_out.data) - ssn->clean_out.used);
+ if (err <= 0) {
+ int code;
+
+ RDEBUG3("(TLS) SSL_read Error");
+
+ code = SSL_get_error(ssn->ssl, err);
+ switch (code) {
+ case SSL_ERROR_WANT_READ:
+ if (ssn->clean_out.used > 0) { /* just process what application data we have */
+ err = 0;
+ break;
+ }
+
+ RDEBUG("(TLS) OpenSSL says that it needs to read more data.");
+ return FR_TLS_MORE_FRAGMENTS;
+
+ case SSL_ERROR_WANT_WRITE:
+ if (ssn->clean_out.used > 0) { /* just process what application data we have */
+ err = 0;
+ break;
+ }
+
+ REDEBUG("(TLS) Error in fragmentation logic: SSL_WANT_WRITE");
+ return FR_TLS_FAIL;
+
+ case SSL_ERROR_NONE:
+ RDEBUG2("(TLS) No application data received. Assuming handshake is continuing...");
+ err = 0;
+ break;
+
+ case SSL_ERROR_ZERO_RETURN:
+ RDEBUG2("(TLS) Other end closed the TLS tunnel.");
+ return FR_TLS_FAIL;
+
+ default:
+ REDEBUG("(TLS) Error in fragmentation logic - code %d", code);
+ tls_error_io_log(request, ssn, err, "Failed reading application data from OpenSSL");
+ return FR_TLS_FAIL;
+ }
+ }
+
+ /*
+ * Passed all checks, successfully decrypted data
+ */
+ ssn->clean_out.used += err;
+
+add_certs:
+ /*
+ * Add the certificates to intermediate packets, so that
+ * the inner tunnel policies can use them.
+ */
+ certs = (VALUE_PAIR **)SSL_get_ex_data(ssn->ssl, fr_tls_ex_index_certs);
+
+ if (certs) fr_pair_add(&request->packet->vps, fr_pair_list_copy(request->packet, *certs));
+
+ return FR_TLS_OK;
+}
+
+
+/*
+ * Acknowledge received is for one of the following messages sent earlier
+ * 1. Handshake completed Message, so now send, EAP-Success
+ * 2. Alert Message, now send, EAP-Failure
+ * 3. Fragment Message, now send, next Fragment
+ */
+fr_tls_status_t tls_ack_handler(tls_session_t *ssn, REQUEST *request)
+{
+ if (ssn == NULL){
+ REDEBUG("(TLS) Unexpected ACK received: No ongoing SSL session");
+ return FR_TLS_INVALID;
+ }
+ if (!ssn->info.initialized) {
+ RDEBUG("(TLS) No SSL info available. Waiting for more SSL data");
+ return FR_TLS_REQUEST;
+ }
+
+ if ((ssn->info.content_type == handshake) && (ssn->info.origin == 0)) {
+ REDEBUG("(TLS) Unexpected ACK received: We sent no previous messages");
+ return FR_TLS_INVALID;
+ }
+
+ switch (ssn->info.content_type) {
+ case alert:
+ RDEBUG2("(TLS) Peer ACKed our alert");
+ return FR_TLS_FAIL;
+
+ case handshake:
+ if (ssn->dirty_out.used > 0) {
+ RDEBUG2("(TLS) Peer ACKed our handshake fragment");
+ /* Fragmentation handler, send next fragment */
+ return FR_TLS_REQUEST;
+ }
+
+ if (ssn->is_init_finished || SSL_is_init_finished(ssn->ssl)) {
+ RDEBUG2("(TLS) Peer ACKed our handshake fragment. handshake is finished");
+
+ /*
+ * From now on all the content is
+ * application data set it here as nobody else
+ * sets it.
+ */
+ ssn->info.content_type = application_data;
+ return FR_TLS_SUCCESS;
+ } /* else more data to send */
+
+ REDEBUG("(TLS) Cannot continue, as the peer is misbehaving.");
+ return FR_TLS_FAIL;
+
+ case application_data:
+ RDEBUG2("(TLS) Peer ACKed our application data fragment");
+ return FR_TLS_REQUEST;
+
+ /*
+ * For the rest of the conditions, switch over
+ * to the default section below.
+ */
+ default:
+ REDEBUG("(TLS) Invalid ACK received: %d", ssn->info.content_type);
+ return FR_TLS_INVALID;
+ }
+}
+#endif /* WITH_TLS */
+
diff --git a/src/main/tls_listen.c b/src/main/tls_listen.c
new file mode 100644
index 0000000..fa8c382
--- /dev/null
+++ b/src/main/tls_listen.c
@@ -0,0 +1,1568 @@
+/*
+ * tls.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef WITH_TCP
+#ifdef WITH_TLS
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
+
+#ifdef HAVE_OPENSSL_OCSP_H
+#include <openssl/ocsp.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+static void dump_hex(char const *msg, uint8_t const *data, size_t data_len)
+{
+ size_t i;
+
+ if (rad_debug_lvl < 3) return;
+
+ printf("%s %d\n", msg, (int) data_len);
+ if (data_len > 256) data_len = 256;
+
+ for (i = 0; i < data_len; i++) {
+ if ((i & 0x0f) == 0x00) printf ("%02x: ", (unsigned int) i);
+ printf("%02x ", data[i]);
+ if ((i & 0x0f) == 0x0f) printf ("\n");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+static void tls_socket_close(rad_listen_t *listener)
+{
+ listen_socket_t *sock = listener->data;
+
+ SSL_shutdown(sock->ssn->ssl);
+
+ listener->status = RAD_LISTEN_STATUS_EOL;
+ listener->tls = NULL; /* parent owns this! */
+
+ /*
+ * Tell the event handler that an FD has disappeared.
+ */
+ DEBUG("(TLS) Closing connection");
+ radius_update_listener(listener);
+
+ /*
+ * Do NOT free the listener here. It may be in use by
+ * a request, and will need to hang around until
+ * all of the requests are done.
+ *
+ * It is instead free'd when all of the requests using it
+ * are done.
+ */
+}
+
+static void tls_write_available(fr_event_list_t *el, int sock, void *ctx);
+
+static int CC_HINT(nonnull) tls_socket_write(rad_listen_t *listener)
+{
+ ssize_t rcode;
+ listen_socket_t *sock = listener->data;
+
+ /*
+ * It's not writable, so we don't bother writing to it.
+ */
+ if (listener->blocked) return 0;
+
+ /*
+ * Write as much as possible.
+ */
+ rcode = write(listener->fd, sock->ssn->dirty_out.data, sock->ssn->dirty_out.used);
+ if (rcode <= 0) {
+#ifdef EWOULDBLOCK
+ /*
+ * Writing to the socket would cause it to block.
+ * As a result, we just mark it as "don't use"
+ * until such time as it becomes writable.
+ */
+ if (errno == EWOULDBLOCK) {
+ proxy_listener_freeze(listener, tls_write_available);
+ return 0;
+ }
+#endif
+
+
+ ERROR("(TLS) Error writing to socket: %s", fr_syserror(errno));
+
+ tls_socket_close(listener);
+ return -1;
+ }
+
+ /*
+ * All of the data was written. It's fine.
+ */
+ if ((size_t) rcode == sock->ssn->dirty_out.used) {
+ sock->ssn->dirty_out.used = 0;
+ return 0;
+ }
+
+ /*
+ * Move the data to the start of the buffer.
+ *
+ * Yes, this is horrible. But doing this means that we
+ * don't have to modify the rest of the code which mangles dirty_out, and assumes that the write offset is always &data[used].
+ */
+ memmove(&sock->ssn->dirty_out.data[0], &sock->ssn->dirty_out.data[rcode], sock->ssn->dirty_out.used - rcode);
+ sock->ssn->dirty_out.used -= rcode;
+
+ return 0;
+}
+
+static void tls_write_available(UNUSED fr_event_list_t *el, UNUSED int fd, void *ctx)
+{
+ rad_listen_t *listener = ctx;
+ listen_socket_t *sock = listener->data;
+
+ proxy_listener_thaw(listener);
+
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ (void) tls_socket_write(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+}
+
+
+/*
+ * Check for PROXY protocol. Once that's done, clear
+ * listener->proxy_protocol.
+ */
+static int proxy_protocol_check(rad_listen_t *listener, REQUEST *request)
+{
+ listen_socket_t *sock = listener->data;
+ uint8_t const *p, *end, *eol;
+ int af, argc, src_port, dst_port;
+ unsigned long num;
+ fr_ipaddr_t src, dst;
+ char *argv[5], *eos;
+ ssize_t rcode;
+ RADCLIENT *client;
+
+ /*
+ * Begin by trying to fill the buffer.
+ */
+ rcode = read(request->packet->sockfd,
+ sock->ssn->dirty_in.data + sock->ssn->dirty_in.used,
+ sizeof(sock->ssn->dirty_in.data) - sock->ssn->dirty_in.used);
+ if (rcode < 0) {
+ if (errno == EINTR) return 0;
+ RDEBUG("(TLS) Closing PROXY socket from client port %u due to read error - %s", sock->other_port, fr_syserror(errno));
+ return -1;
+ }
+
+ if (rcode == 0) {
+ DEBUG("(TLS) Closing PROXY socket from client port %u - other end closed connection", sock->other_port);
+ return -1;
+ }
+
+ /*
+ * We've read data, scan the buffer for a CRLF.
+ */
+ sock->ssn->dirty_in.used += rcode;
+
+ dump_hex("READ FROM PROXY PROTOCOL SOCKET", sock->ssn->dirty_in.data, sock->ssn->dirty_in.used);
+
+ p = sock->ssn->dirty_in.data;
+
+ /*
+ * CRLF MUST be within the first 107 bytes.
+ */
+ if (sock->ssn->dirty_in.used < 107) {
+ end = p + sock->ssn->dirty_in.used;
+ } else {
+ end = p + 107;
+ }
+ eol = NULL;
+
+ /*
+ * Scan for CRLF.
+ */
+ while ((p + 1) < end) {
+ if ((p[0] == 0x0d) && (p[1] == 0x0a)) {
+ eol = p;
+ break;
+ }
+
+ /*
+ * Other control characters, or non-ASCII data.
+ * That's a problem.
+ */
+ if ((*p < ' ') || (*p >= 0x80)) {
+ invalid_data:
+ DEBUG("(TLS) Closing PROXY socket from client port %u - received invalid data", sock->other_port);
+ return -1;
+ }
+
+ p++;
+ }
+
+ /*
+ * No CRLF, keep reading until we have it.
+ */
+ if (!eol) return 0;
+
+ p = sock->ssn->dirty_in.data;
+
+ /*
+ * Let's see if the PROXY line is well-formed.
+ */
+ if ((eol - p) < 14) goto invalid_data;
+
+ /*
+ * We only support TCP4 and TCP6.
+ */
+ if (memcmp(p, "PROXY TCP", 9) != 0) goto invalid_data;
+
+ p += 9;
+
+ if (*p == '4') {
+ af = AF_INET;
+
+ } else if (*p == '6') {
+ af = AF_INET6;
+
+ } else goto invalid_data;
+
+ p++;
+ if (*p != ' ') goto invalid_data;
+ p++;
+
+ sock->ssn->dirty_in.data[eol - sock->ssn->dirty_in.data] = '\0'; /* overwite the CRLF */
+
+ /*
+ * Parse the fields (being a little forgiving), while
+ * checking for too many / too few fields.
+ */
+ argc = str2argv((char *) &sock->ssn->dirty_in.data[p - sock->ssn->dirty_in.data], (char **) &argv, 5);
+ if (argc != 4) goto invalid_data;
+
+ memset(&src, 0, sizeof(src));
+ memset(&dst, 0, sizeof(dst));
+
+ if (fr_pton(&src, argv[0], -1, af, false) < 0) goto invalid_data;
+ if (fr_pton(&dst, argv[1], -1, af, false) < 0) goto invalid_data;
+
+ num = strtoul(argv[2], &eos, 10);
+ if (num > 65535) goto invalid_data;
+ if (*eos) goto invalid_data;
+ src_port = num;
+
+ num = strtoul(argv[3], &eos, 10);
+ if (num > 65535) goto invalid_data;
+ if (*eos) goto invalid_data;
+ dst_port = num;
+
+ /*
+ * And copy the various fields around.
+ */
+ sock->haproxy_src_ipaddr = sock->other_ipaddr;
+ sock->haproxy_src_port = sock->other_port;
+
+ sock->haproxy_dst_ipaddr = sock->my_ipaddr;
+ sock->haproxy_dst_port = sock->my_port;
+
+ sock->my_ipaddr = dst;
+ sock->my_port = dst_port;
+
+ sock->other_ipaddr = src;
+ sock->other_port = src_port;
+
+ /*
+ * Print out what we've changed. Note that the TCP
+ * socket address family and the PROXY address family may
+ * be different!
+ */
+ if (RDEBUG_ENABLED) {
+ char src_buf[128], dst_buf[128];
+
+ RDEBUG("(TLS) Received PROXY protocol connection from client %s:%s -> %s:%s, via proxy %s:%u -> %s:%u",
+ argv[0], argv[2], argv[1], argv[3],
+ inet_ntop(af, &sock->haproxy_src_ipaddr.ipaddr, src_buf, sizeof(src_buf)),
+ sock->haproxy_src_port,
+ inet_ntop(af, &sock->haproxy_dst_ipaddr.ipaddr, dst_buf, sizeof(dst_buf)),
+ sock->haproxy_dst_port);
+ }
+
+ /*
+ * Ensure that the source IP indicated by the PROXY
+ * protocol is a known TLS client.
+ */
+ if ((client = client_listener_find(listener, &src, src_port)) == NULL ||
+ client->proto != IPPROTO_TCP) {
+ RDEBUG("(TLS) Unknown client %s - dropping PROXY protocol connection", argv[0]);
+ return -1;
+ }
+
+ /*
+ * Use the client indicated by the proxy.
+ */
+ sock->client = client;
+
+ /*
+ * Fix up the current request so that the first packet's
+ * src/dst is valid. Subsequent packets will get the
+ * clients IP from the listener and listen_sock
+ * structures.
+ */
+ request->packet->dst_ipaddr = dst;
+ request->packet->dst_port = dst_port;
+ request->packet->src_ipaddr = src;
+ request->packet->src_port = src_port;
+
+ /*
+ * Move any remaining TLS data to the start of the buffer.
+ */
+ eol += 2;
+ end = sock->ssn->dirty_in.data + sock->ssn->dirty_in.used;
+ if (eol < end) {
+ memmove(sock->ssn->dirty_in.data, eol, end - eol);
+ sock->ssn->dirty_in.used = end - eol;
+ } else {
+ sock->ssn->dirty_in.used = 0;
+ }
+
+ /*
+ * It's no longer a PROXY protocol, but just straight TLS.
+ */
+ listener->proxy_protocol = false;
+
+ return 1;
+}
+
+static int tls_socket_recv(rad_listen_t *listener)
+{
+ bool doing_init = false, already_read = false;
+ ssize_t rcode;
+ RADIUS_PACKET *packet;
+ REQUEST *request;
+ listen_socket_t *sock = listener->data;
+ fr_tls_status_t status;
+ RADCLIENT *client = sock->client;
+
+ if (!sock->packet) {
+ sock->packet = rad_alloc(sock, false);
+ if (!sock->packet) return 0;
+
+ sock->packet->sockfd = listener->fd;
+ sock->packet->src_ipaddr = sock->other_ipaddr;
+ sock->packet->src_port = sock->other_port;
+ sock->packet->dst_ipaddr = sock->my_ipaddr;
+ sock->packet->dst_port = sock->my_port;
+
+ if (sock->request) sock->request->packet = talloc_steal(sock->request, sock->packet);
+ }
+
+ /*
+ * Allocate a REQUEST for debugging, and initialize the TLS session.
+ */
+ if (!sock->request) {
+ sock->request = request = request_alloc(sock);
+ if (!sock->request) {
+ ERROR("Out of memory");
+ return 0;
+ }
+
+ rad_assert(request->packet == NULL);
+ rad_assert(sock->packet != NULL);
+ request->packet = talloc_steal(request, sock->packet);
+
+ request->component = "<tls-connect>";
+
+ request->reply = rad_alloc(request, false);
+ if (!request->reply) return 0;
+
+ rad_assert(sock->ssn == NULL);
+
+ sock->ssn = tls_new_session(sock, listener->tls, sock->request,
+ listener->tls->require_client_cert, true);
+ if (!sock->ssn) {
+ TALLOC_FREE(sock->request);
+ sock->packet = NULL;
+ return 0;
+ }
+
+ SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);
+ SSL_set_ex_data(sock->ssn->ssl, fr_tls_ex_index_certs, (void *) &sock->certs);
+ SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_TALLOC, sock);
+
+ sock->ssn->quick_session_tickets = true; /* we don't have inner-tunnel authentication */
+
+ doing_init = true;
+ }
+
+ rad_assert(sock->request != NULL);
+ rad_assert(sock->request->packet != NULL);
+ rad_assert(sock->packet != NULL);
+ rad_assert(sock->ssn != NULL);
+
+ request = sock->request;
+
+ /*
+ * Bypass ALL of the TLS stuff until we've read the PROXY
+ * header.
+ *
+ * If the PROXY header checks pass, then the flag is
+ * cleared, as we don't need it any more.
+ */
+ if (listener->proxy_protocol) {
+ rcode = proxy_protocol_check(listener, request);
+ if (rcode < 0) {
+ RDEBUG("(TLS) Closing PROXY TLS socket from client port %u", sock->other_port);
+ tls_socket_close(listener);
+ return 0;
+ }
+ if (rcode == 0) return 1;
+
+ /*
+ * The buffer might already have data. In that
+ * case, we don't want to do a blocking read
+ * later.
+ */
+ already_read = (sock->ssn->dirty_in.used > 0);
+ }
+
+ if (sock->state == LISTEN_TLS_SETUP) {
+ RDEBUG3("(TLS) Setting connection state to RUNNING");
+ sock->state = LISTEN_TLS_RUNNING;
+
+ if (sock->ssn->clean_out.used < 20) {
+ goto get_application_data;
+ }
+
+ goto read_application_data;
+ }
+
+ RDEBUG3("(TLS) Reading from socket %d", request->packet->sockfd);
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+
+ /*
+ * If there is pending application data, as set up by
+ * SSL_peek(), read that before reading more data from
+ * the socket.
+ */
+ if (SSL_pending(sock->ssn->ssl)) {
+ RDEBUG3("(TLS) Reading pending buffered data");
+ sock->ssn->dirty_in.used = 0;
+ goto check_for_setup;
+ }
+
+ if (!already_read) {
+ rcode = read(request->packet->sockfd,
+ sock->ssn->dirty_in.data,
+ sizeof(sock->ssn->dirty_in.data));
+ if ((rcode < 0) && (errno == ECONNRESET)) {
+ do_close:
+ DEBUG("(TLS) Closing socket from client port %u", sock->other_port);
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ if (rcode < 0) {
+ RDEBUG("(TLS) Error reading socket: %s", fr_syserror(errno));
+ goto do_close;
+ }
+
+ /*
+ * Normal socket close.
+ */
+ if (rcode == 0) {
+ RDEBUG("(TLS) Client has closed the TCP connection");
+ goto do_close;
+ }
+
+ sock->ssn->dirty_in.used = rcode;
+ }
+
+ dump_hex("READ FROM SSL", sock->ssn->dirty_in.data, sock->ssn->dirty_in.used);
+
+ /*
+ * Catch attempts to use non-SSL.
+ */
+ if (doing_init && (sock->ssn->dirty_in.data[0] != handshake)) {
+ RDEBUG("(TLS) Non-TLS data sent to TLS socket: closing");
+ goto do_close;
+ }
+
+ /*
+ * If we need to do more initialization, do that here.
+ */
+check_for_setup:
+ if (!sock->ssn->is_init_finished) {
+ if (!tls_handshake_recv(request, sock->ssn)) {
+ RDEBUG("(TLS) Failed in TLS handshake receive");
+ goto do_close;
+ }
+
+ /*
+ * More ACK data to send. Do so.
+ */
+ if (sock->ssn->dirty_out.used > 0) {
+ RDEBUG3("(TLS) Writing to socket %d", listener->fd);
+ tls_socket_write(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ /*
+ * If SSL handshake still isn't finished, then there
+ * is more data to read. Release the mutex and
+ * return so this function will be called again
+ */
+ if (!SSL_is_init_finished(sock->ssn->ssl)) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+ }
+
+ /*
+ * Run the request through a virtual server in
+ * order to see if we like the certificate
+ * presented by the client.
+ */
+ if (sock->state == LISTEN_TLS_INIT) {
+ if (!SSL_is_init_finished(sock->ssn->ssl)) {
+ RDEBUG("(TLS) OpenSSL says that the TLS session is still negotiating, but there's no more data to send!");
+ goto do_close;
+ }
+
+ sock->ssn->is_init_finished = true;
+ if (!listener->check_client_connections) {
+ sock->state = LISTEN_TLS_RUNNING;
+ goto get_application_data;
+ }
+
+ request->packet->vps = fr_pair_list_copy(request->packet, sock->certs);
+
+ /*
+ * Fake out a Status-Server packet, which
+ * does NOT have a Message-Authenticator,
+ * or any other contents.
+ */
+ request->packet->code = PW_CODE_STATUS_SERVER;
+ request->packet->data = talloc_zero_array(request->packet, uint8_t, 20);
+ request->packet->data[0] = PW_CODE_STATUS_SERVER;
+ request->packet->data[3] = 20;
+ request->listener = listener;
+ sock->state = LISTEN_TLS_CHECKING;
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ /*
+ * Don't read from the socket until the request
+ * returns.
+ */
+ listener->status = RAD_LISTEN_STATUS_PAUSE;
+ radius_update_listener(listener);
+
+ return 1;
+ }
+
+ /*
+ * Try to get application data.
+ */
+get_application_data:
+ /*
+ * More data to send. Do so.
+ */
+ if (sock->ssn->dirty_out.used > 0) {
+ RDEBUG3("(TLS) Writing to socket %d", listener->fd);
+ rcode = tls_socket_write(listener);
+ if (rcode < 0) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return rcode;
+ }
+ }
+
+ status = tls_application_data(sock->ssn, request);
+ RDEBUG3("(TLS) Application data status %d", status);
+
+ /*
+ * Some kind of failure. Close the socket.
+ */
+ if (status == FR_TLS_FAIL) {
+ DEBUG("(TLS) Unable to recover from TLS error, closing socket from client port %u", sock->other_port);
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ if (status == FR_TLS_MORE_FRAGMENTS) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ if (sock->ssn->clean_out.used == 0) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+ /*
+ * Hold application data if we're not yet in the RUNNING
+ * state.
+ */
+ if (sock->state != LISTEN_TLS_RUNNING) {
+ RDEBUG3("(TLS) Holding application data until setup is complete");
+ return 0;
+ }
+
+read_application_data:
+ /*
+ * We now have a bunch of application data.
+ */
+ dump_hex("TUNNELED DATA > ", sock->ssn->clean_out.data, sock->ssn->clean_out.used);
+
+ /*
+ * If the packet is a complete RADIUS packet, return it to
+ * the caller. Otherwise...
+ */
+ if ((sock->ssn->clean_out.used < 20) ||
+ (((sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]) != (int) sock->ssn->clean_out.used)) {
+ RDEBUG("(TLS) Received bad packet: Length %zd contents %d",
+ sock->ssn->clean_out.used,
+ (sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]);
+ goto do_close;
+ }
+
+ packet = sock->packet;
+ packet->data = talloc_array(packet, uint8_t, sock->ssn->clean_out.used);
+ packet->data_len = sock->ssn->clean_out.used;
+ sock->ssn->record_minus(&sock->ssn->clean_out, packet->data, packet->data_len);
+ packet->vps = NULL;
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+#ifdef WITH_RADIUSV11
+ packet->radiusv11 = sock->radiusv11;
+#endif
+
+ if (!rad_packet_ok(packet, 0, NULL)) {
+ if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
+ DEBUG("(TLS) Closing TLS socket from client");
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0; /* do_close unlocks the mutex */
+ }
+
+ /*
+ * Copied from src/lib/radius.c, rad_recv();
+ */
+ if (fr_debug_lvl) {
+ char host_ipaddr[128];
+
+ if (is_radius_code(packet->code)) {
+ RDEBUG("(TLS): %s packet from host %s port %d, id=%d, length=%d",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ packet->src_port,
+ packet->id, (int) packet->data_len);
+ } else {
+ RDEBUG("(TLS): Packet from host %s port %d code=%d, id=%d, length=%d",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ packet->src_port,
+ packet->code,
+ packet->id, (int) packet->data_len);
+ }
+ }
+
+ FR_STATS_INC(auth, total_requests);
+
+ return 1;
+}
+
+
+int dual_tls_recv(rad_listen_t *listener)
+{
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ listen_socket_t *sock = listener->data;
+ RADCLIENT *client = sock->client;
+ BIO *rbio;
+#ifdef WITH_COA_TUNNEL
+ bool is_reply = false;
+#endif
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+redo:
+ if (!tls_socket_recv(listener)) {
+ return 0;
+ }
+
+ rad_assert(sock->packet != NULL);
+ rad_assert(sock->ssn != NULL);
+ rad_assert(client != NULL);
+
+ packet = talloc_steal(NULL, sock->packet);
+ sock->request->packet = NULL;
+ sock->packet = NULL;
+
+ /*
+ * Some sanity checks, based on the packet code.
+ *
+ * "auth+acct" are marked as "auth", with the "dual" flag
+ * set.
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ if (listener->type != RAD_LISTEN_AUTH) goto bad_packet;
+ FR_STATS_INC(auth, total_requests);
+ fun = rad_authenticate;
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (listener->type != RAD_LISTEN_ACCT) {
+ /*
+ * Allow auth + dual. Disallow
+ * everything else.
+ */
+ if (!((listener->type == RAD_LISTEN_AUTH) &&
+ (listener->dual))) {
+ goto bad_packet;
+ }
+ }
+ FR_STATS_INC(acct, total_requests);
+ fun = rad_accounting;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ if (listener->type != RAD_LISTEN_COA) goto bad_packet;
+ FR_STATS_INC(coa, total_requests);
+ fun = rad_coa_recv;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ if (listener->type != RAD_LISTEN_COA) goto bad_packet;
+ FR_STATS_INC(dsc, total_requests);
+ fun = rad_coa_recv;
+ break;
+
+#ifdef WITH_COA_TUNNEL
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ if (!listener->send_coa) goto bad_packet;
+ is_reply = true;
+ break;
+#endif
+#endif
+
+ case PW_CODE_STATUS_SERVER:
+ if (!main_config.status_server
+#ifdef WITH_TLS
+ && !listener->check_client_connections
+#endif
+ ) {
+ FR_STATS_INC(auth, total_unknown_types);
+ WARN("Ignoring Status-Server request due to security configuration");
+ rad_free(&packet);
+ return 0;
+ }
+ fun = rad_status_server;
+ break;
+
+ default:
+ bad_packet:
+ FR_STATS_INC(auth, total_unknown_types);
+
+ DEBUG("(TLS) Invalid packet code %d sent from client %s port %d : IGNORED",
+ packet->code, client->shortname, packet->src_port);
+ rad_free(&packet);
+ return 0;
+ } /* switch over packet types */
+
+#ifdef WITH_COA_TUNNEL
+ if (is_reply) {
+ if (!request_proxy_reply(packet)) {
+ rad_free(&packet);
+ return 0;
+ }
+ } else
+#endif
+
+ if (!request_receive(NULL, listener, packet, client, fun)) {
+ FR_STATS_INC(auth, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+
+ /*
+ * Check for more application data.
+ *
+ * If there is pending SSL data, "peek" at the
+ * application data. If we get at least one byte of
+ * application data, go back to tls_socket_recv().
+ * SSL_peek() will set SSL_pending(), and
+ * tls_socket_recv() will read another packet.
+ */
+ rbio = SSL_get_rbio(sock->ssn->ssl);
+ if (BIO_ctrl_pending(rbio)) {
+ char buf[1];
+ int peek = SSL_peek(sock->ssn->ssl, buf, 1);
+
+ if (peek > 0) {
+ DEBUG("(TLS) more TLS records after dual_tls_recv");
+ goto redo;
+ }
+ }
+
+ return 1;
+}
+
+
+/*
+ * Send a response packet
+ */
+int dual_tls_send(rad_listen_t *listener, REQUEST *request)
+{
+ listen_socket_t *sock = listener->data;
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == dual_tls_send);
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+ /*
+ * See if the policies allowed this connection.
+ */
+ if (sock->state == LISTEN_TLS_CHECKING) {
+ if (request->reply->code != PW_CODE_ACCESS_ACCEPT) {
+ listener->status = RAD_LISTEN_STATUS_EOL;
+ listener->tls = NULL; /* parent owns this! */
+
+ /*
+ * Tell the event handler that an FD has disappeared.
+ */
+ radius_update_listener(listener);
+ return 0;
+ }
+
+ /*
+ * Resume reading from the listener.
+ */
+ listener->status = RAD_LISTEN_STATUS_RESUME;
+ radius_update_listener(listener);
+
+ rad_assert(sock->request->packet != request->packet);
+
+ sock->state = LISTEN_TLS_SETUP;
+ (void) dual_tls_recv(listener);
+ return 0;
+ }
+
+ /*
+ * Accounting reject's are silently dropped.
+ *
+ * We do it here to avoid polluting the rest of the
+ * code with this knowledge
+ */
+ if (request->reply->code == 0) return 0;
+
+#ifdef WITH_COA_TUNNEL
+ /*
+ * Save the key, if we haven't already done that.
+ */
+ if (listener->send_coa && !listener->key) {
+ VALUE_PAIR *vp = NULL;
+
+ vp = fr_pair_find_by_num(request->config, PW_ORIGINATING_REALM_KEY, 0, TAG_ANY);
+ if (vp) {
+ RDEBUG("Adding send CoA listener with key %s", vp->vp_strvalue);
+ listen_coa_add(request->listener, vp->vp_strvalue);
+ }
+ }
+#endif
+
+ /*
+ * Pack the VPs
+ */
+ if (rad_encode(request->reply, request->packet,
+ request->client->secret) < 0) {
+ RERROR("Failed encoding packet: %s", fr_strerror());
+ return 0;
+ }
+
+ if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+ RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+ request->reply->data_len, MAX_PACKET_LEN);
+ }
+
+ /*
+ * Sign the packet.
+ */
+ if (rad_sign(request->reply, request->packet,
+ request->client->secret) < 0) {
+ RERROR("Failed signing packet: %s", fr_strerror());
+ return 0;
+ }
+
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+
+ /*
+ * Write the packet to the SSL buffers.
+ */
+ sock->ssn->record_plus(&sock->ssn->clean_in,
+ request->reply->data, request->reply->data_len);
+
+ dump_hex("TUNNELED DATA < ", sock->ssn->clean_in.data, sock->ssn->clean_in.used);
+
+ /*
+ * Do SSL magic to get encrypted data.
+ */
+ tls_handshake_send(request, sock->ssn);
+
+ /*
+ * And finally write the data to the socket.
+ */
+ if (sock->ssn->dirty_out.used > 0) {
+ dump_hex("WRITE TO SSL", sock->ssn->dirty_out.data, sock->ssn->dirty_out.used);
+
+ RDEBUG3("(TLS) Writing to socket %d", listener->fd);
+ tls_socket_write(listener);
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ return 0;
+}
+
+#ifdef WITH_COA_TUNNEL
+/*
+ * Send a CoA request to a NAS, as a proxied packet.
+ *
+ * The proxied packet MUST already have been encoded.
+ */
+int dual_tls_send_coa_request(rad_listen_t *listener, REQUEST *request)
+{
+ listen_socket_t *sock = listener->data;
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(listener->proxy_send == dual_tls_send_coa_request);
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+ rad_assert(request->proxy->data);
+
+ if (request->proxy->data_len > (MAX_PACKET_LEN - 100)) {
+ RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+ request->proxy->data_len, MAX_PACKET_LEN);
+ }
+
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+
+ /*
+ * Write the packet to the SSL buffers.
+ */
+ sock->ssn->record_plus(&sock->ssn->clean_in,
+ request->proxy->data, request->proxy->data_len);
+
+ dump_hex("TUNNELED DATA < ", sock->ssn->clean_in.data, sock->ssn->clean_in.used);
+
+ /*
+ * Do SSL magic to get encrypted data.
+ */
+ tls_handshake_send(request, sock->ssn);
+
+ /*
+ * And finally write the data to the socket.
+ */
+ if (sock->ssn->dirty_out.used > 0) {
+ dump_hex("WRITE TO SSL", sock->ssn->dirty_out.data, sock->ssn->dirty_out.used);
+
+ RDEBUG3("(TLS) Writing to socket %d", listener->fd);
+ tls_socket_write(listener);
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ return 0;
+}
+#endif
+
+static int try_connect(listen_socket_t *sock)
+{
+ int ret;
+ time_t now;
+
+ now = time(NULL);
+ if ((sock->opened + sock->connect_timeout) < now) {
+ tls_error_io_log(NULL, sock->ssn, 0, "Timeout in SSL_connect");
+ return -1;
+ }
+
+ ret = SSL_connect(sock->ssn->ssl);
+ if (ret <= 0) {
+ switch (SSL_get_error(sock->ssn->ssl, ret)) {
+ default:
+ tls_error_io_log(NULL, sock->ssn, ret, "Failed in " STRINGIFY(__FUNCTION__) " (SSL_connect)");
+ return -1;
+
+ case SSL_ERROR_WANT_READ:
+ DEBUG3("(TLS) SSL_connect() returned WANT_READ");
+ return 2;
+
+ case SSL_ERROR_WANT_WRITE:
+ DEBUG3("(TLS) SSL_connect() returned WANT_WRITE");
+ return 2;
+ }
+ }
+
+ sock->ssn->connected = true;
+ return 1;
+}
+
+
+#ifdef WITH_PROXY
+#ifdef WITH_RADIUSV11
+extern int fr_radiusv11_client_get_alpn(rad_listen_t *listener);
+#endif
+
+/*
+ * Read from the SSL socket. Safe with either blocking or
+ * non-blocking IO. This level of complexity is probably not
+ * necessary, as each packet gets put into one SSL application
+ * record. When SSL has a full record, we should be able to read
+ * the entire packet via one SSL_read().
+ *
+ * When SSL has a partial record, SSL_read() will return
+ * WANT_READ or WANT_WRITE, and zero application data.
+ *
+ * Called with the mutex held.
+ */
+static ssize_t proxy_tls_read(rad_listen_t *listener)
+{
+ int rcode;
+ size_t length;
+ uint8_t *data;
+ listen_socket_t *sock = listener->data;
+
+ if (!sock->ssn->connected) {
+ rcode = try_connect(sock);
+ if (rcode <= 0) return rcode;
+
+ if (rcode == 2) return 0; /* more negotiation needed */
+
+#ifdef WITH_RADIUSV11
+ if (!sock->alpn_checked && (fr_radiusv11_client_get_alpn(listener) < 0)) {
+ tls_socket_close(listener);
+ return -1;
+ }
+#endif
+ }
+
+ if (sock->ssn->clean_out.used) {
+ DEBUG3("(TLS) proxy writing %zu to socket", sock->ssn->clean_out.used);
+ /*
+ * Write to SSL.
+ */
+ rcode = SSL_write(sock->ssn->ssl, sock->ssn->clean_out.data, sock->ssn->clean_out.used);
+ if (rcode > 0) {
+ if ((size_t) rcode < sock->ssn->clean_out.used) {
+ memmove(sock->ssn->clean_out.data, sock->ssn->clean_out.data + rcode,
+ sock->ssn->clean_out.used - rcode);
+ sock->ssn->clean_out.used -= rcode;
+ } else {
+ sock->ssn->clean_out.used = 0;
+ }
+ }
+ }
+
+ /*
+ * Get the maximum size of data to receive.
+ */
+ if (!sock->data) sock->data = talloc_array(sock, uint8_t,
+ sock->ssn->mtu);
+
+ data = sock->data;
+
+ if (sock->partial < 4) {
+ rcode = SSL_read(sock->ssn->ssl, data + sock->partial,
+ 4 - sock->partial);
+ if (rcode <= 0) {
+ int err = SSL_get_error(sock->ssn->ssl, rcode);
+ switch (err) {
+
+ case SSL_ERROR_WANT_READ:
+ DEBUG3("(TLS) OpenSSL returned WANT_READ");
+ return 0;
+
+ case SSL_ERROR_WANT_WRITE:
+ DEBUG3("(TLS) OpenSSL returned WANT_WRITE");
+ return 0;
+
+ case SSL_ERROR_ZERO_RETURN:
+ /* remote end sent close_notify, send one back */
+ SSL_shutdown(sock->ssn->ssl);
+ /* FALL-THROUGH */
+
+ case SSL_ERROR_SYSCALL:
+ do_close:
+ return -1;
+
+ case SSL_ERROR_SSL:
+ DEBUG("(TLS) Home server has closed the connection");
+ goto do_close;
+
+ default:
+ tls_error_log(NULL, "Failed in proxy receive with OpenSSL error %d", err);
+ goto do_close;
+ }
+ }
+
+ sock->partial = rcode;
+ } /* try reading the packet header */
+
+ if (sock->partial < 4) return 0; /* read more data */
+
+ length = (data[2] << 8) | data[3];
+
+ /*
+ * Do these checks only once, when we read the header.
+ */
+ if (sock->partial == 4) {
+ DEBUG3("Proxy received header saying we have a packet of %u bytes",
+ (unsigned int) length);
+
+ /*
+ * FIXME: allocate a RADIUS_PACKET, and set
+ * "data" to be as large as necessary.
+ */
+ if (length > sock->ssn->mtu) {
+ INFO("Received packet will be too large! Set \"fragment_size = %u\"",
+ (data[2] << 8) | data[3]);
+ goto do_close;
+ }
+ }
+
+ /*
+ * Try to read some more.
+ */
+ if (sock->partial < length) {
+ rcode = SSL_read(sock->ssn->ssl, data + sock->partial,
+ length - sock->partial);
+ if (rcode <= 0) {
+ int err = SSL_get_error(sock->ssn->ssl, rcode);
+ switch (err) {
+
+ case SSL_ERROR_WANT_READ:
+ DEBUG3("(TLS) OpenSSL returned WANT_READ");
+ return 0;
+
+ case SSL_ERROR_WANT_WRITE:
+ DEBUG3("(TLS) OpenSSL returned WANT_WRITE");
+ return 0;
+
+ case SSL_ERROR_ZERO_RETURN:
+ /* remote end sent close_notify, send one back */
+ SSL_shutdown(sock->ssn->ssl);
+ goto do_close;
+
+ case SSL_ERROR_SSL:
+ DEBUG("(TLS) Home server has closed the connection");
+ goto do_close;
+
+ default:
+ DEBUG("(TLS) Unexpected OpenSSL error %d", err);
+ goto do_close;
+ }
+ }
+
+ sock->partial += rcode;
+ }
+
+ /*
+ * If we're not done, say so.
+ *
+ * Otherwise, reset the partially read data flag, and say
+ * we have a packet.
+ */
+ if (sock->partial < length) {
+ return 0;
+ }
+
+ sock->partial = 0; /* we've now read the packet */
+ return length;
+}
+
+
+int proxy_tls_recv(rad_listen_t *listener)
+{
+ listen_socket_t *sock = listener->data;
+ char buffer[256];
+ RADIUS_PACKET *packet;
+ uint8_t *data;
+ ssize_t data_len;
+#ifdef WITH_COA_TUNNEL
+ bool is_request = false;
+ RADCLIENT *client = sock->client;
+#endif
+
+ if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0;
+
+ rad_assert(sock->ssn != NULL);
+
+ DEBUG3("Proxy SSL socket has data to read");
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ data_len = proxy_tls_read(listener);
+ if (data_len < 0) {
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ DEBUG("Closing TLS socket to home server");
+ return 0;
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ if (data_len == 0) return 0; /* not done yet */
+
+ data = sock->data;
+
+ packet = rad_alloc(sock, false);
+ packet->sockfd = listener->fd;
+ packet->src_ipaddr = sock->other_ipaddr;
+ packet->src_port = sock->other_port;
+ packet->dst_ipaddr = sock->my_ipaddr;
+ packet->dst_port = sock->my_port;
+ packet->code = data[0];
+ packet->id = data[1];
+ packet->data_len = data_len;
+ packet->data = talloc_array(packet, uint8_t, packet->data_len);
+ memcpy(packet->data, data, packet->data_len);
+ memcpy(packet->vector, packet->data + 4, 16);
+
+#ifdef WITH_RADIUSV11
+ packet->radiusv11 = sock->radiusv11;
+
+ if (sock->radiusv11) {
+ uint32_t id;
+
+ memcpy(&id, data + 4, sizeof(id));
+ packet->id = ntohl(id);
+ }
+
+#endif
+
+ /*
+ * FIXME: Client MIB updates?
+ */
+ switch (packet->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_ACCESS_REJECT:
+ break;
+
+#ifdef WITH_ACCOUNTING
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ break;
+
+#ifdef WITH_COA_TUNNEL
+ case PW_CODE_COA_REQUEST:
+ if (!listener->send_coa) goto bad_packet;
+ FR_STATS_INC(coa, total_requests);
+ is_request = true;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ if (!listener->send_coa) goto bad_packet;
+ FR_STATS_INC(dsc, total_requests);
+ is_request = true;
+ break;
+#endif
+#endif
+
+ default:
+#ifdef WITH_COA_TUNNEL
+ bad_packet:
+#endif
+ /*
+ * FIXME: Update MIB for packet types?
+ */
+ ERROR("Invalid packet code %d sent to a proxy port "
+ "from home server %s port %d - ID %d : IGNORED",
+ packet->code,
+ ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)),
+ packet->src_port, packet->id);
+ rad_free(&packet);
+ return 0;
+ }
+
+#ifdef WITH_COA_TUNNEL
+ if (is_request) {
+ if (!request_receive(NULL, listener, packet, client, rad_coa_recv)) {
+ FR_STATS_INC(auth, total_packets_dropped);
+ rad_free(&packet);
+ return 0;
+ }
+ } else
+#endif
+ if (!request_proxy_reply(packet)) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int proxy_tls_send(rad_listen_t *listener, REQUEST *request)
+{
+ int rcode;
+ listen_socket_t *sock = listener->data;
+
+ VERIFY_REQUEST(request);
+
+ if ((listener->status != RAD_LISTEN_STATUS_INIT) &&
+ (listener->status != RAD_LISTEN_STATUS_KNOWN)) return 0;
+
+ /*
+ * Normal proxying calls us with the data already
+ * encoded. The "ping home server" code does not. So,
+ * if there's no packet, encode it here.
+ */
+ if (!request->proxy->data) {
+ request->proxy_listener->proxy_encode(request->proxy_listener,
+ request);
+ }
+
+ rad_assert(sock->ssn != NULL);
+
+ if (!sock->ssn->connected) {
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ rcode = try_connect(sock);
+ if (rcode <= 0) {
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return rcode;
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ /*
+ * More negotiation is needed, but remember to
+ * save this packet to an intermediate buffer.
+ * Once the SSL connection is established, the
+ * later code writes the packet to the
+ * connection.
+ */
+ if (rcode == 2) {
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ if ((sock->ssn->clean_out.used + request->proxy->data_len) > MAX_RECORD_SIZE) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ RERROR("(TLS) Too much data buffered during SSL_connect()");
+ listener->status = RAD_LISTEN_STATUS_EOL;
+ radius_update_listener(listener);
+ return -1;
+ }
+
+ memcpy(sock->ssn->clean_out.data + sock->ssn->clean_out.used, request->proxy->data, request->proxy->data_len);
+ sock->ssn->clean_out.used += request->proxy->data_len;
+ RDEBUG3("(TLS) Writing %zu bytes for later (total %zu)", request->proxy->data_len, sock->ssn->clean_out.used);
+
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+
+#ifdef WITH_RADIUSV11
+ if (!sock->alpn_checked && (fr_radiusv11_client_get_alpn(listener) < 0)) {
+ listener->status = RAD_LISTEN_STATUS_EOL;
+ radius_update_listener(listener);
+ return -1;
+ }
+#endif
+ }
+
+ DEBUG3("Proxy is writing %u bytes to SSL",
+ (unsigned int) request->proxy->data_len);
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+
+ /*
+ * We may have previously cached data on SSL_connect(), which now needs to be written to the home server.
+ */
+ if (sock->ssn->clean_out.used > 0) {
+ if ((sock->ssn->clean_out.used + request->proxy->data_len) > MAX_RECORD_SIZE) {
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ RERROR("(TLS) Too much data buffered after SSL_connect()");
+ listener->status = RAD_LISTEN_STATUS_EOL;
+ radius_update_listener(listener);
+ return -1;
+ }
+
+ /*
+ * Add in our packet.
+ */
+ memcpy(sock->ssn->clean_out.data + sock->ssn->clean_out.used, request->proxy->data, request->proxy->data_len);
+ sock->ssn->clean_out.used += request->proxy->data_len;
+
+ /*
+ * Write to SSL.
+ */
+ DEBUG3("(TLS) proxy writing %zu to socket", sock->ssn->clean_out.used);
+
+ rcode = SSL_write(sock->ssn->ssl, sock->ssn->clean_out.data, sock->ssn->clean_out.used);
+ if (rcode > 0) {
+ if ((size_t) rcode < sock->ssn->clean_out.used) {
+ memmove(sock->ssn->clean_out.data, sock->ssn->clean_out.data + rcode,
+ sock->ssn->clean_out.used - rcode);
+ sock->ssn->clean_out.used -= rcode;
+ } else {
+ sock->ssn->clean_out.used = 0;
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 1;
+ }
+ } else {
+ rcode = SSL_write(sock->ssn->ssl, request->proxy->data,
+ request->proxy->data_len);
+ }
+ if (rcode < 0) {
+ int err;
+
+ err = ERR_get_error();
+ switch (err) {
+ case SSL_ERROR_NONE:
+ break;
+
+ case SSL_ERROR_WANT_READ:
+ DEBUG3("(TLS) OpenSSL returned WANT_READ");
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+ DEBUG3("(TLS) OpenSSL returned WANT_WRITE");
+ break;
+
+ default:
+ tls_error_log(NULL, "Failed in proxy send with OpenSSL error %d", err);
+ DEBUG("(TLS) Closing socket to home server");
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ return 1;
+}
+
+#ifdef WITH_COA_TUNNEL
+int proxy_tls_send_reply(rad_listen_t *listener, REQUEST *request)
+{
+ int rcode;
+ listen_socket_t *sock = listener->data;
+
+ VERIFY_REQUEST(request);
+
+ rad_assert(sock->ssn->connected);
+
+ if ((listener->status != RAD_LISTEN_STATUS_INIT &&
+ (listener->status != RAD_LISTEN_STATUS_KNOWN))) return 0;
+
+ /*
+ * Pack the VPs
+ */
+ if (rad_encode(request->reply, request->packet,
+ request->client->secret) < 0) {
+ RERROR("Failed encoding packet: %s", fr_strerror());
+ return 0;
+ }
+
+ if (request->reply->data_len > (MAX_PACKET_LEN - 100)) {
+ RWARN("Packet is large, and possibly truncated - %zd vs max %d",
+ request->reply->data_len, MAX_PACKET_LEN);
+ }
+
+ /*
+ * Sign the packet.
+ */
+ if (rad_sign(request->reply, request->packet,
+ request->client->secret) < 0) {
+ RERROR("Failed signing packet: %s", fr_strerror());
+ return 0;
+ }
+
+ rad_assert(sock->ssn != NULL);
+
+ DEBUG3("Proxy is writing %u bytes to SSL",
+ (unsigned int) request->reply->data_len);
+ PTHREAD_MUTEX_LOCK(&sock->mutex);
+ rcode = SSL_write(sock->ssn->ssl, request->reply->data,
+ request->reply->data_len);
+ if (rcode < 0) {
+ int err;
+
+ err = ERR_get_error();
+ switch (err) {
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ DEBUG3("(TLS) SSL_write() returned %s", ERR_reason_error_string(err));
+ break; /* let someone else retry */
+
+ default:
+ tls_error_log(NULL, "Failed in proxy send with OpenSSL error %d", err);
+ DEBUG("Closing TLS socket to home server");
+ tls_socket_close(listener);
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+ return 0;
+ }
+ }
+ PTHREAD_MUTEX_UNLOCK(&sock->mutex);
+
+ return 1;
+}
+#endif /* WITH_COA_TUNNEL */
+#endif /* WITH_PROXY */
+
+#endif /* WITH_TLS */
+#endif /* WITH_TCP */
diff --git a/src/main/tmpl.c b/src/main/tmpl.c
new file mode 100644
index 0000000..6ec2598
--- /dev/null
+++ b/src/main/tmpl.c
@@ -0,0 +1,2399 @@
+/*
+ * 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 #VALUE_PAIR template functions
+ * @file main/tmpl.c
+ *
+ * @ingroup AVP
+ *
+ * @copyright 2014-2015 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+/** Map #tmpl_type_t values to descriptive strings
+ */
+FR_NAME_NUMBER const tmpl_names[] = {
+ { "literal", TMPL_TYPE_LITERAL },
+ { "xlat", TMPL_TYPE_XLAT },
+ { "attr", TMPL_TYPE_ATTR },
+ { "unknown attr", TMPL_TYPE_ATTR_UNDEFINED },
+ { "list", TMPL_TYPE_LIST },
+ { "regex", TMPL_TYPE_REGEX },
+ { "exec", TMPL_TYPE_EXEC },
+ { "data", TMPL_TYPE_DATA },
+ { "parsed xlat", TMPL_TYPE_XLAT_STRUCT },
+ { "parsed regex", TMPL_TYPE_REGEX_STRUCT },
+ { "null", TMPL_TYPE_NULL },
+ { NULL, 0 }
+};
+
+/** Map keywords to #pair_lists_t values
+ */
+const FR_NAME_NUMBER pair_lists[] = {
+ { "request", PAIR_LIST_REQUEST },
+ { "reply", PAIR_LIST_REPLY },
+ { "control", PAIR_LIST_CONTROL }, /* New name should have priority */
+ { "config", PAIR_LIST_CONTROL },
+ { "session-state", PAIR_LIST_STATE },
+#ifdef WITH_PROXY
+ { "proxy-request", PAIR_LIST_PROXY_REQUEST },
+ { "proxy-reply", PAIR_LIST_PROXY_REPLY },
+#endif
+#ifdef WITH_COA
+ { "coa", PAIR_LIST_COA },
+ { "coa-reply", PAIR_LIST_COA_REPLY },
+ { "disconnect", PAIR_LIST_DM },
+ { "disconnect-reply", PAIR_LIST_DM_REPLY },
+#endif
+ { NULL , -1 }
+};
+
+/** Map keywords to #request_refs_t values
+ */
+const FR_NAME_NUMBER request_refs[] = {
+ { "outer", REQUEST_OUTER },
+ { "current", REQUEST_CURRENT },
+ { "parent", REQUEST_PARENT },
+ { NULL , -1 }
+};
+
+/** @name Parse list and request qualifiers to #pair_lists_t and #request_refs_t values
+ *
+ * These functions also resolve #pair_lists_t and #request_refs_t values to #REQUEST
+ * structs and the head of #VALUE_PAIR lists in those structs.
+ *
+ * For adding new #VALUE_PAIR to the lists, the #radius_list_ctx function can be used
+ * to obtain the appropriate TALLOC_CTX pointer.
+ *
+ * @note These don't really have much to do with #vp_tmpl_t. They're in the same
+ * file as they're used almost exclusively by the tmpl_* functions.
+ * @{
+ */
+
+/** Resolve attribute name to a #pair_lists_t value.
+ *
+ * Check the name string for #pair_lists qualifiers and write a #pair_lists_t value
+ * for that list to out. This value may be passed to #radius_list, along with the current
+ * #REQUEST, to get a pointer to the actual list in the #REQUEST.
+ *
+ * If we're sure we've definitely found a list qualifier token delimiter (``:``) but the
+ * string doesn't match a #radius_list qualifier, return 0 and write #PAIR_LIST_UNKNOWN
+ * to out.
+ *
+ * If we can't find a string that looks like a request qualifier, set out to def, and
+ * return 0.
+ *
+ * @note #radius_list_name should be called before passing a name string that may
+ * contain qualifiers to #dict_attrbyname.
+ *
+ * @param[out] out Where to write the list qualifier.
+ * @param[in] name String containing list qualifiers to parse.
+ * @param[in] def the list to return if no qualifiers were found.
+ * @return 0 if no valid list qualifier could be found, else the number of bytes consumed.
+ * The caller may then advanced the name pointer by the value returned, to get the
+ * start of the attribute name (if any).
+ *
+ * @see pair_list
+ * @see radius_list
+ */
+size_t radius_list_name(pair_lists_t *out, char const *name, pair_lists_t def)
+{
+ char const *p = name;
+ char const *q;
+
+ /* This should never be a NULL pointer */
+ rad_assert(name);
+
+ /*
+ * Try and determine the end of the token
+ */
+ for (q = p; dict_attr_allowed_chars[(uint8_t) *q]; q++);
+
+ switch (*q) {
+ /*
+ * It's a bareword made up entirely of dictionary chars
+ * check and see if it's a list qualifier, and if it's
+ * not, return the def and say we couldn't parse
+ * anything.
+ */
+ case '\0':
+ *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ if (*out != PAIR_LIST_UNKNOWN) return q - p;
+ *out = def;
+ return 0;
+
+ /*
+ * It may be a list qualifier delimiter. Because of tags
+ * We need to check that it doesn't look like a tag suffix.
+ * We do this by looking at the chars between ':' and the
+ * next token delimiter, and seeing if they're all digits.
+ */
+ case ':':
+ {
+ char const *d = q + 1;
+
+ if (isdigit((uint8_t) *d)) {
+ while (isdigit((uint8_t) *d)) d++;
+
+ /*
+ * Char after the number string
+ * was a token delimiter, so this is a
+ * tag, not a list qualifier.
+ */
+ if (!dict_attr_allowed_chars[(uint8_t) *d]) {
+ *out = def;
+ return 0;
+ }
+ }
+
+ *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
+ if (*out == PAIR_LIST_UNKNOWN) return 0;
+
+ return (q + 1) - name; /* Consume the list and delimiter */
+ }
+
+ default:
+ *out = def;
+ return 0;
+ }
+}
+
+/** Resolve attribute #pair_lists_t value to an attribute list.
+ *
+ * The value returned is a pointer to the pointer of the HEAD of a #VALUE_PAIR list in the
+ * #REQUEST. If the head of the list changes, the pointer will still be valid.
+ *
+ * @param[in] request containing the target lists.
+ * @param[in] list #pair_lists_t value to resolve to #VALUE_PAIR list. Will be NULL if list
+ * name couldn't be resolved.
+ * @return a pointer to the HEAD of a list in the #REQUEST.
+ *
+ * @see tmpl_cursor_init
+ * @see fr_cursor_init
+ */
+VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
+{
+ if (!request) return NULL;
+
+ switch (list) {
+ /* Don't add default */
+ case PAIR_LIST_UNKNOWN:
+ break;
+
+ case PAIR_LIST_REQUEST:
+ if (!request->packet) return NULL;
+ return &request->packet->vps;
+
+ case PAIR_LIST_REPLY:
+ if (!request->reply) return NULL;
+ return &request->reply->vps;
+
+ case PAIR_LIST_CONTROL:
+ return &request->config;
+
+ case PAIR_LIST_STATE:
+ return &request->state;
+
+#ifdef WITH_PROXY
+ case PAIR_LIST_PROXY_REQUEST:
+ if (!request->proxy) break;
+ return &request->proxy->vps;
+
+ case PAIR_LIST_PROXY_REPLY:
+ if (!request->proxy_reply) break;
+ return &request->proxy_reply->vps;
+#endif
+#ifdef WITH_COA
+ case PAIR_LIST_COA:
+ if (request->coa &&
+ (request->coa->proxy->code == PW_CODE_COA_REQUEST)) {
+ return &request->coa->proxy->vps;
+ }
+ break;
+
+ case PAIR_LIST_COA_REPLY:
+ if (request->coa && /* match reply with request */
+ (request->coa->proxy->code == PW_CODE_COA_REQUEST) &&
+ request->coa->proxy_reply) {
+ return &request->coa->proxy_reply->vps;
+ }
+ break;
+
+ case PAIR_LIST_DM:
+ if (request->coa &&
+ (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST)) {
+ return &request->coa->proxy->vps;
+ }
+ break;
+
+ case PAIR_LIST_DM_REPLY:
+ if (request->coa && /* match reply with request */
+ (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST) &&
+ request->coa->proxy_reply) {
+ return &request->coa->proxy_reply->vps;
+ }
+ break;
+#endif
+ }
+
+ RWDEBUG2("List \"%s\" is not available",
+ fr_int2str(pair_lists, list, "<INVALID>"));
+
+ return NULL;
+}
+
+/** Resolve a list to the #RADIUS_PACKET holding the HEAD pointer for a #VALUE_PAIR list
+ *
+ * Returns a pointer to the #RADIUS_PACKET that holds the HEAD pointer of a given list,
+ * for the current #REQUEST.
+ *
+ * @param[in] request To resolve list in.
+ * @param[in] list #pair_lists_t value to resolve to #RADIUS_PACKET.
+ * @return a #RADIUS_PACKET on success, else NULL.
+ *
+ * @see radius_list
+ */
+RADIUS_PACKET *radius_packet(REQUEST *request, pair_lists_t list)
+{
+ switch (list) {
+ /* Don't add default */
+ case PAIR_LIST_STATE:
+ case PAIR_LIST_CONTROL:
+ case PAIR_LIST_UNKNOWN:
+ return NULL;
+
+ case PAIR_LIST_REQUEST:
+ return request->packet;
+
+ case PAIR_LIST_REPLY:
+ return request->reply;
+
+#ifdef WITH_PROXY
+ case PAIR_LIST_PROXY_REQUEST:
+ return request->proxy;
+
+ case PAIR_LIST_PROXY_REPLY:
+ return request->proxy_reply;
+#endif
+
+#ifdef WITH_COA
+ case PAIR_LIST_COA:
+ case PAIR_LIST_DM:
+ return request->coa->proxy;
+
+ case PAIR_LIST_COA_REPLY:
+ case PAIR_LIST_DM_REPLY:
+ return request->coa->proxy_reply;
+#endif
+ }
+
+ return NULL;
+}
+
+/** Return the correct TALLOC_CTX to alloc #VALUE_PAIR in, for a list
+ *
+ * Allocating new #VALUE_PAIR in the context of a #REQUEST is usually wrong.
+ * #VALUE_PAIR should be allocated in the context of a #RADIUS_PACKET, so that if the
+ * #RADIUS_PACKET is freed before the #REQUEST, the associated #VALUE_PAIR lists are
+ * freed too.
+ *
+ * @param[in] request containing the target lists.
+ * @param[in] list #pair_lists_t value to resolve to TALLOC_CTX.
+ * @return a TALLOC_CTX on success, else NULL.
+ *
+ * @see radius_list
+ */
+TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list)
+{
+ if (!request) return NULL;
+
+ switch (list) {
+ case PAIR_LIST_REQUEST:
+ return request->packet;
+
+ case PAIR_LIST_REPLY:
+ return request->reply;
+
+ case PAIR_LIST_CONTROL:
+ return request;
+
+ case PAIR_LIST_STATE:
+ return request->state_ctx;
+
+#ifdef WITH_PROXY
+ case PAIR_LIST_PROXY_REQUEST:
+ return request->proxy;
+
+ case PAIR_LIST_PROXY_REPLY:
+ return request->proxy_reply;
+#endif
+
+#ifdef WITH_COA
+ case PAIR_LIST_COA:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
+ return request->coa->proxy;
+
+ case PAIR_LIST_COA_REPLY:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
+ return request->coa->proxy_reply;
+
+ case PAIR_LIST_DM:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
+ return request->coa->proxy;
+
+ case PAIR_LIST_DM_REPLY:
+ if (!request->coa) return NULL;
+ rad_assert(request->coa->proxy != NULL);
+ if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
+ return request->coa->proxy_reply;
+#endif
+ /* Don't add default */
+ case PAIR_LIST_UNKNOWN:
+ break;
+ }
+
+ return NULL;
+}
+
+/** Resolve attribute name to a #request_refs_t value.
+ *
+ * Check the name string for qualifiers that reference a parent #REQUEST.
+ *
+ * If we find a string that matches a #request_refs qualifier, return the number of chars
+ * we consumed.
+ *
+ * If we're sure we've definitely found a list qualifier token delimiter (``*``) but the
+ * qualifier doesn't match one of the #request_refs qualifiers, return 0 and set out to
+ * #REQUEST_UNKNOWN.
+ *
+ * If we can't find a string that looks like a request qualifier, set out to def, and
+ * return 0.
+ *
+ * @param[out] out The #request_refs_t value the name resolved to (or #REQUEST_UNKNOWN).
+ * @param[in] name of attribute.
+ * @param[in] def default request ref to return if no request qualifier is present.
+ * @return 0 if no valid request qualifier could be found, else the number of bytes consumed.
+ * The caller may then advanced the name pointer by the value returned, to get the
+ * start of the attribute list or attribute name(if any).
+ *
+ * @see radius_list_name
+ * @see request_refs
+ */
+size_t radius_request_name(request_refs_t *out, char const *name, request_refs_t def)
+{
+ char const *p, *q;
+
+ p = name;
+ /*
+ * Try and determine the end of the token
+ */
+ for (q = p; dict_attr_allowed_chars[(uint8_t) *q] && (*q != '.') && (*q != '-'); q++);
+
+ /*
+ * First token delimiter wasn't a '.'
+ */
+ if (*q != '.') {
+ *out = def;
+ return 0;
+ }
+
+ *out = fr_substr2int(request_refs, name, REQUEST_UNKNOWN, q - p);
+ if (*out == REQUEST_UNKNOWN) return 0;
+
+ return (q + 1) - p;
+}
+
+/** Resolve a #request_refs_t to a #REQUEST.
+ *
+ * Sometimes #REQUEST structs may be chained to each other, as is the case
+ * when internally proxying EAP. This function resolves a #request_refs_t
+ * to a #REQUEST higher in the chain than the current #REQUEST.
+ *
+ * @see radius_list
+ * @param[in,out] context #REQUEST to start resolving from, and where to write
+ * a pointer to the resolved #REQUEST back to.
+ * @param[in] name (request) to resolve.
+ * @return 0 if request is valid in this context, else -1.
+ */
+int radius_request(REQUEST **context, request_refs_t name)
+{
+ REQUEST *request = *context;
+
+ switch (name) {
+ case REQUEST_CURRENT:
+ return 0;
+
+ case REQUEST_PARENT: /* for future use in request chaining */
+ case REQUEST_OUTER:
+ if (!request->parent) {
+ return -1;
+ }
+ *context = request->parent;
+ break;
+
+ case REQUEST_UNKNOWN:
+ default:
+ rad_assert(0);
+ return -1;
+ }
+
+ return 0;
+}
+/** @} */
+
+/** @name Alloc or initialise #vp_tmpl_t
+ *
+ * @note Should not usually be called outside of tmpl_* functions, use one of
+ * the tmpl_*from_* functions instead.
+ * @{
+ */
+
+/** Initialise stack allocated #vp_tmpl_t
+ *
+ * @note Name is not strdupe'd or memcpy'd so must be available, and must not change
+ * for the lifetime of the #vp_tmpl_t.
+ *
+ * @param[out] vpt to initialise.
+ * @param[in] type to set in the #vp_tmpl_t.
+ * @param[in] name of the #vp_tmpl_t.
+ * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
+ * If < 0 strlen will be used to determine the length.
+ * @return a pointer to the initialised #vp_tmpl_t. The same value as
+ * vpt.
+ */
+vp_tmpl_t *tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len)
+{
+ rad_assert(vpt);
+ rad_assert(type != TMPL_TYPE_UNKNOWN);
+ rad_assert(type <= TMPL_TYPE_NULL);
+
+ memset(vpt, 0, sizeof(vp_tmpl_t));
+ vpt->type = type;
+
+ if (name) {
+ vpt->name = name;
+ vpt->len = len < 0 ? strlen(name) :
+ (size_t) len;
+ }
+ return vpt;
+}
+
+/** Create a new heap allocated #vp_tmpl_t
+ *
+ * @param[in,out] ctx to allocate in.
+ * @param[in] type to set in the #vp_tmpl_t.
+ * @param[in] name of the #vp_tmpl_t (will be copied to a new talloc buffer parented
+ * by the #vp_tmpl_t).
+ * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
+ * If < 0 strlen will be used to determine the length.
+ * @return the newly allocated #vp_tmpl_t.
+ */
+vp_tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name, ssize_t len)
+{
+ vp_tmpl_t *vpt;
+
+ rad_assert(type != TMPL_TYPE_UNKNOWN);
+ rad_assert(type <= TMPL_TYPE_NULL);
+
+ vpt = talloc_zero(ctx, vp_tmpl_t);
+ if (!vpt) return NULL;
+ vpt->type = type;
+ if (name) {
+ vpt->name = talloc_bstrndup(vpt, name, len < 0 ? strlen(name) : (size_t)len);
+ vpt->len = talloc_array_length(vpt->name) - 1;
+ }
+
+ return vpt;
+}
+/* @} **/
+
+/** @name Create new #vp_tmpl_t from a string
+ *
+ * @{
+ */
+/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
+ *
+ * @note The name field is just a copy of the input pointer, if you know that string might be
+ * freed before you're done with the #vp_tmpl_t use #tmpl_afrom_attr_str
+ * instead.
+ *
+ * @param[out] vpt to modify.
+ * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
+ * If only #request_refs and #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
+ * #vp_tmpl_t will be produced.
+ * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
+ * found in name.
+ * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
+ * name.
+ * @param[in] allow_unknown If true attributes in the format accepted by
+ * #dict_unknown_from_substr will be allowed, even if they're not in the main
+ * dictionaries.
+ * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
+ * produced with the unknown #DICT_ATTR stored in the ``unknown.da`` buffer.
+ * This #DICT_ATTR will have its ``flags.is_unknown`` field set to true.
+ * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
+ * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
+ * dictionary.
+ * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
+ * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
+ * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
+ * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
+ * will be produced.
+ * @return <= 0 on error (offset as negative integer), > 0 on success
+ * (number of bytes parsed).
+ *
+ * @see REMARKER to produce pretty error markers from the return value.
+ */
+ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined)
+{
+ char const *p;
+ long num;
+ char *q;
+ tmpl_type_t type = TMPL_TYPE_ATTR;
+
+ value_pair_tmpl_attr_t attr; /* So we don't fill the tmpl with junk and then error out */
+
+ memset(vpt, 0, sizeof(*vpt));
+ memset(&attr, 0, sizeof(attr));
+
+ p = name;
+
+ if (*p == '&') p++;
+
+ p += radius_request_name(&attr.request, p, request_def);
+ if (attr.request == REQUEST_UNKNOWN) {
+ fr_strerror_printf("Invalid request qualifier");
+ return -(p - name);
+ }
+
+ /*
+ * Finding a list qualifier is optional
+ */
+ p += radius_list_name(&attr.list, p, list_def);
+ if (attr.list == PAIR_LIST_UNKNOWN) {
+ fr_strerror_printf("Invalid list qualifier");
+ return -(p - name);
+ }
+
+ attr.tag = TAG_ANY;
+ attr.num = NUM_ANY;
+
+ /*
+ * This may be just a bare list, but it can still
+ * have instance selectors and tag selectors.
+ */
+ switch (*p) {
+ case '\0':
+ type = TMPL_TYPE_LIST;
+ attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
+ goto finish;
+
+ case '[':
+ type = TMPL_TYPE_LIST;
+ attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
+ goto do_num;
+
+ default:
+ break;
+ }
+
+ attr.da = dict_attrbyname_substr(&p);
+ if (!attr.da) {
+ char const *a;
+
+ /*
+ * Record start of attribute in case we need to error out.
+ */
+ a = p;
+
+ fr_strerror(); /* Clear out any existing errors */
+
+ /*
+ * Attr-1.2.3.4 is OK.
+ */
+ if (dict_unknown_from_substr((DICT_ATTR *)&attr.unknown.da, &p) == 0) {
+ /*
+ * Check what we just parsed really hasn't been defined
+ * in the main dictionaries.
+ *
+ * If it has, parsing is the same as if the attribute
+ * name had been used instead of its OID.
+ */
+ attr.da = dict_attrbyvalue(((DICT_ATTR *)&attr.unknown.da)->attr,
+ ((DICT_ATTR *)&attr.unknown.da)->vendor);
+ if (attr.da) {
+ vpt->auto_converted = true;
+ goto do_num;
+ }
+
+ if (!allow_unknown) {
+ fr_strerror_printf("Unknown attribute");
+ return -(a - name);
+ }
+
+ /*
+ * Unknown attributes can't be encoded, as we don't
+ * know how to encode them!
+ */
+ attr.da = (DICT_ATTR *)&attr.unknown.da;
+
+ goto do_num; /* unknown attributes can't have tags */
+ }
+
+ /*
+ * Can't parse it as an attribute, might be a literal string
+ * let the caller decide.
+ *
+ * Don't alter the fr_strerror buffer, should contain the parse
+ * error from dict_unknown_from_substr.
+ */
+ if (!allow_undefined) return -(a - name);
+
+ /*
+ * Copy the name to a field for later resolution
+ */
+ type = TMPL_TYPE_ATTR_UNDEFINED;
+ for (q = attr.unknown.name; dict_attr_allowed_chars[(int) *p]; *q++ = *p++) {
+ if (q >= (attr.unknown.name + sizeof(attr.unknown.name) - 1)) {
+ fr_strerror_printf("Attribute name is too long");
+ return -(p - name);
+ }
+ }
+ *q = '\0';
+
+ goto do_num;
+ }
+
+ /*
+ * The string MIGHT have a tag.
+ */
+ if (*p == ':') {
+ if (attr.da && !attr.da->flags.has_tag) { /* Lists don't have a da */
+ fr_strerror_printf("Attribute '%s' cannot have a tag", attr.da->name);
+ return -(p - name);
+ }
+
+ num = strtol(p + 1, &q, 10);
+ if ((num > 0x1f) || (num < 0)) {
+ fr_strerror_printf("Invalid tag value '%li' (should be between 0-31)", num);
+ return -((p + 1)- name);
+ }
+
+ attr.tag = num;
+ p = q;
+ }
+
+do_num:
+ if (*p == '\0') goto finish;
+
+ if (*p == '[') {
+ p++;
+
+ switch (*p) {
+ case '#':
+ attr.num = NUM_COUNT;
+ p++;
+ break;
+
+ case '*':
+ attr.num = NUM_ALL;
+ p++;
+ break;
+
+ case 'n':
+ attr.num = NUM_LAST;
+ p++;
+ break;
+
+ default:
+ num = strtol(p, &q, 10);
+ if (p == q) {
+ fr_strerror_printf("Array index is not an integer");
+ return -(p - name);
+ }
+
+ if ((num > 1000) || (num < 0)) {
+ fr_strerror_printf("Invalid array reference '%li' (should be between 0-1000)", num);
+ return -(p - name);
+ }
+ attr.num = num;
+ p = q;
+ break;
+ }
+
+ if (*p != ']') {
+ fr_strerror_printf("No closing ']' for array index");
+ return -(p - name);
+ }
+ p++;
+ }
+
+finish:
+ vpt->type = type;
+ vpt->name = name;
+ vpt->len = p - name;
+
+ /*
+ * Copy over the attribute definition, now we're
+ * sure what we were passed is valid.
+ */
+ memcpy(&vpt->data.attribute, &attr, sizeof(vpt->data.attribute));
+ if ((vpt->type == TMPL_TYPE_ATTR) && attr.da->flags.is_unknown) {
+ vpt->tmpl_da = (DICT_ATTR *)&vpt->data.attribute.unknown.da;
+ }
+
+ VERIFY_TMPL(vpt);
+
+ return vpt->len;
+}
+
+/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
+ *
+ * @note Unlike #tmpl_from_attr_substr this function will error out if the entire
+ * name string isn't parsed.
+ *
+ * @copydetails tmpl_from_attr_substr
+ */
+ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined)
+{
+ ssize_t slen;
+
+ slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
+ if (slen <= 0) return slen;
+ if (name[slen] != '\0') {
+ /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
+ fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
+ return -slen;
+ }
+
+ VERIFY_TMPL(vpt);
+
+ return slen;
+}
+
+/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
+ *
+ * @param[in,out] ctx to allocate #vp_tmpl_t in.
+ * @param[out] out Where to write pointer to new #vp_tmpl_t.
+ * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
+ * If only #request_refs #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
+ * #vp_tmpl_t will be produced.
+ * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
+ * found in name.
+ * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
+ * name.
+ * @param[in] allow_unknown If true attributes in the format accepted by
+ * #dict_unknown_from_substr will be allowed, even if they're not in the main
+ * dictionaries.
+ * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
+ * produced with the unknown #DICT_ATTR stored in the ``unknown.da`` buffer.
+ * This #DICT_ATTR will have its ``flags.is_unknown`` field set to true.
+ * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
+ * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
+ * dictionary.
+ * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
+ * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
+ * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
+ * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
+ * will be produced.
+ * @return <= 0 on error (offset as negative integer), > 0 on success
+ * (number of bytes parsed).
+ *
+ * @see REMARKER to produce pretty error markers from the return value.
+ */
+ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined)
+{
+ ssize_t slen;
+ vp_tmpl_t *vpt;
+
+ MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
+
+ slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
+ if (slen <= 0) {
+ TALLOC_FREE(vpt);
+ return slen;
+ }
+ vpt->name = talloc_strndup(vpt, vpt->name, slen);
+
+ VERIFY_TMPL(vpt);
+
+ *out = vpt;
+
+ return slen;
+}
+
+/** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
+ *
+ * @note Unlike #tmpl_afrom_attr_substr this function will error out if the entire
+ * name string isn't parsed.
+ *
+ * @copydetails tmpl_afrom_attr_substr
+ */
+ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
+ request_refs_t request_def, pair_lists_t list_def,
+ bool allow_unknown, bool allow_undefined)
+{
+ ssize_t slen;
+ vp_tmpl_t *vpt;
+
+ MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
+
+ slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
+ if (slen <= 0) {
+ TALLOC_FREE(vpt);
+ return slen;
+ }
+ if (name[slen] != '\0') {
+ /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
+ fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
+ TALLOC_FREE(vpt);
+ return -slen;
+ }
+ vpt->name = talloc_strndup(vpt, vpt->name, vpt->len);
+
+ VERIFY_TMPL(vpt);
+
+ *out = vpt;
+
+ return slen;
+}
+
+/** Convert an arbitrary string into a #vp_tmpl_t
+ *
+ * @note Unlike #tmpl_afrom_attr_str return code 0 doesn't necessarily indicate failure,
+ * may just mean a 0 length string was parsed.
+ *
+ * @note xlats and regexes are left uncompiled. This is to support the two pass parsing
+ * done by the modcall code. Compilation on pass1 of that code could fail, as
+ * attributes or xlat functions registered by modules may not be available (yet).
+ *
+ * @note For details of attribute parsing see #tmpl_from_attr_substr.
+ *
+ * @param[in,out] ctx To allocate #vp_tmpl_t in.
+ * @param[out] out Where to write the pointer to the new #vp_tmpl_t.
+ * @param[in] in String to convert to a #vp_tmpl_t.
+ * @param[in] inlen length of string to convert.
+ * @param[in] type of quoting around value. May be one of:
+ * - #T_BARE_WORD - If string begins with ``&`` produces #TMPL_TYPE_ATTR,
+ * #TMPL_TYPE_ATTR_UNDEFINED, #TMPL_TYPE_LIST or error.
+ * If string does not begin with ``&`` produces #TMPL_TYPE_LITERAL,
+ * #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
+ * - #T_SINGLE_QUOTED_STRING - Produces #TMPL_TYPE_LITERAL
+ * - #T_DOUBLE_QUOTED_STRING - Produces #TMPL_TYPE_XLAT or #TMPL_TYPE_LITERAL (if
+ * string doesn't contain ``%``).
+ * - #T_BACK_QUOTED_STRING - Produces #TMPL_TYPE_EXEC
+ * - #T_OP_REG_EQ - Produces #TMPL_TYPE_REGEX
+ * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
+ * found in name.
+ * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
+ * name.
+ * @param[in] do_unescape whether or not we should do unescaping. Should be false if the
+ * caller already did it.
+ * @return <= 0 on error (offset as negative integer), > 0 on success
+ * (number of bytes parsed).
+ * @see REMARKER to produce pretty error markers from the return value.
+ *
+ * @see tmpl_from_attr_substr
+ */
+ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *in, size_t inlen, FR_TOKEN type,
+ request_refs_t request_def, pair_lists_t list_def, bool do_unescape)
+{
+ bool do_xlat;
+ char quote;
+ char const *p;
+ ssize_t slen;
+ PW_TYPE data_type = PW_TYPE_STRING;
+ vp_tmpl_t *vpt = NULL;
+ value_data_t data;
+
+ switch (type) {
+ case T_BARE_WORD:
+ /*
+ * If we can parse it as an attribute, it's an attribute.
+ * Otherwise, treat it as a literal.
+ */
+ quote = '\0';
+
+ slen = tmpl_afrom_attr_str(ctx, &vpt, in, request_def, list_def, true, (in[0] == '&'));
+ if ((in[0] == '&') && (slen <= 0)) return slen;
+ if (slen > 0) break;
+ goto parse;
+
+ case T_SINGLE_QUOTED_STRING:
+ quote = '\'';
+
+ parse:
+ if (cf_new_escape && do_unescape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, quote);
+ if (slen < 0) return 0;
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, in, inlen);
+ }
+ vpt->quote = quote;
+ slen = vpt->len;
+ break;
+
+ case T_DOUBLE_QUOTED_STRING:
+ do_xlat = false;
+
+ p = in;
+ while (*p) {
+ if (do_unescape) { /* otherwise \ is just another character */
+ if (*p == '\\') {
+ if (!p[1]) break;
+ p += 2;
+ continue;
+ }
+ }
+
+ if (*p == '%') {
+ do_xlat = true;
+ break;
+ }
+
+ p++;
+ }
+
+ /*
+ * If the double quoted string needs to be
+ * expanded at run time, make it an xlat
+ * expansion. Otherwise, convert it to be a
+ * literal.
+ */
+ if (cf_new_escape && do_unescape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, '"');
+ if (slen < 0) return slen;
+
+ if (do_xlat) {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, data.strvalue,
+ talloc_array_length(data.strvalue) - 1);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue,
+ talloc_array_length(data.strvalue) - 1);
+ vpt->quote = '"';
+ }
+ talloc_free(data.ptr);
+ } else {
+ if (do_xlat) {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, in, inlen);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, in, inlen);
+ vpt->quote = '"';
+ }
+ }
+ slen = vpt->len;
+ break;
+
+ case T_BACK_QUOTED_STRING:
+ if (cf_new_escape && do_unescape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, '`');
+ if (slen < 0) return slen;
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, in, inlen);
+ }
+ slen = vpt->len;
+ break;
+
+ case T_OP_REG_EQ: /* hack */
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, in, inlen);
+ slen = vpt->len;
+ break;
+
+ default:
+ rad_assert(0);
+ return 0; /* 0 is an error here too */
+ }
+
+ rad_assert((slen >= 0) && (vpt != NULL));
+
+ VERIFY_TMPL(vpt);
+
+ *out = vpt;
+
+ return slen;
+}
+/* @} **/
+
+/** @name Cast or convert #vp_tmpl_t
+ *
+ * #tmpl_cast_in_place can be used to convert #TMPL_TYPE_LITERAL to a #TMPL_TYPE_DATA of a
+ * specified #PW_TYPE.
+ *
+ * #tmpl_cast_in_place_str does the same as #tmpl_cast_in_place, but will always convert to
+ * #PW_TYPE #PW_TYPE_STRING.
+ *
+ * #tmpl_cast_to_vp does the same as #tmpl_cast_in_place, but outputs a #VALUE_PAIR.
+ *
+ * #tmpl_define_unknown_attr converts a #TMPL_TYPE_ATTR with an unknown #DICT_ATTR to a
+ * #TMPL_TYPE_ATTR with a known #DICT_ATTR, by adding the unknown #DICT_ATTR to the main
+ * dictionary, and updating the ``tmpl_da`` pointer.
+ * @{
+ */
+
+/** Convert #vp_tmpl_t of type #TMPL_TYPE_LITERAL or #TMPL_TYPE_DATA to #TMPL_TYPE_DATA of type specified
+ *
+ * @note Conversion is done in place.
+ * @note Irrespective of whether the #vp_tmpl_t was #TMPL_TYPE_LITERAL or #TMPL_TYPE_DATA,
+ * on successful cast it will be #TMPL_TYPE_DATA.
+ *
+ * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_LITERAL
+ * or #TMPL_TYPE_DATA.
+ * @param[in] type to cast to.
+ * @param[in] enumv Enumerated dictionary values associated with a #DICT_ATTR.
+ * @return 0 on success, -1 on failure.
+ */
+int tmpl_cast_in_place(vp_tmpl_t *vpt, PW_TYPE type, DICT_ATTR const *enumv)
+{
+ ssize_t ret;
+
+ VERIFY_TMPL(vpt);
+
+ rad_assert(vpt != NULL);
+ rad_assert((vpt->type == TMPL_TYPE_LITERAL) || (vpt->type == TMPL_TYPE_DATA));
+
+ switch (vpt->type) {
+ case TMPL_TYPE_LITERAL:
+ /*
+ * Why do we pass a pointer to the tmpl type? Goddamn WiMAX.
+ */
+ ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &type,
+ enumv, vpt->name, vpt->len, '\0');
+ if (ret < 0) {
+ VERIFY_TMPL(vpt);
+ return -1;
+ }
+
+ vpt->tmpl_data_type = type;
+ vpt->type = TMPL_TYPE_DATA;
+ vpt->tmpl_data_length = (size_t) ret;
+ break;
+
+ case TMPL_TYPE_DATA:
+ {
+ value_data_t new;
+
+ if (type == vpt->tmpl_data_type) return 0; /* noop */
+
+ ret = value_data_cast(vpt, &new, type, enumv, vpt->tmpl_data_type,
+ NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length);
+ if (ret < 0) return -1;
+
+ /*
+ * Free old value buffers
+ */
+ switch (vpt->tmpl_data_type) {
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ talloc_free(vpt->tmpl_data_value.ptr);
+ break;
+
+ default:
+ break;
+ }
+
+ memcpy(&vpt->tmpl_data_value, &new, sizeof(vpt->tmpl_data_value));
+ vpt->tmpl_data_type = type;
+ vpt->tmpl_data_length = (size_t) ret;
+ }
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ VERIFY_TMPL(vpt);
+
+ return 0;
+}
+
+/** Convert #vp_tmpl_t of type #TMPL_TYPE_LITERAL to #TMPL_TYPE_DATA of type #PW_TYPE_STRING
+ *
+ * @note Conversion is done in place.
+ *
+ * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_LITERAL.
+ */
+void tmpl_cast_in_place_str(vp_tmpl_t *vpt)
+{
+ rad_assert(vpt != NULL);
+ rad_assert(vpt->type == TMPL_TYPE_LITERAL);
+
+ vpt->tmpl_data.vp_strvalue = talloc_typed_strdup(vpt, vpt->name);
+ rad_assert(vpt->tmpl_data.vp_strvalue != NULL);
+
+ vpt->type = TMPL_TYPE_DATA;
+ vpt->tmpl_data_type = PW_TYPE_STRING;
+ vpt->tmpl_data_length = talloc_array_length(vpt->tmpl_data.vp_strvalue) - 1;
+}
+
+/** Expand a #vp_tmpl_t to a string, parse it as an attribute of type cast, create a #VALUE_PAIR from the result
+ *
+ * @note Like #tmpl_expand, but produces a #VALUE_PAIR.
+ *
+ * @param out Where to write pointer to the new #VALUE_PAIR.
+ * @param request The current #REQUEST.
+ * @param vpt to cast. Must be one of the following types:
+ * - #TMPL_TYPE_LITERAL
+ * - #TMPL_TYPE_EXEC
+ * - #TMPL_TYPE_XLAT
+ * - #TMPL_TYPE_XLAT_STRUCT
+ * - #TMPL_TYPE_ATTR
+ * - #TMPL_TYPE_DATA
+ * @param cast type of #VALUE_PAIR to create.
+ * @return 0 on success, -1 on failure.
+ */
+int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request,
+ vp_tmpl_t const *vpt, DICT_ATTR const *cast)
+{
+ int rcode;
+ VALUE_PAIR *vp;
+ value_data_t data;
+ char *p;
+
+ VERIFY_TMPL(vpt);
+
+ *out = NULL;
+
+ vp = fr_pair_afrom_da(request, cast);
+ if (!vp) return -1;
+
+ if (vpt->type == TMPL_TYPE_DATA) {
+ VERIFY_VP(vp);
+ rad_assert(vp->da->type == vpt->tmpl_data_type);
+
+ value_data_copy(vp, &vp->data, vpt->tmpl_data_type, &vpt->tmpl_data_value, vpt->tmpl_data_length);
+ *out = vp;
+ return 0;
+ }
+
+ rcode = tmpl_aexpand(vp, &p, request, vpt, NULL, NULL);
+ if (rcode < 0) {
+ fr_pair_list_free(&vp);
+ return rcode;
+ }
+ data.strvalue = p;
+
+ /*
+ * New escapes: strings are in binary form.
+ */
+ if (cf_new_escape && (vp->da->type == PW_TYPE_STRING)) {
+ vp->data.ptr = talloc_steal(vp, data.ptr);
+ vp->vp_length = rcode;
+
+ } else if (fr_pair_value_from_str(vp, data.strvalue, rcode) < 0) {
+ talloc_free(data.ptr);
+ fr_pair_list_free(&vp);
+ return -1;
+ }
+
+ /*
+ * Copy over any additional fields needed...
+ */
+ if ((vpt->type == TMPL_TYPE_ATTR) && vp->da->flags.has_tag) {
+ vp->tag = vpt->tmpl_tag;
+ }
+
+ *out = vp;
+ return 0;
+}
+
+/** Add an unknown #DICT_ATTR specified by a #vp_tmpl_t to the main dictionary
+ *
+ * @param vpt to add. ``tmpl_da`` pointer will be updated to point to the
+ * #DICT_ATTR inserted into the dictionary.
+ * @return 0 on success, -1 on failure.
+ */
+int tmpl_define_unknown_attr(vp_tmpl_t *vpt)
+{
+ DICT_ATTR const *da;
+
+ if (!vpt) return -1;
+
+ VERIFY_TMPL(vpt);
+
+ if (vpt->type != TMPL_TYPE_ATTR) return 0;
+
+ if (!vpt->tmpl_da->flags.is_unknown) return 0;
+
+ da = dict_unknown_add(vpt->tmpl_da);
+ if (!da) return -1;
+ vpt->tmpl_da = da;
+ return 0;
+}
+/* @} **/
+
+/** @name Resolve a #vp_tmpl_t outputting the result in various formats
+ *
+ * @{
+ */
+
+/** Expand a #vp_tmpl_t to a string writing the result to a buffer
+ *
+ * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
+ * provided by the conf parser, into a usable value.
+ * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
+ * and the printable (string) version of the data for all others.
+ *
+ * Depending what arguments are passed, either copies the value to buff, or writes a pointer
+ * to a string buffer to out. This allows the most efficient access to the value resolved by
+ * the #vp_tmpl_t, avoiding unecessary string copies.
+ *
+ * @note This function is used where raw string values are needed, which may mean the string
+ * returned may be binary data or contain unprintable chars. #fr_prints or #fr_aprints should
+ * be used before using these values in debug statements. #is_printable can be used to check
+ * if the string only contains printable chars.
+ *
+ * @param out Where to write a pointer to the string buffer. On return may point to buff if
+ * buff was used to store the value. Otherwise will point to a #value_data_t buffer,
+ * or the name of the template. To force copying to buff, out should be NULL.
+ * @param buff Expansion buffer, may be NULL if out is not NULL, and processing #TMPL_TYPE_LITERAL
+ * or string types.
+ * @param bufflen Length of expansion buffer.
+ * @param request Current request.
+ * @param vpt to expand. Must be one of the following types:
+ * - #TMPL_TYPE_LITERAL
+ * - #TMPL_TYPE_EXEC
+ * - #TMPL_TYPE_XLAT
+ * - #TMPL_TYPE_XLAT_STRUCT
+ * - #TMPL_TYPE_ATTR
+ * - #TMPL_TYPE_DATA
+ * @param escape xlat escape function (only used for xlat types).
+ * @param escape_ctx xlat escape function data.
+ * @return -1 on error, else the length of data written to buff, or pointed to by out.
+ */
+ssize_t tmpl_expand(char const **out, char *buff, size_t bufflen, REQUEST *request,
+ vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
+{
+ VALUE_PAIR *vp;
+ ssize_t slen = -1; /* quiet compiler */
+
+ VERIFY_TMPL(vpt);
+
+ rad_assert(vpt->type != TMPL_TYPE_LIST);
+
+ if (out) *out = NULL;
+
+ switch (vpt->type) {
+ case TMPL_TYPE_LITERAL:
+ RDEBUG4("EXPAND TMPL LITERAL");
+
+ if (!out) {
+ rad_assert(buff);
+ memcpy(buff, vpt->name, vpt->len >= bufflen ? bufflen : vpt->len + 1);
+ } else {
+ *out = vpt->name;
+ }
+ return vpt->len;
+
+ case TMPL_TYPE_EXEC:
+ {
+ RDEBUG4("EXPAND TMPL EXEC");
+ rad_assert(buff);
+ if (radius_exec_program(request, buff, bufflen, NULL, request, vpt->name, NULL,
+ true, false, EXEC_TIMEOUT) != 0) {
+ return -1;
+ }
+ slen = strlen(buff);
+ if (out) *out = buff;
+ }
+ break;
+
+ case TMPL_TYPE_XLAT:
+ RDEBUG4("EXPAND TMPL XLAT");
+ rad_assert(buff);
+ /* Error in expansion, this is distinct from zero length expansion */
+ slen = radius_xlat(buff, bufflen, request, vpt->name, escape, escape_ctx);
+ if (slen < 0) return slen;
+ if (out) *out = buff;
+ break;
+
+ case TMPL_TYPE_XLAT_STRUCT:
+ RDEBUG4("EXPAND TMPL XLAT STRUCT");
+ rad_assert(buff);
+ /* Error in expansion, this is distinct from zero length expansion */
+ slen = radius_xlat_struct(buff, bufflen, request, vpt->tmpl_xlat, escape, escape_ctx);
+ if (slen < 0) {
+ return slen;
+ }
+ slen = strlen(buff);
+ if (out) *out = buff;
+ break;
+
+ case TMPL_TYPE_ATTR:
+ {
+ int ret;
+
+ RDEBUG4("EXPAND TMPL ATTR");
+ rad_assert(buff);
+ ret = tmpl_find_vp(&vp, request, vpt);
+ if (ret < 0) return -2;
+
+ if (out && ((vp->da->type == PW_TYPE_STRING) || (vp->da->type == PW_TYPE_OCTETS))) {
+ *out = vp->data.ptr;
+ slen = vp->vp_length;
+ } else {
+ if (out) *out = buff;
+ slen = vp_prints_value(buff, bufflen, vp, '\0');
+ }
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ {
+ RDEBUG4("EXPAND TMPL DATA");
+
+ if (out && ((vpt->tmpl_data_type == PW_TYPE_STRING) || (vpt->tmpl_data_type == PW_TYPE_OCTETS))) {
+ *out = vpt->tmpl_data_value.ptr;
+ slen = vpt->tmpl_data_length;
+ } else {
+ if (out) *out = buff;
+ /**
+ * @todo tmpl_expand should accept an enumv da from the lhs of the map.
+ */
+ slen = value_data_prints(buff, bufflen, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length, '\0');
+ }
+ }
+ break;
+
+ /*
+ * We should never be expanding these.
+ */
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_NULL:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ case TMPL_TYPE_REGEX_STRUCT:
+ rad_assert(0 == 1);
+ slen = -1;
+ break;
+ }
+
+ if (slen < 0) return slen;
+
+
+#if 0
+ /*
+ * If we're doing correct escapes, we may have to re-parse the string.
+ * If the string is from another expansion, it needs re-parsing.
+ * Or, if it's from a "string" attribute, it needs re-parsing.
+ * Integers, IP addresses, etc. don't need re-parsing.
+ */
+ if (cf_new_escape && (vpt->type != TMPL_TYPE_ATTR)) {
+ value_data_t vd;
+ int ret;
+
+ PW_TYPE type = PW_TYPE_STRING;
+
+ slen = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
+ talloc_free(*out); /* free the old value */
+ *out = vd.ptr;
+ }
+#endif
+
+ if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
+ RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
+ RDEBUG2(" --> %s", buff);
+ }
+
+ return slen;
+}
+
+/** Expand a template to a string, allocing a new buffer to hold the string
+ *
+ * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
+ * provided by the conf parser, into a usable value.
+ * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
+ * and the printable (string) version of the data for all others.
+ *
+ * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
+ * existing buffer.
+ *
+ * @note This function is used where raw string values are needed, which may mean the string
+ * returned may be binary data or contain unprintable chars. #fr_prints or #fr_aprints should
+ * be used before using these values in debug statements. #is_printable can be used to check
+ * if the string only contains printable chars.
+ *
+ * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
+ * hint as to how to process or print the data.
+ *
+ * @param ctx to allocate new buffer in.
+ * @param out Where to write pointer to the new buffer.
+ * @param request Current request.
+ * @param vpt to expand. Must be one of the following types:
+ * - #TMPL_TYPE_LITERAL
+ * - #TMPL_TYPE_EXEC
+ * - #TMPL_TYPE_XLAT
+ * - #TMPL_TYPE_XLAT_STRUCT
+ * - #TMPL_TYPE_ATTR
+ * - #TMPL_TYPE_DATA
+ * @param escape xlat escape function (only used for xlat types).
+ * @param escape_ctx xlat escape function data (only used for xlat types).
+ * @return
+ * - -1 on failure.
+ * - The length of data written to buff, or pointed to by out.
+ */
+ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt,
+ xlat_escape_t escape, void *escape_ctx)
+{
+ VALUE_PAIR *vp;
+ ssize_t slen = -1; /* quiet compiler */
+
+ rad_assert(vpt->type != TMPL_TYPE_LIST);
+
+ VERIFY_TMPL(vpt);
+
+ *out = NULL;
+
+ switch (vpt->type) {
+ case TMPL_TYPE_LITERAL:
+ RDEBUG4("EXPAND TMPL LITERAL");
+ *out = talloc_bstrndup(ctx, vpt->name, vpt->len);
+ return vpt->len;
+
+ case TMPL_TYPE_EXEC:
+ {
+ char *buff = NULL;
+
+ RDEBUG4("EXPAND TMPL EXEC");
+ buff = talloc_array(ctx, char, 1024);
+ if (radius_exec_program(request, buff, 1024, NULL, request, vpt->name, NULL,
+ true, false, EXEC_TIMEOUT) != 0) {
+ TALLOC_FREE(buff);
+ return -1;
+ }
+ slen = strlen(buff);
+ *out = buff;
+ }
+ break;
+
+ case TMPL_TYPE_XLAT:
+ RDEBUG4("EXPAND TMPL XLAT");
+ /* Error in expansion, this is distinct from zero length expansion */
+ slen = radius_axlat(out, request, vpt->name, escape, escape_ctx);
+ if (slen < 0) {
+ rad_assert(!*out);
+ return slen;
+ }
+ rad_assert(*out);
+ slen = strlen(*out);
+ break;
+
+ case TMPL_TYPE_XLAT_STRUCT:
+ RDEBUG4("EXPAND TMPL XLAT STRUCT");
+ /* Error in expansion, this is distinct from zero length expansion */
+ slen = radius_axlat_struct(out, request, vpt->tmpl_xlat, escape, escape_ctx);
+ if (slen < 0) {
+ rad_assert(!*out);
+ return slen;
+ }
+ slen = strlen(*out);
+ break;
+
+ case TMPL_TYPE_ATTR:
+ {
+ int ret;
+
+ RDEBUG4("EXPAND TMPL ATTR");
+ ret = tmpl_find_vp(&vp, request, vpt);
+ if (ret < 0) return -2;
+
+ switch (vpt->tmpl_da->type) {
+ case PW_TYPE_STRING:
+ *out = talloc_bstrndup(ctx, vp->vp_strvalue, vp->vp_length);
+ if (!*out) return -1;
+ slen = vp->vp_length;
+ break;
+
+ case PW_TYPE_OCTETS:
+ *out = talloc_memdup(ctx, vp->vp_octets, vp->vp_length);
+ if (!*out) return -1;
+ slen = vp->vp_length;
+ break;
+
+ default:
+ *out = vp_aprints_value(ctx, vp, '\0');
+ if (!*out) return -1;
+ slen = talloc_array_length(*out) - 1;
+ break;
+ }
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ {
+ RDEBUG4("EXPAND TMPL DATA");
+
+ switch (vpt->tmpl_data_type) {
+ case PW_TYPE_STRING:
+ *out = talloc_bstrndup(ctx, vpt->tmpl_data_value.strvalue, vpt->tmpl_data_length);
+ if (!*out) return -1;
+ slen = vpt->tmpl_data_length;
+ break;
+
+ case PW_TYPE_OCTETS:
+ *out = talloc_memdup(ctx, vpt->tmpl_data_value.octets, vpt->tmpl_data_length);
+ if (!*out) return -1;
+ slen = vpt->tmpl_data_length;
+ break;
+
+ default:
+ *out = value_data_aprints(ctx, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length, '\0');
+ if (!*out) return -1;
+ slen = talloc_array_length(*out) - 1;
+ break;
+ }
+ }
+ break;
+
+ /*
+ * We should never be expanding these.
+ */
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_NULL:
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ case TMPL_TYPE_REGEX_STRUCT:
+ rad_assert(0 == 1);
+ slen = -1;
+ break;
+ }
+
+ if (slen < 0) return slen;
+
+ /*
+ * If we're doing correct escapes, we may have to re-parse the string.
+ * If the string is from another expansion, it needs re-parsing.
+ * Or, if it's from a "string" attribute, it needs re-parsing.
+ * Integers, IP addresses, etc. don't need re-parsing.
+ */
+ if (cf_new_escape && (vpt->type != TMPL_TYPE_ATTR)) {
+ value_data_t vd;
+
+ PW_TYPE type = PW_TYPE_STRING;
+
+ slen = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
+ talloc_free(*out); /* free the old value */
+ *out = vd.ptr;
+ }
+
+ if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
+ RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
+ RDEBUG2(" --> %s", *out);
+ }
+
+ return slen;
+}
+
+/** Print a #vp_tmpl_t to a string
+ *
+ * @param[out] out Where to write the presentation format #vp_tmpl_t string.
+ * @param[in] outlen Size of output buffer.
+ * @param[in] vpt to print
+ * @param[in] values Used for integer attributes only. #DICT_ATTR to use when mapping integer
+ * values to strings.
+ * @return the size of the string written to the output buffer.
+ */
+size_t tmpl_prints(char *out, size_t outlen, vp_tmpl_t const *vpt, DICT_ATTR const *values)
+{
+ size_t len;
+ char c;
+ char const *p;
+ char *q = out;
+
+ if (!vpt) {
+ *out = '\0';
+ return 0;
+ }
+
+ VERIFY_TMPL(vpt);
+
+ switch (vpt->type) {
+ default:
+ return 0;
+
+ case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_REGEX_STRUCT:
+ c = '/';
+ break;
+
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ c = '"';
+ break;
+ case TMPL_TYPE_LITERAL: /* single-quoted or bare word */
+ /*
+ * Hack
+ */
+ for (p = vpt->name; *p != '\0'; p++) {
+ if (*p == ' ') break;
+ if (*p == '\'') break;
+ if (!dict_attr_allowed_chars[(int) *p]) break;
+ }
+
+ if (!*p) {
+ strlcpy(out, vpt->name, outlen);
+ return strlen(out);
+ }
+
+ c = vpt->quote;
+ break;
+
+ case TMPL_TYPE_EXEC:
+ c = '`';
+ break;
+
+ case TMPL_TYPE_LIST:
+ out[0] = '&';
+ if (vpt->tmpl_request == REQUEST_CURRENT) {
+ snprintf(out + 1, outlen - 1, "%s:",
+ fr_int2str(pair_lists, vpt->tmpl_list, ""));
+ } else {
+ snprintf(out + 1, outlen - 1, "%s.%s:",
+ fr_int2str(request_refs, vpt->tmpl_request, ""),
+ fr_int2str(pair_lists, vpt->tmpl_list, ""));
+ }
+ len = strlen(out);
+ goto attr_inst_tag;
+
+ case TMPL_TYPE_ATTR:
+ out[0] = '&';
+ if (vpt->tmpl_request == REQUEST_CURRENT) {
+ if (vpt->tmpl_list == PAIR_LIST_REQUEST) {
+ strlcpy(out + 1, vpt->tmpl_da->name, outlen - 1);
+ } else {
+ snprintf(out + 1, outlen - 1, "%s:%s",
+ fr_int2str(pair_lists, vpt->tmpl_list, ""),
+ vpt->tmpl_da->name);
+ }
+
+ } else {
+ snprintf(out + 1, outlen - 1, "%s.%s:%s",
+ fr_int2str(request_refs, vpt->tmpl_request, ""),
+ fr_int2str(pair_lists, vpt->tmpl_list, ""),
+ vpt->tmpl_da->name);
+ }
+
+ len = strlen(out);
+
+ attr_inst_tag:
+ if ((vpt->tmpl_tag == TAG_ANY) && (vpt->tmpl_num == NUM_ANY)) return len;
+
+ q = out + len;
+ outlen -= len;
+
+ if (vpt->tmpl_tag != TAG_ANY) {
+ snprintf(q, outlen, ":%d", vpt->tmpl_tag);
+ len = strlen(q);
+ q += len;
+ outlen -= len;
+ }
+
+ switch (vpt->tmpl_num) {
+ case NUM_ANY:
+ break;
+
+ case NUM_ALL:
+ snprintf(q, outlen, "[*]");
+ len = strlen(q);
+ q += len;
+ break;
+
+ case NUM_COUNT:
+ snprintf(q, outlen, "[#]");
+ len = strlen(q);
+ q += len;
+ break;
+
+ case NUM_LAST:
+ snprintf(q, outlen, "[n]");
+ len = strlen(q);
+ q += len;
+ break;
+
+ default:
+ snprintf(q, outlen, "[%i]", vpt->tmpl_num);
+ len = strlen(q);
+ q += len;
+ break;
+ }
+
+ return (q - out);
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ out[0] = '&';
+ if (vpt->tmpl_request == REQUEST_CURRENT) {
+ if (vpt->tmpl_list == PAIR_LIST_REQUEST) {
+ strlcpy(out + 1, vpt->tmpl_unknown_name, outlen - 1);
+ } else {
+ snprintf(out + 1, outlen - 1, "%s:%s",
+ fr_int2str(pair_lists, vpt->tmpl_list, ""),
+ vpt->tmpl_unknown_name);
+ }
+
+ } else {
+ snprintf(out + 1, outlen - 1, "%s.%s:%s",
+ fr_int2str(request_refs, vpt->tmpl_request, ""),
+ fr_int2str(pair_lists, vpt->tmpl_list, ""),
+ vpt->tmpl_unknown_name);
+ }
+
+ len = strlen(out);
+
+ if (vpt->tmpl_num == NUM_ANY) {
+ return len;
+ }
+
+ q = out + len;
+ outlen -= len;
+
+ if (vpt->tmpl_num != NUM_ANY) {
+ snprintf(q, outlen, "[%i]", vpt->tmpl_num);
+ len = strlen(q);
+ q += len;
+ }
+
+ return (q - out);
+
+ case TMPL_TYPE_DATA:
+ return value_data_prints(out, outlen, vpt->tmpl_data_type, values, &vpt->tmpl_data_value,
+ vpt->tmpl_data_length, vpt->quote);
+ }
+
+ if (outlen <= 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ *(q++) = c;
+
+ /*
+ * Print it with appropriate escaping
+ */
+ if (cf_new_escape && (c == '/')) {
+ len = fr_prints(q, outlen - 3, vpt->name, vpt->len, '\0');
+ } else {
+ len = fr_prints(q, outlen - 3, vpt->name, vpt->len, c);
+ }
+
+ q += len;
+ *(q++) = c;
+ *q = '\0';
+
+ return q - out;
+}
+
+/** Initialise a #vp_cursor_t to the #VALUE_PAIR specified by a #vp_tmpl_t
+ *
+ * This makes iterating over the one or more #VALUE_PAIR specified by a #vp_tmpl_t
+ * significantly easier.
+ *
+ * @param err May be NULL if no error code is required. Will be set to:
+ * - 0 on success.
+ * - -1 if no matching #VALUE_PAIR could be found.
+ * - -2 if list could not be found (doesn't exist in current #REQUEST).
+ * - -3 if context could not be found (no parent #REQUEST available).
+ * @param cursor to store iterator state.
+ * @param request The current #REQUEST.
+ * @param vpt specifying the #VALUE_PAIR type/tag or list to iterate over.
+ * @return the first #VALUE_PAIR specified by the #vp_tmpl_t, or NULL if no matching
+ * #VALUE_PAIR found, and NULL on error.
+ *
+ * @see tmpl_cursor_next
+ */
+VALUE_PAIR *tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
+{
+ VALUE_PAIR **vps, *vp = NULL;
+ int num;
+
+ VERIFY_TMPL(vpt);
+
+ rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
+
+ if (err) *err = 0;
+
+ if (radius_request(&request, vpt->tmpl_request) < 0) {
+ if (err) *err = -3;
+ return NULL;
+ }
+ vps = radius_list(request, vpt->tmpl_list);
+ if (!vps) {
+ if (err) *err = -2;
+ return NULL;
+ }
+ (void) fr_cursor_init(cursor, vps);
+
+ switch (vpt->type) {
+ /*
+ * May not may not be found, but it *is* a known name.
+ */
+ case TMPL_TYPE_ATTR:
+ switch (vpt->tmpl_num) {
+ case NUM_ANY:
+ vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
+ if (!vp) {
+ if (err) *err = -1;
+ return NULL;
+ }
+ VERIFY_VP(vp);
+ return vp;
+
+ /*
+ * Get the last instance of a VALUE_PAIR.
+ */
+ case NUM_LAST:
+ {
+ VALUE_PAIR *last = NULL;
+
+ while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
+ VERIFY_VP(vp);
+ last = vp;
+ }
+ VERIFY_VP(last);
+ if (!last) break;
+ return last;
+ }
+
+ /*
+ * Callers expect NUM_COUNT to setup the cursor to point
+ * to the first attribute in the list we're meant to be
+ * counting.
+ *
+ * It does not produce a virtual attribute containing the
+ * total number of attributes.
+ */
+ case NUM_COUNT:
+ return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
+
+ default:
+ num = vpt->tmpl_num;
+ while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
+ VERIFY_VP(vp);
+ if (num-- <= 0) return vp;
+ }
+ break;
+ }
+
+ if (err) *err = -1;
+ return NULL;
+
+ case TMPL_TYPE_LIST:
+ switch (vpt->tmpl_num) {
+ case NUM_COUNT:
+ case NUM_ANY:
+ case NUM_ALL:
+ vp = fr_cursor_init(cursor, vps);
+ if (!vp) {
+ if (err) *err = -1;
+ return NULL;
+ }
+ VERIFY_VP(vp);
+ return vp;
+
+ /*
+ * Get the last instance of a VALUE_PAIR.
+ */
+ case NUM_LAST:
+ {
+ VALUE_PAIR *last = NULL;
+
+ for (vp = fr_cursor_init(cursor, vps);
+ vp;
+ vp = fr_cursor_next(cursor)) {
+ VERIFY_VP(vp);
+ last = vp;
+ }
+ if (!last) break;
+ VERIFY_VP(last);
+ return last;
+ }
+
+ default:
+ num = vpt->tmpl_num;
+ for (vp = fr_cursor_init(cursor, vps);
+ vp;
+ vp = fr_cursor_next(cursor)) {
+ VERIFY_VP(vp);
+ if (num-- <= 0) return vp;
+ }
+ break;
+ }
+
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ return vp;
+}
+
+/** Returns the next #VALUE_PAIR specified by vpt
+ *
+ * @param cursor initialised with #tmpl_cursor_init.
+ * @param vpt specifying the #VALUE_PAIR type/tag to iterate over.
+ * Must be one of the following types:
+ * - #TMPL_TYPE_LIST
+ * - #TMPL_TYPE_ATTR
+ * @return NULL if no more matching #VALUE_PAIR of the specified type/tag are found.
+ */
+VALUE_PAIR *tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
+{
+ rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
+
+ VERIFY_TMPL(vpt);
+
+ switch (vpt->type) {
+ /*
+ * May not may not be found, but it *is* a known name.
+ */
+ case TMPL_TYPE_ATTR:
+ switch (vpt->tmpl_num) {
+ default:
+ return NULL;
+
+ case NUM_ALL:
+ case NUM_COUNT: /* This cursor is being used to count matching attrs */
+ break;
+ }
+ return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
+
+ case TMPL_TYPE_LIST:
+ switch (vpt->tmpl_num) {
+ default:
+ return NULL;
+
+ case NUM_ALL:
+ case NUM_COUNT: /* This cursor is being used to count matching attrs */
+ break;
+ }
+ return fr_cursor_next(cursor);
+
+ default:
+ rad_assert(0);
+ return NULL; /* Older versions of GCC flag the lack of return as an error */
+ }
+}
+
+/** Copy pairs matching a #vp_tmpl_t in the current #REQUEST
+ *
+ * @param ctx to allocate new #VALUE_PAIR in.
+ * @param out Where to write the copied #VALUE_PAIR (s).
+ * @param request The current #REQUEST.
+ * @param vpt specifying the #VALUE_PAIR type/tag or list to copy.
+ * Must be one of the following types:
+ * - #TMPL_TYPE_LIST
+ * - #TMPL_TYPE_ATTR
+ * @return
+ * - -1 if no matching #VALUE_PAIR could be found.
+ * - -2 if list could not be found (doesn't exist in current #REQUEST).
+ * - -3 if context could not be found (no parent #REQUEST available).
+ * - -4 on memory allocation error.
+ */
+int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t from, to;
+
+ VERIFY_TMPL(vpt);
+
+ int err;
+
+ rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
+
+ *out = NULL;
+
+ fr_cursor_init(&to, out);
+
+ for (vp = tmpl_cursor_init(&err, &from, request, vpt);
+ vp;
+ vp = tmpl_cursor_next(&from, vpt)) {
+ vp = fr_pair_copy(ctx, vp);
+ if (!vp) {
+ fr_pair_list_free(out);
+ return -4;
+ }
+ fr_cursor_insert(&to, vp);
+ }
+
+ return err;
+}
+
+/** Returns the first VP matching a #vp_tmpl_t
+ *
+ * @param out where to write the retrieved vp.
+ * @param request The current #REQUEST.
+ * @param vpt specifying the #VALUE_PAIR type/tag to find.
+ * Must be one of the following types:
+ * - #TMPL_TYPE_LIST
+ * - #TMPL_TYPE_ATTR
+ * @return
+ * - -1 if no matching #VALUE_PAIR could be found.
+ * - -2 if list could not be found (doesn't exist in current #REQUEST).
+ * - -3 if context could not be found (no parent #REQUEST available).
+ */
+int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ VERIFY_TMPL(vpt);
+
+ int err;
+
+ vp = tmpl_cursor_init(&err, &cursor, request, vpt);
+ if (out) *out = vp;
+
+ return err;
+}
+/* @} **/
+
+#ifdef WITH_VERIFY_PTR
+/** Used to check whether areas of a vp_tmpl_t are zeroed out
+ *
+ * @param ptr Offset to begin checking at.
+ * @param len How many bytes to check.
+ * @return pointer to the first non-zero byte, or NULL if all bytes were zero.
+ */
+static uint8_t const *not_zeroed(uint8_t const *ptr, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (ptr[i] != 0x00) return ptr + i;
+ }
+
+ return NULL;
+}
+#define CHECK_ZEROED(_x) not_zeroed((uint8_t const *)&_x + sizeof(_x), sizeof(vpt->data) - sizeof(_x))
+
+/** Verify fields of a vp_tmpl_t make sense
+ *
+ * @note If the #vp_tmpl_t is invalid, causes the server to exit.
+ *
+ * @param file obtained with __FILE__.
+ * @param line obtained with __LINE__.
+ * @param vpt to check.
+ */
+void tmpl_verify(char const *file, int line, vp_tmpl_t const *vpt)
+{
+ rad_assert(vpt);
+
+ if (vpt->type == TMPL_TYPE_UNKNOWN) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was "
+ "TMPL_TYPE_UNKNOWN (uninitialised)", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->type > TMPL_TYPE_NULL) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was %i "
+ "(outside range of tmpl_names)", file, line, vpt->type);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ /*
+ * Do a memcmp of the bytes after where the space allocated for
+ * the union member should have ended and the end of the union.
+ * These should always be zero if the union has been initialised
+ * properly.
+ *
+ * If they're still all zero, do TMPL_TYPE specific checks.
+ */
+ switch (vpt->type) {
+ case TMPL_TYPE_NULL:
+ if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_NULL "
+ "has non-zero bytes in its data union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_LITERAL:
+ if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LITERAL "
+ "has non-zero bytes in its data union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_XLAT_STRUCT:
+ break;
+
+/* @todo When regexes get converted to xlat the flags field of the regex union is used
+ case TMPL_TYPE_XLAT:
+ if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
+ "has non-zero bytes in its data union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_XLAT_STRUCT:
+ if (CHECK_ZEROED(vpt->data.xlat)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT_STRUCT "
+ "has non-zero bytes after the data.xlat pointer in the union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+*/
+
+ case TMPL_TYPE_EXEC:
+ if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_EXEC "
+ "has non-zero bytes in its data union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ rad_assert(vpt->tmpl_da == NULL);
+ break;
+
+ case TMPL_TYPE_ATTR:
+ if (CHECK_ZEROED(vpt->data.attribute)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
+ "has non-zero bytes after the data.attribute struct in the union",
+ file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_da->flags.is_unknown) {
+ if (vpt->tmpl_da != (DICT_ATTR const *)&vpt->data.attribute.unknown.da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
+ "da is marked as unknown, but does not point to the template's "
+ "unknown da buffer", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ } else {
+ DICT_ATTR const *da;
+
+ /*
+ * Attribute may be present with multiple names
+ */
+ da = dict_attrbyname(vpt->tmpl_da->name);
+ if (!da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
+ "attribute \"%s\" (%s) not found in global dictionary",
+ file, line, vpt->tmpl_da->name,
+ fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if ((da->type == PW_TYPE_COMBO_IP_ADDR) && (da->type != vpt->tmpl_da->type)) {
+ da = dict_attrbytype(vpt->tmpl_da->attr, vpt->tmpl_da->vendor, vpt->tmpl_da->type);
+ if (!da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
+ "attribute \"%s\" variant (%s) not found in global dictionary",
+ file, line, vpt->tmpl_da->name,
+ fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+
+ if (da != vpt->tmpl_da) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
+ "dictionary pointer %p \"%s\" (%s) "
+ "and global dictionary pointer %p \"%s\" (%s) differ",
+ file, line,
+ vpt->tmpl_da, vpt->tmpl_da->name,
+ fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"),
+ da, da->name,
+ fr_int2str(dict_attr_types, da->type, "<INVALID>"));
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+ break;
+
+ case TMPL_TYPE_LIST:
+ if (CHECK_ZEROED(vpt->data.attribute)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST"
+ "has non-zero bytes after the data.attribute struct in the union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_da != NULL) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST da pointer was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_DATA:
+ if (CHECK_ZEROED(vpt->data.literal)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA "
+ "has non-zero bytes after the data.literal struct in the union",
+ file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_data_type == PW_TYPE_INVALID) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
+ "PW_TYPE_INVALID (uninitialised)", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_data_type >= PW_TYPE_MAX) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
+ "%i (outside the range of PW_TYPEs)", file, line, vpt->tmpl_data_type);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ /*
+ * Unlike VALUE_PAIRs we can't guarantee that VALUE_PAIR_TMPL buffers will
+ * be talloced. They may be allocated on the stack or in global variables.
+ */
+ switch (vpt->tmpl_data_type) {
+ case PW_TYPE_STRING:
+ if (vpt->tmpl_data.vp_strvalue[vpt->tmpl_data_length] != '\0') {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA char buffer not \\0 "
+ "terminated", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case PW_TYPE_TLV:
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA is of type TLV",
+ file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+
+ case PW_TYPE_OCTETS:
+ break;
+
+ default:
+ if (vpt->tmpl_data_length == 0) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA data pointer not NULL "
+ "but len field is zero", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ }
+
+ break;
+
+ case TMPL_TYPE_REGEX:
+ /*
+ * iflag field is used for non compiled regexes too.
+ */
+ if (CHECK_ZEROED(vpt->data.preg)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
+ "has non-zero bytes after the data.preg struct in the union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_preg != NULL) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
+ "preg field was not nULL", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
+ "iflag field was neither true or false", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
+ "mflag field was neither true or false", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ break;
+
+ case TMPL_TYPE_REGEX_STRUCT:
+ if (CHECK_ZEROED(vpt->data.preg)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
+ "has non-zero bytes after the data.preg struct in the union", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if (vpt->tmpl_preg == NULL) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
+ "comp field was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
+ "iflag field was neither true or false", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+
+ if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
+ FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
+ "mflag field was neither true or false", file, line);
+ fr_assert(0);
+ fr_exit_now(1);
+ }
+ break;
+
+ case TMPL_TYPE_UNKNOWN:
+ rad_assert(0);
+ }
+}
+#endif
diff --git a/src/main/unittest.c b/src/main/unittest.c
new file mode 100644
index 0000000..72fdadc
--- /dev/null
+++ b/src/main/unittest.c
@@ -0,0 +1,982 @@
+/*
+ * unittest.c Unit test wrapper for the RADIUS daemon.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2013 The FreeRADIUS server project
+ * Copyright 2013 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/state.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/event.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <ctype.h>
+
+/*
+ * Global variables.
+ */
+char const *radacct_dir = NULL;
+char const *radlog_dir = NULL;
+bool log_stripped_names = false;
+
+static bool memory_report = false;
+static bool filedone = false;
+
+char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+", for host " HOSTINFO
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+fr_event_list_t *el = NULL;
+
+/*
+ * Static functions.
+ */
+static void usage(int);
+
+void listen_free(UNUSED rad_listen_t **head)
+{
+ /* do nothing */
+}
+
+void request_inject(UNUSED REQUEST *request)
+{
+ /* do nothing */
+}
+
+#ifdef WITH_RADIUSV11
+int fr_radiusv11_client_init(UNUSED fr_tls_server_conf_t *tls);
+
+int fr_radiusv11_client_init(UNUSED fr_tls_server_conf_t *tls)
+{
+ return 0;
+}
+#endif
+
+static rad_listen_t *listen_alloc(void *ctx)
+{
+ rad_listen_t *this;
+
+ this = talloc_zero(ctx, rad_listen_t);
+ if (!this) return NULL;
+
+ this->type = RAD_LISTEN_AUTH;
+ this->recv = NULL;
+ this->send = NULL;
+ this->print = NULL;
+ this->encode = NULL;
+ this->decode = NULL;
+
+ /*
+ * We probably don't care about this. We can always add
+ * fields later.
+ */
+ this->data = talloc_zero(this, listen_socket_t);
+ if (!this->data) {
+ talloc_free(this);
+ return NULL;
+ }
+
+ return this;
+}
+
+static RADCLIENT *client_alloc(void *ctx)
+{
+ RADCLIENT *client;
+
+ client = talloc_zero(ctx, RADCLIENT);
+ if (!client) return NULL;
+
+ return client;
+}
+
+static REQUEST *request_setup(FILE *fp)
+{
+ VALUE_PAIR *vp;
+ REQUEST *request;
+ vp_cursor_t cursor;
+ struct timeval now;
+
+ /*
+ * Create and initialize the new request.
+ */
+ request = request_alloc(NULL);
+ gettimeofday(&now, NULL);
+ request->timestamp = now.tv_sec;
+
+ request->packet = rad_alloc(request, false);
+ if (!request->packet) {
+ ERROR("No memory");
+ talloc_free(request);
+ return NULL;
+ }
+ request->packet->timestamp = now;
+
+ request->reply = rad_alloc(request, false);
+ if (!request->reply) {
+ ERROR("No memory");
+ talloc_free(request);
+ return NULL;
+ }
+
+ request->listener = listen_alloc(request);
+ request->client = client_alloc(request);
+
+ request->number = 0;
+
+ request->master_state = REQUEST_ACTIVE;
+ request->child_state = REQUEST_RUNNING;
+ request->handle = NULL;
+ request->server = talloc_typed_strdup(request, "default");
+
+ request->root = &main_config;
+
+ /*
+ * Read packet from fp
+ */
+ if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, fp, &filedone) < 0) {
+ fr_perror("unittest");
+ talloc_free(request);
+ return NULL;
+ }
+
+ /*
+ * Set the defaults for IPs, etc.
+ */
+ request->packet->code = PW_CODE_ACCESS_REQUEST;
+
+ request->packet->src_ipaddr.af = AF_INET;
+ request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
+ request->packet->src_port = 18120;
+
+ request->packet->dst_ipaddr.af = AF_INET;
+ request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
+ request->packet->dst_port = 1812;
+
+ /*
+ * Copied from radclient
+ *
+ * Fix up Digest-Attributes issues
+ */
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Double quoted strings get marked up as xlat expansions,
+ * but we don't support that here.
+ */
+ if (vp->type == VT_XLAT) {
+ vp->vp_strvalue = vp->value.xlat;
+ vp->value.xlat = NULL;
+ vp->type = VT_DATA;
+ }
+
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ default:
+ break;
+
+ /*
+ * Allow it to set the packet type in
+ * the attributes read from the file.
+ */
+ case PW_PACKET_TYPE:
+ request->packet->code = vp->vp_integer;
+ break;
+
+ case PW_PACKET_DST_PORT:
+ request->packet->dst_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_DST_IP_ADDRESS:
+ request->packet->dst_ipaddr.af = AF_INET;
+ request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->dst_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_DST_IPV6_ADDRESS:
+ request->packet->dst_ipaddr.af = AF_INET6;
+ request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->dst_ipaddr.prefix = 128;
+ break;
+
+ case PW_PACKET_SRC_PORT:
+ request->packet->src_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_SRC_IP_ADDRESS:
+ request->packet->src_ipaddr.af = AF_INET;
+ request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->packet->src_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_SRC_IPV6_ADDRESS:
+ request->packet->src_ipaddr.af = AF_INET6;
+ request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->packet->src_ipaddr.prefix = 128;
+ break;
+
+ case PW_CHAP_PASSWORD: {
+ int i, already_hex = 0;
+
+ /*
+ * If it's 17 octets, it *might* be already encoded.
+ * Or, it might just be a 17-character password (maybe UTF-8)
+ * Check it for non-printable characters. The odds of ALL
+ * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
+ * or 1/(2^51), which is pretty much zero.
+ */
+ if (vp->vp_length == 17) {
+ for (i = 0; i < 17; i++) {
+ if (vp->vp_octets[i] < 32) {
+ already_hex = 1;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Allow the user to specify ASCII or hex CHAP-Password
+ */
+ if (!already_hex) {
+ uint8_t *p;
+ size_t len, len2;
+
+ len = len2 = vp->vp_length;
+ if (len2 < 17) len2 = 17;
+
+ p = talloc_zero_array(vp, uint8_t, len2);
+
+ memcpy(p, vp->vp_strvalue, len);
+
+ rad_chap_encode(request->packet,
+ p,
+ fr_rand() & 0xff, vp);
+ vp->vp_octets = p;
+ vp->vp_length = 17;
+ }
+ }
+ break;
+
+ case PW_DIGEST_REALM:
+ case PW_DIGEST_NONCE:
+ case PW_DIGEST_METHOD:
+ case PW_DIGEST_URI:
+ case PW_DIGEST_QOP:
+ case PW_DIGEST_ALGORITHM:
+ case PW_DIGEST_BODY_DIGEST:
+ case PW_DIGEST_CNONCE:
+ case PW_DIGEST_NONCE_COUNT:
+ case PW_DIGEST_USER_NAME:
+ /* overlapping! */
+ {
+ DICT_ATTR const *da;
+ uint8_t *p, *q;
+
+ p = talloc_array(vp, uint8_t, vp->vp_length + 2);
+
+ memcpy(p + 2, vp->vp_octets, vp->vp_length);
+ p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
+ vp->vp_length += 2;
+ p[1] = vp->vp_length;
+
+ da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
+ rad_assert(da != NULL);
+ vp->da = da;
+
+ /*
+ * Re-do fr_pair_value_memsteal ourselves,
+ * because we play games with
+ * vp->da, and fr_pair_value_memsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
+ }
+
+ break;
+ }
+ } /* loop over the VP's we read in */
+
+ if (rad_debug_lvl) {
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Take this opportunity to verify all the VALUE_PAIRs are still valid.
+ */
+ if (!talloc_get_type(vp, VALUE_PAIR)) {
+ ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
+
+ fr_log_talloc_report(vp);
+ rad_assert(0);
+ }
+
+ vp_print(fr_log_fp, vp);
+ }
+ fflush(fr_log_fp);
+ }
+
+ /*
+ * Build the reply template from the request.
+ */
+ request->reply->sockfd = request->packet->sockfd;
+ request->reply->dst_ipaddr = request->packet->src_ipaddr;
+ request->reply->src_ipaddr = request->packet->dst_ipaddr;
+ request->reply->dst_port = request->packet->src_port;
+ request->reply->src_port = request->packet->dst_port;
+ request->reply->id = request->packet->id;
+ request->reply->code = 0; /* UNKNOWN code */
+ memcpy(request->reply->vector, request->packet->vector,
+ sizeof(request->reply->vector));
+ request->reply->vps = NULL;
+ request->reply->data = NULL;
+ request->reply->data_len = 0;
+
+ /*
+ * Debugging
+ */
+ request->log.lvl = rad_debug_lvl;
+ request->log.func = vradlog_request;
+
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+ return request;
+}
+
+
+static void print_packet(FILE *fp, RADIUS_PACKET *packet)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ if (!packet) {
+ fprintf(fp, "\n");
+ return;
+ }
+
+ fprintf(fp, "%s\n", fr_packet_codes[packet->code]);
+
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Take this opportunity to verify all the VALUE_PAIRs are still valid.
+ */
+ if (!talloc_get_type(vp, VALUE_PAIR)) {
+ ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));
+
+ fr_log_talloc_report(vp);
+ rad_assert(0);
+ }
+
+ vp_print(fp, vp);
+ }
+ fflush(fp);
+}
+
+
+#include <freeradius-devel/modpriv.h>
+
+/*
+ * %{poke:sql.foo=bar}
+ */
+static ssize_t xlat_poke(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ int i;
+ void *data, *base;
+ char *p, *q;
+ module_instance_t *mi;
+ char *buffer;
+ CONF_SECTION *modules;
+ CONF_PAIR *cp;
+ CONF_PARSER const *variables;
+ size_t len;
+
+ rad_assert(outlen > 1);
+ rad_assert(request != NULL);
+ rad_assert(fmt != NULL);
+ rad_assert(out != NULL);
+
+ *out = '\0';
+
+ modules = cf_section_sub_find(request->root->config, "modules");
+ if (!modules) return 0;
+
+ buffer = talloc_strdup(request, fmt);
+ if (!buffer) return 0;
+
+ p = strchr(buffer, '.');
+ if (!p) return 0;
+
+ *(p++) = '\0';
+
+ mi = module_find(modules, buffer);
+ if (!mi) {
+ RDEBUG("Failed finding module '%s'", buffer);
+ fail:
+ talloc_free(buffer);
+ return 0;
+ }
+
+ q = strchr(p, '=');
+ if (!q) {
+ RDEBUG("Failed finding '=' in string '%s'", fmt);
+ goto fail;
+ }
+
+ *(q++) = '\0';
+
+ if (strchr(p, '.') != NULL) {
+ RDEBUG("Can't do sub-sections right now");
+ goto fail;
+ }
+
+ cp = cf_pair_find(mi->cs, p);
+ if (!cp) {
+ RDEBUG("No such item '%s'", p);
+ goto fail;
+ }
+
+ /*
+ * Copy the old value to the output buffer, that way
+ * tests can restore it later, if they need to.
+ */
+ len = strlcpy(out, cf_pair_value(cp), outlen);
+
+ if (cf_pair_replace(mi->cs, cp, q) < 0) {
+ RDEBUG("Failed replacing pair");
+ goto fail;
+ }
+
+ base = mi->insthandle;
+ variables = mi->entry->module->config;
+
+ /*
+ * Handle the known configuration parameters.
+ */
+ for (i = 0; variables[i].name != NULL; i++) {
+ int ret;
+
+ if (variables[i].type == PW_TYPE_SUBSECTION) continue;
+ /* else it's a CONF_PAIR */
+
+ /*
+ * Not the pair we want. Skip it.
+ */
+ if (strcmp(variables[i].name, p) != 0) continue;
+
+ if (variables[i].data) {
+ data = variables[i].data; /* prefer this. */
+ } else if (base) {
+ data = ((char *)base) + variables[i].offset;
+ } else {
+ DEBUG2("Internal sanity check 2 failed in cf_section_parse");
+ goto fail;
+ }
+
+ /*
+ * Parse the pair we found, or a default value.
+ */
+ ret = cf_item_parse(mi->cs, variables[i].name, variables[i].type, data, variables[i].dflt);
+ if (ret < 0) {
+ DEBUG2("Failed inserting new value into module instance data");
+ goto fail;
+ }
+ break; /* we found it, don't do any more */
+ }
+
+ talloc_free(buffer);
+
+ return len;
+}
+
+
+/*
+ * Read a file compose of xlat's and expected results
+ */
+static bool do_xlats(char const *filename, FILE *fp)
+{
+ int lineno = 0;
+ ssize_t len;
+ char *p;
+ char input[8192];
+ char output[8192];
+ REQUEST *request;
+ struct timeval now;
+
+ /*
+ * Create and initialize the new request.
+ */
+ request = request_alloc(NULL);
+ gettimeofday(&now, NULL);
+ request->timestamp = now.tv_sec;
+
+ request->log.lvl = rad_debug_lvl;
+ request->log.func = vradlog_request;
+
+ output[0] = '\0';
+
+ while (fgets(input, sizeof(input), fp) != NULL) {
+ lineno++;
+
+ /*
+ * Ignore blank lines and comments
+ */
+ p = input;
+ while (isspace((uint8_t) *p)) p++;
+
+ if (*p < ' ') continue;
+ if (*p == '#') continue;
+
+ p = strchr(p, '\n');
+ if (!p) {
+ if (!feof(fp)) {
+ fprintf(stderr, "Line %d too long in %s\n",
+ lineno, filename);
+ TALLOC_FREE(request);
+ return false;
+ }
+ } else {
+ *p = '\0';
+ }
+
+ /*
+ * Look for "xlat"
+ */
+ if (strncmp(input, "xlat ", 5) == 0) {
+ ssize_t slen;
+ char const *error = NULL;
+ char *fmt = talloc_typed_strdup(NULL, input + 5);
+ xlat_exp_t *head;
+
+ slen = xlat_tokenize(fmt, fmt, &head, &error);
+ if (slen <= 0) {
+ talloc_free(fmt);
+ snprintf(output, sizeof(output), "ERROR offset %d '%s'", (int) -slen, error);
+ continue;
+ }
+
+ if (input[slen + 5] != '\0') {
+ talloc_free(fmt);
+ snprintf(output, sizeof(output), "ERROR offset %d 'Too much text' ::%s::", (int) slen, input + slen + 5);
+ continue;
+ }
+
+ len = radius_xlat_struct(output, sizeof(output), request, head, NULL, NULL);
+ if (len < 0) {
+ snprintf(output, sizeof(output), "ERROR expanding xlat: %s", fr_strerror());
+ continue;
+ }
+
+ TALLOC_FREE(fmt); /* also frees 'head' */
+ continue;
+ }
+
+ /*
+ * Look for "data".
+ */
+ if (strncmp(input, "data ", 5) == 0) {
+ if (strcmp(input + 5, output) != 0) {
+ fprintf(stderr, "Mismatch at line %d of %s\n\tgot : %s\n\texpected : %s\n",
+ lineno, filename, output, input + 5);
+ TALLOC_FREE(request);
+ return false;
+ }
+ continue;
+ }
+
+ fprintf(stderr, "Unknown keyword in %s[%d]\n", filename, lineno);
+ TALLOC_FREE(request);
+ return false;
+ }
+
+ TALLOC_FREE(request);
+ return true;
+}
+
+/*
+ * Dummy event_list_corral
+ */
+fr_event_list_t *radius_event_list_corral(UNUSED event_corral_t hint) {
+ if (!el) {
+ el = fr_event_list_create(NULL, NULL);
+ }
+
+ return el;
+}
+
+/*
+ * The main guy.
+ */
+int main(int argc, char *argv[])
+{
+ int rcode = EXIT_SUCCESS;
+ int argval;
+ const char *input_file = NULL;
+ const char *output_file = NULL;
+ const char *filter_file = NULL;
+ FILE *fp;
+ REQUEST *request = NULL;
+ VALUE_PAIR *vp;
+ VALUE_PAIR *filter_vps = NULL;
+ bool xlat_only = false;
+ fr_state_t *state = NULL;
+
+ fr_talloc_fault_setup();
+
+ /*
+ * If the server was built with debugging enabled always install
+ * the basic fatal signal handlers.
+ */
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("unittest");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ rad_debug_lvl = 0;
+ set_radius_dir(NULL, RADIUS_DIR);
+
+ /*
+ * Ensure that the configuration is initialized.
+ */
+ memset(&main_config, 0, sizeof(main_config));
+ main_config.myip.af = AF_UNSPEC;
+ main_config.port = 0;
+ main_config.name = "radiusd";
+
+ /*
+ * The tests should have only IPs, not host names.
+ */
+ fr_hostname_lookups = false;
+
+ /*
+ * We always log to stdout.
+ */
+ fr_log_fp = stdout;
+ default_log.dst = L_DST_STDOUT;
+ default_log.fd = STDOUT_FILENO;
+
+ /* Process the options. */
+ while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:O:xX")) != EOF) {
+
+ switch (argval) {
+ case 'd':
+ set_radius_dir(NULL, optarg);
+ break;
+
+ case 'D':
+ main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
+ break;
+
+ case 'f':
+ filter_file = optarg;
+ break;
+
+ case 'h':
+ usage(0);
+ break;
+
+ case 'i':
+ input_file = optarg;
+ break;
+
+ case 'm':
+ main_config.debug_memory = true;
+ break;
+
+ case 'M':
+ memory_report = true;
+ main_config.debug_memory = true;
+ break;
+
+ case 'n':
+ main_config.name = optarg;
+ break;
+
+ case 'o':
+ output_file = optarg;
+ break;
+
+ case 'O':
+ if (strcmp(optarg, "xlat_only") == 0) {
+ xlat_only = true;
+ break;
+ }
+
+ fprintf(stderr, "Unknown option '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+
+ case 'X':
+ rad_debug_lvl += 2;
+ main_config.log_auth = true;
+ main_config.log_auth_badpass = true;
+ main_config.log_auth_goodpass = true;
+ break;
+
+ case 'x':
+ rad_debug_lvl++;
+ break;
+
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ if (rad_debug_lvl) version_print();
+ fr_debug_lvl = rad_debug_lvl;
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radiusd");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Initialising OpenSSL once, here, is safer than having individual modules do it.
+ */
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ tls_global_init(false, false);
+#endif
+
+ if (xlat_register("poke", xlat_poke, NULL, NULL) < 0) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /* Read the configuration files, BEFORE doing anything else. */
+ if (main_config_init() < 0) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /*
+ * Load the modules
+ */
+ if (modules_init(main_config.config) < 0) {
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ state =fr_state_init(NULL);
+
+ /*
+ * Set the panic action (if required)
+ */
+ {
+ char const *panic_action = NULL;
+
+ panic_action = getenv("PANIC_ACTION");
+ if (!panic_action) panic_action = main_config.panic_action;
+
+ if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) {
+ fr_perror("radiusd");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ setlinebuf(stdout); /* unbuffered output */
+
+ if (!input_file || (strcmp(input_file, "-") == 0)) {
+ fp = stdin;
+ } else {
+ fp = fopen(input_file, "r");
+ if (!fp) {
+ fprintf(stderr, "Failed reading %s: %s\n",
+ input_file, fr_syserror(errno));
+ goto finish;
+ }
+ }
+
+ /*
+ * For simplicity, read xlat's.
+ */
+ if (xlat_only) {
+ if (!do_xlats(input_file, fp)) rcode = EXIT_FAILURE;
+ if (input_file) fclose(fp);
+ goto finish;
+ }
+
+ /*
+ * Grab the VPs from stdin, or from the file.
+ */
+ request = request_setup(fp);
+ if (!request) {
+ fprintf(stderr, "Failed reading input: %s\n", fr_strerror());
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /*
+ * No filter file, OR there's no more input, OR we're
+ * reading from a file, and it's different from the
+ * filter file.
+ */
+ if (!filter_file || filedone ||
+ ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) {
+ if (output_file) {
+ fclose(fp);
+ fp = NULL;
+ }
+ filedone = false;
+ }
+
+ /*
+ * There is a filter file. If necessary, open it. If we
+ * already are reading it via "input_file", then we don't
+ * need to re-open it.
+ */
+ if (filter_file) {
+ if (!fp) {
+ fp = fopen(filter_file, "r");
+ if (!fp) {
+ fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno));
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+ }
+
+
+ if (fr_pair_list_afrom_file(request, &filter_vps, fp, &filedone) < 0) {
+ fprintf(stderr, "Failed reading attributes from %s: %s\n",
+ filter_file, fr_strerror());
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+
+ /*
+ * FIXME: loop over input packets.
+ */
+ fclose(fp);
+ }
+
+ rad_virtual_server(request);
+
+ if (!output_file || (strcmp(output_file, "-") == 0)) {
+ fp = stdout;
+ } else {
+ fp = fopen(output_file, "w");
+ if (!fp) {
+ fprintf(stderr, "Failed writing %s: %s\n",
+ output_file, fr_syserror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ print_packet(fp, request->reply);
+
+ if (output_file) fclose(fp);
+
+ /*
+ * Update the list with the response type.
+ */
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_RESPONSE_PACKET_TYPE, 0);
+ vp->vp_integer = request->reply->code;
+
+ {
+ VALUE_PAIR const *failed[2];
+
+ if (filter_vps && !fr_pair_validate(failed, filter_vps, request->reply->vps)) {
+ fr_pair_validate_debug(request, failed);
+ fr_perror("Output file %s does not match attributes in filter %s (%s)",
+ output_file ? output_file : input_file, filter_file, fr_strerror());
+ rcode = EXIT_FAILURE;
+ goto finish;
+ }
+ }
+
+ INFO("Exiting normally");
+
+finish:
+ talloc_free(request);
+
+ /*
+ * Detach any modules.
+ */
+ modules_free();
+
+ xlat_unregister("poke", xlat_poke, NULL);
+
+ xlat_free(); /* modules may have xlat's */
+
+ fr_state_delete(state);
+
+ /*
+ * Free the configuration items.
+ */
+ main_config_free();
+
+ if (el) talloc_free(el);
+
+ if (memory_report) {
+ INFO("Allocated memory at time of report:");
+ fr_log_talloc_report(NULL);
+ }
+
+ return rcode;
+}
+
+
+/*
+ * Display the syntax for starting this program.
+ */
+static void NEVER_RETURNS usage(int status)
+{
+ FILE *output = status?stderr:stdout;
+
+ fprintf(output, "Usage: %s [options]\n", main_config.name);
+ fprintf(output, "Options:\n");
+ fprintf(output, " -d raddb_dir Configuration files are in \"raddb_dir/*\".\n");
+ fprintf(output, " -D dict_dir Dictionary files are in \"dict_dir/*\".\n");
+ fprintf(output, " -f file Filter reply against attributes in 'file'.\n");
+ fprintf(output, " -h Print this help message.\n");
+ fprintf(output, " -i file File containing request attributes.\n");
+ fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
+ fprintf(output, " -n name Read raddb/name.conf instead of raddb/radiusd.conf.\n");
+ fprintf(output, " -X Turn on full debugging.\n");
+ fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
+ exit(status);
+}
diff --git a/src/main/unittest.mk b/src/main/unittest.mk
new file mode 100644
index 0000000..edd4f13
--- /dev/null
+++ b/src/main/unittest.mk
@@ -0,0 +1,25 @@
+TARGET := unittest
+SOURCES := acct.c auth.c client.c crypt.c files.c \
+ mainconfig.c modules.c modcall.c \
+ unittest.c soh.c state.c connection.c \
+ session.c threads.c version.c \
+ realms.c
+
+ifneq ($(OPENSSL_LIBS),)
+SOURCES += cb.c tls.c
+endif
+
+SRC_CFLAGS := -DHOSTINFO=\"${HOSTINFO}\"
+TGT_INSTALLDIR :=
+TGT_LDLIBS := $(LIBS) $(OPENSSL_LIBS) $(SYSTEMD_LIBS) $(LCRYPT)
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+
+# Libraries can't depend on libraries (oops), so make the binary
+# depend on the EAP code...
+ifneq "$(filter rlm_eap_%,${ALL_TGTS})" ""
+TGT_PREREQS += libfreeradius-eap.a
+endif
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
diff --git a/src/main/util.c b/src/main/util.c
new file mode 100644
index 0000000..b216cc9
--- /dev/null
+++ b/src/main/util.c
@@ -0,0 +1,1732 @@
+/*
+ * util.c Various utility functions.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*
+ * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
+ * sa_flags, which causes grief if signal() is called in the
+ * handler before the cause of the signal has been cleared.
+ * (Infinite recursion).
+ *
+ * The same problem appears on HPUX, so we avoid it, if we can.
+ *
+ * Using sigaction() to reset the signal handler fixes the problem,
+ * so where available, we prefer that solution.
+ */
+
+void (*reset_signal(int signo, void (*func)(int)))(int)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction act, oact;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = func;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+#ifdef SA_INTERRUPT /* SunOS */
+ act.sa_flags |= SA_INTERRUPT;
+#endif
+ if (sigaction(signo, &act, &oact) < 0)
+ return SIG_ERR;
+ return oact.sa_handler;
+#else
+
+ /*
+ * re-set by calling the 'signal' function, which
+ * may cause infinite recursion and core dumps due to
+ * stack growth.
+ *
+ * However, the system is too dumb to implement sigaction(),
+ * so we don't have a choice.
+ */
+ signal(signo, func);
+
+ return NULL;
+#endif
+}
+
+/*
+ * Per-request data, added by modules...
+ */
+struct request_data_t {
+ request_data_t *next;
+
+ void *unique_ptr;
+ int unique_int;
+ void *opaque;
+ bool free_opaque;
+};
+
+/*
+ * Add opaque data (with a "free" function) to a REQUEST.
+ *
+ * The unique ptr is meant to be a module configuration,
+ * and the unique integer allows the caller to have multiple
+ * opaque data associated with a REQUEST.
+ */
+int request_data_add(REQUEST *request, void *unique_ptr, int unique_int, void *opaque, bool free_opaque)
+{
+ request_data_t *this, **last, *next;
+
+ /*
+ * Some simple sanity checks.
+ */
+ if (!request || !opaque) return -1;
+
+ this = next = NULL;
+ for (last = &(request->data);
+ *last != NULL;
+ last = &((*last)->next)) {
+ if (((*last)->unique_ptr == unique_ptr) &&
+ ((*last)->unique_int == unique_int)) {
+ this = *last;
+ next = this->next;
+
+ /*
+ * If caller requires custom behaviour on free
+ * they must set a destructor.
+ */
+ if (this->opaque && this->free_opaque) talloc_free(this->opaque);
+
+ break; /* replace the existing entry */
+ }
+ }
+
+ /*
+ * Only alloc new memory if we're not replacing
+ * an existing entry.
+ */
+ if (!this) this = talloc_zero(request, request_data_t);
+ if (!this) return -1;
+
+ this->next = next;
+ this->unique_ptr = unique_ptr;
+ this->unique_int = unique_int;
+ this->opaque = opaque;
+ this->free_opaque = free_opaque;
+
+ *last = this;
+
+ return 0;
+}
+
+/*
+ * Get opaque data from a request.
+ */
+void *request_data_get(REQUEST *request, void *unique_ptr, int unique_int)
+{
+ request_data_t **last;
+
+ if (!request) return NULL;
+
+ for (last = &(request->data);
+ *last != NULL;
+ last = &((*last)->next)) {
+ if (((*last)->unique_ptr == unique_ptr) &&
+ ((*last)->unique_int == unique_int)) {
+ request_data_t *this;
+ void *ptr;
+
+ this = *last;
+ ptr = this->opaque;
+
+ /*
+ * Remove the entry from the list, and free it.
+ */
+ *last = this->next;
+ talloc_free(this);
+
+ return ptr; /* don't free it, the caller does that */
+ }
+ }
+
+ return NULL; /* wasn't found, too bad... */
+}
+
+/*
+ * Get opaque data from a request without removing it.
+ */
+void *request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
+{
+ request_data_t **last;
+
+ for (last = &(request->data);
+ *last != NULL;
+ last = &((*last)->next)) {
+ if (((*last)->unique_ptr == unique_ptr) &&
+ ((*last)->unique_int == unique_int)) {
+ return (*last)->opaque;
+ }
+ }
+
+ return NULL; /* wasn't found, too bad... */
+}
+
+/** Create possibly many directories.
+ *
+ * @note that the input directory name is NOT treated as a constant. This is so that
+ * if an error is returned, the 'directory' ptr points to the name of the file
+ * which caused the error.
+ *
+ * @param dir path to directory to create.
+ * @param mode for new directories.
+ * @param uid to set on new directories, may be -1 to use effective uid.
+ * @param gid to set on new directories, may be -1 to use effective gid.
+ * @return 0 on success, -1 on error. Error available as errno.
+ */
+int rad_mkdir(char *dir, mode_t mode, uid_t uid, gid_t gid)
+{
+ int rcode, fd;
+ char *p;
+
+ /*
+ * Try to make the dir. If it exists, chmod it.
+ * If a path doesn't exist, that's OK. Otherwise
+ * return with an error.
+ *
+ * Directories permissions are initially set so
+ * that only we should have access. This prevents
+ * an attacker removing them and swapping them
+ * out for a link to somewhere else.
+ * We change them to the correct permissions later.
+ */
+ rcode = mkdir(dir, 0700);
+ if (rcode < 0) {
+ switch (errno) {
+ case EEXIST:
+ return 0; /* don't change permissions */
+
+ case ENOENT:
+ break;
+
+ default:
+ return rcode;
+ }
+
+ /*
+ * A component in the dir path doesn't
+ * exist. Look for the LAST dir name. Try
+ * to create that. If there's an error, we leave
+ * the dir path as the one at which the
+ * error occured.
+ */
+ p = strrchr(dir, FR_DIR_SEP);
+ if (!p || (p == dir)) return -1;
+
+ *p = '\0';
+ rcode = rad_mkdir(dir, mode, uid, gid);
+ if (rcode < 0) return rcode;
+
+ /*
+ * Reset the dir path, and try again to
+ * make the dir.
+ */
+ *p = FR_DIR_SEP;
+ rcode = mkdir(dir, 0700);
+ if (rcode < 0) return rcode;
+ } /* else we successfully created the dir */
+
+ /*
+ * Set the permissions on the directory we created
+ * this should never fail unless there's a race.
+ */
+ fd = open(dir, O_DIRECTORY);
+ if (fd < 0) return -1;
+
+ rcode = fchmod(fd, mode);
+ if (rcode < 0) {
+ close(fd);
+ return rcode;
+ }
+
+ if ((uid != (uid_t)-1) || (gid != (gid_t)-1)) {
+ rad_suid_up();
+ rcode = fchown(fd, uid, gid);
+ rad_suid_down();
+ }
+ close(fd);
+
+ return rcode;
+}
+
+/** Ensures that a filename cannot walk up the directory structure
+ *
+ * Also sanitizes control chars.
+ *
+ * @param request Current request (may be NULL).
+ * @param out Output buffer.
+ * @param outlen Size of the output buffer.
+ * @param in string to escape.
+ * @param arg Context arguments (unused, should be NULL).
+ */
+size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ char const *q = in;
+ char *p = out;
+ size_t left = outlen;
+
+ while (*q) {
+ if (*q != '/') {
+ if (left < 2) break;
+
+ /*
+ * Smash control characters and spaces to
+ * something simpler.
+ */
+ if (*q < ' ') {
+ *(p++) = '_';
+ q++;
+ continue;
+ }
+
+ *(p++) = *(q++);
+ left--;
+ continue;
+ }
+
+ /*
+ * For now, allow slashes in the expanded
+ * filename. This allows the admin to set
+ * attributes which create sub-directories.
+ * Unfortunately, it also allows users to send
+ * attributes which *may* end up creating
+ * sub-directories.
+ */
+ if (left < 2) break;
+ *(p++) = *(q++);
+
+ /*
+ * Get rid of ////../.././///.///..//
+ */
+ redo:
+ /*
+ * Get rid of ////
+ */
+ if (*q == '/') {
+ q++;
+ goto redo;
+ }
+
+ /*
+ * Get rid of /./././
+ */
+ if ((q[0] == '.') &&
+ (q[1] == '/')) {
+ q += 2;
+ goto redo;
+ }
+
+ /*
+ * Get rid of /../../../
+ */
+ if ((q[0] == '.') && (q[1] == '.') &&
+ (q[2] == '/')) {
+ q += 3;
+ goto redo;
+ }
+ }
+ *p = '\0';
+
+ return (p - out);
+}
+
+/** Escapes the raw string such that it should be safe to use as part of a file path
+ *
+ * This function is designed to produce a string that's still readable but portable
+ * across the majority of file systems.
+ *
+ * For security reasons it cannot remove characters from the name, and must not allow
+ * collisions to occur between different strings.
+ *
+ * With that in mind '-' has been chosen as the escape character, and will be double
+ * escaped '-' -> '--' to avoid collisions.
+ *
+ * Escaping should be reversible if the original string needs to be extracted.
+ *
+ * @note function takes additional arguments so that it may be used as an xlat escape
+ * function but it's fine to call it directly.
+ *
+ * @note OSX/Unix/NTFS/VFAT have a max filename size of 255 bytes.
+ *
+ * @param request Current request (may be NULL).
+ * @param out Output buffer.
+ * @param outlen Size of the output buffer.
+ * @param in string to escape.
+ * @param arg Context arguments (unused, should be NULL).
+ */
+size_t rad_filename_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ size_t freespace = outlen;
+
+ while (*in != '\0') {
+ size_t utf8_len;
+
+ /*
+ * Encode multibyte UTF8 chars
+ */
+ utf8_len = fr_utf8_char((uint8_t const *) in, -1);
+ if (utf8_len > 1) {
+ if (freespace <= (utf8_len * 3)) break;
+
+ switch (utf8_len) {
+ case 2:
+ snprintf(out, freespace, "-%x-%x", in[0], in[1]);
+ break;
+
+ case 3:
+ snprintf(out, freespace, "-%x-%x-%x", in[0], in[1], in[2]);
+ break;
+
+ case 4:
+ snprintf(out, freespace, "-%x-%x-%x-%x", in[0], in[1], in[2], in[3]);
+ break;
+ }
+
+ freespace -= (utf8_len * 3);
+ out += (utf8_len * 3);
+ in += utf8_len;
+
+ continue;
+ }
+
+ /*
+ * Safe chars
+ */
+ if (((*in >= 'A') && (*in <= 'Z')) ||
+ ((*in >= 'a') && (*in <= 'z')) ||
+ ((*in >= '0') && (*in <= '9')) ||
+ (*in == '_')) {
+ if (freespace <= 1) break;
+
+ *out++ = *in++;
+ freespace--;
+ continue;
+ }
+ if (freespace <= 2) break;
+
+ /*
+ * Double escape '-' (like \\)
+ */
+ if (*in == '-') {
+ *out++ = '-';
+ *out++ = '-';
+
+ freespace -= 2;
+ in++;
+ continue;
+ }
+
+ /*
+ * Unsafe chars
+ */
+ *out++ = '-';
+ fr_bin2hex(out, (uint8_t const *)in++, 1);
+ out += 2;
+ freespace -= 3;
+ }
+ *out = '\0';
+
+ return outlen - freespace;
+}
+
+/** Converts data stored in a file name back to its original form
+ *
+ * @param out Where to write the unescaped string (may be the same as in).
+ * @param outlen Length of the output buffer.
+ * @param in Input filename.
+ * @param inlen Length of input.
+ * @return number of bytes written to output buffer, or offset where parse error
+ * occurred on failure.
+ */
+ssize_t rad_filename_unescape(char *out, size_t outlen, char const *in, size_t inlen)
+{
+ char const *p, *end = in + inlen;
+ size_t freespace = outlen;
+
+ for (p = in; p < end; p++) {
+ if (freespace <= 1) break;
+
+ if (((*p >= 'A') && (*p <= 'Z')) ||
+ ((*p >= 'a') && (*p <= 'z')) ||
+ ((*p >= '0') && (*p <= '9')) ||
+ (*p == '_')) {
+ *out++ = *p;
+ freespace--;
+ continue;
+ }
+
+ if (p[0] == '-') {
+ /*
+ * End of input, '-' needs at least one extra char after
+ * it to be valid.
+ */
+ if ((end - p) < 2) return in - p;
+ if (p[1] == '-') {
+ p++;
+ *out++ = '-';
+ freespace--;
+ continue;
+ }
+
+ /*
+ * End of input, '-' must be followed by <hex><hex>
+ * but there aren't enough chars left
+ */
+ if ((end - p) < 3) return in - p;
+
+ /*
+ * If hex2bin returns 0 the next two chars weren't hexits.
+ */
+ if (fr_hex2bin((uint8_t *) out, 1, in, 1) == 0) return in - (p + 1);
+ in += 2;
+ out++;
+ freespace--;
+ }
+
+ return in - p; /* offset we found the bad char at */
+ }
+ *out = '\0';
+
+ return outlen - freespace; /* how many bytes were written */
+}
+
+/*
+ * Allocate memory, or exit.
+ *
+ * This call ALWAYS succeeds!
+ */
+void *rad_malloc(size_t size)
+{
+ void *ptr = malloc(size);
+
+ if (ptr == NULL) {
+ ERROR("no memory");
+ fr_exit(1);
+ }
+
+ return ptr;
+}
+
+
+void rad_const_free(void const *ptr)
+{
+ void *tmp;
+ if (!ptr) return;
+
+ memcpy(&tmp, &ptr, sizeof(tmp));
+ talloc_free(tmp);
+}
+
+
+/*
+ * Logs an error message and aborts the program
+ *
+ */
+
+void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
+{
+ ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
+ fr_fault(SIGABRT);
+ fr_exit_now(1);
+}
+
+/*
+ * Free a REQUEST struct.
+ */
+static int _request_free(REQUEST *request)
+{
+ rad_assert(!request->in_request_hash);
+#ifdef WITH_PROXY
+ rad_assert(!request->in_proxy_hash);
+#endif
+ rad_assert(!request->ev);
+
+#ifdef WITH_COA
+ rad_assert(request->coa == NULL);
+#endif
+
+#ifndef NDEBUG
+ request->magic = 0x01020304; /* set the request to be nonsense */
+#endif
+ request->client = NULL;
+#ifdef WITH_PROXY
+ request->home_server = NULL;
+#endif
+
+ /*
+ * This is parented separately.
+ */
+ if (request->state_ctx) {
+ talloc_free(request->state_ctx);
+ }
+
+ return 0;
+}
+
+/*
+ * Create a new REQUEST data structure.
+ */
+REQUEST *request_alloc(TALLOC_CTX *ctx)
+{
+ REQUEST *request;
+
+ request = talloc_zero(ctx, REQUEST);
+ if (!request) return NULL;
+ talloc_set_destructor(request, _request_free);
+#ifndef NDEBUG
+ request->magic = REQUEST_MAGIC;
+#endif
+#ifdef WITH_PROXY
+ request->proxy = NULL;
+#endif
+ request->reply = NULL;
+#ifdef WITH_PROXY
+ request->proxy_reply = NULL;
+#endif
+ request->config = NULL;
+ request->username = NULL;
+ request->password = NULL;
+ request->timestamp = time(NULL);
+ request->log.lvl = rad_debug_lvl; /* Default to global debug level */
+
+ request->module = "";
+ request->component = "<core>";
+ request->log.func = vradlog_request;
+
+ request->state_ctx = talloc_init("session-state");
+
+ return request;
+}
+
+
+/*
+ * Create a new REQUEST, based on an old one.
+ *
+ * This function allows modules to inject fake requests
+ * into the server, for tunneled protocols like TTLS & PEAP.
+ */
+REQUEST *request_alloc_fake(REQUEST *request)
+{
+ REQUEST *fake;
+
+ fake = request_alloc(request);
+ if (!fake) return NULL;
+
+ fake->number = request->number;
+#ifdef HAVE_PTHREAD_H
+ fake->child_pid = request->child_pid;
+#endif
+ fake->parent = request;
+ fake->root = request->root;
+ fake->client = request->client;
+
+ /*
+ * For new server support.
+ *
+ * FIXME: Key instead off of a "virtual server" data structure.
+ *
+ * FIXME: Permit different servers for inner && outer sessions?
+ */
+ fake->server = request->server;
+
+ fake->packet = rad_alloc(fake, true);
+ if (!fake->packet) {
+ talloc_free(fake);
+ return NULL;
+ }
+
+ fake->reply = rad_alloc(fake, false);
+ if (!fake->reply) {
+ talloc_free(fake);
+ return NULL;
+ }
+
+ fake->master_state = REQUEST_ACTIVE;
+ fake->child_state = REQUEST_RUNNING;
+
+ /*
+ * Fill in the fake request.
+ */
+ fake->packet->sockfd = -1;
+ fake->packet->src_ipaddr = request->packet->src_ipaddr;
+ fake->packet->src_port = request->packet->src_port;
+ fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
+ fake->packet->dst_port = 0;
+
+ /*
+ * This isn't STRICTLY required, as the fake request MUST NEVER
+ * be put into the request list. However, it's still reasonable
+ * practice.
+ */
+ fake->packet->id = fake->number & 0xff;
+ fake->packet->code = request->packet->code;
+ fake->timestamp = request->timestamp;
+ fake->packet->timestamp = request->packet->timestamp;
+
+ /*
+ * Required for new identity support
+ */
+ fake->listener = request->listener;
+
+ /*
+ * Fill in the fake reply, based on the fake request.
+ */
+ fake->reply->sockfd = fake->packet->sockfd;
+ fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
+ fake->reply->src_port = fake->packet->dst_port;
+ fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
+ fake->reply->dst_port = fake->packet->src_port;
+ fake->reply->id = fake->packet->id;
+ fake->reply->code = 0; /* UNKNOWN code */
+
+ /*
+ * Copy debug information.
+ */
+ memcpy(&(fake->log), &(request->log), sizeof(fake->log));
+ fake->log.indent = 0; /* Apart from the indent which we reset */
+
+ return fake;
+}
+
+#ifdef WITH_COA
+static int null_handler(UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+REQUEST *request_alloc_coa(REQUEST *request)
+{
+ if (!request || request->coa) return NULL;
+
+ /*
+ * Originate CoA requests only when necessary.
+ */
+ if ((request->packet->code != PW_CODE_ACCESS_REQUEST) &&
+ (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
+
+ request->coa = request_alloc_fake(request);
+ if (!request->coa) return NULL;
+
+ request->coa->handle = null_handler;
+ request->coa->options = RAD_REQUEST_OPTION_COA; /* is a CoA packet */
+ request->coa->packet->code = 0; /* unknown, as of yet */
+ request->coa->child_state = REQUEST_RUNNING;
+ request->coa->proxy = rad_alloc(request->coa, false);
+ if (!request->coa->proxy) {
+ TALLOC_FREE(request->coa);
+ return NULL;
+ }
+
+ return request->coa;
+}
+#endif
+
+/*
+ * Copy a quoted string.
+ */
+int rad_copy_string(char *to, char const *from)
+{
+ int length = 0;
+ char quote = *from;
+
+ do {
+ if (*from == '\\') {
+ *(to++) = *(from++);
+ length++;
+ }
+ *(to++) = *(from++);
+ length++;
+ } while (*from && (*from != quote));
+
+ if (*from != quote) return -1; /* not properly quoted */
+
+ *(to++) = quote;
+ length++;
+ *to = '\0';
+
+ return length;
+}
+
+/*
+ * Copy a quoted string but without the quotes. The length
+ * returned is the number of chars written; the number of
+ * characters consumed is 2 more than this.
+ */
+int rad_copy_string_bare(char *to, char const *from)
+{
+ int length = 0;
+ char quote = *from;
+
+ from++;
+ while (*from && (*from != quote)) {
+ if (*from == '\\') {
+ *(to++) = *(from++);
+ length++;
+ }
+ *(to++) = *(from++);
+ length++;
+ }
+
+ if (*from != quote) return -1; /* not properly quoted */
+
+ *to = '\0';
+
+ return length;
+}
+
+
+/*
+ * Copy a %{} string.
+ */
+int rad_copy_variable(char *to, char const *from)
+{
+ int length = 0;
+ int sublen;
+
+ *(to++) = *(from++);
+ length++;
+
+ while (*from) {
+ switch (*from) {
+ case '"':
+ case '\'':
+ sublen = rad_copy_string(to, from);
+ if (sublen < 0) return sublen;
+ from += sublen;
+ to += sublen;
+ length += sublen;
+ break;
+
+ case '}': /* end of variable expansion */
+ *(to++) = *(from++);
+ *to = '\0';
+ length++;
+ return length; /* proper end of variable */
+
+ case '\\':
+ *(to++) = *(from++);
+ *(to++) = *(from++);
+ length += 2;
+ break;
+
+ case '%': /* start of variable expansion */
+ if (from[1] == '{') {
+ *(to++) = *(from++);
+ length++;
+
+ sublen = rad_copy_variable(to, from);
+ if (sublen < 0) return sublen;
+ from += sublen;
+ to += sublen;
+ length += sublen;
+ break;
+ } /* else FIXME: catch %%{ ?*/
+
+ /* FALL-THROUGH */
+ default:
+ *(to++) = *(from++);
+ length++;
+ break;
+ }
+ } /* loop over the input string */
+
+ /*
+ * We ended the string before a trailing '}'
+ */
+
+ return -1;
+}
+
+#ifndef USEC
+#define USEC 1000000
+#endif
+
+uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
+{
+ uint32_t pps;
+
+ if (*then != now->tv_sec) {
+ *then = now->tv_sec;
+ *past = *present;
+ *present = 0;
+ }
+
+ /*
+ * Bootstrap PPS by looking at a percentage of
+ * the previous PPS. This lets us take a moving
+ * count, without doing a moving average. If
+ * we're a fraction "f" (0..1) into the current
+ * second, we can get a good guess for PPS by
+ * doing:
+ *
+ * PPS = pps_now + pps_old * (1 - f)
+ *
+ * It's an instantaneous measurement, rather than
+ * a moving average. This will hopefully let it
+ * respond better to sudden spikes.
+ *
+ * Doing the calculations by thousands allows us
+ * to not overflow 2^32, AND to not underflow
+ * when we divide by USEC.
+ */
+ pps = USEC - now->tv_usec; /* useconds left in previous second */
+ pps /= 1000; /* scale to milliseconds */
+ pps *= *past; /* multiply by past count to get fraction */
+ pps /= 1000; /* scale to usec again */
+ pps += *present; /* add in current count */
+
+ return pps;
+}
+
+/** Split string into words and expand each one
+ *
+ * @param request Current request.
+ * @param cmd string to split.
+ * @param max_argc the maximum number of arguments to split into.
+ * @param argv Where to write the pointers into argv_buf.
+ * @param can_fail If false, stop processing if any of the xlat expansions fail.
+ * @param argv_buflen size of argv_buf.
+ * @param argv_buf temporary buffer we used to mangle/expand cmd.
+ * Pointers to offsets of this buffer will be written to argv.
+ * @return argc or -1 on failure.
+ */
+
+int rad_expand_xlat(REQUEST *request, char const *cmd,
+ int max_argc, char const *argv[], bool can_fail,
+ size_t argv_buflen, char *argv_buf)
+{
+ char const *from;
+ char *to;
+ int argc = -1;
+ int i;
+ int left;
+
+ if (strlen(cmd) > (argv_buflen - 1)) {
+ ERROR("rad_expand_xlat: Command line is too long");
+ return -1;
+ }
+
+ /*
+ * Check for bad escapes.
+ */
+ if (cmd[strlen(cmd) - 1] == '\\') {
+ ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
+ return -1;
+ }
+
+ strlcpy(argv_buf, cmd, argv_buflen);
+
+ /*
+ * Split the string into argv's BEFORE doing radius_xlat...
+ */
+ from = cmd;
+ to = argv_buf;
+ argc = 0;
+ while (*from) {
+ int length;
+
+ /*
+ * Skip spaces.
+ */
+ if ((*from == ' ') || (*from == '\t')) {
+ from++;
+ continue;
+ }
+
+ argv[argc] = to;
+ argc++;
+
+ if (argc >= (max_argc - 1)) break;
+
+ /*
+ * Copy the argv over to our buffer.
+ */
+ while (*from && (*from != ' ') && (*from != '\t')) {
+ if (to >= argv_buf + argv_buflen - 1) {
+ ERROR("rad_expand_xlat: Ran out of space in command line");
+ return -1;
+ }
+
+ switch (*from) {
+ case '"':
+ case '\'':
+ length = rad_copy_string_bare(to, from);
+ if (length < 0) {
+ ERROR("rad_expand_xlat: Invalid string passed as argument");
+ return -1;
+ }
+ from += length+2;
+ to += length;
+ break;
+
+ case '%':
+ if (from[1] == '{') {
+ *(to++) = *(from++);
+
+ length = rad_copy_variable(to, from);
+ if (length < 0) {
+ ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
+ return -1;
+ }
+ from += length;
+ to += length;
+ } else { /* FIXME: catch %%{ ? */
+ *(to++) = *(from++);
+ }
+ break;
+
+ case '\\':
+ if (from[1] == ' ') from++;
+ /* FALL-THROUGH */
+
+ default:
+ *(to++) = *(from++);
+ }
+ } /* end of string, or found a space */
+
+ *(to++) = '\0'; /* terminate the string */
+ }
+
+ /*
+ * We have to have SOMETHING, at least.
+ */
+ if (argc <= 0) {
+ ERROR("rad_expand_xlat: Empty command line");
+ return -1;
+ }
+
+ /*
+ * Expand each string, as appropriate.
+ */
+ left = argv_buf + argv_buflen - to;
+ for (i = 0; i < argc; i++) {
+ int sublen;
+
+ /*
+ * Don't touch argv's which won't be translated.
+ */
+ if (strchr(argv[i], '%') == NULL) continue;
+
+ if (!request) continue;
+
+ sublen = radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
+ if (sublen <= 0) {
+ if (can_fail) {
+ /*
+ * Fail to be backwards compatible.
+ *
+ * It's yucky, but it won't break anything,
+ * and it won't cause security problems.
+ */
+ sublen = 0;
+ } else {
+ ERROR("rad_expand_xlat: xlat failed");
+ return -1;
+ }
+ }
+
+ argv[i] = to;
+ to += sublen;
+ *(to++) = '\0';
+ left -= sublen;
+ left--;
+
+ if (left <= 0) {
+ ERROR("rad_expand_xlat: Ran out of space while expanding arguments");
+ return -1;
+ }
+ }
+ argv[argc] = NULL;
+
+ return argc;
+}
+
+#ifndef NDEBUG
+/*
+ * Verify a packet.
+ */
+static void verify_packet(char const *file, int line, REQUEST *request, RADIUS_PACKET *packet, char const *name)
+{
+ TALLOC_CTX *parent;
+
+ if (!packet) {
+ fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%i]: RADIUS_PACKET %s pointer was NULL", file, line, name);
+ fr_assert(0);
+ fr_exit_now(0);
+ }
+
+ parent = talloc_parent(packet);
+ if (parent != request) {
+ ERROR("CONSISTENCY CHECK FAILED %s[%i]: Expected RADIUS_PACKET %s to be parented by %p (%s), "
+ "but parented by %p (%s)", file, line, name, request, talloc_get_name(request),
+ parent, parent ? talloc_get_name(parent) : "NULL");
+
+ fr_log_talloc_report(packet);
+ if (parent) fr_log_talloc_report(parent);
+
+ rad_assert(0);
+ }
+
+ VERIFY_PACKET(packet);
+
+ if (!packet->vps) return;
+
+#ifdef WITH_VERIFY_PTR
+ fr_pair_list_verify(file, line, packet, packet->vps, name);
+#endif
+}
+/*
+ * Catch horrible talloc errors.
+ */
+void verify_request(char const *file, int line, REQUEST *request)
+{
+ if (!request) {
+ fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%i]: REQUEST pointer was NULL", file, line);
+ fr_assert(0);
+ fr_exit_now(0);
+ }
+
+ (void) talloc_get_type_abort(request, REQUEST);
+
+#ifdef WITH_VERIFY_PTR
+ fr_pair_list_verify(file, line, request, request->config, "config");
+ fr_pair_list_verify(file, line, request->state_ctx, request->state, "state");
+#endif
+
+ if (request->packet) verify_packet(file, line, request, request->packet, "request");
+ if (request->reply) verify_packet(file, line, request, request->reply, "reply");
+#ifdef WITH_PROXY
+ if (request->proxy) verify_packet(file, line, request, request->proxy, "proxy-request");
+ if (request->proxy_reply) verify_packet(file, line, request, request->proxy_reply, "proxy-reply");
+#endif
+
+#ifdef WITH_COA
+ if (request->coa) {
+ void *parent;
+
+ (void) talloc_get_type_abort(request->coa, REQUEST);
+ parent = talloc_parent(request->coa);
+
+ rad_assert(parent == request);
+
+ verify_request(file, line, request->coa);
+ }
+#endif
+}
+#endif
+
+/** Convert mode_t into humanly readable permissions flags
+ *
+ * @author Jonathan Leffler.
+ *
+ * @param mode to convert.
+ * @param out Where to write the string to, must be exactly 10 bytes long.
+ */
+void rad_mode_to_str(char out[10], mode_t mode)
+{
+ static char const *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
+
+ strcpy(&out[0], rwx[(mode >> 6) & 0x07]);
+ strcpy(&out[3], rwx[(mode >> 3) & 0x07]);
+ strcpy(&out[6], rwx[(mode & 7)]);
+ if (mode & S_ISUID) out[2] = (mode & 0100) ? 's' : 'S';
+ if (mode & S_ISGID) out[5] = (mode & 0010) ? 's' : 'l';
+ if (mode & S_ISVTX) out[8] = (mode & 0100) ? 't' : 'T';
+ out[9] = '\0';
+}
+
+void rad_mode_to_oct(char out[5], mode_t mode)
+{
+ out[0] = '0' + ((mode >> 9) & 0x07);
+ out[1] = '0' + ((mode >> 6) & 0x07);
+ out[2] = '0' + ((mode >> 3) & 0x07);
+ out[3] = '0' + (mode & 0x07);
+ out[4] = '\0';
+}
+
+/** Resolve a uid to a passwd entry
+ *
+ * Resolves a uid to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param uid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+#ifdef _SC_GETPW_R_SIZE_MAX
+ long int sc_len;
+
+ sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+#else
+ len = 1024;
+#endif
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+ talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if ((ret != 0) || !*out) {
+ fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct passwd);
+ *out = (struct passwd *)buff;
+
+ return 0;
+}
+
+/** Resolve a username to a passwd entry
+ *
+ * Resolves a username to a passwd entry. The memory to hold the
+ * passwd entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+#ifdef _SC_GETPW_R_SIZE_MAX
+ long int sc_len;
+
+ sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+#else
+ sc_len = 1024;
+#endif
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
+ talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if ((ret != 0) || !*out) {
+ fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct passwd);
+ *out = (struct passwd *)buff;
+
+ return 0;
+}
+
+/** Resolve a gid to a group database entry
+ *
+ * Resolves a gid to a group database entry. The memory to hold the
+ * group entry is talloced under ctx, and must be freed when no
+ * longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param gid to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+#ifdef _SC_GETGR_R_SIZE_MAX
+ long int sc_len;
+
+ sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+#else
+ sc_len = 1024;
+#endif
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+ talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if ((ret != 0) || !*out) {
+ fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct group);
+ *out = (struct group *)buff;
+
+ return 0;
+}
+
+/** Resolve a group name to a group database entry
+ *
+ * Resolves a group name to a group database entry.
+ * The memory to hold the group entry is talloced under ctx,
+ * and must be freed when no longer required.
+ *
+ * @param ctx to allocate passwd entry in.
+ * @param out Where to write pointer to entry.
+ * @param name to resolve.
+ * @return 0 on success, -1 on error.
+ */
+int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
+{
+ static size_t len;
+ uint8_t *buff;
+ int ret;
+
+ *out = NULL;
+
+ /*
+ * We assume this won't change between calls,
+ * and that the value is the same, so races don't
+ * matter.
+ */
+ if (len == 0) {
+#ifdef _SC_GETGR_R_SIZE_MAX
+ long int sc_len;
+
+ sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (sc_len <= 0) sc_len = 1024;
+ len = (size_t)sc_len;
+#else
+ len = 1024;
+#endif
+ }
+
+ buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
+ if (!buff) return -1;
+
+ /*
+ * In some cases we may need to dynamically
+ * grow the string buffer.
+ */
+ while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)),
+ talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
+ buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
+ if (!buff) {
+ talloc_free(buff);
+ return -1;
+ }
+ }
+
+ if ((ret != 0) || !*out) {
+ fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
+ talloc_free(buff);
+ errno = ret;
+ return -1;
+ }
+
+ talloc_set_type(buff, struct group);
+ *out = (struct group *)buff;
+
+ return 0;
+}
+
+/** Resolve a group name to a GID
+ *
+ * @param ctx TALLOC_CTX for temporary allocations.
+ * @param name of group.
+ * @param out where to write gid.
+ * @return 0 on success, -1 on error;
+ */
+int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
+{
+ int ret;
+ struct group *result;
+
+ ret = rad_getgrnam(ctx, &result, name);
+ if (ret < 0) return -1;
+
+ *out = result->gr_gid;
+ talloc_free(result);
+ return 0;
+}
+
+/** Print uid to a string
+ *
+ * @note The reason for taking a fixed buffer is pure laziness.
+ * It means the caller doesn't have to free the string.
+ *
+ * @note Will always \0 terminate the buffer, even on error.
+ *
+ * @param ctx TALLOC_CTX for temporary allocations.
+ * @param out Where to write the uid string.
+ * @param outlen length of output buffer.
+ * @param uid to resolve.
+ * @return 0 on success, -1 on failure.
+ */
+int rad_prints_uid(TALLOC_CTX *ctx, char *out, size_t outlen, uid_t uid)
+{
+ struct passwd *result;
+
+ rad_assert(outlen > 0);
+
+ *out = '\0';
+
+ if (rad_getpwuid(ctx, &result, uid) < 0) return -1;
+ strlcpy(out, result->pw_name, outlen);
+ talloc_free(result);
+
+ return 0;
+}
+
+/** Print gid to a string
+ *
+ * @note The reason for taking a fixed buffer is pure laziness.
+ * It means the caller doesn't have to free the string.
+ *
+ * @note Will always \0 terminate the buffer, even on error.
+ *
+ * @param ctx TALLOC_CTX for temporary allocations.
+ * @param out Where to write the uid string.
+ * @param outlen length of output buffer.
+ * @param gid to resolve.
+ * @return 0 on success, -1 on failure.
+ */
+int rad_prints_gid(TALLOC_CTX *ctx, char *out, size_t outlen, gid_t gid)
+{
+ struct group *result;
+
+ rad_assert(outlen > 0);
+
+ *out = '\0';
+
+ if (rad_getgrgid(ctx, &result, gid) < 0) return -1;
+ strlcpy(out, result->gr_name, outlen);
+ talloc_free(result);
+
+ return 0;
+}
+
+#ifdef HAVE_SETUID
+static bool doing_setuid = false;
+static uid_t suid_down_uid = (uid_t)-1;
+
+/** Set the uid and gid used when dropping privileges
+ *
+ * @note if this function hasn't been called, rad_suid_down will have no effect.
+ *
+ * @param uid to drop down to.
+ */
+void rad_suid_set_down_uid(uid_t uid)
+{
+ suid_down_uid = uid;
+ doing_setuid = true;
+}
+
+# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
+void rad_suid_up(void)
+{
+ uid_t ruid, euid, suid;
+
+ if (getresuid(&ruid, &euid, &suid) < 0) {
+ ERROR("Failed getting saved UID's");
+ fr_exit_now(1);
+ }
+
+ if (setresuid(-1, suid, -1) < 0) {
+ ERROR("Failed switching to privileged user");
+ fr_exit_now(1);
+ }
+
+ if (geteuid() != suid) {
+ ERROR("Switched to unknown UID");
+ fr_exit_now(1);
+ }
+}
+
+void rad_suid_down(void)
+{
+ if (!doing_setuid) return;
+
+ if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
+ struct passwd *passwd;
+ char const *name;
+
+ name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
+ ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno));
+ talloc_free(passwd);
+ fr_exit_now(1);
+ }
+
+ if (geteuid() != suid_down_uid) {
+ ERROR("Failed switching uid: UID is incorrect");
+ fr_exit_now(1);
+ }
+
+ fr_reset_dumpable();
+}
+
+void rad_suid_down_permanent(void)
+{
+ if (!doing_setuid) return;
+
+ if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
+ struct passwd *passwd;
+ char const *name;
+
+ name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
+ ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno));
+ talloc_free(passwd);
+ fr_exit_now(1);
+ }
+
+ if (geteuid() != suid_down_uid) {
+ ERROR("Switched to unknown uid");
+ fr_exit_now(1);
+ }
+
+ fr_reset_dumpable();
+}
+# else
+/*
+ * Much less secure...
+ */
+void rad_suid_up(void)
+{
+ if (!doing_setuid) return;
+
+ if (seteuid(0) < 0) {
+ ERROR("Failed switching up to euid 0: %s", fr_syserror(errno));
+ fr_exit_now(1);
+ }
+
+}
+
+void rad_suid_down(void)
+{
+ if (!doing_setuid) return;
+
+ if (geteuid() == suid_down_uid) return;
+
+ if (seteuid(suid_down_uid) < 0) {
+ struct passwd *passwd;
+ char const *name;
+
+ name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
+ ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno));
+ talloc_free(passwd);
+ fr_exit_now(1);
+ }
+
+ fr_reset_dumpable();
+}
+
+void rad_suid_down_permanent(void)
+{
+ if (!doing_setuid) return;
+
+ /*
+ * Already done. Don't do anything else.
+ */
+ if (getuid() == suid_down_uid) return;
+
+ /*
+ * We're root, but running as a normal user. Fix that,
+ * so we can call setuid().
+ */
+ if (geteuid() == suid_down_uid) {
+ rad_suid_up();
+ }
+
+ if (setuid(suid_down_uid) < 0) {
+ struct passwd *passwd;
+ char const *name;
+
+ name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
+ ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno));
+ talloc_free(passwd);
+ fr_exit_now(1);
+ }
+
+ fr_reset_dumpable();
+}
+# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
+#else /* HAVE_SETUID */
+void rad_suid_set_down_uid(uid_t uid)
+{
+}
+void rad_suid_up(void)
+{
+}
+void rad_suid_down(void)
+{
+ fr_reset_dumpable();
+}
+void rad_suid_down_permanent(void)
+{
+ fr_reset_dumpable();
+}
+#endif /* HAVE_SETUID */
+
+/** Alter the effective user id
+ *
+ * @param uid to set
+ * @return 0 on success -1 on failure.
+ */
+int rad_seuid(uid_t uid)
+{
+ if (seteuid(uid) < 0) {
+ struct passwd *passwd;
+
+ if (rad_getpwuid(NULL, &passwd, uid) < 0) return -1;
+ fr_strerror_printf("Failed setting euid to %s", passwd->pw_name);
+ talloc_free(passwd);
+
+ return -1;
+ }
+ return 0;
+}
+
+/** Alter the effective user id
+ *
+ * @param gid to set
+ * @return 0 on success -1 on failure.
+ */
+int rad_segid(gid_t gid)
+{
+ if (setegid(gid) < 0) {
+ struct group *group;
+
+ if (rad_getgrgid(NULL, &group, gid) < 0) return -1;
+ fr_strerror_printf("Failed setting egid to %s", group->gr_name);
+ talloc_free(group);
+
+ return -1;
+ }
+ return 0;
+}
+
+/** Determine the elapsed time between two timevals
+ *
+ * @param end timeval nearest to the present
+ * @param start timeval furthest from the present
+ * @param elapsed Where to write the elapsed time
+ */
+void rad_tv_sub(struct timeval const *end, struct timeval const *start, struct timeval *elapsed)
+{
+ elapsed->tv_sec = end->tv_sec - start->tv_sec;
+ if (elapsed->tv_sec > 0) {
+ elapsed->tv_sec--;
+ elapsed->tv_usec = USEC;
+ } else {
+ elapsed->tv_usec = 0;
+ }
+ elapsed->tv_usec += end->tv_usec;
+ elapsed->tv_usec -= start->tv_usec;
+
+ if (elapsed->tv_usec >= USEC) {
+ elapsed->tv_usec -= USEC;
+ elapsed->tv_sec++;
+ }
+}
diff --git a/src/main/version.c b/src/main/version.c
new file mode 100644
index 0000000..2fe3428
--- /dev/null
+++ b/src/main/version.c
@@ -0,0 +1,625 @@
+/*
+ * version.c Print version number and exit.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 1999-2019 The FreeRADIUS server project
+ * Copyright 2012 Alan DeKok <aland@ox.org>
+ * Copyright 2000 Chris Parker <cparker@starnetusa.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+static uint64_t libmagic = RADIUSD_MAGIC_NUMBER;
+char const *radiusd_version_short = RADIUSD_VERSION_STRING;
+
+#ifdef HAVE_OPENSSL_CRYPTO_H
+# include <openssl/crypto.h>
+# include <openssl/opensslv.h>
+
+static long ssl_built = OPENSSL_VERSION_NUMBER;
+
+/** Check built and linked versions of OpenSSL match
+ *
+ * OpenSSL version number consists of:
+ * MNNFFPPS: major minor fix patch status
+ *
+ * Where status >= 0 && < 10 means beta, and status 10 means release.
+ *
+ * https://wiki.openssl.org/index.php/Versioning
+ *
+ * Startup check for whether the linked version of OpenSSL matches the
+ * version the server was built against.
+ *
+ * @return 0 if ok, else -1
+ */
+int ssl_check_consistency(void)
+{
+ long ssl_linked;
+
+ ssl_linked = SSLeay();
+
+ /*
+ * Major and minor versions mismatch, that's bad.
+ */
+ if ((ssl_linked & 0xfff00000) != (ssl_built & 0xfff00000)) goto mismatch;
+
+ /*
+ * 1.1.0 and later export all of the APIs we need, so we
+ * don't care about mismatches in fix / patch / status
+ * fields. If the major && minor fields match, that's
+ * good enough.
+ */
+ if ((ssl_linked & 0xfff00000) >= 0x10100000) return 0;
+
+ /*
+ * Before 1.1.0, we need all kinds of stupid checks to
+ * see if it might work.
+ */
+
+ /*
+ * Status mismatch always triggers error.
+ */
+ if ((ssl_linked & 0x0000000f) != (ssl_built & 0x0000000f)) {
+ mismatch:
+ ERROR("libssl version mismatch. built: %lx linked: %lx",
+ (unsigned long) ssl_built,
+ (unsigned long) ssl_linked);
+
+ return -1;
+ }
+
+ /*
+ * Use the OpenSSH approach and relax fix checks after version
+ * 1.0.0 and only allow moving backwards within a patch
+ * series.
+ */
+ if (ssl_built & 0xf0000000) {
+ if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000) ||
+ (ssl_built & 0x00000ff0) > (ssl_linked & 0x00000ff0)) goto mismatch;
+ /*
+ * Before 1.0.0 we require the same major minor and fix version
+ * and ignore the patch number.
+ */
+ } else if ((ssl_built & 0xfffff000) != (ssl_linked & 0xfffff000)) goto mismatch;
+
+ return 0;
+}
+
+/** Convert a version number to a text string
+ *
+ * @note Not thread safe.
+ *
+ * @param v version to convert.
+ * @return pointer to a static buffer containing the version string.
+ */
+char const *ssl_version_by_num(uint32_t v)
+{
+ /* 2 (%s) + 1 (.) + 2 (%i) + 1 (.) + 2 (%i) + 1 (c) + 8 (%s) + \0 */
+ static char buffer[18];
+ char *p = buffer;
+
+ p += sprintf(p, "%u.%u.%u",
+ (0xf0000000 & v) >> 28,
+ (0x0ff00000 & v) >> 20,
+ (0x000ff000 & v) >> 12);
+
+ if ((0x00000ff0 & v) >> 4) {
+ *p++ = (char) (0x60 + ((0x00000ff0 & v) >> 4));
+ }
+
+ *p++ = ' ';
+
+ /*
+ * Development (0)
+ */
+ if ((0x0000000f & v) == 0) {
+ strcpy(p, "dev");
+ /*
+ * Beta (1-14)
+ */
+ } else if ((0x0000000f & v) <= 14) {
+ sprintf(p, "beta %u", 0x0000000f & v);
+ } else {
+ strcpy(p, "release");
+ }
+
+ return buffer;
+}
+
+/** Return the linked SSL version number as a string
+ *
+ * @return pointer to a static buffer containing the version string.
+ */
+char const *ssl_version_num(void)
+{
+ long ssl_linked;
+
+ ssl_linked = SSLeay();
+ return ssl_version_by_num((uint32_t)ssl_linked);
+}
+
+/** Convert two openssl version numbers into a range string
+ *
+ * @note Not thread safe.
+ *
+ * @param low version to convert.
+ * @param high version to convert.
+ * @return pointer to a static buffer containing the version range string.
+ */
+char const *ssl_version_range(uint32_t low, uint32_t high)
+{
+ /* 12 (version) + 3 ( - ) + 12 (version) */
+ static char buffer[28];
+ char *p = buffer;
+
+ p += strlcpy(p, ssl_version_by_num(low), sizeof(buffer));
+ p += strlcpy(p, " - ", sizeof(buffer) - (p - buffer));
+ strlcpy(p, ssl_version_by_num(high), sizeof(buffer) - (p - buffer));
+
+ return buffer;
+}
+
+/** Print the current linked version of Openssl
+ *
+ * Print the currently linked version of the OpenSSL library.
+ *
+ * @note Not thread safe.
+ * @return pointer to a static buffer containing libssl version information.
+ */
+char const *ssl_version(void)
+{
+ static char buffer[256];
+
+ uint32_t v = SSLeay();
+
+ snprintf(buffer, sizeof(buffer), "%s 0x%.8x (%s)",
+ SSLeay_version(SSLEAY_VERSION), /* Not all builds include a useful version number */
+ v,
+ ssl_version_by_num(v));
+
+ return buffer;
+}
+# else
+int ssl_check_consistency(void) {
+ return 0;
+}
+
+char const *ssl_version_num(void)
+{
+ return "not linked";
+}
+
+char const *ssl_version(void)
+{
+ return "not linked";
+}
+#endif /* ifdef HAVE_OPENSSL_CRYPTO_H */
+
+/** Check if the application linking to the library has the correct magic number
+ *
+ * @param magic number as defined by RADIUSD_MAGIC_NUMBER
+ * @returns 0 on success, -1 on prefix mismatch, -2 on version mismatch -3 on commit mismatch.
+ */
+int rad_check_lib_magic(uint64_t magic)
+{
+ if (MAGIC_PREFIX(magic) != MAGIC_PREFIX(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (prefix) mismatch."
+ " application: %x library: %x",
+ MAGIC_PREFIX(magic), MAGIC_PREFIX(libmagic));
+ return -1;
+ }
+
+ if (MAGIC_VERSION(magic) != MAGIC_VERSION(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (version) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_VERSION(magic), (unsigned long) MAGIC_VERSION(libmagic));
+ return -2;
+ }
+
+ if (MAGIC_COMMIT(magic) != MAGIC_COMMIT(libmagic)) {
+ ERROR("Application and libfreeradius-server magic number (commit) mismatch."
+ " application: %lx library: %lx",
+ (unsigned long) MAGIC_COMMIT(magic), (unsigned long) MAGIC_COMMIT(libmagic));
+ return -3;
+ }
+
+ return 0;
+}
+
+/** Add a feature flag to the main configuration
+ *
+ * Add a feature flag (yes/no) to the 'feature' subsection
+ * off the main config.
+ *
+ * This allows the user to create configurations that work with
+ * across multiple environments.
+ *
+ * @param cs to add feature pair to.
+ * @param name of feature.
+ * @param enabled Whether the feature is present/enabled.
+ * @return 0 on success else -1.
+ */
+int version_add_feature(CONF_SECTION *cs, char const *name, bool enabled)
+{
+ if (!cs) return -1;
+
+ if (!cf_pair_find(cs, name)) {
+ CONF_PAIR *cp;
+
+ cp = cf_pair_alloc(cs, name, enabled ? "yes" : "no",
+ T_OP_SET, T_BARE_WORD, T_BARE_WORD);
+ if (!cp) return -1;
+ cf_pair_add(cs, cp);
+ }
+
+ return 0;
+}
+
+/** Add a library/server version pair to the main configuration
+ *
+ * Add a version number to the 'version' subsection off the main
+ * config.
+ *
+ * Because of the optimisations in the configuration parser, these
+ * may be checked using regular expressions without a performance
+ * penalty.
+ *
+ * The version pairs are there primarily to work around defects
+ * in libraries or the server.
+ *
+ * @param cs to add feature pair to.
+ * @param name of library or feature.
+ * @param version Humanly readable version text.
+ * @return 0 on success else -1.
+ */
+int version_add_number(CONF_SECTION *cs, char const *name, char const *version)
+{
+ CONF_PAIR *old;
+
+ if (!cs) return -1;
+
+ old = cf_pair_find(cs, name);
+ if (!old) {
+ CONF_PAIR *cp;
+
+ cp = cf_pair_alloc(cs, name, version, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (!cp) return -1;
+
+ cf_pair_add(cs, cp);
+ } else {
+ WARN("Replacing user version.%s (%s) with %s", name, cf_pair_value(old), version);
+
+ cf_pair_replace(cs, old, version);
+ }
+
+ return 0;
+}
+
+
+/** Initialise core feature flags
+ *
+ * @param cs Where to add the CONF_PAIRS, if null pairs will be added
+ * to the 'feature' section of the main config.
+ */
+void version_init_features(CONF_SECTION *cs)
+{
+ version_add_feature(cs, "accounting",
+#ifdef WITH_ACCOUNTING
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "authentication", true);
+
+ version_add_feature(cs, "ascend-binary-attributes",
+#ifdef WITH_ASCEND_BINARY
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "coa",
+#ifdef WITH_COA
+ true
+#else
+ false
+#endif
+ );
+
+
+ version_add_feature(cs, "recv-coa-from-home-server",
+#ifdef WITH_COA_TUNNEL
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "control-socket",
+#ifdef WITH_COMMAND_SOCKET
+ true
+#else
+ false
+#endif
+ );
+
+
+ version_add_feature(cs, "detail",
+#ifdef WITH_DETAIL
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "dhcp",
+#ifdef WITH_DHCP
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "dynamic-clients",
+#ifdef WITH_DYNAMIC_CLIENTS
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "osfc2",
+#ifdef OSFC2
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "proxy",
+#ifdef WITH_PROXY
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "regex-pcre",
+#ifdef HAVE_PCRE
+ true
+#else
+ false
+#endif
+ );
+
+#if !defined(HAVE_PCRE) && defined(HAVE_REGEX)
+ version_add_feature(cs, "regex-posix", true);
+ version_add_feature(cs, "regex-posix-extended",
+# ifdef HAVE_REG_EXTENDED
+ true
+# else
+ false
+# endif
+ );
+#else
+ version_add_feature(cs, "regex-posix", false);
+ version_add_feature(cs, "regex-posix-extended", false);
+#endif
+
+ version_add_feature(cs, "session-management",
+#ifdef WITH_SESSION_MGMT
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "stats",
+#ifdef WITH_STATS
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "systemd",
+#ifdef HAVE_SYSTEMD
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "tcp",
+#ifdef WITH_TCP
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "threads",
+#ifdef WITH_THREADS
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "tls",
+#ifdef WITH_TLS
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "unlang",
+#ifdef WITH_UNLANG
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "vmps",
+#ifdef WITH_VMPS
+ true
+#else
+ false
+#endif
+ );
+
+ version_add_feature(cs, "developer",
+#ifndef NDEBUG
+ true
+#else
+ false
+#endif
+ );
+}
+
+/** Initialise core version flags
+ *
+ * @param cs Where to add the CONF_PAIRS, if null pairs will be added
+ * to the 'version' section of the main config.
+ */
+void version_init_numbers(CONF_SECTION *cs)
+{
+ char buffer[128];
+
+ version_add_number(cs, "freeradius-server", radiusd_version_short);
+
+ snprintf(buffer, sizeof(buffer), "%i.%i.*", talloc_version_major(), talloc_version_minor());
+ version_add_number(cs, "talloc", buffer);
+
+ version_add_number(cs, "ssl", ssl_version_num());
+
+#if defined(HAVE_REGEX) && defined(HAVE_PCRE)
+ version_add_number(cs, "pcre", pcre_version());
+#endif
+}
+
+static char const *spaces = " "; /* 40 */
+
+/*
+ * Display the revision number for this program
+ */
+void version_print(void)
+{
+ CONF_SECTION *features, *versions;
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+
+ if (DEBUG_ENABLED3) {
+ int max = 0, len;
+
+ MEM(features = cf_section_alloc(NULL, "feature", NULL));
+ version_init_features(features);
+
+ MEM(versions = cf_section_alloc(NULL, "version", NULL));
+ version_init_numbers(versions);
+
+ DEBUG2("Server was built with: ");
+
+ for (ci = cf_item_find_next(features, NULL);
+ ci;
+ ci = cf_item_find_next(features, ci)) {
+ len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
+ if (max < len) max = len;
+ }
+
+ for (ci = cf_item_find_next(versions, NULL);
+ ci;
+ ci = cf_item_find_next(versions, ci)) {
+ len = talloc_array_length(cf_pair_attr(cf_item_to_pair(ci)));
+ if (max < len) max = len;
+ }
+
+
+ for (ci = cf_item_find_next(features, NULL);
+ ci;
+ ci = cf_item_find_next(features, ci)) {
+ char const *attr;
+
+ cp = cf_item_to_pair(ci);
+ attr = cf_pair_attr(cp);
+
+ DEBUG2(" %s%.*s : %s", attr,
+ (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp));
+ }
+
+ talloc_free(features);
+
+ DEBUG2("Server core libs:");
+
+ for (ci = cf_item_find_next(versions, NULL);
+ ci;
+ ci = cf_item_find_next(versions, ci)) {
+ char const *attr;
+
+ cp = cf_item_to_pair(ci);
+ attr = cf_pair_attr(cp);
+
+ DEBUG2(" %s%.*s : %s", attr,
+ (int)(max - talloc_array_length(attr)), spaces, cf_pair_value(cp));
+ }
+
+ talloc_free(versions);
+
+ DEBUG2("Endianness:");
+#if defined(FR_LITTLE_ENDIAN)
+ DEBUG2(" little");
+#elif defined(FR_BIG_ENDIAN)
+ DEBUG2(" big");
+#else
+ DEBUG2(" unknown");
+#endif
+
+ DEBUG2("Compilation flags:");
+#ifdef BUILT_WITH_CPPFLAGS
+ DEBUG2(" cppflags : " BUILT_WITH_CPPFLAGS);
+#endif
+#ifdef BUILT_WITH_CFLAGS
+ DEBUG2(" cflags : " BUILT_WITH_CFLAGS);
+#endif
+#ifdef BUILT_WITH_LDFLAGS
+ DEBUG2(" ldflags : " BUILT_WITH_LDFLAGS);
+#endif
+#ifdef BUILT_WITH_LIBS
+ DEBUG2(" libs : " BUILT_WITH_LIBS);
+#endif
+ DEBUG2(" ");
+ }
+ INFO("FreeRADIUS Version " RADIUSD_VERSION_STRING);
+ INFO("Copyright (C) 1999-2022 The FreeRADIUS server project and contributors");
+ INFO("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
+ INFO("PARTICULAR PURPOSE");
+ INFO("You may redistribute copies of FreeRADIUS under the terms of the");
+ INFO("GNU General Public License");
+ INFO("For more information about these matters, see the file named COPYRIGHT");
+
+ fflush(NULL);
+}
+
diff --git a/src/main/xlat.c b/src/main/xlat.c
new file mode 100644
index 0000000..4bd0a37
--- /dev/null
+++ b/src/main/xlat.c
@@ -0,0 +1,2696 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file xlat.c
+ * @brief String expansion ("translation"). Implements %Attribute -> value
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/parser.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/base64.h>
+
+#include <ctype.h>
+
+typedef struct xlat_t {
+ char name[MAX_STRING_LEN]; //!< Name of the xlat expansion.
+ int length; //!< Length of name.
+ void *instance; //!< Module instance passed to xlat and escape functions.
+ xlat_func_t func; //!< xlat function.
+ xlat_escape_t escape; //!< Escape function to apply to dynamic input to func.
+ bool internal; //!< If true, cannot be redefined.
+} xlat_t;
+
+typedef enum {
+ XLAT_LITERAL, //!< Literal string
+ XLAT_PERCENT, //!< Literal string with %v
+ XLAT_MODULE, //!< xlat module
+ XLAT_VIRTUAL, //!< virtual attribute
+ XLAT_ATTRIBUTE, //!< xlat attribute
+#ifdef HAVE_REGEX
+ XLAT_REGEX, //!< regex reference
+#endif
+ XLAT_ALTERNATE //!< xlat conditional syntax :-
+} xlat_state_t;
+
+struct xlat_exp {
+ char const *fmt; //!< The format string.
+ size_t len; //!< Length of the format string.
+
+ xlat_state_t type; //!< type of this expansion.
+ xlat_exp_t *next; //!< Next in the list.
+
+ xlat_exp_t *child; //!< Nested expansion.
+ xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
+
+ vp_tmpl_t attr; //!< An attribute template.
+ xlat_t const *xlat; //!< The xlat expansion to expand format with.
+};
+
+static rbtree_t *xlat_root = NULL;
+
+#ifdef WITH_UNLANG
+static char const * const xlat_foreach_names[] = {"Foreach-Variable-0",
+ "Foreach-Variable-1",
+ "Foreach-Variable-2",
+ "Foreach-Variable-3",
+ "Foreach-Variable-4",
+ "Foreach-Variable-5",
+ "Foreach-Variable-6",
+ "Foreach-Variable-7",
+ "Foreach-Variable-8",
+ "Foreach-Variable-9",
+ NULL};
+#endif
+
+
+static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
+
+static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
+ bool escape, bool return_null, char const *concat);
+
+/** Concatenation
+ *
+ */
+static ssize_t xlat_concat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ ssize_t slen;
+ vp_tmpl_t vpt;
+ char *str;
+ char const *concat;
+ char buffer[2];
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ slen = tmpl_from_attr_substr(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ RDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ fmt += slen;
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if (!*fmt) {
+ concat = ",";
+ } else {
+ buffer[0] = *fmt;
+ buffer[1] = '\0';
+
+ concat = buffer;
+ }
+
+ str = xlat_getvp(request, request, &vpt, true, true, concat);
+ if (!str) return 0;
+
+ strlcpy(out, str, outlen);
+ talloc_free(str);
+
+ return strlen(out);
+}
+
+/** Print length of its RHS.
+ *
+ */
+static ssize_t xlat_strlen(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ snprintf(out, outlen, "%u", (unsigned int) strlen(fmt));
+ return strlen(out);
+}
+
+/** Print the size of the attribute in bytes.
+ *
+ */
+static ssize_t xlat_length(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ snprintf(out, outlen, "%zu", vp->vp_length);
+ return strlen(out);
+}
+
+/** Print data as integer, not as VALUE.
+ *
+ */
+static ssize_t xlat_integer(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ uint64_t int64 = 0; /* Needs to be initialised to zero */
+ uint32_t int32 = 0; /* Needs to be initialised to zero */
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_STRING:
+ if (vp->vp_length > 8) {
+ break;
+ }
+
+ if (vp->vp_length > 4) {
+ memcpy(&int64, vp->vp_octets, vp->vp_length);
+ return snprintf(out, outlen, "%" PRIu64, htonll(int64));
+ }
+
+ memcpy(&int32, vp->vp_octets, vp->vp_length);
+ return snprintf(out, outlen, "%i", htonl(int32));
+
+ case PW_TYPE_INTEGER64:
+ return snprintf(out, outlen, "%" PRIu64, vp->vp_integer64);
+
+ /*
+ * IP addresses are treated specially, as parsing functions assume the value
+ * is bigendian and will convert it for us.
+ */
+ case PW_TYPE_IPV4_ADDR:
+ return snprintf(out, outlen, "%u", htonl(vp->vp_ipaddr));
+
+ case PW_TYPE_IPV4_PREFIX:
+ return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(&vp->vp_ipv4prefix[2]))));
+
+ case PW_TYPE_INTEGER:
+ return snprintf(out, outlen, "%u", vp->vp_integer);
+
+ case PW_TYPE_DATE:
+ return snprintf(out, outlen, "%u", vp->vp_date);
+
+ case PW_TYPE_BYTE:
+ return snprintf(out, outlen, "%u", (unsigned int) vp->vp_byte);
+
+ case PW_TYPE_SHORT:
+ return snprintf(out, outlen, "%u", (unsigned int) vp->vp_short);
+
+ /*
+ * Ethernet is weird... It's network related, so we assume to it should be
+ * bigendian.
+ */
+ case PW_TYPE_ETHERNET:
+ memcpy(&int64, vp->vp_ether, vp->vp_length);
+ return snprintf(out, outlen, "%" PRIu64, htonll(int64));
+
+ case PW_TYPE_SIGNED:
+ return snprintf(out, outlen, "%i", vp->vp_signed);
+
+ case PW_TYPE_IPV6_ADDR:
+ return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6addr));
+
+ case PW_TYPE_IPV6_PREFIX:
+ return fr_prints_uint128(out, outlen, ntohlll(*(uint128_t const *) &vp->vp_ipv6prefix[2]));
+
+ default:
+ break;
+ }
+
+ REDEBUG("Type '%s' of length %zu cannot be converted to integer",
+ fr_int2str(dict_attr_types, vp->da->type, "???"), vp->vp_length);
+ *out = '\0';
+
+ return -1;
+}
+
+/** Print data as hex, not as VALUE.
+ *
+ */
+static ssize_t xlat_hex(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ size_t i;
+ VALUE_PAIR *vp;
+ uint8_t const *p;
+ ssize_t ret;
+ size_t len;
+ value_data_t dst;
+ uint8_t const *buff = NULL;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ error:
+ *out = '\0';
+ return -1;
+ }
+
+ /*
+ * The easy case.
+ */
+ if (vp->da->type == PW_TYPE_OCTETS) {
+ p = vp->vp_octets;
+ len = vp->vp_length;
+ /*
+ * Cast the value_data_t of the VP to an octets string and
+ * print that as hex.
+ */
+ } else {
+ ret = value_data_cast(request, &dst, PW_TYPE_OCTETS, NULL, vp->da->type,
+ NULL, &vp->data, vp->vp_length);
+ if (ret < 0) {
+ REDEBUG("%s", fr_strerror());
+ goto error;
+ }
+ len = (size_t) ret;
+ p = buff = dst.octets;
+ }
+
+ rad_assert(p);
+
+ /*
+ * Don't truncate the data.
+ */
+ if (outlen < (len * 2)) {
+ rad_const_free(buff);
+ goto error;
+ }
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + 2*i, 3, "%02x", p[i]);
+ }
+ rad_const_free(buff);
+
+ return len * 2;
+}
+
+/** Return the tag of an attribute reference
+ *
+ */
+static ssize_t xlat_tag(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ if (!vp->da->flags.has_tag || !TAG_VALID(vp->tag)) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->tag);
+}
+
+/** Return the vendor of an attribute reference
+ *
+ */
+static ssize_t xlat_vendor(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+ DICT_VENDOR *vendor;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ vendor = dict_vendorbyvalue(vp->da->vendor);
+ if (!vendor) {
+ *out = '\0';
+ return 0;
+ }
+ strlcpy(out, vendor->name, outlen);
+
+ return vendor->length;
+}
+
+/** Return the vendor number of an attribute reference
+ *
+ */
+static ssize_t xlat_vendor_num(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->da->vendor);
+}
+
+/** Return the attribute name of an attribute reference
+ *
+ */
+static ssize_t xlat_attr(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+ strlcpy(out, vp->da->name, outlen);
+
+ return strlen(vp->da->name);
+}
+
+/** Return the attribute number of an attribute reference
+ *
+ */
+static ssize_t xlat_attr_num(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->da->attr);
+}
+
+/** Print out attribute info
+ *
+ * Prints out all instances of a current attribute, or all attributes in a list.
+ *
+ * At higher debugging levels, also prints out alternative decodings of the same
+ * value. This is helpful to determine types for unknown attributes of long
+ * passed vendors, or just crazy/broken NAS.
+ *
+ * This expands to a zero length string.
+ */
+static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
+ char *out, UNUSED size_t outlen)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ vp_tmpl_t vpt;
+
+ if (!RDEBUG_ENABLED2) {
+ *out = '\0';
+ return -1;
+ }
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
+ RDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ RIDEBUG("Attributes matching \"%s\"", fmt);
+
+ RINDENT();
+ for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
+ vp;
+ vp = tmpl_cursor_next(&cursor, &vpt)) {
+ FR_NAME_NUMBER const *type;
+ char *value;
+
+ value = vp_aprints_value(vp, vp, '\'');
+ if (vp->da->flags.has_tag) {
+ RIDEBUG2("&%s:%s:%i %s %s",
+ fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
+ vp->da->name,
+ vp->tag,
+ fr_int2str(fr_tokens, vp->op, "<INVALID>"),
+ value);
+ } else {
+ RIDEBUG2("&%s:%s %s %s",
+ fr_int2str(pair_lists, vpt.tmpl_list, "<INVALID>"),
+ vp->da->name,
+ fr_int2str(fr_tokens, vp->op, "<INVALID>"),
+ value);
+ }
+ talloc_free(value);
+
+ if (!RDEBUG_ENABLED3) continue;
+
+ if (vp->da->vendor) {
+ DICT_VENDOR *dv;
+
+ dv = dict_vendorbyvalue(vp->da->vendor);
+ RIDEBUG2("Vendor : %i (%s)", vp->da->vendor, dv ? dv->name : "unknown");
+ }
+ RIDEBUG2("Type : %s", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
+ RIDEBUG2("Length : %zu", vp->vp_length);
+
+ if (!RDEBUG_ENABLED4) continue;
+
+ type = dict_attr_types;
+ while (type->name) {
+ int pad;
+
+ value_data_t *dst = NULL;
+
+ ssize_t ret;
+
+ if ((PW_TYPE) type->number == vp->da->type) {
+ goto next_type;
+ }
+
+ switch (type->number) {
+ case PW_TYPE_INVALID: /* Not real type */
+ case PW_TYPE_MAX: /* Not real type */
+ case PW_TYPE_EXTENDED: /* Not safe/appropriate */
+ case PW_TYPE_LONG_EXTENDED: /* Not safe/appropriate */
+ case PW_TYPE_TLV: /* Not safe/appropriate */
+ case PW_TYPE_EVS: /* Not safe/appropriate */
+ case PW_TYPE_VSA: /* @fixme We need special behaviour for these */
+ case PW_TYPE_COMBO_IP_ADDR: /* Covered by IPv4 address IPv6 address */
+ case PW_TYPE_COMBO_IP_PREFIX: /* Covered by IPv4 address IPv6 address */
+ case PW_TYPE_TIMEVAL: /* Not a VALUE_PAIR type */
+ goto next_type;
+
+ default:
+ break;
+ }
+
+ dst = talloc_zero(vp, value_data_t);
+ ret = value_data_cast(dst, dst, type->number, NULL, vp->da->type, vp->da,
+ &vp->data, vp->vp_length);
+ if (ret < 0) goto next_type; /* We expect some to fail */
+
+ value = value_data_aprints(dst, type->number, NULL, dst, (size_t)ret, '\'');
+ if (!value) goto next_type;
+
+ if ((pad = (11 - strlen(type->name))) < 0) {
+ pad = 0;
+ }
+
+ RINDENT();
+ RDEBUG2("as %s%*s: %s", type->name, pad, " ", value);
+ REXDENT();
+ talloc_free(value);
+
+ next_type:
+ talloc_free(dst);
+ type++;
+ }
+ }
+ REXDENT();
+
+ *out = '\0';
+ return 0;
+}
+
+/** Processes fmt as a map string and applies it to the current request
+ *
+ * e.g. "%{map:&User-Name := 'foo'}"
+ *
+ * Allows sets of modifications to be cached and then applied.
+ * Useful for processing generic attributes from LDAP.
+ */
+static ssize_t xlat_map(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ vp_map_t *map = NULL;
+ int ret;
+
+ if (map_afrom_attr_str(request, &map, fmt,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ REDEBUG("Failed parsing \"%s\" as map: %s", fmt, fr_strerror());
+ return -1;
+ }
+
+ RINDENT();
+ ret = map_to_request(request, map, map_to_vp, NULL);
+ REXDENT();
+ talloc_free(map);
+ if (ret < 0) return strlcpy(out, "0", outlen);
+
+ return strlcpy(out, "1", outlen);
+}
+
+/** Prints the current module processing the request
+ *
+ */
+static ssize_t xlat_module(UNUSED void *instance, REQUEST *request,
+ UNUSED char const *fmt, char *out, size_t outlen)
+{
+ strlcpy(out, request->module, outlen);
+
+ return strlen(out);
+}
+
+#if defined(HAVE_REGEX) && defined(HAVE_PCRE)
+static ssize_t xlat_regex(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char *p;
+ size_t len;
+
+ if (regex_request_to_sub_named(request, &p, request, fmt) < 0) {
+ *out = '\0';
+ return 0;
+ }
+
+ len = talloc_array_length(p);
+ if (len > outlen) {
+ RDEBUG("Insufficient buffer space to write subcapture value, needed %zu bytes, have %zu bytes",
+ len, outlen);
+ return -1;
+ }
+ strlcpy(out, p, outlen);
+
+ return len - 1; /* - \0 */
+}
+#endif
+
+#ifdef WITH_UNLANG
+/** Implements the Foreach-Variable-X
+ *
+ * @see modcall()
+ */
+static ssize_t xlat_foreach(void *instance, REQUEST *request,
+ UNUSED char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR **pvp;
+ size_t len;
+
+ /*
+ * See modcall, "FOREACH" for how this works.
+ */
+ pvp = (VALUE_PAIR **) request_data_reference(request, (void *)radius_get_vp, *(int*) instance);
+ if (!pvp || !*pvp) {
+ *out = '\0';
+ return 0;
+ }
+
+ len = vp_prints_value(out, outlen, *pvp, 0);
+ if (is_truncated(len, outlen)) {
+ RDEBUG("Insufficient buffer space to write foreach value");
+ return -1;
+ }
+
+ return len;
+}
+#endif
+
+/** Print data as string, if possible.
+ *
+ * If attribute "Foo" is defined as "octets" it will normally
+ * be printed as 0x0a0a0a. The xlat "%{string:Foo}" will instead
+ * expand to "\n\n\n"
+ */
+static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ size_t len;
+ ssize_t ret;
+ VALUE_PAIR *vp;
+ uint8_t const *p;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if (outlen < 3) {
+ nothing:
+ *out = '\0';
+ return 0;
+ }
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
+
+ ret = rad_vp2data(&p, vp);
+ if (ret < 0) {
+ return ret;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
+ break;
+
+ /*
+ * Note that "%{string:...}" is NOT binary safe!
+ * It is explicitly used to get rid of embedded zeros.
+ */
+ case PW_TYPE_STRING:
+ len = strlcpy(out, vp->vp_strvalue, outlen);
+ break;
+
+ default:
+ len = fr_prints(out, outlen, (char const *) p, ret, '\0');
+ break;
+ }
+
+ return len;
+}
+
+/** xlat expand string attribute value
+ *
+ */
+static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if (outlen < 3) {
+ nothing:
+ *out = '\0';
+ return 0;
+ }
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
+
+ if (vp->da->type != PW_TYPE_STRING) goto nothing;
+
+ return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
+}
+
+/** Dynamically change the debugging level for the current request
+ *
+ * Example %{debug:3}
+ */
+static ssize_t xlat_debug(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ int level = 0;
+
+ /*
+ * Expand to previous (or current) level
+ */
+ snprintf(out, outlen, "%d", request->log.lvl);
+
+ /*
+ * Assume we just want to get the current value and NOT set it to 0
+ */
+ if (!*fmt)
+ goto done;
+
+ level = atoi(fmt);
+ if (level == 0) {
+ request->log.lvl = RAD_REQUEST_LVL_NONE;
+ request->log.func = NULL;
+ } else {
+ if (level > 4) level = 4;
+
+ request->log.lvl = level;
+ request->log.func = vradlog_request;
+ }
+
+ done:
+ return strlen(out);
+}
+
+/*
+ * Compare two xlat_t structs, based ONLY on the module name.
+ */
+static int xlat_cmp(void const *one, void const *two)
+{
+ xlat_t const *a = one;
+ xlat_t const *b = two;
+
+ if (a->length != b->length) {
+ return a->length - b->length;
+ }
+
+ return memcmp(a->name, b->name, a->length);
+}
+
+
+/*
+ * find the appropriate registered xlat function.
+ */
+static xlat_t *xlat_find(char const *name)
+{
+ xlat_t my_xlat;
+
+ strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
+ my_xlat.length = strlen(my_xlat.name);
+
+ return rbtree_finddata(xlat_root, &my_xlat);
+}
+
+
+/** Register an xlat function.
+ *
+ * @param[in] name xlat name.
+ * @param[in] func xlat function to be called.
+ * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
+ * @param[in] instance of module that's registering the xlat function.
+ * @return 0 on success, -1 on failure
+ */
+int xlat_register(char const *name, xlat_func_t func, xlat_escape_t escape, void *instance)
+{
+ xlat_t *c;
+ xlat_t my_xlat;
+ rbnode_t *node;
+
+ if (!name || !*name) {
+ DEBUG("xlat_register: Invalid xlat name");
+ return -1;
+ }
+
+ /*
+ * First time around, build up the tree...
+ *
+ * FIXME: This code should be hoisted out of this function,
+ * and into a global "initialization". But it isn't critical...
+ */
+ if (!xlat_root) {
+#ifdef WITH_UNLANG
+ int i;
+#endif
+
+ xlat_root = rbtree_create(NULL, xlat_cmp, NULL, RBTREE_FLAG_REPLACE);
+ if (!xlat_root) {
+ DEBUG("xlat_register: Failed to create tree");
+ return -1;
+ }
+
+#ifdef WITH_UNLANG
+ for (i = 0; xlat_foreach_names[i] != NULL; i++) {
+ xlat_register(xlat_foreach_names[i],
+ xlat_foreach, NULL, &xlat_inst[i]);
+ c = xlat_find(xlat_foreach_names[i]);
+ rad_assert(c != NULL);
+ c->internal = true;
+ }
+#endif
+
+#define XLAT_REGISTER(_x) xlat_register(STRINGIFY(_x), xlat_ ## _x, NULL, NULL); \
+ c = xlat_find(STRINGIFY(_x)); \
+ rad_assert(c != NULL); \
+ c->internal = true
+
+ XLAT_REGISTER(concat);
+ XLAT_REGISTER(integer);
+ XLAT_REGISTER(strlen);
+ XLAT_REGISTER(length);
+ XLAT_REGISTER(hex);
+ XLAT_REGISTER(tag);
+ XLAT_REGISTER(vendor);
+ XLAT_REGISTER(vendor_num);
+ XLAT_REGISTER(attr);
+ XLAT_REGISTER(attr_num);
+ XLAT_REGISTER(string);
+ XLAT_REGISTER(xlat);
+ XLAT_REGISTER(map);
+ XLAT_REGISTER(module);
+ XLAT_REGISTER(debug_attr);
+#if defined(HAVE_REGEX) && defined(HAVE_PCRE)
+ XLAT_REGISTER(regex);
+#endif
+
+ xlat_register("debug", xlat_debug, NULL, &xlat_inst[0]);
+ c = xlat_find("debug");
+ rad_assert(c != NULL);
+ c->internal = true;
+ }
+
+ /*
+ * If it already exists, replace the instance.
+ */
+ strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
+ my_xlat.length = strlen(my_xlat.name);
+ c = rbtree_finddata(xlat_root, &my_xlat);
+ if (c) {
+ if (c->internal) {
+ DEBUG("xlat_register: Cannot re-define internal xlat");
+ return -1;
+ }
+
+ c->func = func;
+ c->escape = escape;
+ c->instance = instance;
+ return 0;
+ }
+
+ /*
+ * Doesn't exist. Create it.
+ */
+ c = talloc_zero(xlat_root, xlat_t);
+
+ c->func = func;
+ c->escape = escape;
+ strlcpy(c->name, name, sizeof(c->name));
+ c->length = strlen(c->name);
+ c->instance = instance;
+
+ node = rbtree_insert_node(xlat_root, c);
+ if (!node) {
+ talloc_free(c);
+ return -1;
+ }
+
+ /*
+ * Ensure that the data is deleted when the node is
+ * deleted.
+ *
+ * @todo: Maybe this should be the other way around...
+ * when a thing IN the tree is deleted, it's automatically
+ * removed from the tree. But for now, this works.
+ */
+ (void) talloc_steal(node, c);
+ return 0;
+}
+
+/** Unregister an xlat function
+ *
+ * We can only have one function to call per name, so the passing of "func"
+ * here is extraneous.
+ *
+ * @param[in] name xlat to unregister.
+ * @param[in] func unused.
+ * @param[in] instance data.
+ */
+void xlat_unregister(char const *name, UNUSED xlat_func_t func, void *instance)
+{
+ xlat_t *c;
+ xlat_t my_xlat;
+
+ if (!name || !xlat_root) return;
+
+ strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
+ my_xlat.length = strlen(my_xlat.name);
+
+ c = rbtree_finddata(xlat_root, &my_xlat);
+ if (!c) return;
+
+ if (c->instance != instance) return;
+
+ rbtree_deletebydata(xlat_root, c);
+}
+
+static int xlat_unregister_callback(void *instance, void *data)
+{
+ xlat_t *c = (xlat_t *) data;
+
+ if (c->instance != instance) return 0; /* keep walking */
+
+ return 2; /* delete it */
+}
+
+void xlat_unregister_module(void *instance)
+{
+ rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, xlat_unregister_callback, instance);
+}
+
+/*
+ * Internal redundant handler for xlats
+ */
+typedef enum xlat_redundant_type_t {
+ XLAT_INVALID = 0,
+ XLAT_REDUNDANT,
+ XLAT_LOAD_BALANCE,
+ XLAT_REDUNDANT_LOAD_BALANCE,
+} xlat_redundant_type_t;
+
+typedef struct xlat_redundant_t {
+ xlat_redundant_type_t type;
+ uint32_t count;
+ CONF_SECTION *cs;
+} xlat_redundant_t;
+
+
+static ssize_t xlat_redundant(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ xlat_redundant_t *xr = instance;
+ CONF_ITEM *ci;
+ char const *name;
+ xlat_t *xlat;
+
+ rad_assert(xr->type == XLAT_REDUNDANT);
+
+ /*
+ * Pick the first xlat which succeeds
+ */
+ for (ci = cf_item_find_next(xr->cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(xr->cs, ci)) {
+ ssize_t rcode;
+
+ if (!cf_item_is_pair(ci)) continue;
+
+ name = cf_pair_attr(cf_item_to_pair(ci));
+ rad_assert(name != NULL);
+
+ xlat = xlat_find(name);
+ if (!xlat) continue;
+
+ rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
+ if (rcode <= 0) continue;
+ return rcode;
+ }
+
+ /*
+ * Everything failed. Oh well.
+ */
+ *out = 0;
+ return 0;
+}
+
+
+static ssize_t xlat_load_balance(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint32_t count = 0;
+ xlat_redundant_t *xr = instance;
+ CONF_ITEM *ci;
+ CONF_ITEM *found = NULL;
+ char const *name;
+ xlat_t *xlat;
+
+ /*
+ * Choose a child at random.
+ */
+ for (ci = cf_item_find_next(xr->cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(xr->cs, ci)) {
+ if (!cf_item_is_pair(ci)) continue;
+ count++;
+
+ /*
+ * Replace the previously found one with a random
+ * new one.
+ */
+ if ((count * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) {
+ found = ci;
+ }
+ }
+
+ /*
+ * Plain load balancing: do one child, and only one child.
+ */
+ if (xr->type == XLAT_LOAD_BALANCE) {
+ name = cf_pair_attr(cf_item_to_pair(found));
+ rad_assert(name != NULL);
+
+ xlat = xlat_find(name);
+ if (!xlat) return -1;
+
+ return xlat->func(xlat->instance, request, fmt, out, outlen);
+ }
+
+ rad_assert(xr->type == XLAT_REDUNDANT_LOAD_BALANCE);
+
+ /*
+ * Try the random one we found. If it fails, keep going
+ * through the rest of the children.
+ */
+ ci = found;
+ do {
+ name = cf_pair_attr(cf_item_to_pair(ci));
+ rad_assert(name != NULL);
+
+ xlat = xlat_find(name);
+ if (xlat) {
+ ssize_t rcode;
+
+ rcode = xlat->func(xlat->instance, request, fmt, out, outlen);
+ if (rcode > 0) return rcode;
+ }
+
+ /*
+ * Go to the next one, wrapping around at the end.
+ */
+ ci = cf_item_find_next(xr->cs, ci);
+ if (!ci) ci = cf_item_find_next(xr->cs, NULL);
+ } while (ci != found);
+
+ return -1;
+}
+
+
+bool xlat_register_redundant(CONF_SECTION *cs)
+{
+ char const *name1, *name2;
+ xlat_redundant_t *xr;
+
+ name1 = cf_section_name1(cs);
+ name2 = cf_section_name2(cs);
+
+ if (!name2) return false;
+
+ if (xlat_find(name2)) {
+ cf_log_err_cs(cs, "An expansion is already registered for this name");
+ return false;
+ }
+
+ xr = talloc_zero(cs, xlat_redundant_t);
+ if (!xr) return false;
+
+ if (strcmp(name1, "redundant") == 0) {
+ xr->type = XLAT_REDUNDANT;
+
+ } else if (strcmp(name1, "redundant-load-balance") == 0) {
+ xr->type = XLAT_REDUNDANT_LOAD_BALANCE;
+
+ } else if (strcmp(name1, "load-balance") == 0) {
+ xr->type = XLAT_LOAD_BALANCE;
+
+ } else {
+ return false;
+ }
+
+ xr->cs = cs;
+
+ /*
+ * Get the number of children for load balancing.
+ */
+ if (xr->type == XLAT_REDUNDANT) {
+ if (xlat_register(name2, xlat_redundant, NULL, xr) < 0) {
+ talloc_free(xr);
+ return false;
+ }
+
+ } else {
+ CONF_ITEM *ci;
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ if (!cf_item_is_pair(ci)) continue;
+
+ if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
+ talloc_free(xr);
+ return false;
+ }
+
+ xr->count++;
+ }
+
+ if (xlat_register(name2, xlat_load_balance, NULL, xr) < 0) {
+ talloc_free(xr);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/** Crappy temporary function to add attribute ref support to xlats
+ *
+ * This needs to die, and hopefully will die, when xlat functions accept
+ * xlat node structures.
+ *
+ * Provides either a pointer to a buffer which contains the value of the reference VALUE_PAIR
+ * in an architecture independent format. Or a pointer to the start of the fmt string.
+ *
+ * The pointer is only guaranteed to be valid between calls to xlat_fmt_to_ref,
+ * and so long as the source VALUE_PAIR is not freed.
+ *
+ * @param out where to write a pointer to the buffer to the data the xlat function needs to work on.
+ * @param request current request.
+ * @param fmt string.
+ * @returns the length of the data or -1 on error.
+ */
+ssize_t xlat_fmt_to_ref(uint8_t const **out, REQUEST *request, char const *fmt)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if (fmt[0] == '&') {
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = NULL;
+ return -1;
+ }
+
+ return rad_vp2data(out, vp);
+ }
+
+ *out = (uint8_t const *)fmt;
+ return strlen(fmt);
+}
+
+/** De-register all xlat functions, used mainly for debugging.
+ *
+ */
+void xlat_free(void)
+{
+ rbtree_free(xlat_root);
+}
+
+#ifdef DEBUG_XLAT
+# define XLAT_DEBUG DEBUG3
+#else
+# define XLAT_DEBUG(...)
+#endif
+
+static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ char const **error);
+static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ bool brace, char const **error);
+static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
+ xlat_escape_t escape, void *escape_ctx);
+
+static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ char const **error)
+{
+ ssize_t slen;
+ char *p;
+ xlat_exp_t *node;
+
+ rad_assert(fmt[0] == '%');
+ rad_assert(fmt[1] == '{');
+ rad_assert(fmt[2] == '%');
+ rad_assert(fmt[3] == '{');
+
+ XLAT_DEBUG("ALTERNATE <-- %s", fmt);
+
+ node = talloc_zero(ctx, xlat_exp_t);
+ node->type = XLAT_ALTERNATE;
+
+ p = fmt + 2;
+ slen = xlat_tokenize_expansion(node, p, &node->child, error);
+ if (slen <= 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+ p += slen;
+
+ if (p[0] != ':') {
+ talloc_free(node);
+ *error = "Expected ':' after first expansion";
+ return -(p - fmt);
+ }
+ p++;
+
+ if (p[0] != '-') {
+ talloc_free(node);
+ *error = "Expected '-' after ':'";
+ return -(p - fmt);
+ }
+ p++;
+
+ /*
+ * Allow the RHS to be empty as a special case.
+ */
+ if (*p == '}') {
+ /*
+ * Hack up an empty string.
+ */
+ node->alternate = talloc_zero(node, xlat_exp_t);
+ node->alternate->type = XLAT_LITERAL;
+ node->alternate->fmt = talloc_typed_strdup(node->alternate, "");
+ *(p++) = '\0';
+
+ } else {
+ slen = xlat_tokenize_literal(node, p, &node->alternate, true, error);
+ if (slen <= 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+
+ if (!node->alternate) {
+ talloc_free(node);
+ *error = "Empty expansion is invalid";
+ return -(p - fmt);
+ }
+ p += slen;
+ }
+
+ *head = node;
+ return p - fmt;
+}
+
+static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ char const **error)
+{
+ ssize_t slen;
+ char *p, *q;
+ xlat_exp_t *node;
+ long num;
+
+ rad_assert(fmt[0] == '%');
+ rad_assert(fmt[1] == '{');
+
+ /*
+ * %{%{...}:-bar}
+ */
+ if ((fmt[2] == '%') && (fmt[3] == '{')) return xlat_tokenize_alternation(ctx, fmt, head, error);
+
+ XLAT_DEBUG("EXPANSION <-- %s", fmt);
+ node = talloc_zero(ctx, xlat_exp_t);
+ node->fmt = fmt + 2;
+ node->len = 0;
+
+#ifdef HAVE_REGEX
+ /*
+ * Handle regex's specially.
+ */
+ p = fmt + 2;
+ num = strtol(p, &q, 10);
+ if (p != q && (*q == '}')) {
+ XLAT_DEBUG("REGEX <-- %s", fmt);
+ *q = '\0';
+
+ if ((num > REQUEST_MAX_REGEX) || (num < 0)) {
+ talloc_free(node);
+ *error = "Invalid regex reference. Must be in range 0-" STRINGIFY(REQUEST_MAX_REGEX);
+ return -2;
+ }
+ node->attr.tmpl_num = num;
+
+ node->type = XLAT_REGEX;
+ *head = node;
+
+ return (q - fmt) + 1;
+ }
+#endif /* HAVE_REGEX */
+
+ /*
+ * %{Attr-Name}
+ * %{Attr-Name[#]}
+ * %{Tunnel-Password:1}
+ * %{Tunnel-Password:1[#]}
+ * %{request:Attr-Name}
+ * %{request:Tunnel-Password:1}
+ * %{request:Tunnel-Password:1[#]}
+ * %{mod:foo}
+ */
+
+ /*
+ * This is for efficiency, so we don't search for an xlat,
+ * when what's being referenced is obviously an attribute.
+ */
+ p = fmt + 2;
+ for (q = p; *q != '\0'; q++) {
+ if (*q == ':') break;
+
+ if (isspace((uint8_t) *q)) break;
+
+ if (*q == '[') continue;
+
+ if (*q == '}') break;
+ }
+
+ /*
+ * Check for empty expressions %{}
+ */
+ if ((*q == '}') && (q == p)) {
+ talloc_free(node);
+ *error = "Empty expression is invalid";
+ return -(p - fmt);
+ }
+
+ /*
+ * Might be a module name reference.
+ *
+ * If it's not, it's an attribute or parse error.
+ */
+ if (*q == ':') {
+ *q = '\0';
+ node->xlat = xlat_find(node->fmt);
+ if (node->xlat) {
+ /*
+ * %{mod:foo}
+ */
+ node->type = XLAT_MODULE;
+
+ p = q + 1;
+ XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);
+
+ slen = xlat_tokenize_literal(node, p, &node->child, true, error);
+ if (slen < 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+ p += slen;
+
+ *head = node;
+ rad_assert(node->next == NULL);
+
+ return p - fmt;
+ }
+ *q = ':'; /* Avoids a strdup */
+ }
+
+ /*
+ * The first token ends with:
+ * - '[' - Which is an attribute index, so it must be an attribute.
+ * - '}' - The end of the expansion, which means it was a bareword.
+ */
+ slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true, true);
+ if (slen <= 0) {
+ /*
+ * If the parse error occurred before the ':'
+ * then the error is changed to 'Unknown module',
+ * as it was more likely to be a bad module name,
+ * than a request qualifier.
+ */
+ if ((*q == ':') && ((p + (slen * -1)) < q)) {
+ *error = "Unknown module";
+ } else {
+ *error = fr_strerror();
+ }
+
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+
+ /*
+ * Might be a virtual XLAT attribute
+ */
+ if (node->attr.type == TMPL_TYPE_ATTR_UNDEFINED) {
+ node->xlat = xlat_find(node->attr.tmpl_unknown_name);
+ if (node->xlat && node->xlat->instance && !node->xlat->internal) {
+ talloc_free(node);
+ *error = "Missing content in expansion";
+ return -(p - fmt) - slen;
+ }
+
+ if (node->xlat) {
+ node->type = XLAT_VIRTUAL;
+ node->fmt = node->attr.tmpl_unknown_name;
+
+ XLAT_DEBUG("VIRTUAL <-- %s", node->fmt);
+ *head = node;
+ rad_assert(node->next == NULL);
+ q++;
+ return q - fmt;
+ }
+
+ talloc_free(node);
+ *error = "Unknown attribute";
+ return -(p - fmt);
+ }
+
+ /*
+ * Might be a list, too...
+ */
+ node->type = XLAT_ATTRIBUTE;
+ p += slen;
+
+ if (*p != '}') {
+ talloc_free(node);
+ *error = "No matching closing brace";
+ return -1; /* second character of format string */
+ }
+ *p++ = '\0';
+ *head = node;
+ rad_assert(node->next == NULL);
+
+ return p - fmt;
+}
+
+
+static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ bool brace, char const **error)
+{
+ char *p;
+ xlat_exp_t *node;
+
+ if (!*fmt) return 0;
+
+ XLAT_DEBUG("LITERAL <-- %s", fmt);
+
+ node = talloc_zero(ctx, xlat_exp_t);
+ node->fmt = fmt;
+ node->len = 0;
+ node->type = XLAT_LITERAL;
+
+ p = fmt;
+
+ while (*p) {
+ if (*p == '\\') {
+ if (!p[1]) {
+ talloc_free(node);
+ *error = "Invalid escape at end of string";
+ return -(p - fmt);
+ }
+
+ p += 2;
+ node->len += 2;
+ continue;
+ }
+
+ /*
+ * Process the expansion.
+ */
+ if ((p[0] == '%') && (p[1] == '{')) {
+ ssize_t slen;
+
+ XLAT_DEBUG("EXPANSION-2 <-- %s", node->fmt);
+
+ slen = xlat_tokenize_expansion(node, p, &node->next, error);
+ if (slen <= 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+ *p = '\0'; /* end the literal */
+ p += slen;
+
+ rad_assert(node->next != NULL);
+
+ /*
+ * Short-circuit the recursive call.
+ * This saves another function call and
+ * memory allocation.
+ */
+ if (!*p) break;
+
+ /*
+ * "foo %{User-Name} bar"
+ * LITERAL "foo "
+ * EXPANSION User-Name
+ * LITERAL " bar"
+ */
+ slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
+ rad_assert(slen != 0);
+ if (slen < 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+
+ brace = false; /* it was found above, or else the above code errored out */
+ p += slen;
+ break; /* stop processing the string */
+ }
+
+ /*
+ * Check for valid single-character expansions.
+ */
+ if (p[0] == '%') {
+ ssize_t slen;
+ xlat_exp_t *next;
+
+ if (!p[1] || !strchr("%}cdelmntCDGHIMSTYv", p[1])) {
+ talloc_free(node);
+ *error = "Invalid variable expansion";
+ p++;
+ return - (p - fmt);
+ }
+
+ next = talloc_zero(node, xlat_exp_t);
+ next->len = 1;
+
+ switch (p[1]) {
+ case '%':
+ case '}':
+ next->fmt = talloc_strndup(next, p + 1, 1);
+
+ XLAT_DEBUG("LITERAL-ESCAPED <-- %s", next->fmt);
+ next->type = XLAT_LITERAL;
+ break;
+
+ default:
+ next->fmt = p + 1;
+
+ XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
+ next->type = XLAT_PERCENT;
+ break;
+ }
+
+ node->next = next;
+ *p = '\0';
+ p += 2;
+
+ if (!*p) break;
+
+ /*
+ * And recurse.
+ */
+ slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error);
+ rad_assert(slen != 0);
+ if (slen < 0) {
+ talloc_free(node);
+ return slen - (p - fmt);
+ }
+
+ brace = false; /* it was found above, or else the above code errored out */
+ p += slen;
+ break; /* stop processing the string */
+ }
+
+ /*
+ * If required, eat the brace.
+ */
+ if (brace && (*p == '}')) {
+ brace = false;
+ *p = '\0';
+ p++;
+ break;
+ }
+
+ p++;
+ node->len++;
+ }
+
+ /*
+ * We were told to look for a brace, but we ran off of
+ * the end of the string before we found one.
+ */
+ if (brace) {
+ *error = "Missing closing brace at end of string";
+ return -(p - fmt);
+ }
+
+ /*
+ * Squash zero-width literals
+ */
+ if (node->len > 0) {
+ *head = node;
+
+ } else {
+ (void) talloc_steal(ctx, node->next);
+ *head = node->next;
+ talloc_free(node);
+ }
+
+ return p - fmt;
+}
+
+
+static char const xlat_tabs[] = " ";
+
+static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
+{
+ rad_assert(node != NULL);
+
+ if (lvl >= (int) sizeof(xlat_tabs)) lvl = sizeof(xlat_tabs);
+
+ while (node) {
+ switch (node->type) {
+ case XLAT_LITERAL:
+ DEBUG("%.*sliteral --> %s", lvl, xlat_tabs, node->fmt);
+ break;
+
+ case XLAT_PERCENT:
+ DEBUG("%.*spercent --> %c", lvl, xlat_tabs, node->fmt[0]);
+ break;
+
+ case XLAT_ATTRIBUTE:
+ rad_assert(node->attr.tmpl_da != NULL);
+ DEBUG("%.*sattribute --> %s", lvl, xlat_tabs, node->attr.tmpl_da->name);
+ rad_assert(node->child == NULL);
+ if ((node->attr.tmpl_tag != TAG_ANY) || (node->attr.tmpl_num != NUM_ANY)) {
+ DEBUG("%.*s{", lvl, xlat_tabs);
+
+ DEBUG("%.*sref %d", lvl + 1, xlat_tabs, node->attr.tmpl_request);
+ DEBUG("%.*slist %d", lvl + 1, xlat_tabs, node->attr.tmpl_list);
+
+ if (node->attr.tmpl_tag != TAG_ANY) {
+ DEBUG("%.*stag %d", lvl + 1, xlat_tabs, node->attr.tmpl_tag);
+ }
+ if (node->attr.tmpl_num != NUM_ANY) {
+ if (node->attr.tmpl_num == NUM_COUNT) {
+ DEBUG("%.*s[#]", lvl + 1, xlat_tabs);
+ } else if (node->attr.tmpl_num == NUM_ALL) {
+ DEBUG("%.*s[*]", lvl + 1, xlat_tabs);
+ } else {
+ DEBUG("%.*s[%d]", lvl + 1, xlat_tabs, node->attr.tmpl_num);
+ }
+ }
+
+ DEBUG("%.*s}", lvl, xlat_tabs);
+ }
+ break;
+
+ case XLAT_VIRTUAL:
+ rad_assert(node->fmt != NULL);
+ DEBUG("%.*svirtual --> %s", lvl, xlat_tabs, node->fmt);
+ break;
+
+ case XLAT_MODULE:
+ rad_assert(node->xlat != NULL);
+ DEBUG("%.*sxlat --> %s", lvl, xlat_tabs, node->xlat->name);
+ if (node->child) {
+ DEBUG("%.*s{", lvl, xlat_tabs);
+ xlat_tokenize_debug(node->child, lvl + 1);
+ DEBUG("%.*s}", lvl, xlat_tabs);
+ }
+ break;
+
+#ifdef HAVE_REGEX
+ case XLAT_REGEX:
+ DEBUG("%.*sregex-var --> %d", lvl, xlat_tabs, node->attr.tmpl_num);
+ break;
+#endif
+
+ case XLAT_ALTERNATE:
+ DEBUG("%.*sXLAT-IF {", lvl, xlat_tabs);
+ xlat_tokenize_debug(node->child, lvl + 1);
+ DEBUG("%.*s}", lvl, xlat_tabs);
+ DEBUG("%.*sXLAT-ELSE {", lvl, xlat_tabs);
+ xlat_tokenize_debug(node->alternate, lvl + 1);
+ DEBUG("%.*s}", lvl, xlat_tabs);
+ break;
+ }
+ node = node->next;
+ }
+}
+
+size_t xlat_sprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
+{
+ size_t len;
+ char *p, *end;
+
+ if (!node) {
+ *buffer = '\0';
+ return 0;
+ }
+
+ p = buffer;
+ end = buffer + bufsize;
+
+ while (node) {
+ switch (node->type) {
+ case XLAT_LITERAL:
+ strlcpy(p, node->fmt, end - p);
+ p += strlen(p);
+ break;
+
+ case XLAT_PERCENT:
+ p[0] = '%';
+ p[1] = node->fmt[0];
+ p += 2;
+ break;
+
+ case XLAT_ATTRIBUTE:
+ *(p++) = '%';
+ *(p++) = '{';
+
+ /*
+ * The node MAY NOT be an attribute. It
+ * may be a list.
+ */
+ tmpl_prints(p, end - p, &node->attr, NULL);
+ if (*p == '&') {
+ memmove(p, p + 1, strlen(p + 1) + 1);
+ }
+ p += strlen(p);
+ *(p++) = '}';
+ break;
+#ifdef HAVE_REGEX
+ case XLAT_REGEX:
+ snprintf(p, end - p, "%%{%i}", node->attr.tmpl_num);
+ p += strlen(p);
+ break;
+#endif
+ case XLAT_VIRTUAL:
+ *(p++) = '%';
+ *(p++) = '{';
+ strlcpy(p, node->fmt, end - p);
+ p += strlen(p);
+ *(p++) = '}';
+ break;
+
+ case XLAT_MODULE:
+ *(p++) = '%';
+ *(p++) = '{';
+ strlcpy(p, node->xlat->name, end - p);
+ p += strlen(p);
+ *(p++) = ':';
+ rad_assert(node->child != NULL);
+ len = xlat_sprint(p, end - p, node->child);
+ p += len;
+ *(p++) = '}';
+ break;
+
+ case XLAT_ALTERNATE:
+ *(p++) = '%';
+ *(p++) = '{';
+
+ len = xlat_sprint(p, end - p, node->child);
+ p += len;
+
+ *(p++) = ':';
+ *(p++) = '-';
+
+ len = xlat_sprint(p, end - p, node->alternate);
+ p += len;
+
+ *(p++) = '}';
+ break;
+ }
+
+
+ if (p == end) break;
+
+ node = node->next;
+ }
+
+ *p = '\0';
+
+ return p - buffer;
+}
+
+ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
+ char const **error)
+{
+ return xlat_tokenize_literal(ctx, fmt, head, false, error);
+}
+
+
+/** Tokenize an xlat expansion
+ *
+ * @param[in] request the input request. Memory will be attached here.
+ * @param[in] fmt the format string to expand
+ * @param[out] head the head of the xlat list / tree structure.
+ */
+static ssize_t xlat_tokenize_request(REQUEST *request, char const *fmt, xlat_exp_t **head)
+{
+ ssize_t slen;
+ char *tokens;
+ char const *error = NULL;
+
+ *head = NULL;
+
+ /*
+ * Copy the original format string to a buffer so that
+ * the later functions can mangle it in-place, which is
+ * much faster.
+ */
+ tokens = talloc_typed_strdup(request, fmt);
+ if (!tokens) {
+ error = "Out of memory";
+ return -1;
+ }
+
+ slen = xlat_tokenize_literal(request, tokens, head, false, &error);
+
+ /*
+ * Zero length expansion, return a zero length node.
+ */
+ if (slen == 0) {
+ *head = talloc_zero(request, xlat_exp_t);
+ }
+
+ /*
+ * Output something like:
+ *
+ * "format string"
+ * " ^ error was here"
+ */
+ if (slen < 0) {
+ talloc_free(tokens);
+
+ if (!error) error = "Unknown error";
+
+ REMARKER(fmt, -slen, error);
+ return slen;
+ }
+
+ if (*head && (rad_debug_lvl > 2)) {
+ DEBUG("%s", fmt);
+ DEBUG("Parsed xlat tree:");
+ xlat_tokenize_debug(*head, 0);
+ }
+
+ /*
+ * All of the nodes point to offsets in the "tokens"
+ * string. Let's ensure that free'ing head will free
+ * "tokens", too.
+ */
+ (void) talloc_steal(*head, tokens);
+
+ return slen;
+}
+
+
+static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
+ bool escape, bool return_null, char const *concat)
+{
+ VALUE_PAIR *vp = NULL, *virtual = NULL;
+ RADIUS_PACKET *packet = NULL;
+ DICT_VALUE *dv;
+ char *ret = NULL;
+
+ vp_cursor_t cursor;
+ char quote = escape ? '"' : '\0';
+
+ rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
+
+ /*
+ * We only support count and concatenate operations on lists.
+ */
+ if (vpt->type == TMPL_TYPE_LIST) {
+ vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
+ goto do_print;
+ }
+
+ /*
+ * See if we're dealing with an attribute in the request
+ *
+ * This allows users to manipulate virtual attributes as if
+ * they were real ones.
+ */
+ vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
+ if (vp) goto do_print;
+
+ /*
+ * We didn't find the VP in a list.
+ * If it's not a virtual one, and we're not meant to
+ * be counting it, return.
+ */
+ if (!vpt->tmpl_da->flags.virtual) {
+ if (vpt->tmpl_num == NUM_COUNT) goto do_print;
+ return NULL;
+ }
+
+ /*
+ * Switch out the request to the one specified by the template
+ */
+ if (radius_request(&request, vpt->tmpl_request) < 0) return NULL;
+
+ /*
+ * Some non-packet expansions
+ */
+ switch (vpt->tmpl_da->attr) {
+ default:
+ break; /* ignore them */
+
+ case PW_CLIENT_SHORTNAME:
+ if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
+ if (request->client && request->client->shortname) {
+ return talloc_typed_strdup(ctx, request->client->shortname);
+ }
+ return talloc_typed_strdup(ctx, "<UNKNOWN-CLIENT>");
+
+ case PW_REQUEST_PROCESSING_STAGE:
+ if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
+ if (request->component) {
+ return talloc_typed_strdup(ctx, request->component);
+ }
+ return talloc_typed_strdup(ctx, "server_core");
+
+ case PW_VIRTUAL_SERVER:
+ if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
+ if (!request->server) return NULL;
+ return talloc_typed_strdup(ctx, request->server);
+
+ case PW_MODULE_RETURN_CODE:
+ if (vpt->tmpl_num == NUM_COUNT) goto count_virtual;
+ if (!request->rcode) return NULL;
+ return talloc_typed_strdup(ctx, fr_int2str(modreturn_table, request->rcode, ""));
+ }
+
+ /*
+ * All of the attributes must now refer to a packet.
+ * If there's no packet, we can't print any attribute
+ * referencing it.
+ */
+ packet = radius_packet(request, vpt->tmpl_list);
+ if (!packet) {
+ if (return_null) return NULL;
+ return vp_aprints_type(ctx, vpt->tmpl_da->type);
+ }
+
+ vp = NULL;
+ switch (vpt->tmpl_da->attr) {
+ default:
+ break;
+
+ case PW_PACKET_TYPE:
+ dv = dict_valbyattr(PW_PACKET_TYPE, 0, packet->code);
+ if (dv) return talloc_typed_strdup(ctx, dv->name);
+ return talloc_typed_asprintf(ctx, "%d", packet->code);
+
+ case PW_RESPONSE_PACKET_TYPE:
+ {
+ int code = 0;
+
+#ifdef WITH_PROXY
+ if (request->proxy_reply && (!request->reply || !request->reply->code)) {
+ code = request->proxy_reply->code;
+ } else
+#endif
+ if (request->reply) {
+ code = request->reply->code;
+ }
+
+ if (!code) return NULL;
+
+ if (code >= FR_MAX_PACKET_CODE) {
+ return talloc_typed_asprintf(ctx, "%d", packet->code);
+ }
+
+ return talloc_typed_strdup(ctx, fr_packet_codes[code]);
+ }
+
+ /*
+ * Virtual attributes which require a temporary VALUE_PAIR
+ * to be allocated. We can't use stack allocated memory
+ * because of the talloc checks sprinkled throughout the
+ * various VP functions.
+ */
+ case PW_PACKET_AUTHENTICATION_VECTOR:
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ fr_pair_value_memcpy(virtual, packet->vector, sizeof(packet->vector));
+ vp = virtual;
+ break;
+
+ case PW_CLIENT_IP_ADDRESS:
+ case PW_PACKET_SRC_IP_ADDRESS:
+ if (packet->src_ipaddr.af == AF_INET) {
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ virtual->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ vp = virtual;
+ }
+ break;
+
+ case PW_PACKET_DST_IP_ADDRESS:
+ if (packet->dst_ipaddr.af == AF_INET) {
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ virtual->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+ vp = virtual;
+ }
+ break;
+
+ case PW_PACKET_SRC_IPV6_ADDRESS:
+ if (packet->src_ipaddr.af == AF_INET6) {
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ memcpy(&virtual->vp_ipv6addr,
+ &packet->src_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->src_ipaddr.ipaddr.ip6addr));
+ vp = virtual;
+ }
+ break;
+
+ case PW_PACKET_DST_IPV6_ADDRESS:
+ if (packet->dst_ipaddr.af == AF_INET6) {
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ memcpy(&virtual->vp_ipv6addr,
+ &packet->dst_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
+ vp = virtual;
+ }
+ break;
+
+ case PW_PACKET_SRC_PORT:
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ virtual->vp_integer = packet->src_port;
+ vp = virtual;
+ break;
+
+ case PW_PACKET_DST_PORT:
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ virtual->vp_integer = packet->dst_port;
+ vp = virtual;
+ break;
+ }
+
+ /*
+ * Fake various operations for virtual attributes.
+ */
+ if (virtual) {
+ if (vpt->tmpl_num != NUM_ANY) switch (vpt->tmpl_num) {
+ /*
+ * [n] is NULL (we only have [0])
+ */
+ default:
+ goto finish;
+ /*
+ * [*] means only one.
+ */
+ case NUM_ALL:
+ break;
+
+ /*
+ * [#] means 1 (as there's only one)
+ */
+ case NUM_COUNT:
+ count_virtual:
+ ret = talloc_strdup(ctx, "1");
+ goto finish;
+
+ /*
+ * [0] is fine (get the first instance)
+ */
+ case 0:
+ break;
+ }
+ goto print;
+ }
+
+do_print:
+ switch (vpt->tmpl_num) {
+ /*
+ * Return a count of the VPs.
+ */
+ case NUM_COUNT:
+ {
+ int count = 0;
+
+ for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
+ vp;
+ vp = tmpl_cursor_next(&cursor, vpt)) count++;
+
+ return talloc_typed_asprintf(ctx, "%d", count);
+ }
+
+
+ /*
+ * Concatenate all values together,
+ * separated by commas.
+ */
+ case NUM_ALL:
+ {
+ char *p, *q;
+
+ if (!fr_cursor_current(&cursor)) return NULL;
+ p = vp_aprints_value(ctx, vp, quote);
+ if (!p) return NULL;
+
+ while ((vp = tmpl_cursor_next(&cursor, vpt)) != NULL) {
+ q = vp_aprints_value(ctx, vp, quote);
+ if (!q) return NULL;
+ p = talloc_strdup_append(p, concat);
+ p = talloc_strdup_append(p, q);
+ }
+
+ return p;
+ }
+
+ default:
+ /*
+ * The cursor was set to the correct
+ * position above by tmpl_cursor_init.
+ */
+ vp = fr_cursor_current(&cursor);
+ break;
+ }
+
+ if (!vp) {
+ if (return_null) return NULL;
+ return vp_aprints_type(ctx, vpt->tmpl_da->type);
+ }
+
+print:
+ ret = vp_aprints_value(ctx, vp, quote);
+
+finish:
+ talloc_free(virtual);
+ return ret;
+}
+
+#ifdef DEBUG_XLAT
+static const char xlat_spaces[] = " ";
+#endif
+
+static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
+ xlat_escape_t escape, void *escape_ctx,
+#ifndef DEBUG_XLAT
+ UNUSED
+#endif
+ int lvl)
+{
+ ssize_t rcode;
+ char *str = NULL, *child;
+ char const *p;
+
+ XLAT_DEBUG("%.*sxlat aprint %d %s", lvl, xlat_spaces, node->type, node->fmt);
+
+ switch (node->type) {
+ /*
+ * Don't escape this.
+ */
+ case XLAT_LITERAL:
+ XLAT_DEBUG("%.*sxlat_aprint LITERAL", lvl, xlat_spaces);
+ return talloc_typed_strdup(ctx, node->fmt);
+
+ /*
+ * Do a one-character expansion.
+ */
+ case XLAT_PERCENT:
+ {
+ char *nl;
+ size_t freespace = 256;
+ struct tm ts;
+ time_t when;
+ int usec;
+
+ XLAT_DEBUG("%.*sxlat_aprint PERCENT", lvl, xlat_spaces);
+
+ str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
+ p = node->fmt;
+
+ when = request->timestamp;
+ usec = 0;
+ if (request->packet) {
+ when = request->packet->timestamp.tv_sec;
+ usec = request->packet->timestamp.tv_usec;
+ }
+
+ switch (*p) {
+ case '%':
+ str[0] = '%';
+ str[1] = '\0';
+ break;
+
+ case 'c': /* current epoch time seconds */
+ snprintf(str, freespace, "%" PRIu64, (uint64_t) time(NULL));
+ break;
+
+ case 'd': /* request day */
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%d", &ts);
+ break;
+
+ case 'e': /* request second */
+ if (!localtime_r(&when, &ts)) goto error;
+
+ snprintf(str, freespace, "%d", ts.tm_sec);
+ break;
+
+ case 'l': /* request timestamp */
+ snprintf(str, freespace, "%lu",
+ (unsigned long) when);
+ break;
+
+ case 'm': /* request month */
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%m", &ts);
+ break;
+
+ case 'n': /* Request Number*/
+ snprintf(str, freespace, "%u", request->number);
+ break;
+
+ case 't': /* request timestamp */
+ CTIME_R(&when, str, freespace);
+ nl = strchr(str, '\n');
+ if (nl) *nl = '\0';
+ break;
+
+ case 'C': /* current epoch time microseconds */
+ {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ snprintf(str, freespace, "%" PRIu64, (uint64_t) tv.tv_usec);
+ }
+ break;
+
+ case 'D': /* request date */
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%Y%m%d", &ts);
+ break;
+
+ case 'G': /* request minute */
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%M", &ts);
+ break;
+
+ case 'H': /* request hour */
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%H", &ts);
+ break;
+
+ case 'I': /* Request ID */
+ if (request->packet) {
+ snprintf(str, freespace, "%i", request->packet->id);
+ }
+ break;
+
+ case 'M': /* request microsecond component */
+ snprintf(str, freespace, "%06u", (unsigned int) usec);
+ break;
+
+ case 'S': /* request timestamp in SQL format*/
+ if (!localtime_r(&when, &ts)) goto error;
+ strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
+ break;
+
+ case 'T': /* request timestamp */
+ if (!localtime_r(&when, &ts)) goto error;
+ nl = str + strftime(str, freespace, "%Y-%m-%d-%H.%M.%S", &ts);
+ rad_assert(((str + freespace) - nl) >= 8);
+ snprintf(nl, (str + freespace) - nl, ".%06d", usec);
+ break;
+
+ case 'Y': /* request year */
+ if (!localtime_r(&when, &ts)) {
+ error:
+ REDEBUG("Failed converting packet timestamp to localtime: %s", fr_syserror(errno));
+ talloc_free(str);
+ return NULL;
+ }
+ strftime(str, freespace, "%Y", &ts);
+ break;
+
+ case 'v': /* Version of code */
+ RWDEBUG("%%v is deprecated and will be removed. Use ${version.freeradius-server}");
+ snprintf(str, freespace, "%s", radiusd_version_short);
+ break;
+
+ default:
+ rad_assert(0 == 1);
+ break;
+ }
+ }
+ break;
+
+ case XLAT_ATTRIBUTE:
+ XLAT_DEBUG("%.*sxlat_aprint ATTRIBUTE", lvl, xlat_spaces);
+
+ /*
+ * Some attributes are virtual <sigh>
+ */
+ str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true, ",");
+ if (str) {
+ XLAT_DEBUG("%.*sEXPAND attr %s", lvl, xlat_spaces, node->attr.tmpl_da->name);
+ XLAT_DEBUG("%.*s ---> %s", lvl ,xlat_spaces, str);
+ }
+ break;
+
+ case XLAT_VIRTUAL:
+ XLAT_DEBUG("xlat_aprint VIRTUAL");
+ str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
+ rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 2048);
+ if (rcode < 0) {
+ talloc_free(str);
+ return NULL;
+ }
+ RDEBUG2("EXPAND %s", node->xlat->name);
+ RDEBUG2(" --> %s", str);
+
+ /*
+ * Resize the buffer to the correct size.
+ */
+ if (rcode == 0) {
+ talloc_free(str);
+ str = talloc_strdup(ctx, "");
+ } else if (rcode < 2047) {
+ child = talloc_memdup(ctx, str, rcode + 1);
+ talloc_free(str);
+ str = child;
+ }
+ break;
+
+ case XLAT_MODULE:
+ XLAT_DEBUG("xlat_aprint MODULE");
+
+ if (node->child) {
+ if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
+ return NULL;
+ }
+
+ XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
+ } else {
+ XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
+ child = talloc_typed_strdup(ctx, "");
+ }
+
+ XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
+
+ /*
+ * Smash \n --> CR.
+ *
+ * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string.
+ *
+ * This is really the reverse of fr_prints().
+ */
+ if (cf_new_escape && *child) {
+ ssize_t slen;
+ PW_TYPE type;
+ value_data_t data;
+
+ type = PW_TYPE_STRING;
+ slen = value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"');
+ if (slen <= 0) {
+ talloc_free(child);
+ return NULL;
+ }
+
+ talloc_free(child);
+ child = data.ptr;
+
+ } else {
+ char *q;
+
+ p = q = child;
+ while (*p) {
+ if (*p == '\\') switch (p[1]) {
+ default:
+ *(q++) = p[1];
+ p += 2;
+ continue;
+
+ case 'n':
+ *(q++) = '\n';
+ p += 2;
+ continue;
+
+ case 't':
+ *(q++) = '\t';
+ p += 2;
+ continue;
+ }
+
+ *(q++) = *(p++);
+ }
+ *q = '\0';
+ }
+
+ str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
+ *str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */
+
+ rcode = node->xlat->func(node->xlat->instance, request, child, str, 2048);
+ talloc_free(child);
+ if (rcode < 0) {
+ talloc_free(str);
+ return NULL;
+ }
+ break;
+
+#ifdef HAVE_REGEX
+ case XLAT_REGEX:
+ XLAT_DEBUG("%.*sxlat_aprint REGEX", lvl, xlat_spaces);
+ if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
+
+ break;
+#endif
+
+ case XLAT_ALTERNATE:
+ XLAT_DEBUG("%.*sxlat_aprint ALTERNATE", lvl, xlat_spaces);
+ rad_assert(node->child != NULL);
+ rad_assert(node->alternate != NULL);
+
+ /*
+ * Call xlat_process recursively. The child /
+ * alternate nodes may have "next" pointers, and
+ * those need to be expanded.
+ */
+ if (xlat_process(&str, request, node->child, escape, escape_ctx) > 0) {
+ XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
+ } else {
+ (void) xlat_process(&str, request, node->alternate, escape, escape_ctx);
+ XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
+ }
+ break;
+ }
+
+ /*
+ * If there's no data, return that, instead of an empty string.
+ */
+ if (str && !str[0]) {
+ talloc_free(str);
+ return NULL;
+ }
+
+ /*
+ * Escape the non-literals we found above.
+ */
+ if (str && escape) {
+ size_t len;
+ char *escaped;
+
+ len = talloc_array_length(str) * 3;
+
+ escaped = talloc_array(ctx, char, len);
+ escape(request, escaped, len, str, escape_ctx);
+ talloc_free(str);
+ str = escaped;
+ }
+
+ return str;
+}
+
+
+static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
+ xlat_escape_t escape, void *escape_ctx)
+{
+ int i, list;
+ size_t total;
+ char **array, *answer;
+ xlat_exp_t const *node;
+
+ *out = NULL;
+
+ /*
+ * There are no nodes to process, so the result is a zero
+ * length string.
+ */
+ if (!head) {
+ *out = talloc_zero_array(request, char, 1);
+ return 0;
+ }
+
+ /*
+ * Hack for speed. If it's one expansion, just allocate
+ * that and return, instead of allocating an intermediary
+ * array.
+ */
+ if (!head->next) {
+ /*
+ * Pass the MAIN escape function. Recursive
+ * calls will call node-specific escape
+ * functions.
+ */
+ answer = xlat_aprint(request, request, head, escape, escape_ctx, 0);
+ if (!answer) {
+ *out = talloc_zero_array(request, char, 1);
+ return 0;
+ }
+ *out = answer;
+ return strlen(answer);
+ }
+
+ list = 0; /* FIXME: calculate this once */
+ for (node = head; node != NULL; node = node->next) {
+ list++;
+ }
+
+ array = talloc_array(request, char *, list);
+ if (!array) return -1;
+
+ for (node = head, i = 0; node != NULL; node = node->next, i++) {
+ array[i] = xlat_aprint(array, request, node, escape, escape_ctx, 0); /* may be NULL */
+ }
+
+ total = 0;
+ for (i = 0; i < list; i++) {
+ if (array[i]) total += strlen(array[i]); /* FIXME: calculate strlen once */
+ }
+
+ if (!total) {
+ talloc_free(array);
+ *out = talloc_zero_array(request, char, 1);
+ return 0;
+ }
+
+ answer = talloc_array(request, char, total + 1);
+
+ total = 0;
+ for (i = 0; i < list; i++) {
+ size_t len;
+
+ if (array[i]) {
+ len = strlen(array[i]);
+ memcpy(answer + total, array[i], len);
+ total += len;
+ }
+ }
+ answer[total] = '\0';
+ talloc_free(array); /* and child entries */
+
+ *out = answer;
+ return total;
+}
+
+
+/** Replace %whatever in a string.
+ *
+ * See 'doc/configuration/variables.rst' for more information.
+ *
+ * @param[out] out Where to write pointer to output buffer.
+ * @param[in] outlen Size of out.
+ * @param[in] request current request.
+ * @param[in] node the xlat structure to expand
+ * @param[in] escape function to escape final value e.g. SQL quoting.
+ * @param[in] escape_ctx pointer to pass to escape function.
+ * @return length of string written @bug should really have -1 for failure
+ */
+static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
+ xlat_escape_t escape, void *escape_ctx)
+{
+ char *buff;
+ ssize_t len;
+
+ rad_assert(node != NULL);
+
+ len = xlat_process(&buff, request, node, escape, escape_ctx);
+ if ((len < 0) || !buff) {
+ rad_assert(buff == NULL);
+ if (*out) *out[0] = '\0';
+ return len;
+ }
+
+ len = strlen(buff);
+
+ /*
+ * If out doesn't point to an existing buffer
+ * copy the pointer to our buffer over.
+ */
+ if (!*out) {
+ *out = buff;
+ return len;
+ }
+
+ /*
+ * Otherwise copy the malloced buffer to the fixed one.
+ */
+ strlcpy(*out, buff, outlen);
+ talloc_free(buff);
+ return len;
+}
+
+static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
+ xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
+
+/** Replace %whatever in a string.
+ *
+ * See 'doc/configuration/variables.rst' for more information.
+ *
+ * @param[out] out Where to write pointer to output buffer.
+ * @param[in] outlen Size of out.
+ * @param[in] request current request.
+ * @param[in] fmt string to expand.
+ * @param[in] escape function to escape final value e.g. SQL quoting.
+ * @param[in] escape_ctx pointer to pass to escape function.
+ * @return length of string written @bug should really have -1 for failure
+ */
+static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
+ xlat_escape_t escape, void *escape_ctx)
+{
+ ssize_t len;
+ xlat_exp_t *node;
+
+ /*
+ * Give better errors than the old code.
+ */
+ len = xlat_tokenize_request(request, fmt, &node);
+ if (len == 0) {
+ if (*out) {
+ *out[0] = '\0';
+ } else {
+ *out = talloc_zero_array(request, char, 1);
+ }
+ return 0;
+ }
+
+ if (len < 0) {
+ if (*out) *out[0] = '\0';
+ return -1;
+ }
+
+ len = xlat_expand_struct(out, outlen, request, node, escape, escape_ctx);
+ talloc_free(node);
+
+ RDEBUG2("EXPAND %s", fmt);
+ RDEBUG2(" --> %s", *out);
+
+ return len;
+}
+
+/** Try to convert an xlat to a tmpl for efficiency
+ *
+ * @param ctx to allocate new vp_tmpl_t in.
+ * @param node to convert.
+ * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
+ */
+vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
+{
+ vp_tmpl_t *vpt;
+
+ if (node->next || (node->type != XLAT_ATTRIBUTE) || (node->attr.type != TMPL_TYPE_ATTR)) return NULL;
+
+ /*
+ * Concat means something completely different as an attribute reference
+ * Count isn't implemented.
+ */
+ if ((node->attr.tmpl_num == NUM_COUNT) || (node->attr.tmpl_num == NUM_ALL)) return NULL;
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, node->fmt, -1);
+ if (!vpt) return NULL;
+ memcpy(&vpt->data, &node->attr.data, sizeof(vpt->data));
+
+ VERIFY_TMPL(vpt);
+
+ return vpt;
+}
+
+/** Try to convert attr tmpl to an xlat for &attr[*] and artificially constructing expansions
+ *
+ * @param ctx to allocate new xlat_expt_t in.
+ * @param vpt to convert.
+ * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
+ */
+xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt)
+{
+ xlat_exp_t *node;
+
+ if (vpt->type != TMPL_TYPE_ATTR) return NULL;
+
+ node = talloc_zero(ctx, xlat_exp_t);
+ node->type = XLAT_ATTRIBUTE;
+ node->fmt = talloc_bstrndup(node, vpt->name, vpt->len);
+ tmpl_init(&node->attr, TMPL_TYPE_ATTR, node->fmt, talloc_array_length(node->fmt) - 1);
+ memcpy(&node->attr.data, &vpt->data, sizeof(vpt->data));
+
+ return node;
+}
+
+ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
+{
+ return xlat_expand(&out, outlen, request, fmt, escape, ctx);
+}
+
+ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
+{
+ return xlat_expand_struct(&out, outlen, request, xlat, escape, ctx);
+}
+
+ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
+{
+ *out = NULL;
+ return xlat_expand(out, 0, request, fmt, escape, ctx);
+}
+
+ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
+{
+ *out = NULL;
+ return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
+}
diff --git a/src/mkinstalldirs b/src/mkinstalldirs
new file mode 100755
index 0000000..bd1c963
--- /dev/null
+++ b/src/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/src/modules/.gitignore b/src/modules/.gitignore
new file mode 100644
index 0000000..c9b5839
--- /dev/null
+++ b/src/modules/.gitignore
@@ -0,0 +1,3 @@
+rlm_winbind
+rlm_sigtran
+*_ext
diff --git a/src/modules/all.mk b/src/modules/all.mk
new file mode 100644
index 0000000..e1eafcc
--- /dev/null
+++ b/src/modules/all.mk
@@ -0,0 +1,28 @@
+#
+# Changes the behaviour of autoconf.h to undef definitions that would conflict
+# with module config.h files.
+#
+CFLAGS += -DIS_MODULE=1
+
+#
+# If we haven't run configure, ignore the modules which require it.
+# Otherwise, load in all of the module makefiles, including ones
+# which have not yet been configured. We do the "sort" to remove
+# duplicates.
+#
+ifeq "$(CONFIGURE_ARGS)" ""
+SUBMAKEFILES := $(wildcard ${top_srcdir}/src/modules/rlm_*/all.mk)
+else
+SUBMAKEFILES := $(sort $(wildcard ${top_srcdir}/src/modules/rlm_*/all.mk) \
+ $(patsubst %.in,%,$(wildcard ${top_srcdir}/src/modules/rlm_*/all.mk.in)))
+endif
+
+SUBMAKEFILES += $(wildcard ${top_srcdir}/src/modules/proto_*/all.mk)
+
+ifeq "$(MAKECMDGOALS)" "reconfig"
+src/modules/%/configure: src/modules/%/configure.ac $(wildcard $(top_builddir)/m4/*.m4)
+ @echo AUTOCONF $(dir $@)
+ @cd $(dir $@) && \
+ $(ACLOCAL) --force -I $(top_builddir) -I $(top_builddir)/m4 && \
+ $(AUTOCONF) --force
+endif
diff --git a/src/modules/proto_dhcp/README.md b/src/modules/proto_dhcp/README.md
new file mode 100644
index 0000000..16a29a9
--- /dev/null
+++ b/src/modules/proto_dhcp/README.md
@@ -0,0 +1,9 @@
+# proto_dhcp
+## Metadata
+<dl>
+ <dt>category</dt><dd>protocols</dd>
+</dl>
+
+## Summary
+
+Implements the DHCP protocol for IPv4.
diff --git a/src/modules/proto_dhcp/all.mk b/src/modules/proto_dhcp/all.mk
new file mode 100644
index 0000000..12242b6
--- /dev/null
+++ b/src/modules/proto_dhcp/all.mk
@@ -0,0 +1,3 @@
+ifneq "$(WITH_DHCP)" "no"
+SUBMAKEFILES := libfreeradius-dhcp.mk proto_dhcp.mk rlm_dhcp.mk dhcpclient.mk
+endif
diff --git a/src/modules/proto_dhcp/dhcp.c b/src/modules/proto_dhcp/dhcp.c
new file mode 100644
index 0000000..f922d63
--- /dev/null
+++ b/src/modules/proto_dhcp/dhcp.c
@@ -0,0 +1,2268 @@
+/*
+ * dhcp.c Functions to send/receive dhcp packets.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/udpfromto.h>
+#include <freeradius-devel/dhcp.h>
+#include <freeradius-devel/net.h>
+
+#ifndef __MINGW32__
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef __MINGW32__
+#include <net/if_arp.h>
+#endif
+
+#define DHCP_CHADDR_LEN (16)
+#define DHCP_SNAME_LEN (64)
+#define DHCP_FILE_LEN (128)
+#define DHCP_VEND_LEN (308)
+#define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
+
+#ifndef INADDR_BROADCAST
+#define INADDR_BROADCAST INADDR_NONE
+#endif
+
+/* @todo: this is a hack */
+# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
+# define debug_pair(vp) do { if (fr_debug_lvl && fr_log_fp) { \
+ vp_print(fr_log_fp, vp); \
+ } \
+ } while(0)
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+#define ETH_HDR_SIZE 14
+#define IP_HDR_SIZE 20
+#define UDP_HDR_SIZE 8
+#define ETH_ADDR_LEN 6
+#define ETH_TYPE_IP 0x0800
+#define ETH_P_ALL 0x0003
+
+static uint8_t eth_bcast[ETH_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/* Discard raw packets which we are not interested in. Allow to trace why we discard. */
+#define DISCARD_RP(...) { \
+ if (fr_debug_lvl > 2) { \
+ fprintf(stdout, "dhcpclient: discarding received packet: "); \
+ fprintf(stdout, ## __VA_ARGS__); \
+ fprintf(stdout, "\n"); \
+ } \
+ rad_free(&packet); \
+ return NULL; \
+}
+#endif
+
+#define VENDORPEC_ADSL 3561
+
+typedef struct dhcp_packet_t {
+ uint8_t opcode;
+ uint8_t htype;
+ uint8_t hlen;
+ uint8_t hops;
+ uint32_t xid; /* 4 */
+ uint16_t secs; /* 8 */
+ uint16_t flags;
+ uint32_t ciaddr; /* 12 */
+ uint32_t yiaddr; /* 16 */
+ uint32_t siaddr; /* 20 */
+ uint32_t giaddr; /* 24 */
+ uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
+ uint8_t sname[DHCP_SNAME_LEN]; /* 44 */
+ uint8_t file[DHCP_FILE_LEN]; /* 108 */
+ uint32_t option_format; /* 236 */
+ uint8_t options[DHCP_VEND_LEN];
+} dhcp_packet_t;
+
+typedef struct dhcp_option_t {
+ uint8_t code;
+ uint8_t length;
+} dhcp_option_t;
+
+/*
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
+ * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
+ * INADDR_BROADCAST : 68 <- SERVER_IP : 67 ACK
+ */
+static char const *dhcp_header_names[] = {
+ "DHCP-Opcode",
+ "DHCP-Hardware-Type",
+ "DHCP-Hardware-Address-Length",
+ "DHCP-Hop-Count",
+ "DHCP-Transaction-Id",
+ "DHCP-Number-of-Seconds",
+ "DHCP-Flags",
+ "DHCP-Client-IP-Address",
+ "DHCP-Your-IP-Address",
+ "DHCP-Server-IP-Address",
+ "DHCP-Gateway-IP-Address",
+ "DHCP-Client-Hardware-Address",
+ "DHCP-Server-Host-Name",
+ "DHCP-Boot-Filename",
+
+ NULL
+};
+
+static char const *dhcp_message_types[] = {
+ "invalid",
+ "DHCP-Discover",
+ "DHCP-Offer",
+ "DHCP-Request",
+ "DHCP-Decline",
+ "DHCP-Ack",
+ "DHCP-NAK",
+ "DHCP-Release",
+ "DHCP-Inform",
+ "DHCP-Force-Renew",
+ "DHCP-Lease-Query",
+ "DHCP-Lease-Unassigned",
+ "DHCP-Lease-Unknown",
+ "DHCP-Lease-Active",
+ "DHCP-Bulk-Lease-Query",
+ "DHCP-Lease-Query-Done"
+};
+
+#define DHCP_MAX_MESSAGE_TYPE (sizeof(dhcp_message_types) / sizeof(dhcp_message_types[0]))
+
+static int dhcp_header_sizes[] = {
+ 1, 1, 1, 1,
+ 4, 2, 2, 4,
+ 4, 4, 4,
+ DHCP_CHADDR_LEN,
+ DHCP_SNAME_LEN,
+ DHCP_FILE_LEN
+};
+
+
+/*
+ * Some clients silently ignore responses less than 300 bytes.
+ */
+#define MIN_PACKET_SIZE (244)
+#define DEFAULT_PACKET_SIZE (300)
+#define MAX_PACKET_SIZE (1500 - 40)
+
+#define DHCP_OPTION_FIELD (0)
+#define DHCP_FILE_FIELD (1)
+#define DHCP_SNAME_FIELD (2)
+
+static uint8_t *dhcp_get_option(dhcp_packet_t *packet, size_t packet_size,
+ unsigned int option)
+{
+ int overload = 0;
+ int field = DHCP_OPTION_FIELD;
+ size_t where, size;
+ uint8_t *data;
+
+ where = 0;
+ size = packet_size - offsetof(dhcp_packet_t, options);
+ data = &packet->options[where];
+
+ while (where < size) {
+ if (data[0] == 0) { /* padding */
+ where++;
+ continue;
+ }
+
+ if (data[0] == 255) { /* end of options */
+ if ((field == DHCP_OPTION_FIELD) &&
+ (overload & DHCP_FILE_FIELD)) {
+ data = packet->file;
+ where = 0;
+ size = sizeof(packet->file);
+ field = DHCP_FILE_FIELD;
+ continue;
+
+ } else if ((field == DHCP_FILE_FIELD) &&
+ (overload & DHCP_SNAME_FIELD)) {
+ data = packet->sname;
+ where = 0;
+ size = sizeof(packet->sname);
+ field = DHCP_SNAME_FIELD;
+ continue;
+ }
+
+ return NULL;
+ }
+
+ /*
+ * We MUST have a real option here.
+ */
+ if ((where + 2) > size) {
+ fr_strerror_printf("Options overflow field at %u",
+ (unsigned int) (data - (uint8_t *) packet));
+ return NULL;
+ }
+
+ if ((where + 2 + data[1]) > size) {
+ fr_strerror_printf("Option length overflows field at %u",
+ (unsigned int) (data - (uint8_t *) packet));
+ return NULL;
+ }
+
+ if (data[0] == option) return data;
+
+ if (data[0] == 52) { /* overload sname and/or file */
+ overload = data[3];
+ }
+
+ where += data[1] + 2;
+ data += data[1] + 2;
+ }
+
+ return NULL;
+}
+
+/*
+ * DHCPv4 is only for IPv4. Broadcast only works if udpfromto is
+ * defined.
+ */
+RADIUS_PACKET *fr_dhcp_recv(int sockfd)
+{
+ uint32_t magic;
+ struct sockaddr_storage src;
+ struct sockaddr_storage dst;
+ socklen_t sizeof_src;
+ socklen_t sizeof_dst;
+ RADIUS_PACKET *packet;
+ uint16_t port;
+ uint8_t *code;
+ ssize_t data_len;
+
+ packet = rad_alloc(NULL, false);
+ if (!packet) {
+ fr_strerror_printf("Failed allocating packet");
+ return NULL;
+ }
+
+ packet->data = talloc_zero_array(packet, uint8_t, MAX_PACKET_SIZE);
+ if (!packet->data) {
+ fr_strerror_printf("Out of memory");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ packet->sockfd = sockfd;
+ sizeof_src = sizeof(src);
+#ifdef WITH_UDPFROMTO
+ sizeof_dst = sizeof(dst);
+ data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
+ (struct sockaddr *)&src, &sizeof_src,
+ (struct sockaddr *)&dst, &sizeof_dst);
+#else
+ data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
+ (struct sockaddr *)&src, &sizeof_src);
+#endif
+
+ if (data_len <= 0) {
+ fr_strerror_printf("Failed reading DHCP socket: %s", fr_syserror(errno));
+ rad_free(&packet);
+ return NULL;
+ }
+
+ packet->data_len = data_len;
+ if (packet->data_len < MIN_PACKET_SIZE) {
+ fr_strerror_printf("DHCP packet is too small (%zu < %d)",
+ packet->data_len, MIN_PACKET_SIZE);
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if (packet->data_len > MAX_PACKET_SIZE) {
+ fr_strerror_printf("DHCP packet is too large (%zx > %d)",
+ packet->data_len, MAX_PACKET_SIZE);
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if (packet->data[1] > 1) {
+ fr_strerror_printf("DHCP can only receive ethernet requests, not type %02x",
+ packet->data[1]);
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if ((packet->data[2] != 0) && (packet->data[2] != 6)) {
+ fr_strerror_printf("Ethernet HW length is wrong length %d",
+ packet->data[2]);
+ rad_free(&packet);
+ return NULL;
+ }
+
+ memcpy(&magic, packet->data + 236, 4);
+ magic = ntohl(magic);
+ if (magic != DHCP_OPTION_MAGIC_NUMBER) {
+ fr_strerror_printf("Cannot do BOOTP");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * Create unique keys for the packet.
+ */
+ memcpy(&magic, packet->data + 4, 4);
+ packet->id = ntohl(magic);
+
+ code = dhcp_get_option((dhcp_packet_t *) packet->data,
+ packet->data_len, PW_DHCP_MESSAGE_TYPE);
+ if (!code) {
+ fr_strerror_printf("No message-type option was found in the packet");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if ((code[1] < 1) || (code[2] == 0) || (code[2] >= DHCP_MAX_MESSAGE_TYPE)) {
+ fr_strerror_printf("Unknown value %d for message-type option", code[2]);
+ rad_free(&packet);
+ return NULL;
+ }
+
+ packet->code = code[2] | PW_DHCP_OFFSET;
+
+ /*
+ * Create a unique vector from the xid and the client
+ * hardware address. This is a hack for the RADIUS
+ * infrastructure in the rest of the server.
+ * It is also used for de-duplicating DHCP packets
+ */
+ memcpy(packet->vector, packet->data + 4, 4); /* xid */
+ memcpy(packet->vector + 4, packet->data + 24, 4); /* giaddr */
+ packet->vector[8] = packet->code & 0xff; /* message type */
+ memcpy(packet->vector + 9, packet->data + 28, 6); /* chaddr is always 6 for us */
+
+ /*
+ * FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
+ * FIXME: for OFFER / ACK : src_port = dst_port - 1
+ */
+
+ sizeof_dst = sizeof(dst);
+
+#ifndef WITH_UDPFROMTO
+ /*
+ * This should never fail...
+ */
+ if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
+ fr_strerror_printf("getsockname failed: %s", fr_syserror(errno));
+ rad_free(&packet);
+ return NULL;
+ }
+#endif
+
+ fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
+ packet->dst_port = port;
+
+ fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
+ packet->src_port = port;
+
+ if (fr_debug_lvl > 1) {
+ char type_buf[64];
+ char const *name = type_buf;
+ char src_ip_buf[256], dst_ip_buf[256];
+
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ snprintf(type_buf, sizeof(type_buf), "%d",
+ packet->code - PW_DHCP_OFFSET);
+ }
+
+ DEBUG("Received %s of Id %08x from %s:%d to %s:%d\n",
+ name, (unsigned int) packet->id,
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
+ }
+
+ return packet;
+}
+
+
+/*
+ * Send a DHCP packet.
+ */
+int fr_dhcp_send(RADIUS_PACKET *packet)
+{
+ struct sockaddr_storage dst;
+ socklen_t sizeof_dst;
+#ifdef WITH_UDPFROMTO
+ struct sockaddr_storage src;
+ socklen_t sizeof_src;
+
+ fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
+ &src, &sizeof_src);
+#endif
+
+ fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
+ &dst, &sizeof_dst);
+
+ if (packet->data_len == 0) {
+ fr_strerror_printf("No data to send");
+ return -1;
+ }
+
+ if (fr_debug_lvl > 1) {
+ char type_buf[64];
+ char const *name = type_buf;
+#ifdef WITH_UDPFROMTO
+ char src_ip_buf[INET6_ADDRSTRLEN];
+#endif
+ char dst_ip_buf[INET6_ADDRSTRLEN];
+
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ snprintf(type_buf, sizeof(type_buf), "%d",
+ packet->code - PW_DHCP_OFFSET);
+ }
+
+ DEBUG(
+#ifdef WITH_UDPFROMTO
+ "Sending %s Id %08x from %s:%d to %s:%d\n",
+#else
+ "Sending %s Id %08x to %s:%d\n",
+#endif
+ name, (unsigned int) packet->id,
+#ifdef WITH_UDPFROMTO
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+#endif
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
+ }
+
+#ifndef WITH_UDPFROMTO
+ /*
+ * Assume that the packet is encoded before sending it.
+ */
+ return sendto(packet->sockfd, packet->data, packet->data_len, 0,
+ (struct sockaddr *)&dst, sizeof_dst);
+#else
+
+ return sendfromto(packet->sockfd, packet->data, packet->data_len, 0,
+ (struct sockaddr *)&src, sizeof_src,
+ (struct sockaddr *)&dst, sizeof_dst);
+#endif
+}
+
+static int fr_dhcp_attr2vp(TALLOC_CTX *ctx, VALUE_PAIR **vp_p, uint8_t const *p, size_t alen);
+
+/** Returns the number of array members for arrays with fixed element sizes
+ *
+ */
+static int fr_dhcp_array_members(size_t *len, DICT_ATTR const *da)
+{
+ int num_entries = 1;
+
+ if (!len || !da) return -1;
+
+ /*
+ * Could be an array of bytes, integers, etc.
+ */
+ if (da->flags.array) switch (da->type) {
+ case PW_TYPE_BYTE:
+ num_entries = *len;
+ *len = 1;
+ break;
+
+ case PW_TYPE_SHORT: /* ignore any trailing data */
+ num_entries = *len >> 1;
+ *len = 2;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE: /* ignore any trailing data */
+ num_entries = *len >> 2;
+ *len = 4;
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ num_entries = *len >> 4;
+ *len = 16;
+ break;
+
+ default:
+ break;
+ }
+
+ return num_entries;
+}
+
+/** RFC 4243 Vendor Specific Suboptions
+ *
+ * Vendor specific suboptions are in the format.
+ @verbatim
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Enterprise Number 0 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Len 0 | /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ / Suboption Data 0 /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Enterprise Number n |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Len n | /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ / Suboption Data n /
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ @endverbatim
+ *
+ * So although the vendor is identified, the format of the data isn't
+ * specified so we can't actually resolve the suboption to an
+ * attribute. For now, we just convert it to an attribute of
+ * DHCP-Vendor-Specific-Information with raw octets contents.
+ */
+
+
+/** Decode DHCP suboptions
+ *
+ * @param[in,out] tlv to decode. *tlv will be set to the head of the list of suboptions and original will be freed.
+ * @param[in] ctx context to alloc new attributes in.
+ * @param[in] data to parse.
+ * @param[in] len length of data to parse.
+ */
+static int fr_dhcp_decode_suboption(TALLOC_CTX *ctx, VALUE_PAIR **tlv, uint8_t const *data, size_t len)
+{
+ uint8_t const *p, *q;
+ VALUE_PAIR *head, *vp;
+ vp_cursor_t cursor;
+
+ /*
+ * TLV must already point to a VALUE_PAIR.
+ */
+ VERIFY_VP(*tlv);
+
+ /*
+ * Take a pass at parsing it.
+ */
+ p = data;
+ q = data + len;
+ while (p < q) {
+ /*
+ * RFC 3046 is very specific about not allowing termination
+ * with a 255 sub-option. But it's required for decoding
+ * option 43, and vendors will probably screw it up
+ * anyway.
+ */
+ if (*p == 0) {
+ p++;
+ continue;
+ }
+ if (*p == 255) {
+ q--;
+ break;
+ }
+
+ /*
+ * Check if reading length would take us past the end of the buffer
+ */
+ if (++p >= q) goto malformed;
+ p += p[0];
+
+ /*
+ * Check if length > the length of the buffer we have left
+ */
+ if (p >= q) goto malformed;
+ p++;
+ }
+
+ /*
+ * Got here... must be well formed.
+ */
+ head = NULL;
+ fr_cursor_init(&cursor, &head);
+
+ p = data;
+ while (p < q) {
+ uint8_t const *a_p;
+ size_t a_len;
+ int num_entries, i;
+
+ DICT_ATTR const *da;
+ uint32_t attr;
+
+ /*
+ * Not enough room for the option header, it's a
+ * bad packet.
+ */
+ if ((p + 2) > (data + len)) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ /*
+ * Not enough room for the option header + data,
+ * it's a bad packet.
+ */
+ if ((p + 2 + p[1]) > (data + len)) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ /*
+ * The initial OID string looks like:
+ * <iana>.0
+ *
+ * If <iana>.0 is type TLV then we attempt to decode its contents as more
+ * DHCP suboptions, which gives us:
+ * <iana>.<attr>
+ *
+ * If <iana>.0 is not defined in the dictionary or is type octets, we leave
+ * the attribute as is.
+ */
+ attr = (*tlv)->da->attr ? ((*tlv)->da->attr | (p[0] << 8)) : p[0];
+
+ /*
+ * Use the vendor of the parent TLV which is not necessarily
+ * DHCP_MAGIC_VENDOR.
+ *
+ * Note: This does not deal with dictionary numbering clashes. If
+ * the vendor uses different numbers for DHCP suboptions and RADIUS
+ * attributes then it's time to break out %{hex:} and regular
+ * expressions.
+ */
+ da = dict_attrbyvalue(attr, (*tlv)->da->vendor);
+ if (!da) {
+ da = dict_unknown_afrom_fields(ctx, attr, (*tlv)->da->vendor);
+ if (!da) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ }
+
+ a_len = p[1];
+ a_p = p + 2;
+ num_entries = fr_dhcp_array_members(&a_len, da);
+ for (i = 0; i < num_entries; i++) {
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ vp->op = T_OP_EQ;
+ fr_pair_steal(ctx, vp); /* for unknown attributes hack */
+
+ if (fr_dhcp_attr2vp(ctx, &vp, a_p, a_len) < 0) {
+ dict_attr_free(&da);
+ fr_pair_list_free(&head);
+ goto malformed;
+ }
+ fr_cursor_merge(&cursor, vp);
+
+ a_p += a_len;
+ }
+
+ dict_attr_free(&da); /* for unknown attributes hack */
+
+ p += 2 + p[1]; /* code (1) + len (1) + suboption len (n)*/
+ }
+
+ /*
+ * The caller allocated a TLV, if decoding it generated
+ * additional attributes, we now need to free it, and write
+ * the HEAD of our new list of attributes in its place.
+ */
+ if (head) {
+ vp_cursor_t tlv_cursor;
+
+ /*
+ * Free the old TLV attribute
+ */
+ TALLOC_FREE(*tlv);
+
+ /*
+ * Cursor not necessary but means we don't have to set
+ * ->next directly.
+ */
+ fr_cursor_init(&tlv_cursor, tlv);
+ fr_cursor_merge(&tlv_cursor, head);
+ }
+
+ return 0;
+
+malformed:
+ fr_pair_to_unknown(*tlv);
+ fr_pair_value_memcpy(*tlv, data, len);
+
+ return 0;
+}
+
+/*
+ * Decode ONE value into a VP
+ */
+static int fr_dhcp_attr2vp(TALLOC_CTX *ctx, VALUE_PAIR **vp_p, uint8_t const *data, size_t len)
+{
+ VALUE_PAIR *vp = *vp_p;
+ VERIFY_VP(vp);
+
+ switch (vp->da->type) {
+ case PW_TYPE_BYTE:
+ if (len != 1) goto raw;
+ vp->vp_byte = data[0];
+ break;
+
+ case PW_TYPE_SHORT:
+ if (len != 2) goto raw;
+ memcpy(&vp->vp_short, data, 2);
+ vp->vp_short = ntohs(vp->vp_short);
+ break;
+
+ case PW_TYPE_INTEGER:
+ if (len != 4) goto raw;
+ memcpy(&vp->vp_integer, data, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ if (len != 4) goto raw;
+ /*
+ * Keep value in Network Order!
+ */
+ memcpy(&vp->vp_ipaddr, data, 4);
+ vp->vp_length = 4;
+ break;
+
+ /*
+ * In DHCPv4, string options which can also be arrays,
+ * have their values '\0' delimited.
+ */
+ case PW_TYPE_STRING:
+ {
+ uint8_t const *p;
+ uint8_t const *q, *end;
+ vp_cursor_t cursor;
+
+ p = data;
+ q = end = data + len;
+
+ if (!vp->da->flags.array) {
+ fr_pair_value_bstrncpy(vp, (char const *)p, q - p);
+ break;
+ }
+
+ /*
+ * Initialise the cursor as we may be inserting
+ * multiple additional VPs
+ */
+ fr_cursor_init(&cursor, vp_p);
+ while (p < end) {
+ q = memchr(p, '\0', end - p);
+ /* Malformed but recoverable */
+ if (!q) q = end;
+
+ fr_pair_value_bstrncpy(vp, (char const *)p, q - p);
+ p = q + 1;
+
+ if (p >= end) break;
+
+ /* Need another VP for the next round */
+ vp = fr_pair_afrom_da(ctx, vp->da);
+ if (!vp) {
+ fr_pair_list_free(vp_p);
+ return -1;
+ }
+ fr_cursor_insert(&cursor, vp);
+ }
+ }
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(vp->vp_ether, data, sizeof(vp->vp_ether));
+ vp->vp_length = sizeof(vp->vp_ether);
+ break;
+
+ /*
+ * Value doesn't match up with attribute type, overwrite the
+ * vp's original DICT_ATTR with an unknown one.
+ */
+ raw:
+ if (fr_pair_to_unknown(vp) < 0) return -1;
+ /* FALL-THROUGH */
+
+ case PW_TYPE_OCTETS:
+ if (len > 255) return -1;
+ fr_pair_value_memcpy(vp, data, len);
+ break;
+
+ /*
+ * For option 82 et al...
+ */
+ case PW_TYPE_TLV:
+ return fr_dhcp_decode_suboption(ctx, vp_p, data, len);
+
+ default:
+ fr_strerror_printf("Internal sanity check %d %d", vp->da->type, __LINE__);
+ return -1;
+ } /* switch over type */
+
+ vp->vp_length = len;
+ return 0;
+}
+
+/** Decode DHCP options
+ *
+ * @param[in,out] out Where to write the decoded options.
+ * @param[in] ctx context to alloc new attributes in.
+ * @param[in] data to parse.
+ * @param[in] len of data to parse.
+ */
+ssize_t fr_dhcp_decode_options(TALLOC_CTX *ctx, VALUE_PAIR **out, uint8_t const *data, size_t len)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ uint8_t const *p, *q;
+
+ *out = NULL;
+ fr_cursor_init(&cursor, out);
+
+ /*
+ * FIXME: This should also check sname && file fields.
+ * See the dhcp_get_option() function above.
+ */
+ p = data;
+ q = data + len;
+ while (p < q) {
+ uint8_t const *a_p;
+ size_t a_len;
+ int num_entries, i;
+
+ DICT_ATTR const *da;
+
+ if (*p == 0) { /* 0x00 - Padding option */
+ p++;
+ continue;
+ }
+
+ if (*p == 255) { /* 0xff - End of options signifier */
+ break;
+ }
+
+ if ((p + 2) > q) break;
+
+ a_len = p[1];
+ a_p = p + 2;
+
+ /*
+ * Ensure we've not been given a bad length value
+ */
+ if ((a_p + a_len) > q) {
+ fr_strerror_printf("Length field value of option %u is incorrect. "
+ "Got %u bytes, expected <= %zu bytes", p[0], p[1], q - a_p);
+ fr_pair_list_free(out);
+ return -1;
+ }
+
+ /*
+ * Unknown attribute, create an octets type
+ * attribute with the contents of the sub-option.
+ */
+ da = dict_attrbyvalue(p[0], DHCP_MAGIC_VENDOR);
+ if (!da) {
+ da = dict_unknown_afrom_fields(ctx, p[0], DHCP_MAGIC_VENDOR);
+ if (!da) {
+ fr_pair_list_free(out);
+ return -1;
+ }
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_pair_list_free(out);
+ return -1;
+ }
+ fr_pair_value_memcpy(vp, a_p, a_len);
+ fr_cursor_insert(&cursor, vp);
+
+ goto next;
+ }
+
+ /*
+ * Decode ADSL Forum vendor-specific options.
+ */
+ if ((p[0] == 125) && (p[1] > 6) && (p[2] == 0) && (p[3] == 0) && (p[4] == 0x0d) && (p[5] == 0xe9) &&
+ (p[6] + 5 == p[1])) {
+ da = dict_attrbyvalue(255, VENDORPEC_ADSL);
+ if (!da) goto normal;
+
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_pair_list_free(out);
+ return -1;
+ }
+
+ (void) fr_dhcp_decode_suboption(ctx, &vp, p + 7, p[6]);
+ if (vp) fr_cursor_merge(&cursor, vp);
+ goto next;
+ }
+
+ normal:
+ /*
+ * Array type sub-option create a new VALUE_PAIR
+ * for each array element.
+ */
+ num_entries = fr_dhcp_array_members(&a_len, da);
+ for (i = 0; i < num_entries; i++) {
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) {
+ fr_pair_list_free(out);
+ return -1;
+ }
+ vp->op = T_OP_EQ;
+
+ if (fr_dhcp_attr2vp(ctx, &vp, a_p, a_len) < 0) {
+ fr_pair_list_free(&vp);
+ fr_pair_list_free(out);
+ return -1;
+ }
+ fr_cursor_merge(&cursor, vp);
+ a_p += a_len;
+ } /* loop over array entries */
+ next:
+ p += 2 + p[1]; /* code (1) + len (1) + option len (n)*/
+ } /* loop over the entire packet */
+
+ return p - data;
+}
+
+int fr_dhcp_decode(RADIUS_PACKET *packet)
+{
+ size_t i;
+ uint8_t *p;
+ uint32_t giaddr;
+ vp_cursor_t cursor;
+ VALUE_PAIR *head = NULL, *vp;
+ VALUE_PAIR *maxms, *mtu, *netaddr;
+
+ fr_cursor_init(&cursor, &head);
+ p = packet->data;
+
+ if ((fr_debug_lvl > 2) && fr_log_fp) {
+ for (i = 0; i < packet->data_len; i++) {
+ if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", (int) i);
+ fprintf(fr_log_fp, "%02x ", packet->data[i]);
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ fprintf(fr_log_fp, "\n");
+ }
+
+ if (packet->data[1] > 1) {
+ fr_strerror_printf("Packet is not Ethernet: %u",
+ packet->data[1]);
+ return -1;
+ }
+
+ /*
+ * Decode the header.
+ */
+ for (i = 0; i < 14; i++) {
+
+ vp = fr_pair_afrom_num(packet, 256 + i, DHCP_MAGIC_VENDOR);
+ if (!vp) {
+ char buffer[256];
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+ fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
+ fr_pair_list_free(&head);
+ return -1;
+ }
+
+ /*
+ * If chaddr != 6 bytes it's probably not ethernet, and we should store
+ * it as an opaque type (octets).
+ */
+ if (i == 11) {
+ /*
+ * Skip chaddr if it doesn't exist.
+ */
+ if ((packet->data[1] == 0) || (packet->data[2] == 0)) continue;
+
+ if ((packet->data[1] == 1) && (packet->data[2] != sizeof(vp->vp_ether))) {
+ DICT_ATTR const *da = dict_unknown_afrom_fields(packet, vp->da->attr, vp->da->vendor);
+ if (!da) {
+ return -1;
+ }
+ vp->da = da;
+ }
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_BYTE:
+ vp->vp_byte = p[0];
+ vp->vp_length = 1;
+ break;
+
+ case PW_TYPE_SHORT:
+ vp->vp_short = (p[0] << 8) | p[1];
+ vp->vp_length = 2;
+ break;
+
+ case PW_TYPE_INTEGER:
+ memcpy(&vp->vp_integer, p, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ vp->vp_length = 4;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(&vp->vp_ipaddr, p, 4);
+ vp->vp_length = 4;
+ break;
+
+ case PW_TYPE_STRING:
+ /*
+ * According to RFC 2131, these are null terminated strings.
+ * We don't trust everyone to abide by the RFC, though.
+ */
+ if (*p != '\0') {
+ uint8_t *end;
+ int len;
+ end = memchr(p, '\0', dhcp_header_sizes[i]);
+ len = end ? end - p : dhcp_header_sizes[i];
+ fr_pair_value_bstrncpy(vp, p, len);
+ }
+ if (vp->vp_length == 0) fr_pair_list_free(&vp);
+ break;
+
+ case PW_TYPE_OCTETS:
+ if (packet->data[2] == 0) break;
+
+ fr_pair_value_memcpy(vp, p, packet->data[2]);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
+ vp->vp_length = sizeof(vp->vp_ether);
+ break;
+
+ default:
+ fr_strerror_printf("BAD TYPE %d", vp->da->type);
+ fr_pair_list_free(&vp);
+ break;
+ }
+ p += dhcp_header_sizes[i];
+
+ if (!vp) continue;
+
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+ }
+
+ /*
+ * Loop over the options.
+ */
+
+ /*
+ * Nothing uses tail after this call, if it does in the future
+ * it'll need to find the new tail...
+ */
+ {
+ VALUE_PAIR *options = NULL;
+ vp_cursor_t options_cursor;
+
+ if (fr_dhcp_decode_options(packet, &options, packet->data + 240, packet->data_len - 240) < 0) {
+ return -1;
+ }
+
+ if (options) {
+ for (vp = fr_cursor_init(&options_cursor, &options);
+ vp;
+ vp = fr_cursor_next(&options_cursor)) {
+ debug_pair(vp);
+ }
+ fr_cursor_merge(&cursor, options);
+ }
+ }
+
+ /*
+ * If DHCP request, set ciaddr to zero.
+ */
+
+ /*
+ * Set broadcast flag for broken vendors, but only if
+ * giaddr isn't set.
+ */
+ memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
+ if (giaddr == htonl(INADDR_ANY)) {
+ /*
+ * DHCP-Message-Type is request
+ */
+ vp = fr_pair_find_by_num(head, 53, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp && vp->vp_byte == 3) {
+ /*
+ * Vendor is "MSFT 98"
+ */
+ vp = fr_pair_find_by_num(head, 60, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp && (vp->vp_length >= 7) && (memcmp(vp->vp_octets, "MSFT 98", 7) == 0)) {
+ vp = fr_pair_find_by_num(head, 262, DHCP_MAGIC_VENDOR, TAG_ANY);
+
+ /*
+ * Reply should be broadcast.
+ */
+ if (vp) vp->vp_short |= 0x8000;
+ packet->data[10] |= 0x80;
+ }
+ }
+ }
+
+ /*
+ * Determine the address to use in looking up which subnet the
+ * client belongs to based on packet data. The sequence here
+ * is based on ISC DHCP behaviour and RFCs 3527 and 3011. We
+ * store the found address in an internal attribute of 274 -
+ * DHCP-Network-Subnet. This is stored as an IPv4 prefix
+ * with a /32 netmask allowing "closest containing subnet"
+ * matching in rlm_files
+ */
+ vp = fr_pair_afrom_num(packet, 274, DHCP_MAGIC_VENDOR);
+ /*
+ * First look for Relay-Link-Selection - option 82, suboption 5
+ */
+ netaddr = fr_pair_find_by_num(head, (82 | (5 << 8)), DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (!netaddr) {
+ /*
+ * Next try Subnet-Selection-Option - option 118
+ */
+ netaddr = fr_pair_find_by_num(head, 118, DHCP_MAGIC_VENDOR, TAG_ANY);
+ }
+ if (!netaddr) {
+ if (giaddr != htonl(INADDR_ANY)) {
+ /*
+ * Gateway address is set - use that one
+ */
+ memcpy(&vp->vp_ipv4prefix[2], packet->data + 24, 4);
+ } else {
+ /*
+ * else, store client address whatever it is
+ */
+ memcpy(&vp->vp_ipv4prefix[2], packet->data + 12, 4);
+ }
+ } else {
+ /*
+ * Store whichever address we've found from options
+ */
+ memcpy(&vp->vp_ipv4prefix[2], &netaddr->vp_ipaddr, 4);
+ }
+ /*
+ * Set the netmask to /32
+ */
+ vp->vp_ipv4prefix[0] = 0;
+ vp->vp_ipv4prefix[1] = 32;
+
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+
+ /*
+ * FIXME: Nuke attributes that aren't used in the normal
+ * header for discover/requests.
+ */
+ packet->vps = head;
+
+ /*
+ * Client can request a LARGER size, but not a smaller
+ * one. They also cannot request a size larger than MTU.
+ */
+ maxms = fr_pair_find_by_num(packet->vps, 57, DHCP_MAGIC_VENDOR, TAG_ANY);
+ mtu = fr_pair_find_by_num(packet->vps, 26, DHCP_MAGIC_VENDOR, TAG_ANY);
+
+ if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
+ fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification");
+ return -1;
+ }
+
+ if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
+ fr_strerror_printf("DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
+ maxms->vp_integer = DEFAULT_PACKET_SIZE;
+ }
+
+ if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
+ fr_strerror_printf("DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
+ maxms->vp_integer = mtu->vp_integer;
+ }
+
+ if (fr_debug_lvl) fflush(stdout);
+
+ return 0;
+}
+
+
+int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
+{
+ VALUE_PAIR const *my_a = a;
+ VALUE_PAIR const *my_b = b;
+
+ VERIFY_VP(my_a);
+ VERIFY_VP(my_b);
+
+ /*
+ * ADSL Forum vendor-specific options after others to remain grouped
+ */
+ if ((my_a->da->vendor == VENDORPEC_ADSL) && (my_b->da->vendor != VENDORPEC_ADSL)) return +1;
+ if ((my_a->da->vendor != VENDORPEC_ADSL) && (my_b->da->vendor == VENDORPEC_ADSL)) return -1;
+
+ /*
+ * DHCP-Message-Type is first, for simplicity.
+ */
+ if ((my_a->da->attr == PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr != PW_DHCP_MESSAGE_TYPE)) return -1;
+ if ((my_a->da->attr != PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr == PW_DHCP_MESSAGE_TYPE)) return +1;
+
+ /*
+ * Relay-Agent is last
+ */
+ if ((my_a->da->attr == PW_DHCP_OPTION_82) && (my_b->da->attr != PW_DHCP_OPTION_82)) return +1;
+ if ((my_a->da->attr != PW_DHCP_OPTION_82) && (my_b->da->attr == PW_DHCP_OPTION_82)) return -1;
+
+ if (my_a->da->attr < my_b->da->attr) return -1;
+ if (my_a->da->attr > my_b->da->attr) return 1;
+
+ return 0;
+}
+
+/** Write DHCP option value into buffer
+ *
+ * Does not include DHCP option length or number.
+ *
+ * @param out where to write the DHCP option.
+ * @param outlen length of output buffer.
+ * @param vp option to encode.
+ * @return the length of data writen, -1 if out of buffer, -2 if unsupported type.
+ */
+static ssize_t fr_dhcp_vp2data(uint8_t *out, size_t outlen, VALUE_PAIR *vp)
+{
+ uint32_t lvalue;
+ uint8_t *p = out;
+
+ if (outlen < vp->vp_length) {
+ return -1;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_BYTE:
+ *p = vp->vp_byte;
+ break;
+
+ case PW_TYPE_SHORT:
+ p[0] = (vp->vp_short >> 8) & 0xff;
+ p[1] = vp->vp_short & 0xff;
+ break;
+
+ case PW_TYPE_INTEGER:
+ lvalue = htonl(vp->vp_integer);
+ memcpy(p, &lvalue, 4);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(p, &vp->vp_ipaddr, 4);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(p, vp->vp_ether, 6);
+ break;
+
+ case PW_TYPE_STRING:
+ memcpy(p, vp->vp_strvalue, vp->vp_length);
+ break;
+
+ case PW_TYPE_OCTETS:
+ memcpy(p, vp->vp_octets, vp->vp_length);
+ break;
+
+ default:
+ fr_strerror_printf("Unsupported option type %d", vp->da->type);
+ return -2;
+ }
+
+ return vp->vp_length;
+}
+
+/** Create a new TLV attribute from multiple sub options
+ *
+ * @param[in,out] out buffer to write the data
+ * @param[out] outlen length of the output buffer
+ * @param[in,out] cursor should be set to the start of the list of TLV attributes.
+ * Will be advanced to the first non-TLV attribute.
+ * @return length of data encoded, or -1 on error
+ */
+static ssize_t fr_dhcp_vp2data_tlv(uint8_t *out, ssize_t outlen, vp_cursor_t *cursor)
+{
+ ssize_t len;
+ unsigned int parent; /* Parent attribute of suboption */
+ uint8_t attr = 0;
+ uint8_t *p, *opt_len;
+ vp_cursor_t tlv_cursor;
+ VALUE_PAIR *vp;
+
+#define SUBOPTION_PARENT(_x) (_x & 0xffff00ff)
+#define SUBOPTION_ATTR(_x) ((_x & 0xff00) >> 8)
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) return -1;
+
+ parent = SUBOPTION_PARENT(vp->da->attr);
+
+ /*
+ * Remember where we started off.
+ */
+ fr_cursor_copy(&tlv_cursor, cursor);
+
+ /*
+ * Loop over TLVs to determine how much memory we need to allocate
+ *
+ * We advanced the tlv_cursor we were passed, so if we
+ * fail encoding, the tlv_cursor is at the right position
+ * for the next potentially encodable attr.
+ */
+ len = 0;
+ for (vp = fr_cursor_current(&tlv_cursor);
+ vp && vp->da->flags.is_tlv && (SUBOPTION_PARENT(vp->da->attr) == parent);
+ vp = fr_cursor_next(&tlv_cursor)) {
+ if (SUBOPTION_ATTR(vp->da->attr) == 0) {
+ fr_strerror_printf("Invalid attribute number 0");
+ return -1;
+ }
+
+ /*
+ * If it's not an array type or is an array type,
+ * but is not the same as the previous attribute,
+ * we add 2 for the additional sub-option header
+ * bytes.
+ */
+ if (!vp->da->flags.array || (SUBOPTION_ATTR(vp->da->attr) != attr)) {
+ attr = SUBOPTION_ATTR(vp->da->attr);
+ len += 2;
+ }
+ len += vp->vp_length;
+ }
+
+ if (len > outlen) {
+ fr_strerror_printf("Insufficient room for suboption");
+ return -1;
+ }
+
+ attr = 0;
+ opt_len = NULL;
+ p = out;
+
+ for (vp = fr_cursor_current(cursor);
+ vp && vp->da->flags.is_tlv && (SUBOPTION_PARENT(vp->da->attr) == parent);
+ vp = fr_cursor_next(cursor)) {
+ /* Don't write out the header, were packing array options */
+ if (!opt_len || !vp->da->flags.array || (attr != SUBOPTION_ATTR(vp->da->attr))) {
+ attr = SUBOPTION_ATTR(vp->da->attr);
+ *p++ = attr;
+ opt_len = p++;
+ *opt_len = 0;
+ }
+
+ len = fr_dhcp_vp2data(p, out + outlen - p, vp);
+ if ((len < 0) || (len > 255)) {
+ return -1;
+ }
+
+ debug_pair(vp);
+ *opt_len += len;
+ p += len;
+ };
+
+ return p - out;
+}
+
+static ssize_t fr_dhcp_encode_adsl(uint8_t *out, size_t outlen, vp_cursor_t *cursor)
+{
+ VALUE_PAIR *vp;
+ uint8_t *p;
+ size_t room;
+
+ if (outlen <= (2 + 4 + 1)) return -1;
+
+ out[0] = 125; /* Vendor-Specific */
+ out[1] = 5; /* vendorpec + 1 octet of length */
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0x0d;
+ out[5] = 0xe9; /* ADSL forum vendorpec */
+ out[6] = 0; /* vendor-specific length */
+
+ p = out + 7;
+ room = outlen - 7;
+
+ for (vp = fr_cursor_current(cursor);
+ ((vp != NULL) && (vp->da->vendor == VENDORPEC_ADSL) &&
+ (vp->da->attr > 255) && ((vp->da->attr & 0xff) == 0xff));
+ vp = fr_cursor_next(cursor)) {
+ ssize_t length;
+
+ /*
+ * Silently discard options when there isn't enough room.
+ */
+ if (room < 2) break;
+
+ p[0] = (vp->da->attr >> 8) & 0xff;
+
+ length = fr_dhcp_vp2data(p + 2, room - 2, vp);
+ if (length < 0) break; /* not enough room */
+ if (length > 255) break; /* too much data */
+
+ p[1] = length;
+
+ length += 2; /* include the attribute header */
+
+ /*
+ * We don't (yet) split Vendor-Specific. So if
+ * there's too much data, just discard the extra
+ * data.
+ */
+ if ((out[1] + length) > 255) break;
+
+ out[1] += length;
+ out[6] += length;
+ p += length;
+ room -= length;
+ }
+
+ /*
+ * Don't encode options with no data.
+ */
+ if (out[1] == 5) return 0;
+
+ return out[1] + 2;
+}
+
+/** Encode a DHCP option and any sub-options.
+ *
+ * @param out Where to write encoded DHCP attributes.
+ * @param outlen Length of out buffer.
+ * @param ctx to use for any allocated memory.
+ * @param cursor with current VP set to the option to be encoded. Will be advanced to the next option to encode.
+ * @return > 0 length of data written, < 0 error, 0 not valid option (skipping).
+ */
+ssize_t fr_dhcp_encode_option(UNUSED TALLOC_CTX *ctx, uint8_t *out, size_t outlen, vp_cursor_t *cursor)
+{
+ VALUE_PAIR *vp;
+ DICT_ATTR const *previous;
+ uint8_t *opt_len, *p = out;
+ size_t freespace = outlen;
+ ssize_t len;
+
+ vp = fr_cursor_current(cursor);
+ if (!vp) return -1;
+
+ if (vp->da->vendor != DHCP_MAGIC_VENDOR) {
+ if ((vp->da->vendor == VENDORPEC_ADSL) &&
+ (vp->da->attr > 255) && ((vp->da->attr & 0xff) == 0xff)) {
+ return fr_dhcp_encode_adsl(out, outlen, cursor);
+ }
+ goto next; /* not a DHCP option */
+ }
+ if (vp->da->attr == PW_DHCP_MESSAGE_TYPE) goto next; /* already done */
+ if ((vp->da->attr > 255) && (DHCP_BASE_ATTR(vp->da->attr) != PW_DHCP_OPTION_82)) goto next;
+
+ if (vp->da->flags.extended) {
+ next:
+ fr_strerror_printf("Attribute \"%s\" is not a DHCP option", vp->da->name);
+ fr_cursor_next(cursor);
+ return 0;
+ }
+
+ /* Write out the option number */
+ *(p++) = vp->da->attr & 0xff;
+
+ /* Pointer to the length field of the option */
+ opt_len = p++;
+
+ /* Zero out the option's length field */
+ *opt_len = 0;
+
+ /* We just consumed two bytes for the header */
+ freespace -= 2;
+
+ /* DHCP options with the same number get coalesced into a single option */
+ do {
+ /*
+ * Sub-option encoder will encode the data and
+ * advance the cursor.
+ */
+ if (vp->da->flags.is_tlv) {
+ len = fr_dhcp_vp2data_tlv(p, freespace, cursor);
+ previous = NULL;
+
+ } else {
+ len = fr_dhcp_vp2data(p, freespace, vp);
+ if (len >= 0) debug_pair(vp);
+ fr_cursor_next(cursor);
+ previous = vp->da;
+ }
+
+ if (len < 0) return len;
+
+ if ((*opt_len + len) > 255) {
+ fr_strerror_printf("Skipping \"%s\": Option splitting not supported "
+ "(option > 255 bytes)", vp->da->name);
+ return 0;
+ }
+
+ p += len;
+ *opt_len += len;
+ freespace -= len;
+
+ } while ((vp = fr_cursor_current(cursor)) && previous && (previous == vp->da) && vp->da->flags.array);
+
+ return p - out;
+}
+
+int fr_dhcp_encode(RADIUS_PACKET *packet)
+{
+ unsigned int i;
+ uint8_t *p;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ uint32_t lvalue;
+ uint16_t svalue;
+ size_t dhcp_size;
+ ssize_t len;
+#ifndef NDEBUG
+ char const *name;
+# ifdef WITH_UDPFROMTO
+ char src_ip_buf[256];
+# endif
+ char dst_ip_buf[256];
+#endif
+
+ if (packet->data) return 0;
+
+ packet->data_len = MAX_PACKET_SIZE;
+ packet->data = talloc_zero_array(packet, uint8_t, packet->data_len);
+
+ /* XXX Ugly ... should be set by the caller */
+ if (packet->code == 0) packet->code = PW_DHCP_NAK;
+
+ /* store xid */
+ if ((vp = fr_pair_find_by_num(packet->vps, 260, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ packet->id = vp->vp_integer;
+ } else {
+ packet->id = fr_rand();
+ }
+
+#ifndef NDEBUG
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ name = "?Unknown?";
+ }
+
+ DEBUG(
+# ifdef WITH_UDPFROMTO
+ "Encoding %s of id %08x from %s:%d to %s:%d\n",
+# else
+ "Encoding %s of id %08x to %s:%d\n",
+# endif
+ name, (unsigned int) packet->id,
+# ifdef WITH_UDPFROMTO
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+# endif
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
+#endif
+
+ p = packet->data;
+
+ /*
+ * @todo: Make this work again.
+ */
+#if 0
+ mms = DEFAULT_PACKET_SIZE; /* maximum message size */
+
+ /*
+ * Clients can request a LARGER size, but not a
+ * smaller one. They also cannot request a size
+ * larger than MTU.
+ */
+
+ /* DHCP-DHCP-Maximum-Msg-Size */
+ vp = fr_pair_find_by_num(packet->vps, 57, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp && (vp->vp_integer > mms)) {
+ mms = vp->vp_integer;
+
+ if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
+ }
+#endif
+
+ vp = fr_pair_find_by_num(packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
+ *p++ = vp->vp_integer & 0xff;
+ } else {
+ *p++ = 1; /* client message */
+ }
+
+ /* DHCP-Hardware-Type */
+ if ((vp = fr_pair_find_by_num(packet->vps, 257, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p++ = vp->vp_byte;
+ } else {
+ *p++ = 1; /* hardware type = ethernet */
+ }
+
+ /* DHCP-Hardware-Address-Length */
+ if ((vp = fr_pair_find_by_num(packet->vps, 258, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p++ = vp->vp_byte;
+ } else {
+ *p++ = 6; /* 6 bytes of ethernet */
+ }
+
+ /* DHCP-Hop-Count */
+ if ((vp = fr_pair_find_by_num(packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ *p = vp->vp_byte;
+ }
+ p++;
+
+ /* DHCP-Transaction-Id */
+ lvalue = htonl(packet->id);
+ memcpy(p, &lvalue, 4);
+ p += 4;
+
+ /* DHCP-Number-of-Seconds */
+ if ((vp = fr_pair_find_by_num(packet->vps, 261, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ svalue = htons(vp->vp_short);
+ memcpy(p, &svalue, 2);
+ }
+ p += 2;
+
+ /* DHCP-Flags */
+ if ((vp = fr_pair_find_by_num(packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ svalue = htons(vp->vp_short);
+ memcpy(p, &svalue, 2);
+ }
+ p += 2;
+
+ /* DHCP-Client-IP-Address */
+ if ((vp = fr_pair_find_by_num(packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ memcpy(p, &vp->vp_ipaddr, 4);
+ }
+ p += 4;
+
+ /* DHCP-Your-IP-address */
+ if ((vp = fr_pair_find_by_num(packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = vp->vp_ipaddr;
+ } else {
+ lvalue = htonl(INADDR_ANY);
+ }
+ memcpy(p, &lvalue, 4);
+ p += 4;
+
+ /* DHCP-Server-IP-Address */
+ vp = fr_pair_find_by_num(packet->vps, 265, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
+ lvalue = vp->vp_ipaddr;
+ } else {
+ lvalue = htonl(INADDR_ANY);
+ }
+ memcpy(p, &lvalue, 4);
+ p += 4;
+
+ /*
+ * DHCP-Gateway-IP-Address
+ */
+ if ((vp = fr_pair_find_by_num(packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ lvalue = vp->vp_ipaddr;
+ } else {
+ lvalue = htonl(INADDR_ANY);
+ }
+ memcpy(p, &lvalue, 4);
+ p += 4;
+
+ /* DHCP-Client-Hardware-Address */
+ if ((vp = fr_pair_find_by_num(packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ if (vp->vp_length == sizeof(vp->vp_ether)) {
+ /*
+ * Ensure that we mark the packet as being Ethernet.
+ * This is mainly for DHCP-Lease-Query responses.
+ */
+ packet->data[1] = 1;
+ packet->data[2] = 6;
+
+ memcpy(p, vp->vp_ether, vp->vp_length);
+ } /* else ignore it */
+ }
+ p += DHCP_CHADDR_LEN;
+
+ /* DHCP-Server-Host-Name */
+ if ((vp = fr_pair_find_by_num(packet->vps, 268, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ if (vp->vp_length > DHCP_SNAME_LEN) {
+ memcpy(p, vp->vp_strvalue, DHCP_SNAME_LEN);
+ } else {
+ memcpy(p, vp->vp_strvalue, vp->vp_length);
+ }
+ }
+ p += DHCP_SNAME_LEN;
+
+ /*
+ * Copy over DHCP-Boot-Filename.
+ *
+ * FIXME: This copy should be delayed until AFTER the options
+ * have been processed. If there are too many options for
+ * the packet, then they go into the sname && filename fields.
+ * When that happens, the boot filename is passed as an option,
+ * instead of being placed verbatim in the filename field.
+ */
+
+ /* DHCP-Boot-Filename */
+ vp = fr_pair_find_by_num(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
+ if (vp->vp_length > DHCP_FILE_LEN) {
+ memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
+ } else {
+ memcpy(p, vp->vp_strvalue, vp->vp_length);
+ }
+ }
+ p += DHCP_FILE_LEN;
+
+ /* DHCP magic number */
+ lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER);
+ memcpy(p, &lvalue, 4);
+ p += 4;
+
+ /*
+ * Print the header.
+ */
+ if (fr_debug_lvl > 1) {
+ uint8_t *pp = p;
+
+ p = packet->data;
+
+ for (i = 0; i < 14; i++) {
+ char *q;
+
+ vp = fr_pair_make(packet, NULL,
+ dhcp_header_names[i], NULL, T_OP_EQ);
+ if (!vp) {
+ char buffer[256];
+ strlcpy(buffer, fr_strerror(), sizeof(buffer));
+ fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
+ return -1;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_BYTE:
+ vp->vp_byte = p[0];
+ break;
+
+ case PW_TYPE_SHORT:
+ vp->vp_short = (p[0] << 8) | p[1];
+ break;
+
+ case PW_TYPE_INTEGER:
+ memcpy(&vp->vp_integer, p, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(&vp->vp_ipaddr, p, 4);
+ break;
+
+ case PW_TYPE_STRING:
+ vp->vp_strvalue = q = talloc_array(vp, char, dhcp_header_sizes[i] + 1);
+ vp->type = VT_DATA;
+ memcpy(q, p, dhcp_header_sizes[i]);
+ q[dhcp_header_sizes[i]] = '\0';
+ vp->vp_length = strlen(vp->vp_strvalue);
+ break;
+
+ case PW_TYPE_OCTETS: /* only for Client HW Address */
+ fr_pair_value_memcpy(vp, p, packet->data[2]);
+ break;
+
+ case PW_TYPE_ETHERNET: /* only for Client HW Address */
+ memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
+ break;
+
+ default:
+ fr_strerror_printf("Internal sanity check failed %d %d", vp->da->type, __LINE__);
+ fr_pair_list_free(&vp);
+ break;
+ }
+
+ p += dhcp_header_sizes[i];
+
+ debug_pair(vp);
+ fr_pair_list_free(&vp);
+ }
+
+ /*
+ * Jump over DHCP magic number, response, etc.
+ */
+ p = pp;
+ }
+
+ p[0] = 0x35; /* DHCP-Message-Type */
+ p[1] = 1;
+ p[2] = packet->code - PW_DHCP_OFFSET;
+ p += 3;
+
+ /*
+ * Pre-sort attributes into contiguous blocks so that fr_dhcp_encode_option
+ * operates correctly. This changes the order of the list, but never mind...
+ */
+ fr_pair_list_sort(&packet->vps, fr_dhcp_attr_cmp);
+ fr_cursor_init(&cursor, &packet->vps);
+
+ /*
+ * Each call to fr_dhcp_encode_option will encode one complete DHCP option,
+ * and sub options.
+ */
+ while ((vp = fr_cursor_current(&cursor))) {
+ len = fr_dhcp_encode_option(packet, p, packet->data_len - (p - packet->data), &cursor);
+ if (len < 0) break;
+ p += len;
+ };
+
+ p[0] = 0xff; /* end of option option */
+ p[1] = 0x00;
+ p += 2;
+ dhcp_size = p - packet->data;
+
+ /*
+ * FIXME: if (dhcp_size > mms),
+ * then we put the extra options into the "sname" and "file"
+ * fields, AND set the "end option option" in the "options"
+ * field. We also set the "overload option",
+ * and put options into the "file" field, followed by
+ * the "sname" field. Where each option is completely
+ * enclosed in the "file" and/or "sname" field, AND
+ * followed by the "end of option", and MUST be followed
+ * by padding option.
+ *
+ * Yuck. That sucks...
+ */
+ packet->data_len = dhcp_size;
+
+ if (packet->data_len < DEFAULT_PACKET_SIZE) {
+ memset(packet->data + packet->data_len, 0,
+ DEFAULT_PACKET_SIZE - packet->data_len);
+ packet->data_len = DEFAULT_PACKET_SIZE;
+ }
+
+ if ((fr_debug_lvl > 2) && fr_log_fp) {
+ fprintf(fr_log_fp, "DHCP Sending %zu bytes\n", packet->data_len);
+ for (i = 0; i < packet->data_len; i++) {
+ if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", (int) i);
+ fprintf(fr_log_fp, "%02x ", packet->data[i]);
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ fprintf(fr_log_fp, "\n");
+ }
+
+ return 0;
+}
+
+#ifdef SIOCSARP
+int fr_dhcp_add_arp_entry(int fd, char const *interface,
+ VALUE_PAIR *macaddr, VALUE_PAIR *ip)
+{
+ struct sockaddr_in *sin;
+ struct arpreq req;
+
+ if (!interface) {
+ fr_strerror_printf("No interface specified. Cannot update ARP table");
+ return -1;
+ }
+
+ if (!fr_assert(macaddr) ||
+ !fr_assert((macaddr->da->type == PW_TYPE_ETHERNET) || (macaddr->da->type == PW_TYPE_OCTETS))) {
+ fr_strerror_printf("Wrong VP type (%s) for chaddr",
+ fr_int2str(dict_attr_types, macaddr->da->type, "<invalid>"));
+ return -1;
+ }
+
+ if (macaddr->vp_length > sizeof(req.arp_ha.sa_data)) {
+ fr_strerror_printf("arp sa_data field too small (%zu octets) to contain chaddr (%zu octets)",
+ sizeof(req.arp_ha.sa_data), macaddr->vp_length);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ sin = (struct sockaddr_in *) &req.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ip->vp_ipaddr;
+
+ strlcpy(req.arp_dev, interface, sizeof(req.arp_dev));
+
+ if (macaddr->da->type == PW_TYPE_ETHERNET) {
+ memcpy(&req.arp_ha.sa_data, macaddr->vp_ether, sizeof(macaddr->vp_ether));
+ } else {
+ memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->vp_length);
+ }
+
+ req.arp_flags = ATF_COM;
+ if (ioctl(fd, SIOCSARP, &req) < 0) {
+ fr_strerror_printf("Failed to add entry in ARP cache: %s (%d)", fr_syserror(errno), errno);
+ return -1;
+ }
+
+ return 0;
+}
+#else
+int fr_dhcp_add_arp_entry(UNUSED int fd, UNUSED char const *interface,
+ UNUSED VALUE_PAIR *macaddr, UNUSED VALUE_PAIR *ip)
+{
+ fr_strerror_printf("Adding ARP entry is unsupported on this system");
+ return -1;
+}
+#endif
+
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+/*
+ * Open a packet interface raw socket.
+ * Bind it to the specified interface using a device independent physical layer address.
+ */
+int fr_socket_packet(int iface_index, struct sockaddr_ll *p_ll)
+{
+ int lsockfd;
+
+ /* PF_PACKET - packet interface on device level.
+ using a raw socket allows packet data to be unchanged by the device driver.
+ */
+ lsockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (lsockfd < 0) {
+ fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
+ return lsockfd;
+ }
+
+ /* Set link layer parameters */
+ memset(p_ll, 0, sizeof(struct sockaddr_ll));
+
+ p_ll->sll_family = AF_PACKET;
+ p_ll->sll_protocol = htons(ETH_P_ALL);
+ p_ll->sll_ifindex = iface_index;
+ p_ll->sll_hatype = ARPHRD_ETHER;
+ p_ll->sll_pkttype = PACKET_OTHERHOST;
+ p_ll->sll_halen = 6;
+
+ if (bind(lsockfd, (struct sockaddr *)p_ll, sizeof(struct sockaddr_ll)) < 0) {
+ close(lsockfd);
+ fr_strerror_printf("cannot bind raw socket: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ return lsockfd;
+}
+
+/*
+ * Encode and send a DHCP packet on a raw packet socket.
+ */
+int fr_dhcp_send_raw_packet(int sockfd, struct sockaddr_ll *p_ll, RADIUS_PACKET *packet)
+{
+ VALUE_PAIR *vp;
+ u_char dhcp_packet[1518] = { 0 };
+
+ /* set ethernet source address to our MAC address (DHCP-Client-Hardware-Address). */
+ u_char dhmac[ETH_ADDR_LEN] = { 0 };
+ if ((vp = fr_pair_find_by_num(packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ if (vp->length == sizeof(vp->vp_ether)) {
+ memcpy(dhmac, vp->vp_ether, vp->length);
+ }
+ }
+
+ /* fill in Ethernet layer (L2) */
+ struct ethernet_header *ethhdr = (struct ethernet_header *)dhcp_packet;
+ memcpy(ethhdr->ether_dst, eth_bcast, ETH_ADDR_LEN);
+ memcpy(ethhdr->ether_src, dhmac, ETH_ADDR_LEN);
+ ethhdr->ether_type = htons(ETH_TYPE_IP);
+
+ /* fill in IP layer (L3) */
+ struct ip_header *iph = (struct ip_header *)(dhcp_packet + ETH_HDR_SIZE);
+ iph->ip_vhl = IP_VHL(4, 5);
+ iph->ip_tos = 0;
+ iph->ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->data_len);
+ iph->ip_id = 0;
+ iph->ip_off = 0;
+ iph->ip_ttl = 64;
+ iph->ip_p = 17;
+ iph->ip_sum = 0; /* Filled later */
+
+ /* saddr: Packet-Src-IP-Address (default: 0.0.0.0). */
+ iph->ip_src.s_addr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+
+ /* daddr: packet destination IP addr (should be 255.255.255.255 for broadcast). */
+ iph->ip_dst.s_addr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+
+ /* IP header checksum */
+ iph->ip_sum = fr_iph_checksum((uint8_t const *)iph, 5);
+
+ /* fill in UDP layer (L4) */
+ udp_header_t *uh = (udp_header_t *) (dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
+
+ uh->src = htons(68);
+ uh->dst = htons(67);
+ u_int16_t l4_len = (UDP_HDR_SIZE + packet->data_len);
+ uh->len = htons(l4_len);
+ uh->checksum = 0; /* UDP checksum will be done after dhcp header */
+
+ /* DHCP layer (L7) */
+ dhcp_packet_t *dhpointer = (dhcp_packet_t *)(dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
+ /* just copy what FreeRADIUS has encoded for us. */
+ memcpy(dhpointer, packet->data, packet->data_len);
+
+ /* UDP checksum is done here */
+ uh->checksum = fr_udp_checksum((uint8_t const *)(dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE), ntohs(uh->len), uh->checksum,
+ packet->src_ipaddr.ipaddr.ip4addr, packet->dst_ipaddr.ipaddr.ip4addr);
+
+ if (fr_debug_lvl > 1) {
+ char type_buf[64];
+ char const *name = type_buf;
+ char src_ip_buf[INET6_ADDRSTRLEN];
+ char dst_ip_buf[INET6_ADDRSTRLEN];
+
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ snprintf(type_buf, sizeof(type_buf), "%d",
+ packet->code - PW_DHCP_OFFSET);
+ }
+
+ DEBUG(
+ "Sending %s Id %08x from %s:%d to %s:%d\n",
+ name, (unsigned int) packet->id,
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src_ip_buf, sizeof(src_ip_buf)), packet->src_port,
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst_ip_buf, sizeof(dst_ip_buf)), packet->dst_port);
+ }
+
+ return sendto(sockfd, dhcp_packet,
+ (ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE + packet->data_len),
+ 0, (struct sockaddr *) p_ll, sizeof(struct sockaddr_ll));
+}
+
+/*
+ * print an ethernet address in a buffer
+ */
+static char * ether_addr_print(const uint8_t *addr, char *buf)
+{
+ sprintf (buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ return buf;
+}
+
+/*
+ * For a client, receive a DHCP packet from a raw packet
+ * socket. Make sure it matches the ongoing request.
+ *
+ * FIXME: split this into two, recv_raw_packet, and verify(packet, original)
+ */
+RADIUS_PACKET *fr_dhcp_recv_raw_packet(int sockfd, struct sockaddr_ll *p_ll, RADIUS_PACKET *request)
+{
+ VALUE_PAIR *vp;
+ RADIUS_PACKET *packet;
+ uint8_t *code;
+ uint32_t magic, xid;
+ ssize_t data_len;
+
+ uint8_t *raw_packet;
+ ethernet_header_t *eth_hdr;
+ struct ip_header *ip_hdr;
+ udp_header_t *udp_hdr;
+ dhcp_packet_t *dhcp_hdr;
+ uint16_t udp_src_port;
+ uint16_t udp_dst_port;
+ size_t dhcp_data_len;
+ socklen_t sock_len;
+
+ packet = rad_alloc(NULL, false);
+ if (!packet) {
+ fr_strerror_printf("Failed allocating packet");
+ return NULL;
+ }
+
+ raw_packet = talloc_zero_array(packet, uint8_t, MAX_PACKET_SIZE);
+ if (!raw_packet) {
+ fr_strerror_printf("Out of memory");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ packet->sockfd = sockfd;
+
+ /* a packet was received (but maybe it is not for us) */
+ sock_len = sizeof(struct sockaddr_ll);
+ data_len = recvfrom(sockfd, raw_packet, MAX_PACKET_SIZE, 0,
+ (struct sockaddr *)p_ll, &sock_len);
+
+ uint8_t data_offset = ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE; // DHCP data starts after Ethernet, IP, UDP.
+
+ if (data_len <= data_offset) DISCARD_RP("Payload (%d) smaller than required for layers 2+3+4", (int)data_len);
+
+ /* map raw packet to packet header of the different layers (Ethernet, IP, UDP) */
+ eth_hdr = (ethernet_header_t *)raw_packet;
+
+ /* a. Check Ethernet layer data (L2) */
+ if (ntohs(eth_hdr->ether_type) != ETH_TYPE_IP) DISCARD_RP("Ethernet type (%d) != IP", ntohs(eth_hdr->ether_type));
+
+ /* If Ethernet destination is not broadcast (ff:ff:ff:ff:ff:ff)
+ * Check if it matches the source HW address used (DHCP-Client-Hardware-Address = 267)
+ */
+ if ( (memcmp(&eth_bcast, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0) &&
+ (vp = fr_pair_find_by_num(request->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY)) &&
+ (vp->length == sizeof(vp->vp_ether)) &&
+ (memcmp(vp->vp_ether, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0) ) {
+ /* No match. */
+ char eth_dest[17+1];
+ char eth_req_src[17+1];
+ DISCARD_RP("Ethernet destination (%s) is not broadcast and doesn't match request source (%s)",
+ ether_addr_print(eth_hdr->ether_dst, eth_dest),
+ ether_addr_print(vp->vp_ether, eth_req_src));
+ }
+
+ /*
+ * Ethernet is OK. Now look at IP.
+ */
+ ip_hdr = (struct ip_header *)(raw_packet + ETH_HDR_SIZE);
+
+ /* b. Check IPv4 layer data (L3) */
+ if (ip_hdr->ip_p != IPPROTO_UDP) DISCARD_RP("IP protocol (%d) != UDP", ip_hdr->ip_p);
+
+ /*
+ * note: checking the destination IP address is not
+ * useful (it would be the offered IP address - which we
+ * don't know beforehand, or the broadcast address).
+ */
+
+ /*
+ * Now check UDP.
+ */
+ udp_hdr = (udp_header_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
+
+ /* c. Check UDP layer data (L4) */
+ udp_src_port = ntohs(udp_hdr->src);
+ udp_dst_port = ntohs(udp_hdr->dst);
+
+ /*
+ * A DHCP server will always respond to port 68 (to a
+ * client) or 67 (to a relay). Just check that both
+ * ports are 67 or 68.
+ */
+ if (udp_src_port != 67 && udp_src_port != 68) DISCARD_RP("UDP src port (%d) != DHCP (67 or 68)", udp_src_port);
+ if (udp_dst_port != 67 && udp_dst_port != 68) DISCARD_RP("UDP dst port (%d) != DHCP (67 or 68)", udp_dst_port);
+
+ /* d. Check DHCP layer data */
+ dhcp_data_len = data_len - data_offset;
+
+ if (dhcp_data_len < MIN_PACKET_SIZE) DISCARD_RP("DHCP packet is too small (%zu < %d)", dhcp_data_len, MIN_PACKET_SIZE);
+ if (dhcp_data_len > MAX_PACKET_SIZE) DISCARD_RP("DHCP packet is too large (%zu > %d)", dhcp_data_len, MAX_PACKET_SIZE);
+
+ dhcp_hdr = (dhcp_packet_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
+
+ if (dhcp_hdr->htype != 1) DISCARD_RP("DHCP hardware type (%d) != Ethernet (1)", dhcp_hdr->htype);
+ if (dhcp_hdr->hlen != 6) DISCARD_RP("DHCP hardware address length (%d) != 6", dhcp_hdr->hlen);
+
+ magic = ntohl(dhcp_hdr->option_format);
+
+ if (magic != DHCP_OPTION_MAGIC_NUMBER) DISCARD_RP("DHCP magic cookie (0x%04x) != DHCP (0x%04x)", magic, DHCP_OPTION_MAGIC_NUMBER);
+
+ /*
+ * Reply transaction id must match value from request.
+ */
+ xid = ntohl(dhcp_hdr->xid);
+ if (xid != (uint32_t)request->id) DISCARD_RP("DHCP transaction ID (0x%04x) != xid from request (0x%04x)", xid, request->id)
+
+ /* all checks ok! this is a DHCP reply we're interested in. */
+ packet->data_len = dhcp_data_len;
+ packet->data = talloc_memdup(packet, raw_packet + data_offset, dhcp_data_len);
+ TALLOC_FREE(raw_packet);
+ packet->id = xid;
+
+ code = dhcp_get_option((dhcp_packet_t *) packet->data,
+ packet->data_len, PW_DHCP_MESSAGE_TYPE);
+ if (!code) {
+ fr_strerror_printf("No message-type option was found in the packet");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
+ fr_strerror_printf("Unknown value for message-type option");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ packet->code = code[2] | PW_DHCP_OFFSET;
+
+ /*
+ * Create a unique vector from the xid and the client
+ * hardware address. This is a hack for the RADIUS
+ * infrastructure in the rest of the server.
+ * It is also used for de-duplicating DHCP packets
+ */
+ memcpy(packet->vector, packet->data + 4, 4); /* xid */
+ memcpy(packet->vector + 4, packet->data + 24, 4); /* giaddr */
+ packet->vector[8] = packet->code & 0xff; /* message type */
+ memcpy(packet->vector + 9, packet->data + 28, 6); /* chaddr is always 6 for us */
+
+ packet->src_port = udp_src_port;
+ packet->dst_port = udp_dst_port;
+
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip_hdr->ip_src.s_addr;
+ packet->dst_ipaddr.af = AF_INET;
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip_hdr->ip_dst.s_addr;
+
+ if (fr_debug_lvl > 1) {
+ char type_buf[64];
+ char const *name = type_buf;
+ char src_ip_buf[256], dst_ip_buf[256];
+
+ if ((packet->code >= PW_DHCP_DISCOVER) &&
+ (packet->code < (1024 + DHCP_MAX_MESSAGE_TYPE))) {
+ name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
+ } else {
+ snprintf(type_buf, sizeof(type_buf), "%d", packet->code - PW_DHCP_OFFSET);
+ }
+
+ DEBUG("Received %s of Id %08x from %s:%d to %s:%d\n",
+ name, (unsigned int) packet->id,
+ inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, src_ip_buf, sizeof(src_ip_buf)),
+ packet->src_port,
+ inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, dst_ip_buf, sizeof(dst_ip_buf)),
+ packet->dst_port);
+ }
+
+ return packet;
+}
+#endif
diff --git a/src/modules/proto_dhcp/dhcpclient.c b/src/modules/proto_dhcp/dhcpclient.c
new file mode 100644
index 0000000..5ab4365
--- /dev/null
+++ b/src/modules/proto_dhcp/dhcpclient.c
@@ -0,0 +1,652 @@
+/*
+ * dhcpclient.c General radius packet debug tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2010 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/dhcp.h>
+
+#ifdef WITH_DHCP
+
+#include <ctype.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <assert.h>
+
+#include <net/if.h>
+
+static int success = 0;
+static int retries = 3;
+static float timeout = 5.0;
+static struct timeval tv_timeout;
+
+static int sockfd;
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+struct sockaddr_ll ll; /* Socket address structure */
+static char *iface = NULL;
+static int iface_ind = -1;
+
+# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
+#endif
+
+static RADIUS_PACKET *reply = NULL;
+
+static bool reply_expected = true;
+
+#define DHCP_CHADDR_LEN (16)
+#define DHCP_SNAME_LEN (64)
+#define DHCP_FILE_LEN (128)
+
+static char const *dhcpclient_version = "dhcpclient version " RADIUSD_VERSION_STRING
+#ifdef RADIUSD_VERSION_COMMIT
+" (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
+#endif
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+", built on " __DATE__ " at " __TIME__
+#endif
+;
+
+/* structure to keep track of offered IP addresses */
+typedef struct dc_offer {
+ uint32_t server_addr;
+ uint32_t offered_addr;
+} dc_offer_t;
+
+static const FR_NAME_NUMBER request_types[] = {
+ { "discover", PW_DHCP_DISCOVER },
+ { "request", PW_DHCP_REQUEST },
+ { "decline", PW_DHCP_DECLINE },
+ { "release", PW_DHCP_RELEASE },
+ { "inform", PW_DHCP_INFORM },
+ { "lease_query", PW_DHCP_LEASE_QUERY },
+ { "auto", PW_CODE_UNDEFINED },
+ { NULL, 0}
+};
+
+static void NEVER_RETURNS usage(void)
+{
+ fprintf(stderr, "Usage: dhcpclient [options] server[:port] [<command>]\n");
+ fprintf(stderr, "Send a DHCP request with provided RADIUS attrs and output response.\n");
+
+ fprintf(stderr, " <command> One of: discover, request, decline, release, inform; or: auto.\n");
+ fprintf(stderr, " -d <directory> Set the directory where the dictionaries are stored (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stderr, " -f <file> Read packets from file, not stdin.\n");
+#ifdef HAVE_LINUX_IF_PACKET_H
+ fprintf(stderr, " -i <interface> Use this interface to send/receive at packet level on a raw socket.\n");
+#endif
+ fprintf(stderr, " -t <timeout> Wait 'timeout' seconds for a reply (may be a floating point number).\n");
+ fprintf(stderr, " -v Show program version information.\n");
+ fprintf(stderr, " -x Debugging mode.\n");
+
+ exit(1);
+}
+
+
+/*
+ * Initialize the request.
+ */
+static RADIUS_PACKET *request_init(char const *filename)
+{
+ FILE *fp;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ bool filedone = false;
+ RADIUS_PACKET *request;
+
+ /*
+ * Determine where to read the VP's from.
+ */
+ if (filename) {
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "dhcpclient: Error opening %s: %s\n", filename, fr_syserror(errno));
+ return NULL;
+ }
+ } else {
+ fp = stdin;
+ }
+
+ request = rad_alloc(NULL, false);
+ /*
+ * Read the VP's.
+ */
+ if (fr_pair_list_afrom_file(NULL, &request->vps, fp, &filedone) < 0) {
+ fr_perror("dhcpclient");
+ rad_free(&request);
+ if (fp != stdin) fclose(fp);
+ return NULL;
+ }
+
+ /*
+ * Fix / set various options
+ */
+ for (vp = fr_cursor_init(&cursor, &request->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Allow to set packet type using DHCP-Message-Type
+ */
+ if (vp->da->vendor == DHCP_MAGIC_VENDOR && vp->da->attr == PW_DHCP_MESSAGE_TYPE) {
+ request->code = vp->vp_integer + PW_DHCP_OFFSET;
+ } else if (!vp->da->vendor) switch (vp->da->attr) {
+ /*
+ * Allow it to set the packet type in
+ * the attributes read from the file.
+ * (this takes precedence over the command argument.)
+ */
+ case PW_PACKET_TYPE:
+ request->code = vp->vp_integer;
+ break;
+
+ case PW_PACKET_DST_PORT:
+ request->dst_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_DST_IP_ADDRESS:
+ request->dst_ipaddr.af = AF_INET;
+ request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->dst_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_DST_IPV6_ADDRESS:
+ request->dst_ipaddr.af = AF_INET6;
+ request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->dst_ipaddr.prefix = 128;
+ break;
+
+ case PW_PACKET_SRC_PORT:
+ request->src_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_SRC_IP_ADDRESS:
+ request->src_ipaddr.af = AF_INET;
+ request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->src_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_SRC_IPV6_ADDRESS:
+ request->src_ipaddr.af = AF_INET6;
+ request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ request->src_ipaddr.prefix = 128;
+ break;
+
+ default:
+ break;
+ } /* switch over the attribute */
+
+ } /* loop over the VP's we read in */
+
+ if (fp != stdin) fclose(fp);
+
+ /*
+ * And we're done.
+ */
+ return request;
+}
+
+static char const *dhcp_header_names[] = {
+ "DHCP-Opcode",
+ "DHCP-Hardware-Type",
+ "DHCP-Hardware-Address-Length",
+ "DHCP-Hop-Count",
+ "DHCP-Transaction-Id",
+ "DHCP-Number-of-Seconds",
+ "DHCP-Flags",
+ "DHCP-Client-IP-Address",
+ "DHCP-Your-IP-Address",
+ "DHCP-Server-IP-Address",
+ "DHCP-Gateway-IP-Address",
+ "DHCP-Client-Hardware-Address",
+ "DHCP-Server-Host-Name",
+ "DHCP-Boot-Filename",
+
+ NULL
+};
+
+static int dhcp_header_sizes[] = {
+ 1, 1, 1, 1,
+ 4, 2, 2, 4,
+ 4, 4, 4,
+ DHCP_CHADDR_LEN,
+ DHCP_SNAME_LEN,
+ DHCP_FILE_LEN
+};
+
+
+static void print_hex(RADIUS_PACKET *packet)
+{
+ int i, j;
+ uint8_t const *p, *a;
+
+ if (!packet->data) return;
+
+ if (packet->data_len < 244) {
+ printf("Huh?\n");
+ return;
+ }
+
+ printf("----------------------------------------------------------------------\n");
+ fflush(stdout);
+
+ p = packet->data;
+ for (i = 0; i < 14; i++) {
+ printf("%s = 0x", dhcp_header_names[i]);
+ for (j = 0; j < dhcp_header_sizes[i]; j++) {
+ printf("%02x", p[j]);
+
+ }
+ printf("\n");
+ p += dhcp_header_sizes[i];
+ }
+
+ /*
+ * Magic number
+ */
+ printf("%02x %02x %02x %02x\n",
+ p[0], p[1], p[2], p[3]);
+ p += 4;
+
+ while (p < (packet->data + packet->data_len)) {
+
+ if (*p == 0) break;
+ if (*p == 255) break; /* end of options signifier */
+ if ((p + 2) > (packet->data + packet->data_len)) break;
+
+ printf("%02x %02x ", p[0], p[1]);
+ a = p + 2;
+
+ for (i = 0; i < p[1]; i++) {
+ if ((i > 0) && ((i & 0x0f) == 0x00))
+ printf("\t\t");
+ printf("%02x ", a[i]);
+ if ((i & 0x0f) == 0x0f) printf("\n");
+ }
+
+ if ((p[1] & 0x0f) != 0x00) printf("\n");
+
+ p += p[1] + 2;
+ }
+ printf("\n----------------------------------------------------------------------\n");
+ fflush(stdout);
+}
+
+static void send_with_socket(RADIUS_PACKET *request)
+{
+ request->sockfd = sockfd;
+
+ if (fr_dhcp_send(request) < 0) {
+ fprintf(stderr, "dhcpclient: failed sending: %s\n",
+ fr_syserror(errno));
+ fr_exit_now(1);
+ }
+
+ if (!reply_expected) return;
+
+ reply = fr_dhcp_recv(sockfd);
+ if (!reply) {
+ fprintf(stderr, "dhcpclient: Error receiving reply: %s\n", fr_strerror());
+ fr_exit_now(1);
+ }
+
+
+ if (fr_debug_lvl) print_hex(reply);
+
+ if (fr_dhcp_decode(reply) < 0) {
+ fprintf(stderr, "dhcpclient: failed decoding\n");
+ fr_exit_now(1);
+ }
+}
+
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+/*
+ * Loop waiting for DHCP replies until timer expires.
+ * Note that there may be more than one reply: multiple DHCP servers can respond to a broadcast discover.
+ * A real client would pick one of the proposed replies.
+ * We'll just return the first eligible reply, and display the others.
+ */
+static RADIUS_PACKET *fr_dhcp_recv_raw_loop(int sockfd_r, struct sockaddr_ll *p_ll, RADIUS_PACKET *request_p)
+{
+ struct timeval tval;
+ RADIUS_PACKET *reply_p = NULL;
+ RADIUS_PACKET *cur_reply_p = NULL;
+ int num_replies = 0;
+ int num_offers = 0;
+ dc_offer_t *offer_list = NULL;
+ fd_set read_fd;
+ int retval;
+
+ memcpy(&tval, &tv_timeout, sizeof(struct timeval));
+
+ /* Loop waiting for DHCP replies until timer expires */
+ while (timerisset(&tval)) {
+ if ((!reply_p) || (cur_reply_p)) { // only debug at start and each time we get a valid DHCP reply on raw socket
+ DEBUG("Waiting for%sDHCP replies for: %d.%06d\n",
+ (num_replies>0)?" additional ":" ", (int)tval.tv_sec, (int)tval.tv_usec);
+ }
+
+ cur_reply_p = NULL;
+ FD_ZERO(&read_fd);
+ FD_SET(sockfd_r, &read_fd);
+ retval = select(sockfd_r + 1, &read_fd, NULL, NULL, &tval);
+
+ if (retval < 0) {
+ fr_strerror_printf("Select on DHCP socket failed: %s", fr_syserror(errno));
+ return NULL;
+ }
+
+ if ( retval > 0 && FD_ISSET(sockfd_r, &read_fd)) {
+ /* There is something to read on our socket */
+ cur_reply_p = fr_dhcp_recv_raw_packet(sockfd_r, p_ll, request_p);
+ }
+
+ if (cur_reply_p) {
+ num_replies ++;
+
+ if (fr_debug_lvl) print_hex(cur_reply_p);
+
+ if (fr_dhcp_decode(cur_reply_p) < 0) {
+ fprintf(stderr, "dhcpclient: failed decoding reply\n");
+ return NULL;
+ }
+
+ if (!reply_p) reply_p = cur_reply_p;
+
+ if (cur_reply_p->code == PW_DHCP_OFFER) {
+ VALUE_PAIR *vp1 = fr_pair_find_by_num(cur_reply_p->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */
+ VALUE_PAIR *vp2 = fr_pair_find_by_num(cur_reply_p->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-address */
+
+ if (vp1 && vp2) {
+ num_offers ++;
+ offer_list = talloc_realloc(request_p, offer_list, dc_offer_t, num_offers);
+ offer_list[num_offers-1].server_addr = vp1->vp_ipaddr;
+ offer_list[num_offers-1].offered_addr = vp2->vp_ipaddr;
+ }
+ }
+ }
+ }
+
+ if (!num_replies) {
+ fr_strerror_printf("No valid DHCP reply received");
+ return NULL;
+ }
+
+ /* display offer(s) received */
+ if (num_offers > 0 ) {
+ DEBUG("Received %d DHCP Offer(s):\n", num_offers);
+ int i;
+ for (i = 0; i < num_replies; i++) {
+ char server_addr_buf[INET6_ADDRSTRLEN];
+ char offered_addr_buf[INET6_ADDRSTRLEN];
+
+ DEBUG("IP address: %s offered by DHCP server: %s\n",
+ inet_ntop(AF_INET, &offer_list[i].offered_addr, offered_addr_buf, sizeof(offered_addr_buf)),
+ inet_ntop(AF_INET, &offer_list[i].server_addr, server_addr_buf, sizeof(server_addr_buf))
+ );
+ }
+ }
+
+ return reply_p;
+}
+#endif
+
+
+int main(int argc, char **argv)
+{
+ static uint16_t server_port = 0;
+ static int packet_code = 0;
+ static fr_ipaddr_t server_ipaddr;
+ static fr_ipaddr_t client_ipaddr;
+
+ int c;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
+ char const *filename = NULL;
+ DICT_ATTR const *da;
+ RADIUS_PACKET *request = NULL;
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+ bool raw_mode = false;
+#endif
+
+ fr_debug_lvl = 0;
+
+ while ((c = getopt(argc, argv, "d:D:f:hr:t:vx"
+#ifdef HAVE_LINUX_IF_PACKET_H
+ "i:"
+#endif
+ )) != EOF) switch(c) {
+ case 'D':
+ dict_dir = optarg;
+ break;
+
+ case 'd':
+ radius_dir = optarg;
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+#ifdef HAVE_LINUX_IF_PACKET_H
+ case 'i':
+ iface = optarg;
+ break;
+#endif
+ case 'r':
+ if (!isdigit((uint8_t) *optarg))
+ usage();
+ retries = atoi(optarg);
+ if ((retries == 0) || (retries > 1000)) usage();
+ break;
+ case 't':
+ if (!isdigit((uint8_t) *optarg))
+ usage();
+ timeout = atof(optarg);
+ break;
+ case 'v':
+ printf("%s\n", dhcpclient_version);
+ exit(0);
+
+ case 'x':
+ fr_debug_lvl++;
+ fr_log_fp = stdout;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ if (argc < 2) usage();
+
+ /* convert timeout to a struct timeval */
+#define USEC 1000000
+ tv_timeout.tv_sec = timeout;
+ tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC);
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radclient");
+ return 1;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radclient");
+ return 1;
+ }
+ fr_strerror(); /* Clear the error buffer */
+
+ /*
+ * Ensure that dictionary.dhcp is loaded.
+ */
+ da = dict_attrbyname("DHCP-Message-Type");
+ if (!da) {
+ if (dict_read(dict_dir, "dictionary.dhcp") < 0) {
+ fprintf(stderr, "Failed reading dictionary.dhcp: %s\n", fr_strerror());
+ return -1;
+ }
+ }
+
+ /*
+ * Resolve hostname.
+ */
+ server_ipaddr.af = AF_INET;
+ if (strcmp(argv[1], "-") != 0) {
+ if (fr_pton_port(&server_ipaddr, &server_port, argv[1], -1, AF_INET, true) < 0) {
+ fprintf(stderr, "dhcpclient: Failed parsing IP:port - %s", fr_strerror());
+ exit(1);
+ }
+
+ client_ipaddr.af = server_ipaddr.af;
+ }
+
+ /*
+ * See what kind of request we want to send.
+ */
+ if (argc >= 3) {
+ if (!isdigit((uint8_t) argv[2][0])) {
+ packet_code = fr_str2int(request_types, argv[2], -2);
+ if (packet_code == -2) {
+ fprintf(stderr, "Unknown packet type: %s\n", argv[2]);
+ usage();
+ }
+ } else {
+ packet_code = atoi(argv[2]);
+ }
+ }
+ if (!server_port) server_port = 67;
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+ /*
+ * set "raw mode" if an interface is specified and if destination
+ * IP address is the broadcast address.
+ */
+ if (iface) {
+ iface_ind = if_nametoindex(iface);
+ if (iface_ind <= 0) {
+ fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface);
+ fr_exit_now(1);
+ }
+
+ if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) {
+ DEBUG("dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind);
+ raw_mode = true;
+ }
+ }
+
+ if (raw_mode) {
+ sockfd = fr_socket_packet(iface_ind, &ll);
+ } else
+#endif
+ {
+ sockfd = fr_socket(&client_ipaddr, server_port + 1);
+ }
+
+ if (sockfd < 0) {
+ fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror());
+ fr_exit_now(1);
+ }
+
+ /*
+ * Set option 'receive timeout' on socket.
+ * Note: in case of a timeout, the error will be "Resource temporarily unavailable".
+ */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout,sizeof(struct timeval)) == -1) {
+ fprintf(stderr, "dhcpclient: failed setting socket timeout: %s\n",
+ fr_syserror(errno));
+ fr_exit_now(1);
+ }
+
+ request = request_init(filename);
+ if (!request || !request->vps) {
+ fprintf(stderr, "dhcpclient: Nothing to send.\n");
+ fr_exit_now(1);
+ }
+
+ /*
+ * Set defaults if they weren't specified via pairs
+ */
+ if (request->src_port == 0) request->src_port = server_port + 1;
+ if (request->dst_port == 0) request->dst_port = server_port;
+ if (request->src_ipaddr.af == AF_UNSPEC) request->src_ipaddr = client_ipaddr;
+ if (request->dst_ipaddr.af == AF_UNSPEC) request->dst_ipaddr = server_ipaddr;
+ if (!request->code) request->code = packet_code;
+
+ /*
+ * Sanity check.
+ */
+ if (!request->code) {
+ fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n",
+ (argc >= 3) ? "'auto'" : "unspecified");
+ exit(1);
+ }
+
+ if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) {
+ /* These kind of packets do not get a reply, so don't wait for one. */
+ reply_expected = false;
+ }
+
+ /*
+ * Encode the packet
+ */
+ if (fr_dhcp_encode(request) < 0) {
+ fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror());
+ fr_exit_now(1);
+ }
+ if (fr_debug_lvl) print_hex(request);
+
+#ifdef HAVE_LINUX_IF_PACKET_H
+ if (raw_mode) {
+ if (fr_dhcp_send_raw_packet(sockfd, &ll, request) < 0) {
+ fprintf(stderr, "dhcpclient: failed sending (fr_dhcp_send_raw_packet): %s\n",
+ fr_syserror(errno));
+ fr_exit_now(1);
+ }
+
+ if (reply_expected) {
+ reply = fr_dhcp_recv_raw_loop(sockfd, &ll, request);
+ if (!reply) {
+ fprintf(stderr, "dhcpclient: Error receiving reply (fr_dhcp_recv_raw_loop)\n");
+ fr_exit_now(1);
+ }
+ }
+ } else
+#endif
+ {
+ send_with_socket(request);
+ }
+
+ dict_free();
+
+ if (success) return 0;
+
+ return 1;
+}
+
+#endif /* WITH_DHCP */
diff --git a/src/modules/proto_dhcp/dhcpclient.mk b/src/modules/proto_dhcp/dhcpclient.mk
new file mode 100644
index 0000000..4266670
--- /dev/null
+++ b/src/modules/proto_dhcp/dhcpclient.mk
@@ -0,0 +1,5 @@
+TARGET := dhcpclient
+SOURCES := dhcpclient.c dhcp.c
+
+TGT_PREREQS := libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS)
diff --git a/src/modules/proto_dhcp/dhcpd.c b/src/modules/proto_dhcp/dhcpd.c
new file mode 100644
index 0000000..bc51c36
--- /dev/null
+++ b/src/modules/proto_dhcp/dhcpd.c
@@ -0,0 +1,866 @@
+/*
+ * dhcp.c DHCP processing.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2008 The FreeRADIUS server project
+ * Copyright 2008,2011 Alan DeKok <aland@deployingradius.com>
+ */
+
+/*
+ * Standard sequence:
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
+ * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 OFFER
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
+ * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 ACK
+ *
+ * Relay sequence:
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
+ * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 DISCOVER
+ * (NEXT_SERVER_IP can be a relay itself)
+ * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 OFFER
+ * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 OFFER
+ * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
+ * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 REQUEST
+ * (NEXT_SERVER_IP can be a relay itself)
+ * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 ACK
+ * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 ACK
+ *
+ * Note: NACK are broadcasted, rest is unicast, unless client asked
+ * for a broadcast
+ */
+
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/protocol.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/dhcp.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifndef __MINGW32__
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Same contents as listen_socket_t.
+ */
+typedef struct dhcp_socket_t {
+ listen_socket_t lsock;
+
+ /*
+ * DHCP-specific additions.
+ */
+ bool suppress_responses;
+ RADCLIENT dhcp_client;
+ char const *src_interface;
+ fr_ipaddr_t src_ipaddr;
+} dhcp_socket_t;
+
+#ifdef WITH_UDPFROMTO
+static int dhcprelay_process_client_request(REQUEST *request)
+{
+ int rcode;
+ uint8_t maxhops = 16;
+ VALUE_PAIR *vp, *giaddr;
+ dhcp_socket_t *sock;
+ RADIUS_PACKET *packet;
+
+ rad_assert(request->packet->data[0] == 1);
+
+ /*
+ * Do the forward by ourselves, do not rely on dhcp_socket_send()
+ */
+ request->reply->code = 0;
+
+ /*
+ * It's invalid to have giaddr=0 AND a relay option
+ */
+ giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
+ if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
+ fr_pair_find_by_num(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
+ DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n");
+ return 1;
+ }
+
+ /*
+ * RFC 1542 (BOOTP), page 15
+ *
+ * Drop requests if hop-count > 16 or admin specified another value
+ */
+ if ((vp = fr_pair_find_by_num(request->config, 271, DHCP_MAGIC_VENDOR, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */
+ maxhops = vp->vp_integer;
+ }
+ vp = fr_pair_find_by_num(request->packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Hop-Count */
+ rad_assert(vp != NULL);
+ if (vp->vp_byte > maxhops) {
+ DEBUG("DHCP: Number of hops is greater than %d: not relaying\n", maxhops);
+ return 1;
+ } else {
+ /* Increment hop count */
+ vp->vp_byte++;
+ }
+
+ sock = request->listener->data;
+
+ /*
+ * Don't muck with the original request packet. That's
+ * bad form. Plus, dhcp_encode() does nothing if
+ * packet->data is already set.
+ */
+ packet = rad_alloc(request, false);
+
+ /*
+ * Forward the request to the next server using the
+ * incoming request as a template.
+ */
+ packet->code = request->packet->code;
+ packet->sockfd = request->packet->sockfd;
+
+ /*
+ * Forward the request to the next server using the
+ * incoming request as a template.
+ */
+ /* set SRC ipaddr/port to the listener ipaddr/port */
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
+ packet->src_port = sock->lsock.my_port;
+
+ vp = fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
+ rad_assert(vp != NULL);
+
+ /* set DEST ipaddr/port to the next server ipaddr/port */
+ packet->dst_ipaddr.af = AF_INET;
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ packet->dst_port = sock->lsock.my_port;
+
+ packet->vps = request->packet->vps; /* hackity hack */
+
+ if (fr_dhcp_encode(packet) < 0) {
+ packet->vps = NULL;
+ talloc_free(packet);
+ DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n");
+ return -1;
+ }
+
+ rcode = fr_dhcp_send(packet);
+ packet->vps = NULL;
+ talloc_free(packet);
+
+ return rcode;
+}
+
+
+/*
+ * We've seen a reply from a server.
+ * i.e. we're a relay.
+ */
+static int dhcprelay_process_server_reply(REQUEST *request)
+{
+ int rcode;
+ VALUE_PAIR *vp, *giaddr;
+ dhcp_socket_t *sock;
+ RADIUS_PACKET *packet;
+
+ rad_assert(request->packet->data[0] == 2);
+
+ /*
+ * Do the forward by ourselves, do not rely on dhcp_socket_send()
+ */
+ request->reply->code = 0;
+
+ sock = request->listener->data;
+
+ /*
+ * Check that packet is for us.
+ */
+ giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
+
+ /* --with-udpfromto is needed just for the following test */
+ if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
+ DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet",
+ ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
+ return 1;
+ }
+
+ /*
+ * Don't muck with the original request packet. That's
+ * bad form. Plus, dhcp_encode() does nothing if
+ * packet->data is already set.
+ */
+ packet = rad_alloc(request, false);
+ rcode = -1;
+
+ /*
+ * Forward the request to the next server using the
+ * incoming request as a template.
+ */
+ packet->code = request->packet->code;
+ packet->sockfd = request->packet->sockfd;
+
+ /* set SRC ipaddr/port to the listener ipaddr/port */
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_port = sock->lsock.my_port;
+
+ /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
+ packet->dst_ipaddr.af = AF_INET;
+
+ /*
+ * We're a relay, figure out where to send the packet.
+ */
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ packet->dst_port = request->packet->dst_port; /* server port */
+
+ /*
+ * Unicast the response to another relay if requested.
+ */
+ vp = fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
+ if (vp) {
+ RDEBUG("DHCP: response will be relayed to previous gateway");
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ giaddr->vp_ipaddr = vp->vp_ipaddr;
+
+ } else if ((packet->code == PW_DHCP_NAK) ||
+ !sock->src_interface ||
+ ((vp = fr_pair_find_by_num(request->packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Flags */ &&
+ (vp->vp_integer & 0x8000) &&
+ ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
+ (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
+ /*
+ * RFC 2131, page 23
+ *
+ * Broadcast on
+ * - DHCPNAK
+ * or
+ * - Broadcast flag is set up and ciaddr == NULL
+ */
+ RDEBUG("DHCP: response will be broadcast");
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+
+ } else if ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
+ (vp->vp_ipaddr != htonl(INADDR_ANY))) {
+ /*
+ * RFC 2131, page 23
+ *
+ * Unicast to
+ * - ciaddr if present
+ * otherwise to yiaddr
+ */
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ } else {
+ vp = fr_pair_find_by_num(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
+ if (!vp) {
+ DEBUG("DHCP: Failed to find IP Address for request");
+ goto error;
+ }
+
+ RDEBUG("DHCP: response will be unicast to your-ip-address");
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+
+ /*
+ * When sending a DHCP_OFFER, make sure our ARP table
+ * contains an entry for the client IP address, or else
+ * packet may not be forwarded if it was the first time
+ * the client was requesting an IP address.
+ */
+ if (packet->code == PW_DHCP_OFFER) {
+ VALUE_PAIR *hwvp = fr_pair_find_by_num(request->packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
+ if (hwvp == NULL) {
+ DEBUG("DHCP: DHCP_OFFER packet received with "
+ "no Client Hardware Address. Discarding packet");
+ goto error;
+ }
+ if (fr_dhcp_add_arp_entry(packet->sockfd, sock->src_interface, hwvp, vp) < 0) {
+ DEBUG("Failed adding ARP entry: %s", fr_strerror());
+ goto error;
+ }
+ }
+ }
+
+ packet->vps = request->packet->vps; /* hackity hack */
+
+ if (fr_dhcp_encode(packet) < 0) {
+ DEBUG("dhcprelay_process_server_reply: ERROR in fr_dhcp_encode\n");
+ goto error;
+ }
+
+ rcode = fr_dhcp_send(packet);
+
+error:
+ packet->vps = NULL;
+ talloc_free(packet);
+ return rcode;
+}
+#else /* WITH_UDPFROMTO */
+static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
+{
+ WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
+ return -1;
+}
+
+static int dhcprelay_process_client_request(UNUSED REQUEST *request)
+{
+ WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
+ return -1;
+}
+
+#endif /* WITH_UDPFROMTO */
+
+static const uint32_t attrnums[] = {
+ 57, /* DHCP-DHCP-Maximum-Msg-Size */
+ 256, /* DHCP-Opcode */
+ 257, /* DHCP-Hardware-Type */
+ 258, /* DHCP-Hardware-Address-Length */
+ 259, /* DHCP-Hop-Count */
+ 260, /* DHCP-Transaction-Id */
+ 262, /* DHCP-Flags */
+ 263, /* DHCP-Client-IP-Address */
+ 266, /* DHCP-Gateway-IP-Address */
+ 267 /* DHCP-Client-Hardware-Address */
+};
+
+static int dhcp_process(REQUEST *request)
+{
+ int rcode;
+ unsigned int i;
+ VALUE_PAIR *vp;
+ dhcp_socket_t *sock;
+
+ /*
+ * If there's a giaddr, save it as the Relay-IP-Address
+ * in the response. That way the later code knows where
+ * to send the reply.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
+ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
+ VALUE_PAIR *relay;
+
+ /* DHCP-Relay-IP-Address */
+ relay = radius_pair_create(request->reply, &request->reply->vps,
+ 272, DHCP_MAGIC_VENDOR);
+ if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
+ }
+
+ /*
+ * RFC 6842: If there's a DHCP-Client-Identifier ("uid") in the
+ * request then echo this in the reply.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, 61, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Identifier */
+ if (vp && !fr_pair_find_by_num(request->reply->vps, 61, DHCP_MAGIC_VENDOR, TAG_ANY)) {
+ fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
+ }
+
+ vp = fr_pair_find_by_num(request->packet->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
+ if (vp) {
+ DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_byte);
+ DEBUG("Trying sub-section dhcp %s {...}",
+ dv ? dv->name : "<unknown>");
+ rcode = process_post_auth(vp->vp_byte, request);
+ } else {
+ DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
+ rcode = RLM_MODULE_FAIL;
+ }
+
+ vp = fr_pair_find_by_num(request->reply->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
+ if (vp) {
+ request->reply->code = vp->vp_byte;
+ if ((request->reply->code != 0) &&
+ (request->reply->code < PW_DHCP_OFFSET)) {
+ request->reply->code += PW_DHCP_OFFSET;
+ }
+ }
+ else switch (rcode) {
+ case RLM_MODULE_OK:
+ case RLM_MODULE_UPDATED:
+ if (request->packet->code == PW_DHCP_DISCOVER) {
+ request->reply->code = PW_DHCP_OFFER;
+ break;
+
+ } else if (request->packet->code == PW_DHCP_REQUEST) {
+ request->reply->code = PW_DHCP_ACK;
+ break;
+ }
+ request->reply->code = PW_DHCP_NAK;
+ break;
+
+ default:
+ case RLM_MODULE_REJECT:
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_NOOP:
+ case RLM_MODULE_NOTFOUND:
+ if (request->packet->code == PW_DHCP_DISCOVER) {
+ request->reply->code = 0; /* ignore the packet */
+ } else {
+ request->reply->code = PW_DHCP_NAK;
+ }
+ break;
+
+ case RLM_MODULE_HANDLED:
+ request->reply->code = 0; /* ignore the packet */
+ break;
+ }
+
+ /*
+ * TODO: Handle 'output' of RLM_MODULE when acting as a
+ * DHCP relay We may want to not forward packets in
+ * certain circumstances.
+ */
+
+ /*
+ * Handle requests when acting as a DHCP relay
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
+ if (!vp) {
+ RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!");
+ return 1;
+ }
+
+ /* BOOTREPLY received on port 67 (i.e. from a server) */
+ if (vp->vp_byte == 2) {
+ if (request->reply->code == 0) {
+ return 1;
+ }
+ return dhcprelay_process_server_reply(request);
+ }
+
+ /*
+ * If it's not BOOTREQUEST, we ignore it.
+ */
+ if (vp->vp_byte != 1) {
+ REDEBUG("Ignoring invalid packet code %u", vp->vp_byte);
+ return 1;
+ }
+
+ /* Packet from client, and we have DHCP-Relay-To-IP-Address */
+ if (fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY)) {
+ return dhcprelay_process_client_request(request);
+ }
+
+ sock = request->listener->data;
+
+ /*
+ * Handle requests when acting as a DHCP server
+ */
+
+ /*
+ * Releases don't get replies.
+ */
+ if (request->packet->code == PW_DHCP_RELEASE) {
+ request->reply->code = 0;
+ }
+
+ if (request->reply->code == 0) {
+ return 1;
+ }
+
+ request->reply->sockfd = request->packet->sockfd;
+
+ /*
+ * Copy specific fields from packet to reply, if they
+ * don't already exist
+ */
+ for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
+ uint32_t attr = attrnums[i];
+
+ if (fr_pair_find_by_num(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue;
+
+ vp = fr_pair_find_by_num(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
+ fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
+ }
+ }
+
+ vp = fr_pair_find_by_num(request->reply->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
+ rad_assert(vp != NULL);
+ vp->vp_byte = 2; /* BOOTREPLY */
+
+ /*
+ * Allow NAKs to be delayed for a short period of time.
+ */
+ if (request->reply->code == PW_DHCP_NAK) {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10) {
+ request->response_delay.tv_sec = vp->vp_integer;
+ request->response_delay.tv_usec = 0;
+ } else {
+ request->response_delay.tv_sec = 10;
+ request->response_delay.tv_usec = 0;
+ }
+ } else {
+#define USEC 1000000
+ vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY_USEC, 0, TAG_ANY);
+ if (vp) {
+ if (vp->vp_integer <= 10 * USEC) {
+ request->response_delay.tv_sec = vp->vp_integer / USEC;
+ request->response_delay.tv_usec = vp->vp_integer % USEC;
+ } else {
+ request->response_delay.tv_sec = 10;
+ request->response_delay.tv_usec = 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * Prepare the reply packet for sending through dhcp_socket_send()
+ */
+ request->reply->dst_ipaddr.af = AF_INET;
+ request->reply->src_ipaddr.af = AF_INET;
+ request->reply->src_ipaddr.prefix = 32;
+
+ /*
+ * Packet-Src-IP-Address has highest precedence
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_SRC_IP_ADDRESS, 0, TAG_ANY);
+ if (vp) {
+ request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ /*
+ * The request was unicast (via a relay)
+ */
+ } else if (request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_BROADCAST) &&
+ request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_ANY)) {
+ request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+ /*
+ * The listener was bound to an IP address, or we determined
+ * the address automatically, as it was the only address bound
+ * to the interface, and we bound to the interface.
+ */
+ } else if (sock->src_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_ANY)) {
+ request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
+ /*
+ * There's a Server-Identification attribute
+ */
+ } else if ((vp = fr_pair_find_by_num(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ } else {
+ REDEBUG("Unable to determine correct src_ipaddr for response");
+ return -1;
+ }
+ request->reply->dst_port = request->packet->src_port;
+ request->reply->src_port = request->packet->dst_port;
+
+ /*
+ * Answer to client's nearest DHCP relay.
+ *
+ * Which may be different than the giaddr given in the
+ * packet to the client. i.e. the relay may have a
+ * public IP, but the gateway a private one.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */
+ if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
+ RDEBUG("DHCP: Reply will be unicast to giaddr from original packet");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->reply->dst_port = request->packet->dst_port;
+
+ vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
+ if (vp) request->reply->dst_port = vp->vp_integer;
+
+ return 1;
+ }
+
+ /*
+ * Answer to client's nearest DHCP gateway. In this
+ * case, the client can reach the gateway, as can the
+ * server.
+ *
+ * We also use *our* source port as the destination port.
+ * Gateways are servers, and listen on the server port,
+ * not the client port.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
+ if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
+ RDEBUG("DHCP: Reply will be unicast to giaddr");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ request->reply->dst_port = request->packet->dst_port;
+ return 1;
+ }
+
+ /*
+ * If it's a NAK, or the broadcast flag was set, ond
+ * there's no client-ip-address, send a broadcast.
+ */
+ if ((request->reply->code == PW_DHCP_NAK) ||
+ ((vp = fr_pair_find_by_num(request->reply->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Flags */
+ (vp->vp_integer & 0x8000) &&
+ ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
+ (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
+ /*
+ * RFC 2131, page 23
+ *
+ * Broadcast on
+ * - DHCPNAK
+ * or
+ * - Broadcast flag is set up and ciaddr == NULL
+ */
+ RDEBUG("DHCP: Reply will be broadcast");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ return 1;
+ }
+
+ /*
+ * RFC 2131, page 23
+ *
+ * Unicast to ciaddr if present, otherwise to yiaddr.
+ */
+ if ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
+ (vp->vp_ipaddr != htonl(INADDR_ANY))) {
+ RDEBUG("DHCP: Reply will be sent unicast to client-ip-address");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ return 1;
+ }
+
+ vp = fr_pair_find_by_num(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
+ if (!vp) {
+ RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; "
+ "not responding");
+ /*
+ * There is nowhere to send the response to, so don't bother.
+ */
+ request->reply->code = 0;
+ return -1;
+ }
+
+#ifdef SIOCSARP
+ /*
+ * The system is configured to listen for broadcast
+ * packets, which means we'll need to send unicast
+ * replies, to IPs which haven't yet been assigned.
+ * Therefore, we need to update the ARP table.
+ *
+ * However, they haven't specified a interface. So we
+ * can't update the ARP table. And we must send a
+ * broadcast response.
+ */
+ if (sock->lsock.broadcast && !sock->src_interface) {
+ WARN("You MUST set \"interface\" if you have \"broadcast = yes\"");
+ RDEBUG("DHCP: Reply will be broadcast as no interface was defined");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ return 1;
+ }
+
+ RDEBUG("DHCP: Reply will be unicast to your-ip-address");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+
+ /*
+ * When sending a DHCP_OFFER, make sure our ARP table
+ * contains an entry for the client IP address.
+ * Otherwise the packet may not be sent to the client, as
+ * the OS has no ARP entry for it.
+ *
+ * This is a cute hack to avoid us having to create a raw
+ * socket to send DHCP packets.
+ */
+ if (request->reply->code == PW_DHCP_OFFER) {
+ VALUE_PAIR *hwvp = fr_pair_find_by_num(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
+
+ if (!hwvp) return -1;
+
+ if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
+ RDEBUG("Failed adding ARP entry: %s", fr_strerror());
+ return -1;
+ }
+ }
+#else
+ if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
+ RDEBUG("DHCP: Request will be unicast to the unicast source IP address");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ } else {
+ RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
+ request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
+ }
+#endif
+
+ return 1;
+}
+
+static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
+{
+ int rcode, broadcast = 1;
+ int on = 1;
+ dhcp_socket_t *sock;
+ RADCLIENT *client;
+ CONF_PAIR *cp;
+
+ /*
+ * Set if before parsing, so the user can forcibly turn
+ * it off later.
+ */
+ this->nodup = true;
+
+ rcode = common_socket_parse(cs, this);
+ if (rcode != 0) return rcode;
+
+ if (check_config) return 0;
+
+ sock = this->data;
+
+ if (!sock->lsock.interface) {
+ WARN("No \"interface\" setting is defined. Only unicast DHCP will work");
+ }
+
+ /*
+ * See whether or not we enable broadcast packets.
+ */
+ cp = cf_pair_find(cs, "broadcast");
+ if (cp) {
+ char const *value = cf_pair_value(cp);
+ if (value && (strcmp(value, "no") == 0)) {
+ broadcast = 0;
+ }
+ }
+
+ if (broadcast) {
+ if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+ ERROR("Can't set broadcast option: %s\n",
+ fr_syserror(errno));
+ return -1;
+ }
+ }
+
+ if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ ERROR("Can't set re-use address option: %s\n",
+ fr_syserror(errno));
+ return -1;
+ }
+
+ /*
+ * Undocumented extension for testing without
+ * destroying your network!
+ */
+ sock->suppress_responses = false;
+ cp = cf_pair_find(cs, "suppress_responses");
+ if (cp) {
+ rcode = cf_item_parse(cs, "suppress_responses", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &sock->suppress_responses), NULL);
+ if (rcode < 0) return -1;
+ }
+
+ cp = cf_pair_find(cs, "src_interface");
+ if (cp) {
+ rcode = cf_item_parse(cs, "src_interface", FR_ITEM_POINTER(PW_TYPE_STRING, &sock->src_interface), NULL);
+ if (rcode < 0) return -1;
+ } else {
+ sock->src_interface = sock->lsock.interface;
+ }
+
+ if (!sock->src_interface && sock->lsock.interface) {
+ sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
+ }
+
+ cp = cf_pair_find(cs, "src_ipaddr");
+ if (cp) {
+ memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
+ sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
+ rcode = cf_item_parse(cs, "src_ipaddr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &sock->src_ipaddr), NULL);
+ if (rcode < 0) return -1;
+
+ sock->src_ipaddr.af = AF_INET;
+ } else {
+ memcpy(&sock->src_ipaddr, &sock->lsock.my_ipaddr, sizeof(sock->src_ipaddr));
+ }
+
+ /*
+ * Initialize the fake client.
+ */
+ client = &sock->dhcp_client;
+ memset(client, 0, sizeof(*client));
+ client->ipaddr.af = AF_INET;
+ client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
+ client->ipaddr.prefix = 0;
+ client->longname = client->shortname = "dhcp";
+ client->secret = client->shortname;
+ client->nas_type = talloc_typed_strdup(sock, "none");
+
+ return 0;
+}
+
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int dhcp_socket_recv(rad_listen_t *listener)
+{
+ RADIUS_PACKET *packet;
+ dhcp_socket_t *sock;
+
+ packet = fr_dhcp_recv(listener->fd);
+ if (!packet) {
+ ERROR("%s", fr_strerror());
+ return 0;
+ }
+
+ sock = listener->data;
+ if (!request_receive(NULL, listener, packet, &sock->dhcp_client, dhcp_process)) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Send an authentication response packet
+ */
+static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ dhcp_socket_t *sock;
+
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == dhcp_socket_send);
+
+ if (request->reply->code == 0) return 0; /* don't reply */
+
+ if (fr_dhcp_encode(request->reply) < 0) {
+ DEBUG("dhcp_socket_send: ERROR\n");
+ return -1;
+ }
+
+ sock = listener->data;
+ if (sock->suppress_responses) return 0;
+
+ return fr_dhcp_send(request->reply);
+}
+
+
+static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
+{
+ return 0;
+}
+
+
+static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ return fr_dhcp_decode(request->packet);
+}
+
+extern fr_protocol_t proto_dhcp;
+fr_protocol_t proto_dhcp = {
+ .magic = RLM_MODULE_INIT,
+ .name = "dhcp",
+ .inst_size = sizeof(dhcp_socket_t),
+ .parse = dhcp_socket_parse,
+ .recv = dhcp_socket_recv,
+ .send = dhcp_socket_send,
+ .print = common_socket_print,
+ .encode = dhcp_socket_encode,
+ .decode = dhcp_socket_decode
+};
diff --git a/src/modules/proto_dhcp/libfreeradius-dhcp.mk b/src/modules/proto_dhcp/libfreeradius-dhcp.mk
new file mode 100644
index 0000000..ab2cfc4
--- /dev/null
+++ b/src/modules/proto_dhcp/libfreeradius-dhcp.mk
@@ -0,0 +1,3 @@
+TARGET := libfreeradius-dhcp.a
+
+SOURCES := dhcp.c
diff --git a/src/modules/proto_dhcp/proto_dhcp.mk b/src/modules/proto_dhcp/proto_dhcp.mk
new file mode 100644
index 0000000..c0baeca
--- /dev/null
+++ b/src/modules/proto_dhcp/proto_dhcp.mk
@@ -0,0 +1,9 @@
+TARGETNAME := proto_dhcp
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := dhcpd.c
+
+TGT_PREREQS := libfreeradius-dhcp.a
diff --git a/src/modules/proto_dhcp/rlm_dhcp.c b/src/modules/proto_dhcp/rlm_dhcp.c
new file mode 100644
index 0000000..b8a740b
--- /dev/null
+++ b/src/modules/proto_dhcp/rlm_dhcp.c
@@ -0,0 +1,203 @@
+/*
+ * 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_dhcp.c
+ * @brief Will contain dhcp listener code.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/dhcp.h>
+
+#include <ctype.h>
+
+#define PW_DHCP_PARAMETER_REQUEST_LIST 55
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_dhcp_t {
+ int nothing;
+} rlm_dhcp_t;
+
+
+/*
+ * Allow single attribute values to be retrieved from the dhcp.
+ */
+static ssize_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t freespace)
+{
+ vp_cursor_t cursor, src_cursor;
+ vp_tmpl_t src;
+ VALUE_PAIR *vp, *head = NULL;
+ int decoded = 0;
+ ssize_t slen;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ slen = tmpl_from_attr_str(&src, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ REMARKER(fmt, slen, fr_strerror());
+ error:
+ *out = '\0';
+ return -1;
+ }
+
+ if (src.type != TMPL_TYPE_ATTR) {
+ REDEBUG("dhcp_options cannot operate on a %s", fr_int2str(tmpl_names, src.type, "<INVALID>"));
+ goto error;
+ }
+
+ if (src.tmpl_da->type != PW_TYPE_OCTETS) {
+ REDEBUG("dhcp_options got a %s attribute needed octets",
+ fr_int2str(dict_attr_types, src.tmpl_da->type, "<INVALID>"));
+ goto error;
+ }
+
+ for (vp = tmpl_cursor_init(NULL, &src_cursor, request, &src);
+ vp;
+ vp = tmpl_cursor_next(&src_cursor, &src)) {
+ /*
+ * @fixme: we should pass in a cursor, then decoding multiple
+ * source attributes can be made atomic.
+ */
+ if ((fr_dhcp_decode_options(request->packet, &head, vp->vp_octets, vp->vp_length) < 0) || (!head)) {
+ RWDEBUG("DHCP option decoding failed: %s", fr_strerror());
+ goto error;
+ }
+
+ for (vp = fr_cursor_init(&cursor, &head);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ rdebug_pair(L_DBG_LVL_2, request, vp, "dhcp_options: ");
+ decoded++;
+ }
+
+ fr_pair_list_move(request->packet, &(request->packet->vps), &head, T_OP_ADD);
+
+ /* Free any unmoved pairs */
+ fr_pair_list_free(&head);
+ }
+
+ snprintf(out, freespace, "%i", decoded);
+
+ return strlen(out);
+}
+
+static ssize_t dhcp_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *head = NULL, *vp;
+ uint8_t binbuf[1024];
+ uint8_t *p = binbuf, *end = p + sizeof(binbuf);
+ ssize_t slen;
+
+ while (isspace((uint8_t) *fmt)) fmt++;
+
+ if ((radius_copy_vp(request, &head, request, fmt) < 0) || !head) {
+ *out = '\0';
+ return 0;
+ }
+ fr_cursor_init(&cursor, &head);
+
+ while ((vp = fr_cursor_current(&cursor))) {
+ slen = fr_dhcp_encode_option(request, p, end - p, &cursor);
+ talloc_free(vp);
+ if (slen <= 0) {
+ REDEBUG("DHCP option encoding failed: %s", fr_strerror());
+
+ return -1;
+ }
+ p += (size_t)slen;
+ }
+
+ if ((size_t)(((p - binbuf) * 2) + 1) > freespace) {
+ REDEBUG("DHCP option encoding failed: Output buffer exhausted, needed %zd bytes, have %zd bytes",
+ ((p - binbuf) * 2) + 1, freespace);
+
+ return -1;
+ }
+
+ return fr_bin2hex(out, binbuf, (p - binbuf));
+}
+
+
+/*
+ * Instantiate the module.
+ */
+static int mod_bootstrap(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_dhcp_t *inst = instance;
+ DICT_ATTR const *da;
+
+ xlat_register("dhcp_options", dhcp_options_xlat, NULL, inst);
+ xlat_register("dhcp", dhcp_xlat, NULL, inst);
+
+ /*
+ * Fixup dictionary entry for DHCP-Paramter-Request-List adding all the options
+ */
+ da = dict_attrbyvalue(PW_DHCP_PARAMETER_REQUEST_LIST, DHCP_MAGIC_VENDOR);
+ if (da) {
+ DICT_ATTR const *value;
+ int i;
+
+ /* No padding or termination options */
+ DEBUG3("Adding values for %s", da->name);
+ for (i = 1; i < 255; i++) {
+ value = dict_attrbyvalue(i, DHCP_MAGIC_VENDOR);
+ if (!value) {
+ DEBUG3("No DHCP RFC space attribute at %i", i);
+ continue;
+ }
+
+ DEBUG3("Adding %s value %i %s", da->name, i, value->name);
+ if (dict_addvalue(value->name, da->name, i) < 0) {
+ DEBUG3("Failed adding value: %s", fr_strerror());
+ }
+ }
+ }
+
+ 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_dhcp;
+module_t rlm_dhcp = {
+ .magic = RLM_MODULE_INIT,
+ .name = "dhcp",
+ .inst_size = sizeof(rlm_dhcp_t),
+ .bootstrap = mod_bootstrap,
+};
diff --git a/src/modules/proto_dhcp/rlm_dhcp.mk b/src/modules/proto_dhcp/rlm_dhcp.mk
new file mode 100644
index 0000000..9cd33c4
--- /dev/null
+++ b/src/modules/proto_dhcp/rlm_dhcp.mk
@@ -0,0 +1,4 @@
+TARGET := rlm_dhcp.a
+SOURCES := rlm_dhcp.c
+
+TGT_PREREQS := libfreeradius-dhcp.a
diff --git a/src/modules/proto_vmps/README.md b/src/modules/proto_vmps/README.md
new file mode 100644
index 0000000..0c7ace4
--- /dev/null
+++ b/src/modules/proto_vmps/README.md
@@ -0,0 +1,10 @@
+# proto_vmps
+## Metadata
+<dl>
+ <dt>category</dt><dd>protocols</dd>
+</dl>
+
+## Summary
+
+Implements the VLAN Management Policy Server (VMPS) protocol, as
+used by Cisco switches to dynamically assign VLANs.
diff --git a/src/modules/proto_vmps/all.mk b/src/modules/proto_vmps/all.mk
new file mode 100644
index 0000000..f7d4bb0
--- /dev/null
+++ b/src/modules/proto_vmps/all.mk
@@ -0,0 +1,8 @@
+TARGETNAME := proto_vmps
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := vmps.c vqp.c
+
diff --git a/src/modules/proto_vmps/vmps.c b/src/modules/proto_vmps/vmps.c
new file mode 100644
index 0000000..1fc0a19
--- /dev/null
+++ b/src/modules/proto_vmps/vmps.c
@@ -0,0 +1,124 @@
+/*
+ * vmps.c Handle VMPS traffic.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/protocol.h>
+#include <freeradius-devel/process.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "vqp.h"
+
+static int vmps_process(REQUEST *request)
+{
+ DEBUG2("Doing VMPS");
+ process_post_auth(0, request);
+ DEBUG2("Done VMPS");
+
+ request->packet->code = 0; /* hack for VMPS */
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+
+ return 0;
+}
+
+/*
+ * Check if an incoming request is "ok"
+ *
+ * It takes packets, not requests. It sees if the packet looks
+ * OK. If so, it does a number of sanity checks on it.
+ */
+static int vqp_socket_recv(rad_listen_t *listener)
+{
+ RADIUS_PACKET *packet;
+ RAD_REQUEST_FUNP fun = NULL;
+ RADCLIENT *client;
+
+ packet = vqp_recv(listener->fd);
+ if (!packet) {
+ ERROR("%s", fr_strerror());
+ return 0;
+ }
+
+ if ((client = client_listener_find(listener,
+ &packet->src_ipaddr,
+ packet->src_port)) == NULL) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ /*
+ * Do new stuff.
+ */
+ fun = vmps_process;
+
+ if (!request_receive(NULL, listener, packet, client, fun)) {
+ rad_free(&packet);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Send an authentication response packet
+ */
+static int vqp_socket_send(rad_listen_t *listener, REQUEST *request)
+{
+ rad_assert(request->listener == listener);
+ rad_assert(listener->send == vqp_socket_send);
+
+ if (vqp_encode(request->reply, request->packet) < 0) {
+ DEBUG2("Failed encoding packet: %s\n", fr_strerror());
+ return -1;
+ }
+
+ return vqp_send(request->reply);
+}
+
+
+static int vqp_socket_encode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ return vqp_encode(request->reply, request->packet);
+}
+
+
+static int vqp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
+{
+ return vqp_decode(request->packet);
+}
+
+extern fr_protocol_t proto_vmps;
+fr_protocol_t proto_vmps = {
+ .magic = RLM_MODULE_INIT,
+ .name = "vmps",
+ .inst_size = sizeof(listen_socket_t),
+ .parse = common_socket_parse,
+ .recv = vqp_socket_recv,
+ .send = vqp_socket_send,
+ .print = common_socket_print,
+ .encode = vqp_socket_encode,
+ .decode = vqp_socket_decode
+};
diff --git a/src/modules/proto_vmps/vqp.c b/src/modules/proto_vmps/vqp.c
new file mode 100644
index 0000000..9667387
--- /dev/null
+++ b/src/modules/proto_vmps/vqp.c
@@ -0,0 +1,721 @@
+/*
+ * vqp.c Functions to send/receive VQP packets.
+ *
+ * Version: $Id$
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/udpfromto.h>
+
+#include "vqp.h"
+
+#define MAX_VMPS_LEN (MAX_STRING_LEN - 1)
+
+/* @todo: this is a hack */
+# define debug_pair(vp) do { if (fr_debug_lvl && fr_log_fp) { \
+ vp_print(fr_log_fp, vp); \
+ } \
+ } while(0)
+/*
+ * http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/tcpdump/print-vqp.c
+ *
+ * Some of how it works:
+ *
+ * http://www.hackingciscoexposed.com/pdf/chapter12.pdf
+ *
+ * VLAN Query Protocol (VQP)
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Version | Opcode | Response Code | Data Count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Transaction ID |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type (1) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length | Data /
+ * / /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type (n) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length | Data /
+ * / /
+ * / /
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * VQP is layered over UDP. The default destination port is 1589.
+ *
+ */
+#define VQP_HDR_LEN (8)
+#define VQP_VERSION (1)
+#define VQP_MAX_ATTRIBUTES (12)
+
+
+/*
+ * Wrapper for sendto which handles sendfromto, IPv6, and all
+ * possible combinations.
+ *
+ * FIXME: This is just a copy of rad_sendto().
+ * Duplicate code is bad.
+ */
+static int vqp_sendto(int sockfd, void *data, size_t data_len, int flags,
+#ifdef WITH_UDPFROMTO
+ fr_ipaddr_t *src_ipaddr,
+#else
+ UNUSED fr_ipaddr_t *src_ipaddr,
+#endif
+ fr_ipaddr_t *dst_ipaddr,
+ uint16_t dst_port)
+{
+ struct sockaddr_storage dst;
+ socklen_t sizeof_dst;
+
+#ifdef WITH_UDPFROMTO
+ struct sockaddr_storage src;
+ socklen_t sizeof_src;
+
+ if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &src, &sizeof_src)) {
+ return -1; /* Unknown address family, Die Die Die! */
+ }
+#endif
+
+ if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) {
+ return -1; /* Unknown address family, Die Die Die! */
+ }
+
+#ifdef WITH_UDPFROMTO
+ /*
+ * Only IPv4 is supported for udpfromto.
+ *
+ * And if they don't specify a source IP address, don't
+ * use udpfromto.
+ */
+ if ((dst_ipaddr->af == AF_INET) &&
+ (src_ipaddr->af != AF_UNSPEC)) {
+ return sendfromto(sockfd, data, data_len, flags,
+ (struct sockaddr *)&src, sizeof_src,
+ (struct sockaddr *)&dst, sizeof_dst);
+ }
+#endif
+
+ /*
+ * No udpfromto, OR an IPv6 socket, fail gracefully.
+ */
+ return sendto(sockfd, data, data_len, flags,
+ (struct sockaddr *)&dst, sizeof_dst);
+}
+
+/*
+ * Wrapper for recvfrom, which handles recvfromto, IPv6, and all
+ * possible combinations.
+ *
+ * FIXME: This is copied from rad_recvfrom, with minor edits.
+ */
+static ssize_t vqp_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags,
+ fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
+ fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port)
+{
+ struct sockaddr_storage src;
+ struct sockaddr_storage dst;
+ socklen_t sizeof_src = sizeof(src);
+ socklen_t sizeof_dst = sizeof(dst);
+ ssize_t data_len;
+ uint8_t header[4];
+ size_t len;
+ uint16_t port;
+
+ memset(&src, 0, sizeof_src);
+ memset(&dst, 0, sizeof_dst);
+
+ /*
+ * Get address family, etc. first, so we know if we
+ * need to do udpfromto.
+ *
+ * FIXME: udpfromto also does this, but it's not
+ * a critical problem.
+ */
+ if (getsockname(sockfd, (struct sockaddr *)&dst,
+ &sizeof_dst) < 0) return -1;
+
+ /*
+ * Read the length of the packet, from the packet.
+ * This lets us allocate the buffer to use for
+ * reading the rest of the packet.
+ */
+ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
+ (struct sockaddr *)&src, &sizeof_src);
+ if (data_len < 0) return -1;
+
+ /*
+ * Too little data is available, discard the packet.
+ */
+ if (data_len < 4) {
+ rad_recv_discard(sockfd);
+
+ return 0;
+
+ /*
+ * Invalid version, packet type, or too many
+ * attributes. Die.
+ */
+ } else if ((header[0] != VQP_VERSION) ||
+ (header[1] < 1) ||
+ (header[1] > 4) ||
+ (header[3] > VQP_MAX_ATTRIBUTES)) {
+ rad_recv_discard(sockfd);
+
+ return 0;
+
+ } else { /* we got 4 bytes of data. */
+ /*
+ * We don't care about the contents for now...
+ */
+#if 0
+ /*
+ * How many attributes are in the packet.
+ */
+ len = header[3];
+
+ if ((header[1] == 1) || (header[1] == 3)) {
+ if (len != VQP_MAX_ATTRIBUTES) {
+ rad_recv_discard(sockfd);
+
+ return 0;
+ }
+ /*
+ * Maximum length we support.
+ */
+ len = (12 * (4 + 4 + MAX_VMPS_LEN));
+
+ } else {
+ if (len != 2) {
+ rad_recv_discard(sockfd);
+
+ return 0;
+ }
+ /*
+ * Maximum length we support.
+ */
+ len = (12 * (4 + 4 + MAX_VMPS_LEN));
+ }
+#endif
+ }
+
+ /*
+ * For now, be generous.
+ */
+ len = (12 * (4 + 4 + MAX_VMPS_LEN));
+
+ packet->data = talloc_array(packet, uint8_t, len);
+ if (!packet->data) return -1;
+
+ /*
+ * Receive the packet. The OS will discard any data in the
+ * packet after "len" bytes.
+ */
+#ifdef WITH_UDPFROMTO
+ if (dst.ss_family == AF_INET) {
+ data_len = recvfromto(sockfd, packet->data, len, flags,
+ (struct sockaddr *)&src, &sizeof_src,
+ (struct sockaddr *)&dst, &sizeof_dst);
+ } else
+#endif
+ /*
+ * No udpfromto, OR an IPv6 socket. Fail gracefully.
+ */
+ data_len = recvfrom(sockfd, packet->data, len, flags,
+ (struct sockaddr *)&src, &sizeof_src);
+ if (data_len < 0) {
+ return data_len;
+ }
+
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, &port)) {
+ return -1; /* Unknown address family, Die Die Die! */
+ }
+ *src_port = port;
+
+ fr_sockaddr2ipaddr(&dst, sizeof_dst, dst_ipaddr, &port);
+ *dst_port = port;
+
+ /*
+ * Different address families should never happen.
+ */
+ if (src.ss_family != dst.ss_family) {
+ return -1;
+ }
+
+ return data_len;
+}
+
+RADIUS_PACKET *vqp_recv(int sockfd)
+{
+ uint8_t *ptr;
+ ssize_t length;
+ uint32_t id;
+ RADIUS_PACKET *packet;
+
+ /*
+ * Allocate the new request data structure
+ */
+ packet = rad_alloc(NULL, false);
+ if (!packet) {
+ fr_strerror_printf("out of memory");
+ return NULL;
+ }
+
+ length = vqp_recvfrom(sockfd, packet, 0,
+ &packet->src_ipaddr, &packet->src_port,
+ &packet->dst_ipaddr, &packet->dst_port);
+
+ /*
+ * Check for socket errors.
+ */
+ if (length < 0) {
+ fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
+ /* packet->data is NULL */
+ rad_free(&packet);
+ return NULL;
+ }
+ packet->data_len = length; /* unsigned vs signed */
+
+ /*
+ * We can only receive packets formatted in a way we
+ * expect. However, we accept MORE attributes in a
+ * packet than normal implementations may send.
+ */
+ if (packet->data_len < VQP_HDR_LEN) {
+ fr_strerror_printf("VQP packet is too short");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ ptr = packet->data;
+
+ if (ptr[3] > VQP_MAX_ATTRIBUTES) {
+ fr_strerror_printf("Too many VQP attributes");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ if (packet->data_len > VQP_HDR_LEN) {
+ int attrlen;
+
+ /*
+ * Skip the header.
+ */
+ ptr += VQP_HDR_LEN;
+ length = packet->data_len - VQP_HDR_LEN;
+
+ while (length > 0) {
+ if (length < 7) {
+ fr_strerror_printf("Packet contains malformed attribute");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * Attributes are 4 bytes
+ * 0x00000c01 ... 0x00000c08
+ */
+ if ((ptr[0] != 0) || (ptr[1] != 0) ||
+ (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) {
+ fr_strerror_printf("Packet contains invalid attribute");
+ rad_free(&packet);
+ return NULL;
+ }
+
+ /*
+ * Length is 2 bytes
+ *
+ * We support lengths 1..253, for internal
+ * server reasons. Also, there's no reason
+ * for bigger lengths to exist... admins
+ * won't be typing in a 32K vlan name.
+ *
+ * Except for received ethernet frames...
+ * they get chopped to 253 internally.
+ */
+ if ((ptr[3] != 5) &&
+ ((ptr[4] != 0) || (ptr[5] > MAX_VMPS_LEN))) {
+ fr_strerror_printf("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]);
+ rad_free(&packet);
+ return NULL;
+ }
+ attrlen = (ptr[4] << 8) | ptr[5];
+ ptr += 6 + attrlen;
+ length -= (6 + attrlen);
+ }
+ }
+
+ packet->sockfd = sockfd;
+ packet->vps = NULL;
+
+ /*
+ * This is more than a bit of a hack.
+ */
+ packet->code = PW_CODE_ACCESS_REQUEST;
+
+ memcpy(&id, packet->data + 4, 4);
+ packet->id = ntohl(id);
+
+ /*
+ * FIXME: Create a fake "request authenticator", to
+ * avoid duplicates? Or is the VQP sequence number
+ * adequate for this purpose?
+ */
+
+ return packet;
+}
+
+/*
+ * We do NOT mirror the old-style RADIUS code that does encode,
+ * sign && send in one function. For VQP, the caller MUST perform
+ * each task manually, and separately.
+ */
+int vqp_send(RADIUS_PACKET *packet)
+{
+ if (!packet || !packet->data || (packet->data_len < 8)) return -1;
+
+ /*
+ * Don't print out the attributes, they were printed out
+ * when it was encoded.
+ */
+
+ /*
+ * And send it on it's way.
+ */
+ return vqp_sendto(packet->sockfd, packet->data, packet->data_len, 0,
+ &packet->src_ipaddr, &packet->dst_ipaddr,
+ packet->dst_port);
+}
+
+
+int vqp_decode(RADIUS_PACKET *packet)
+{
+ uint8_t *ptr, *end;
+ int attribute, length;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ if (!packet || !packet->data) return -1;
+
+ if (packet->data_len < VQP_HDR_LEN) return -1;
+
+ fr_cursor_init(&cursor, &packet->vps);
+ vp = fr_pair_afrom_num(packet, PW_VQP_PACKET_TYPE, 0);
+ if (!vp) {
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+ vp->vp_integer = packet->data[1];
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+
+ vp = fr_pair_afrom_num(packet, PW_VQP_ERROR_CODE, 0);
+ if (!vp) {
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+ vp->vp_integer = packet->data[2];
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+
+ vp = fr_pair_afrom_num(packet, PW_VQP_SEQUENCE_NUMBER, 0);
+ if (!vp) {
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+ vp->vp_integer = packet->id; /* already set by vqp_recv */
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+
+ ptr = packet->data + VQP_HDR_LEN;
+ end = packet->data + packet->data_len;
+
+ /*
+ * Note that vqp_recv() MUST ensure that the packet is
+ * formatted in a way we expect, and that vqp_recv() MUST
+ * be called before vqp_decode().
+ */
+ while (ptr < end) {
+ char *p;
+ DICT_ATTR const *da;
+
+ if ((end - ptr) < 6) break;
+
+ attribute = (ptr[2] << 8) | ptr[3];
+ length = (ptr[4] << 8) | ptr[5];
+ ptr += 6;
+
+ if ((ptr + length) > end) break;
+
+ /*
+ * Hack to get the dictionaries to work correctly.
+ */
+ attribute |= 0x2000;
+
+ /*
+ * We don't care about unknown attributes in VQP.
+ */
+ da = dict_attrbyvalue(attribute, 0);
+ if (!da) continue;
+
+ vp = fr_pair_afrom_da(packet, da);
+ if (!vp) {
+ fr_pair_list_free(&packet->vps);
+
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_ETHERNET:
+ if (length != 6) goto unknown;
+
+ memcpy(&vp->vp_ether, ptr, 6);
+ vp->vp_length = 6;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ if (length == 4) {
+ memcpy(&vp->vp_ipaddr, ptr, 4);
+ vp->vp_length = 4;
+ break;
+ }
+
+ /*
+ * Value doesn't match the type we have for the
+ * valuepair so we must change it's da to an
+ * unknown attr.
+ */
+ unknown:
+ vp->da = dict_unknown_afrom_fields(vp, vp->da->attr, vp->da->vendor);
+ /* FALL-THROUGH */
+
+ default:
+ case PW_TYPE_OCTETS:
+ if (length < 1024) {
+ fr_pair_value_memcpy(vp, ptr, length);
+ } else {
+ fr_pair_value_memcpy(vp, ptr, 1024);
+ }
+ break;
+
+ case PW_TYPE_STRING:
+ if (length < 1024) {
+ vp->vp_length = length;
+ vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
+ vp->type = VT_DATA;
+ memcpy(p, ptr, vp->vp_length);
+ p[vp->vp_length] = '\0';
+ } else {
+ vp->vp_length = 1024;
+ vp->vp_strvalue = p = talloc_array(vp, char, 1025);
+ vp->type = VT_DATA;
+ memcpy(p, ptr, vp->vp_length);
+ p[vp->vp_length] = '\0';
+ }
+ break;
+ }
+
+ ptr += length;
+ debug_pair(vp);
+ fr_cursor_insert(&cursor, vp);
+ }
+
+ /*
+ * FIXME: Map attributes to Calling-Station-Id, etc...
+ */
+
+ return 0;
+}
+
+/*
+ * These are the MUST HAVE contents for a VQP packet.
+ *
+ * We don't allow the caller to give less than these, because
+ * it won't work. We don't encode more than these, because the
+ * clients will ignore it.
+ *
+ * FIXME: Be more generous? Look for CISCO + VQP attributes?
+ */
+static int contents[5][VQP_MAX_ATTRIBUTES] = {
+ { 0, 0, 0, 0, 0, 0 },
+ { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */
+ { 0x0c03, 0x0c08, 0, 0, 0, 0 }, /* Join Response */
+ { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */
+ { 0x0c03, 0x0c08, 0, 0, 0, 0 }
+};
+
+int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
+{
+ int i, code, length;
+ VALUE_PAIR *vp;
+ uint8_t *ptr;
+ VALUE_PAIR *vps[VQP_MAX_ATTRIBUTES];
+
+ if (!packet) {
+ fr_strerror_printf("Failed encoding VQP");
+ return -1;
+ }
+
+ if (packet->data) return 0;
+
+ vp = fr_pair_find_by_num(packet->vps, PW_VQP_PACKET_TYPE, 0, TAG_ANY);
+ if (!vp) {
+ fr_strerror_printf("Failed to find VQP-Packet-Type in response packet");
+ return -1;
+ }
+
+ code = vp->vp_integer;
+ if ((code < 1) || (code > 4)) {
+ fr_strerror_printf("Invalid value %d for VQP-Packet-Type", code);
+ return -1;
+ }
+
+ length = VQP_HDR_LEN;
+ memset(vps, 0, sizeof(vps));
+
+ vp = fr_pair_find_by_num(packet->vps, PW_VQP_ERROR_CODE, 0, TAG_ANY);
+
+ /*
+ * FIXME: Map attributes from calling-station-Id, etc.
+ *
+ * Maybe do this via rlm_vqp? That's probably the
+ * best place to add the code...
+ */
+
+ /*
+ * No error: encode attributes.
+ */
+ if (!vp) for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
+ if (!contents[code][i]) break;
+
+ vps[i] = fr_pair_find_by_num(packet->vps, contents[code][i] | 0x2000, 0, TAG_ANY);
+
+ /*
+ * FIXME: Print the name...
+ */
+ if (!vps[i]) {
+ fr_strerror_printf("Failed to find VQP attribute %02x",
+ contents[code][i]);
+ return -1;
+ }
+
+ length += 6;
+ length += vps[i]->vp_length;
+ }
+
+ packet->data = talloc_array(packet, uint8_t, length);
+ if (!packet->data) {
+ fr_strerror_printf("No memory");
+ return -1;
+ }
+ packet->data_len = length;
+
+ ptr = packet->data;
+
+ ptr[0] = VQP_VERSION;
+ ptr[1] = code;
+
+ if (!vp) {
+ ptr[2] = 0;
+ } else {
+ ptr[2] = vp->vp_integer & 0xff;
+ return 0;
+ }
+
+ /*
+ * The number of attributes is hard-coded.
+ */
+ if ((code == 1) || (code == 3)) {
+ uint32_t sequence;
+
+ ptr[3] = VQP_MAX_ATTRIBUTES;
+
+ sequence = htonl(packet->id);
+ memcpy(ptr + 4, &sequence, 4);
+ } else {
+ if (!original) {
+ fr_strerror_printf("Cannot send VQP response without request");
+ return -1;
+ }
+
+ /*
+ * Packet Sequence Number
+ */
+ memcpy(ptr + 4, original->data + 4, 4);
+
+ ptr[3] = 2;
+ }
+
+ ptr += 8;
+
+ /*
+ * Encode the VP's.
+ */
+ for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) {
+ if (!vps[i]) break;
+ if (ptr >= (packet->data + packet->data_len)) break;
+
+ vp = vps[i];
+
+ debug_pair(vp);
+
+ /*
+ * Type. Note that we look at only the lower 8
+ * bits, as the upper 8 bits have been hacked.
+ * See also dictionary.vqp
+ */
+ ptr[0] = 0;
+ ptr[1] = 0;
+ ptr[2] = 0x0c;
+ ptr[3] = vp->da->attr & 0xff;
+
+ /* Length */
+ ptr[4] = 0;
+ ptr[5] = vp->vp_length & 0xff;
+
+ ptr += 6;
+
+ /* Data */
+ switch (vp->da->type) {
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(ptr, &vp->vp_ipaddr, 4);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(ptr, vp->vp_ether, vp->vp_length);
+ break;
+
+ default:
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_STRING:
+ memcpy(ptr, vp->vp_octets, vp->vp_length);
+ break;
+ }
+ ptr += vp->vp_length;
+ }
+
+ return 0;
+}
diff --git a/src/modules/proto_vmps/vqp.h b/src/modules/proto_vmps/vqp.h
new file mode 100644
index 0000000..2e3f02f
--- /dev/null
+++ b/src/modules/proto_vmps/vqp.h
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef FR_VQP_H
+#define FR_VQP_H
+
+/**
+ * $Id$
+ *
+ * @file vqp.h
+ * @brief Structures and prototypes for Cisco's VLAN Query Protocol
+ *
+ * @copyright 2007 The FreeRADIUS server project
+ * @copyright 2007 Alan DeKok <aland@deployingradius.com>
+ */
+
+RCSIDH(vqp_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+RADIUS_PACKET *vqp_recv(int sockfd);
+int vqp_send(RADIUS_PACKET *packet);
+int vqp_decode(RADIUS_PACKET *packet);
+int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FR_VQP_H */
diff --git a/src/modules/proto_vmps/vqpcli.pl b/src/modules/proto_vmps/vqpcli.pl
new file mode 100755
index 0000000..a877046
--- /dev/null
+++ b/src/modules/proto_vmps/vqpcli.pl
@@ -0,0 +1,207 @@
+#!/usr/bin/env perl
+
+# 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
+
+#
+# vqpcli.pl -s localhost -v mydomain -w 10.0.0.1 -i 2/4 -m 0010.a49f.30e3
+#
+
+use Socket;
+$|=0;
+#$DEBUG=1;
+$DEBUG=0;
+
+sub formatItem($$) {
+
+ my $mybuf;
+ undef($mybuf);
+
+ $itemheader = shift;
+ $itemvalue = shift;
+
+ $mybuf = $mybuf . pack("H*",(unpack("a*",$itemheader))); # Add header
+
+ $payload = pack("a*",(unpack("a*",$itemvalue)));
+ $length=length($payload);
+ $length= pack("H*",(unpack("a*",sprintf("%04x",$length))));
+
+ $mybuf = $mybuf . $length . $payload; # Add payload + length
+
+ return $mybuf;
+}
+
+sub parseOpts() {
+ use Getopt::Std;
+ my $errors = "";
+
+ getopts("s:v:w:i:m:t:c:",\%opt) or usage();
+ usage() if $opt{h};
+ my %request = (
+ server_ip => $opt{s} || "",
+ client_ip => $opt{w} || "127.0.0.1", # IP to say we are - VMPS doesn't care
+ port_name => $opt{i} || "Fa0/1", # Default port name to use
+ vlan => $opt{c} || "", # Isn't really needed.
+ vtp_domain => $opt{v} || "", # Is kinda important
+ macaddr => $opt{m} || "", # Likewise...
+ );
+
+ $opt{m} =~ tr/A-Z/a-z/;
+ $errors=$errors . "MAC address must be in nnnn.nnnn.nnnn format\n"
+ if ($opt{m} !~ /[a-z0-9][a-z0-9][a-z0-9][a-z0-9]\.[a-z0-9][a-z0-9][a-z0-9][a-z0-9]\.[a-z0-9][a-z0-9][a-z0-9][a-z0-9]/);
+ $errors=$errors . "VTP Domain must be specified\n" if ($opt{v} !~ /.*/);
+ $errors=$errors . "No Server name specified\n" if ($opt{s} =~ /^$/);
+ print STDERR $errors if ($errors);
+ usage() if ($errors);
+ $request{macaddr} =~ s/\.//g;
+
+ return %request;
+}
+
+sub usage() {
+ print STDERR << "EOO";
+Options:
+-s ip VMPS Server to query
+-v domain VMPS/VTP Domain to query
+-w ip client switch IP to query for
+-i iface client switch Interface name (ie: Fa0/17)
+-m macaddr attached device MAC address in nnnn.nnnn.nnnn format
+-c vlan Vlan to reconfirm membership to
+
+EOO
+ exit(1);
+
+}
+
+sub makeVQPrequest($) {
+
+ my $request = $_;
+ my $buf;
+
+ # Header...
+ $buf = $buf . pack("H*",(unpack("a*","01"))); # Header bit
+
+ # Is a request to join a vlan
+ $buf = $buf . pack("H*",(unpack("a*","01"))); # Is a request
+
+ # No error
+ $buf = $buf . pack("H*",(unpack("a*","00"))); # No error
+
+ # 6 data items in inbound payload
+ $buf = $buf . pack("H*",(unpack("a*","06")));
+
+ # Sequence number of request
+ $buf = $buf . pack("H*",(unpack("a*","000 1234"))); # Bogus sequence number
+
+ # Add Client switch IP
+ $buf = $buf . formatItem("000 0c01",(sprintf("%s",unpack("a*",inet_aton($request{client_ip})))));
+
+ # Add Port Name
+ $buf = $buf . formatItem("000 0c02",$request{port_name}); # Payload
+
+ # Add VLAN to confirm to buffer
+ $buf = $buf . formatItem("000 0c03",$request{vlan}); # Payload
+
+ # Add VTP domain name
+ $buf = $buf . formatItem("000 0c04",$request{vtp_domain}); # Payload
+
+ # Add UNKNOWN data to buffer...
+ $buf = $buf . pack("H*",(unpack("a*","000 0c07"))); # Header
+ $buf = $buf . pack("H*",(unpack("a*","0001 0"))); # Unknown filler
+
+ # Add MAC address to buffer
+ $buf = $buf . formatItem("000 0c06",sprintf("%s",pack("H*",(unpack("a*",$request{macaddr}))))); # Payload
+
+ return "$buf";
+}
+
+sub sendVQP($$) {
+
+ my $PORTNO="1589";
+ my $HOSTNAME= shift;
+ my $buf = shift;
+
+ if ($DEBUG==1) {
+ print "==============================\n";
+ print "MESSAGE SENT:\n";
+ open (HEX, "|/usr/bin/hexdump");
+ select HEX;
+ print $buf;
+ close HEX;
+ select STDOUT;
+ print "==============================\n";
+ }
+
+ socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
+
+ my $ipaddr = inet_aton($HOSTNAME);
+ my $portaddr = sockaddr_in($PORTNO, $ipaddr);
+ send(SOCKET, $buf, 0, $portaddr) == length($buf)
+ or die "cannot send to $HOSTNAME($PORTNO): $!";
+
+ $portaddr = recv(SOCKET, $buf, 1500, 0); # or die "recv: $!";
+
+ if ($DEBUG==1) {
+ print "MESSAGE RECV:\n";
+ open (HEX, "|/usr/bin/hexdump");
+ select HEX;
+ print $buf;
+ close HEX;
+ select STDOUT;
+ print "==============================\n";
+ }
+ return "$buf";
+}
+
+sub parseVQPresp($) {
+
+ my %response = (
+ status => "",
+ vlan => "",
+ macaddr => "",
+ );
+
+ my $buf = shift;
+ $buf =~ /^(.)(.)(.)(.)(....)/;
+ my ($header,$type,$status,$size,$sequence) =
+ (ord($1),ord($2),ord($3),ord($4),pack("a*",(unpack("H*",$5))));
+
+ $buf =~ s/^........//;
+
+ $response{status}="ALLOW" if ($status == 0);
+ $response{status}="DENY" if ($status == 3);
+ $response{status}="SHUTDOWN" if ($status == 4);
+ $response{status}="WRONG_DOMAIN" if ($status == 5);
+
+ for ($i=1;$i<=$size;$i++) {
+
+ $payload_type=pack("a*",(unpack("H*",substr($buf,0,4))));
+ $payload_size=sprintf("%d",hex(pack("a*",(unpack("H*",substr($buf,4,2))))));
+ $payload=substr($buf,6,$payload_size);
+
+ if ($payload_type eq "00000c03") {
+ $response{vlan}=$payload;
+ } elsif ($payload_type eq"00000c08") {
+ $response{macaddr}=pack("a*",(unpack("H*",$payload)));
+ }
+ substr($buf,0,($payload_size + 6)) = "";
+ }
+ return %response;
+}
+
+%request=parseOpts();
+$buf = makeVQPrequest(%request);
+$buf = sendVQP($request{server_ip},$buf);
+%response = parseVQPresp($buf);
+print "Vlan: $response{vlan}\nMAC Address: $response{macaddr} \nStatus: $response{status}\n";
diff --git a/src/modules/rlm_always/README.md b/src/modules/rlm_always/README.md
new file mode 100644
index 0000000..c14154d
--- /dev/null
+++ b/src/modules/rlm_always/README.md
@@ -0,0 +1,10 @@
+# rlm_always
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Returns a pre-configured result code such as 'ok', 'noop',
+'reject' etc. May be configured at runtime via an XLAT expression.
diff --git a/src/modules/rlm_always/all.mk b/src/modules/rlm_always/all.mk
new file mode 100644
index 0000000..25547f5
--- /dev/null
+++ b/src/modules/rlm_always/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_always.a
+SOURCES := rlm_always.c
diff --git a/src/modules/rlm_always/rlm_always.c b/src/modules/rlm_always/rlm_always.c
new file mode 100644
index 0000000..228bff9
--- /dev/null
+++ b/src/modules/rlm_always/rlm_always.c
@@ -0,0 +1,234 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/**
+ * $Id$
+ * @file rlm_always.c
+ * @brief Return preconfigured fixed rcodes.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modcall.h>
+
+/*
+ * The instance data for rlm_always is the list of fake values we are
+ * going to return.
+ */
+typedef struct rlm_always_t {
+ char const *name; //!< Name of this instance of the always module.
+ char const *rcode_str; //!< The base value.
+ char const *rcode_old; //!< Make changing the rcode work with %{poke:} and radmin.
+
+ rlm_rcode_t rcode; //!< The integer constant representing rcode_str.
+ uint32_t simulcount;
+ bool mpp;
+} rlm_always_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER module_config[] = {
+ { "rcode", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_always_t, rcode_str), "fail" },
+ { "simulcount", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_always_t, simulcount), "0" },
+ { "mpp", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_always_t, mpp), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Set module status or rcode
+ *
+ * Look ma, no locks...
+ *
+ * Example: "%{db_status:dead}"
+ */
+static ssize_t always_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ CONF_SECTION *cs;
+ module_instance_t *mi;
+ rlm_always_t *inst = instance;
+ char const *status = fmt;
+ char const *p;
+ size_t len;
+
+ cs = cf_section_find("modules");
+ if (!cs) return -1;
+
+ mi = module_find(cs, inst->name);
+ if (!mi) {
+ RERROR("Can't find the module that registered this xlat: %s", inst->name);
+ return -1;
+ }
+
+ /*
+ * Expand to the existing status
+ */
+ p = "alive";
+ if (mi->force) {
+ p = fr_int2str(mod_rcode_table, mi->code, "<invalid>");
+ }
+
+ len = strlen(p);
+ if (outlen < len) {
+ RWARN("Output is too short!");
+ *out = '\0';
+ } else {
+ strncpy(out, p, outlen);
+ }
+
+ if (*fmt == '\0') goto done;
+
+ /*
+ * Set the module status
+ */
+ if (strcmp(status, "alive") == 0) {
+ mi->force = false;
+
+ } else if (strcmp(status, "dead") == 0) {
+ mi->code = RLM_MODULE_FAIL;
+ mi->force = true;
+
+ } else {
+ int rcode;
+
+ rcode = fr_str2int(mod_rcode_table, status, -1);
+ if (rcode < 0) {
+ RWARN("Unknown status \"%s\"", status);
+ return -1;
+ }
+
+ mi->code = rcode;
+ mi->force = true;
+
+ }
+
+done:
+ return strlen(out);
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_always_t *inst = instance;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ xlat_register(inst->name, always_xlat, NULL, inst);
+
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_always_t *inst = instance;
+
+ /*
+ * Convert the rcode string to an int
+ */
+ inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
+ if (inst->rcode == RLM_MODULE_UNKNOWN) {
+ cf_log_err_cs(conf, "rcode value \"%s\" is invalid", inst->rcode_str);
+ return -1;
+ }
+ inst->rcode_old = NULL; /* Hack - forces the compiler not to optimise away rcode_old */
+
+ return 0;
+}
+
+/** Reparse the rcode if it changed
+ *
+ * @note Look ma, no locks...
+ *
+ * @param inst Module instance.
+ */
+static void reparse_rcode(rlm_always_t *inst)
+{
+ rlm_rcode_t rcode;
+
+ rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
+ if (rcode == RLM_MODULE_UNKNOWN) {
+ WARN("rlm_always (%s): Ignoring rcode change. rcode value \"%s\" is invalid ", inst->name,
+ inst->rcode_str);
+ return;
+ }
+
+ inst->rcode = rcode;
+ inst->rcode_old = inst->rcode_str;
+}
+
+/*
+ * Just return the rcode ... this function is autz, auth, acct, and
+ * preacct!
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_always_return(void *instance, UNUSED REQUEST *request)
+{
+ rlm_always_t *inst = instance;
+
+ if (inst->rcode_old != inst->rcode_str) reparse_rcode(inst);
+
+ return inst->rcode;
+}
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * checksimul fakes some other variables besides the rcode...
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST *request)
+{
+ struct rlm_always_t *inst = instance;
+
+ if (inst->rcode_old != inst->rcode_str) reparse_rcode(inst);
+
+ request->simul_count = inst->simulcount;
+
+ if (inst->mpp) request->simul_mpp = 2;
+
+ return inst->rcode;
+}
+#endif
+
+extern module_t rlm_always;
+module_t rlm_always = {
+ .magic = RLM_MODULE_INIT,
+ .name = "always",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_always_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_always_return,
+ [MOD_AUTHORIZE] = mod_always_return,
+ [MOD_PREACCT] = mod_always_return,
+ [MOD_ACCOUNTING] = mod_always_return,
+#ifdef WITH_SESSION_MGMT
+ [MOD_SESSION] = mod_checksimul,
+#endif
+ [MOD_PRE_PROXY] = mod_always_return,
+ [MOD_POST_PROXY] = mod_always_return,
+ [MOD_POST_AUTH] = mod_always_return,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_always_return,
+ [MOD_SEND_COA] = mod_always_return
+#endif
+ },
+};
diff --git a/src/modules/rlm_attr_filter/README.md b/src/modules/rlm_attr_filter/README.md
new file mode 100644
index 0000000..1d5f273
--- /dev/null
+++ b/src/modules/rlm_attr_filter/README.md
@@ -0,0 +1,9 @@
+# rlm_attr_filter
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Filters attributes in a request. Can delete attributes or permit them to have only certain values.
diff --git a/src/modules/rlm_attr_filter/all.mk b/src/modules/rlm_attr_filter/all.mk
new file mode 100644
index 0000000..ef23ed2
--- /dev/null
+++ b/src/modules/rlm_attr_filter/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_attr_filter.a
+SOURCES := rlm_attr_filter.c
diff --git a/src/modules/rlm_attr_filter/rlm_attr_filter.c b/src/modules/rlm_attr_filter/rlm_attr_filter.c
new file mode 100644
index 0000000..4109897
--- /dev/null
+++ b/src/modules/rlm_attr_filter/rlm_attr_filter.c
@@ -0,0 +1,374 @@
+/*
+ * 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_attr_filter.c
+ * @brief Filter the contents of a list, allowing only certain attributes.
+ *
+ * @copyright (C) 2001,2006 The FreeRADIUS server project
+ * @copyright (C) 2001 Chris Parker <cparker@starnetusa.net>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+
+/*
+ * Define a structure with the module configuration, so it can
+ * be used as the instance handle.
+ */
+typedef struct rlm_attr_filter {
+ char const *filename;
+ char const *key;
+ bool relaxed;
+ PAIR_LIST *attrs;
+} rlm_attr_filter_t;
+
+static const CONF_PARSER module_config[] = {
+ { "attrsfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_attr_filter_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_attr_filter_t, filename), NULL },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_attr_filter_t, key), "%{Realm}" },
+ { "relaxed", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_attr_filter_t, relaxed), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+static void check_pair(REQUEST *request, VALUE_PAIR *check_item, VALUE_PAIR *reply_item, int *pass, int *fail)
+{
+ int compare;
+
+ if (check_item->op == T_OP_SET) return;
+
+ compare = fr_pair_cmp(check_item, reply_item);
+ if (compare < 0) {
+ REDEBUG("Comparison failed: %s", fr_strerror());
+ }
+
+ if (compare == 1) {
+ ++*(pass);
+ } else {
+ ++*(fail);
+ }
+
+ if (RDEBUG_ENABLED3) {
+ char rule[1024], pair[1024];
+
+ vp_prints(rule, sizeof(rule), check_item);
+ vp_prints(pair, sizeof(pair), reply_item);
+ RDEBUG3("%s %s %s", pair, compare == 1 ? "allowed by" : "disallowed by", rule);
+ }
+
+ return;
+}
+
+static int attr_filter_getfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list)
+{
+ vp_cursor_t cursor;
+ int rcode;
+ PAIR_LIST *attrs = NULL;
+ PAIR_LIST *entry;
+ VALUE_PAIR *vp;
+
+ rcode = pairlist_read(ctx, filename, &attrs, 1);
+ if (rcode < 0) {
+ return -1;
+ }
+
+ /*
+ * Walk through the 'attrs' file list.
+ */
+
+ entry = attrs;
+ while (entry) {
+ entry->check = entry->reply;
+ entry->reply = NULL;
+
+ for (vp = fr_cursor_init(&cursor, &entry->check);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * If it's NOT a vendor attribute,
+ * and it's NOT a wire protocol
+ * and we ignore Fall-Through,
+ * then bitch about it, giving a good warning message.
+ */
+ if ((vp->da->vendor == 0) &&
+ (vp->da->attr > 1000)) {
+ WARN("[%s]:%d Check item \"%s\"\n\tfound in filter list for realm \"%s\".\n",
+ filename, entry->lineno, vp->da->name, entry->name);
+ }
+ }
+
+ entry = entry->next;
+ }
+
+ *pair_list = attrs;
+ return 0;
+}
+
+
+/*
+ * (Re-)read the "attrs" file into memory.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_attr_filter_t *inst = instance;
+ int rcode;
+
+ rcode = attr_filter_getfile(inst, inst->filename, &inst->attrs);
+ if (rcode != 0) {
+ ERROR("Errors reading %s", inst->filename);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Common attr_filter checks
+ */
+static rlm_rcode_t CC_HINT(nonnull(1,2)) attr_filter_common(void *instance, REQUEST *request, RADIUS_PACKET *packet)
+{
+ rlm_attr_filter_t *inst = instance;
+ VALUE_PAIR *vp;
+ vp_cursor_t input, check, out;
+ VALUE_PAIR *input_item, *check_item, *output;
+ PAIR_LIST *pl;
+ int found = 0;
+ int pass, fail = 0;
+ char const *keyname = NULL;
+ char buffer[256];
+
+ if (!packet) return RLM_MODULE_NOOP;
+
+ if (!inst->key) {
+ VALUE_PAIR *namepair;
+
+ namepair = fr_pair_find_by_num(request->packet->vps, PW_REALM, 0, TAG_ANY);
+ if (!namepair) {
+ return (RLM_MODULE_NOOP);
+ }
+ keyname = namepair->vp_strvalue;
+ } else {
+ int len;
+
+ len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL);
+ if (len < 0) {
+ return RLM_MODULE_FAIL;
+ }
+ if (len == 0) {
+ return RLM_MODULE_NOOP;
+ }
+ keyname = buffer;
+ }
+
+ /*
+ * Head of the output list
+ */
+ output = NULL;
+ fr_cursor_init(&out, &output);
+
+ /*
+ * Find the attr_filter profile entry for the entry.
+ */
+ for (pl = inst->attrs; pl; pl = pl->next) {
+ int fall_through = 0;
+ int relax_filter = inst->relaxed;
+
+ /*
+ * If the current entry is NOT a default,
+ * AND the realm does NOT match the current entry,
+ * then skip to the next entry.
+ */
+ if ((strcmp(pl->name, "DEFAULT") != 0) &&
+ (strcmp(keyname, pl->name) != 0)) {
+ continue;
+ }
+
+ RDEBUG2("Matched entry %s at line %d", pl->name, pl->lineno);
+ found = 1;
+
+ for (check_item = fr_cursor_init(&check, &pl->check);
+ check_item;
+ check_item = fr_cursor_next(&check)) {
+ if (!check_item->da->vendor &&
+ (check_item->da->attr == PW_FALL_THROUGH) &&
+ (check_item->vp_integer == 1)) {
+ fall_through = 1;
+ continue;
+ }
+ else if (!check_item->da->vendor && check_item->da->attr == PW_RELAX_FILTER) {
+ relax_filter = check_item->vp_integer;
+ continue;
+ }
+
+ /*
+ * If it is a SET operator, add the attribute to
+ * the output list without checking it.
+ */
+ if (check_item->op == T_OP_SET ) {
+ vp = fr_pair_copy(packet, check_item);
+ if (!vp) {
+ goto error;
+ }
+ radius_xlat_do(request, vp);
+ fr_cursor_insert(&out, vp);
+ }
+ }
+
+ /*
+ * Iterate through the input items, comparing
+ * each item to every rule, then moving it to the
+ * output list only if it matches all rules
+ * for that attribute. IE, Idle-Timeout is moved
+ * only if it matches all rules that describe an
+ * Idle-Timeout.
+ */
+ for (input_item = fr_cursor_init(&input, &packet->vps);
+ input_item;
+ input_item = fr_cursor_next(&input)) {
+ pass = fail = 0; /* reset the pass,fail vars for each reply item */
+
+ /*
+ * Reset the check_item pointer to beginning of the list
+ */
+ for (check_item = fr_cursor_first(&check);
+ check_item;
+ check_item = fr_cursor_next(&check)) {
+ /*
+ * Vendor-Specific is special, and matches any VSA if the
+ * comparison is always true.
+ */
+ if ((check_item->da->vendor == 0) &&
+ (check_item->da->attr == PW_VENDOR_SPECIFIC) &&
+ (input_item->da->vendor != 0) &&
+ (check_item->op == T_OP_CMP_TRUE)) {
+ pass++;
+ continue;
+ }
+
+ if (input_item->da == check_item->da) {
+ check_pair(request, check_item, input_item, &pass, &fail);
+ }
+ }
+
+ RDEBUG3("Attribute \"%s\" allowed by %i rules, disallowed by %i rules",
+ input_item->da->name, pass, fail);
+ /*
+ * Only move attribute if it passed all rules, or if the config says we
+ * should copy unmatched attributes ('relaxed' mode).
+ */
+ if (fail == 0 && (pass > 0 || relax_filter)) {
+ if (!pass) {
+ RDEBUG3("Attribute \"%s\" allowed by relaxed mode", input_item->da->name);
+ }
+ vp = fr_pair_copy(packet, input_item);
+ if (!vp) {
+ goto error;
+ }
+ fr_cursor_insert(&out, vp);
+ }
+ }
+
+ /* If we shouldn't fall through, break */
+ if (!fall_through) {
+ break;
+ }
+ }
+
+ /*
+ * No entry matched. We didn't do anything.
+ */
+ if (!found) {
+ rad_assert(!output);
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Replace the existing request list with our filtered one
+ */
+ fr_pair_list_free(&packet->vps);
+ packet->vps = output;
+
+ if (request->packet->code == PW_CODE_ACCESS_REQUEST) {
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+ if (!request->username) {
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ }
+
+ return RLM_MODULE_UPDATED;
+
+ error:
+ fr_pair_list_free(&output);
+ return RLM_MODULE_FAIL;
+}
+
+#define RLM_AF_FUNC(_x, _y) static rlm_rcode_t CC_HINT(nonnull) mod_##_x(void *instance, REQUEST *request) \
+ { \
+ return attr_filter_common(instance, request, request->_y); \
+ }
+
+RLM_AF_FUNC(authorize, packet)
+RLM_AF_FUNC(post_auth, reply)
+
+RLM_AF_FUNC(preacct, packet)
+RLM_AF_FUNC(accounting, reply)
+
+#ifdef WITH_PROXY
+RLM_AF_FUNC(pre_proxy, proxy)
+RLM_AF_FUNC(post_proxy, proxy_reply)
+#endif
+
+#ifdef WITH_COA
+RLM_AF_FUNC(recv_coa, packet)
+RLM_AF_FUNC(send_coa, reply)
+#endif
+
+/* globally exported name */
+extern module_t rlm_attr_filter;
+module_t rlm_attr_filter = {
+ .magic = RLM_MODULE_INIT,
+ .name = "attr_filter",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_attr_filter_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ },
+};
+
diff --git a/src/modules/rlm_cache/.gitignore b/src/modules/rlm_cache/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_cache/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_cache/README.md b/src/modules/rlm_cache/README.md
new file mode 100644
index 0000000..72b400b
--- /dev/null
+++ b/src/modules/rlm_cache/README.md
@@ -0,0 +1,11 @@
+# rlm_cache
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Stores attributes and/or lists and adds them back to a subsequent
+request, or to the current request on a later execution of the
+module.
diff --git a/src/modules/rlm_cache/all.mk.in b/src/modules/rlm_cache/all.mk.in
new file mode 100644
index 0000000..f527b38
--- /dev/null
+++ b/src/modules/rlm_cache/all.mk.in
@@ -0,0 +1,7 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+SUBMAKEFILES := $(TARGETNAME).mk \
+ $(wildcard ${top_srcdir}/src/modules/rlm_cache/drivers/rlm_cache_*/all.mk)
+endif
+
diff --git a/src/modules/rlm_cache/configure b/src/modules/rlm_cache/configure
new file mode 100755
index 0000000..d75f9d8
--- /dev/null
+++ b/src/modules/rlm_cache/configure
@@ -0,0 +1,3966 @@
+#! /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_cache.c"
+enable_option_checking=no
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+targetname
+subdirs
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_cache
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+ac_subdirs_all='$mysubdirs'
+
+# 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_cache build without rlm_cache
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_cache
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_cache was given.
+if test "${with_rlm_cache+set}" = set; then :
+ withval=$with_rlm_cache;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_cache" != 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
+
+
+mysubdirs=
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `find ./drivers -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ mysubdirs="$mysubdirs $bar"
+ done
+else
+ for foo in `cat stable`; do
+ mysubdirs="$mysubdirs ./drivers/$foo"
+ done
+fi
+
+ln -s ../../../install-sh install-sh
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+
+subdirs="$subdirs $mysubdirs"
+
+rm install-sh
+
+
+ targetname=rlm_cache
+else
+ targetname=
+ echo \*\*\* module rlm_cache is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_cache." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_cache." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_cache requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_cache requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+ # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+ # so they do not pile up.
+ ac_sub_configure_args=
+ ac_prev=
+ eval "set x $ac_configure_args"
+ shift
+ for ac_arg
+ do
+ if test -n "$ac_prev"; then
+ ac_prev=
+ continue
+ fi
+ case $ac_arg in
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
+ | --c=*)
+ ;;
+ --config-cache | -C)
+ ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ ;;
+ --disable-option-checking)
+ ;;
+ *)
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+ esac
+ done
+
+ # Always prepend --prefix to ensure using the same prefix
+ # in subdir configurations.
+ ac_arg="--prefix=$prefix"
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+ # Pass --silent
+ if test "$silent" = yes; then
+ ac_sub_configure_args="--silent $ac_sub_configure_args"
+ fi
+
+ # Always prepend --disable-option-checking to silence warnings, since
+ # different subdirs can have different --enable and --with options.
+ ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+ ac_popdir=`pwd`
+ for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+ # Do not complain, so a configure script can configure whichever
+ # parts of a large source tree are present.
+ test -d "$srcdir/$ac_dir" || continue
+
+ ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+ $as_echo "$ac_msg" >&6
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ cd "$ac_dir"
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ ac_sub_configure=$ac_srcdir/configure.gnu
+ elif test -f "$ac_srcdir/configure"; then
+ ac_sub_configure=$ac_srcdir/configure
+ elif test -f "$ac_srcdir/configure.in"; then
+ # This should be Cygnus configure.
+ ac_sub_configure=$ac_aux_dir/configure
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+ ac_sub_configure=
+ fi
+
+ # The recursion is here.
+ if test -n "$ac_sub_configure"; then
+ # Make the cache file name correct relative to the subdirectory.
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+ *) # Relative name.
+ ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+ # The eval makes quoting arguments work.
+ eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+ as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+ fi
+
+ cd "$ac_popdir"
+ done
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_cache/configure.ac b/src/modules/rlm_cache/configure.ac
new file mode 100644
index 0000000..8007283
--- /dev/null
+++ b/src/modules/rlm_cache/configure.ac
@@ -0,0 +1,35 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_cache.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_cache])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+
+mysubdirs=
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `find ./drivers -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ mysubdirs="$mysubdirs $bar"
+ done
+else
+ for foo in `cat stable`; do
+ mysubdirs="$mysubdirs ./drivers/$foo"
+ done
+fi
+
+dnl # don't ask... this is done to avoid autoconf stupidities.
+ln -s ../../../install-sh install-sh
+
+AC_CONFIG_SUBDIRS($mysubdirs)
+rm install-sh
+
+FR_MODULE_END_TESTS([nostrict])
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/.gitignore b/src/modules/rlm_cache/drivers/rlm_cache_memcached/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/all.mk.in b/src/modules/rlm_cache/drivers/rlm_cache_memcached/all.mk.in
new file mode 100644
index 0000000..8b720e2
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c ../../serialize.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure b/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure
new file mode 100755
index 0000000..b0654a6
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure
@@ -0,0 +1,4593 @@
+#! /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_cache_memcached.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_cache_memcached
+with_libmemcached_include_dir
+with_libmemcached_lib_dir
+with_libmemcached_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_cache_memcached
+ build without rlm_cache_memcached
+ --with-libmemcached-include-dir=DIR
+ Directory where the libmemcached includes may be
+ found
+ --with-libmemcached-lib-dir=DIR
+ Directory where the libmemcached libraries may be
+ found
+ --with-libmemcached-dir=DIR
+ Base directory where libmemcached 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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_cache_memcached
+echo
+
+
+# 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_cache_memcached was given.
+if test "${with_rlm_cache_memcached+set}" = set; then :
+ withval=$with_rlm_cache_memcached;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_cache_memcached" != 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
+
+
+
+libmemcached_include_dir=
+
+# Check whether --with-libmemcached-include-dir was given.
+if test "${with_libmemcached_include_dir+set}" = set; then :
+ withval=$with_libmemcached_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libmemcached-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+libmemcached_lib_dir=
+
+# Check whether --with-libmemcached-lib-dir was given.
+if test "${with_libmemcached_lib_dir+set}" = set; then :
+ withval=$with_libmemcached_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libmemcached-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-libmemcached-dir was given.
+if test "${with_libmemcached_dir+set}" = set; then :
+ withval=$with_libmemcached_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libmemcached-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_lib_dir="$withval/lib"
+ libmemcached_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+
+smart_try_dir="$libmemcached_include_dir"
+
+
+
+ac_safe=`echo "libmemcached/memcached.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 libmemcached/memcached.h in $try" >&5
+$as_echo_n "checking for libmemcached/memcached.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libmemcached/memcached.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}/libmemcached/memcached.h" >&5
+$as_echo_n "checking for ${_prefix}/libmemcached/memcached.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libmemcached/memcached.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 libmemcached/memcached.h" >&5
+$as_echo_n "checking for libmemcached/memcached.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libmemcached/memcached.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 libmemcached/memcached.h in $try" >&5
+$as_echo_n "checking for libmemcached/memcached.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libmemcached/memcached.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_libmemcached_memcached_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libmemcached headers not found. Use --with-libmemcached-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libmemcached headers not found. Use --with-libmemcached-include-dir=<path>." >&2;}
+
+fail="$fail memcached.h"
+
+fi
+
+
+
+
+sm_lib_safe=`echo "pthread" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "pthread_once" | 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 pthread_once in -lpthread in $try" >&5
+$as_echo_n "checking for pthread_once in -lpthread in $try... " >&6; }
+ LIBS="-lpthread $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pthread_once();
+int
+main ()
+{
+pthread_once()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpthread"
+ 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 pthread_once in -lpthread" >&5
+$as_echo_n "checking for pthread_once in -lpthread... " >&6; }
+ LIBS="-lpthread $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pthread_once();
+int
+main ()
+{
+pthread_once()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpthread"
+ { $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 pthread_once in -lpthread in $try" >&5
+$as_echo_n "checking for pthread_once in -lpthread in $try... " >&6; }
+ LIBS="-lpthread $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char pthread_once();
+int
+main ()
+{
+pthread_once()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpthread"
+ 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
+
+
+smart_try_dir="$libmemcached_lib_dir"
+
+
+sm_lib_safe=`echo "memcached" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "memcached" | 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 memcached in -lmemcached in $try" >&5
+$as_echo_n "checking for memcached in -lmemcached in $try... " >&6; }
+ LIBS="-lmemcached $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char memcached();
+int
+main ()
+{
+memcached()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmemcached"
+ 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 memcached in -lmemcached" >&5
+$as_echo_n "checking for memcached in -lmemcached... " >&6; }
+ LIBS="-lmemcached $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char memcached();
+int
+main ()
+{
+memcached()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmemcached"
+ { $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 memcached in -lmemcached in $try" >&5
+$as_echo_n "checking for memcached in -lmemcached in $try... " >&6; }
+ LIBS="-lmemcached $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char memcached();
+int
+main ()
+{
+memcached()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmemcached"
+ 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_memcached_memcached" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libmemcached libraries not found. Use --with-libmemcached-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libmemcached libraries not found. Use --with-libmemcached-lib-dir=<path>." >&2;}
+
+fail="$fail libmemcached"
+
+else
+ for ac_func in \
+ memcached \
+ memcached_free \
+ memcached_get \
+ memcached_set \
+ memcached_delete \
+ libmemcached_check_configuration \
+
+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
+
+else
+
+
+fail="$fail memached functions"
+
+
+fi
+done
+
+fi
+
+
+
+ targetname=rlm_cache_memcached
+else
+ targetname=
+ echo \*\*\* module rlm_cache_memcached is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_cache_memcached to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_cache_memcached." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_cache_memcached." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_cache_memcached requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_cache_memcached requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure.ac b/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure.ac
new file mode 100644
index 0000000..e0ee16d
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/configure.ac
@@ -0,0 +1,115 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_cache_memcached.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_cache_memcached])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl ############################################################
+dnl # Check for libmemcached
+dnl ############################################################
+
+dnl extra argument: --with-libmemcached-include-dir=DIR
+libmemcached_include_dir=
+AC_ARG_WITH(libmemcached-include-dir,
+ [AS_HELP_STRING([--with-libmemcached-include-dir=DIR],
+ [Directory where the libmemcached includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libmemcached-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-libmemcached-lib-dir=DIR
+libmemcached_lib_dir=
+AC_ARG_WITH(libmemcached-lib-dir,
+[AS_HELP_STRING([--with-libmemcached-lib-dir=DIR],
+ [Directory where the libmemcached libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libmemcached-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-libmemcached-dir=DIR
+AC_ARG_WITH(libmemcached-dir,
+[AS_HELP_STRING([--with-libmemcached-dir=DIR],
+ [Base directory where libmemcached is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libmemcached-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libmemcached_lib_dir="$withval/lib"
+ libmemcached_include_dir="$withval/include"
+ ;;
+ esac])
+
+
+dnl ############################################################
+dnl # Check for libmemcached header files
+dnl ############################################################
+
+smart_try_dir="$libmemcached_include_dir"
+FR_SMART_CHECK_INCLUDE([libmemcached/memcached.h])
+if test "x$ac_cv_header_libmemcached_memcached_h" != "xyes"; then
+ AC_MSG_WARN([libmemcached headers not found. Use --with-libmemcached-include-dir=<path>.])
+ FR_MODULE_FAIL([memcached.h])
+fi
+
+dnl ############################################################
+dnl # Check for libmemcached libraries
+dnl ############################################################
+
+dnl # Check if libpthread is available. Should add -lpthread
+dnl # to CFLAGS when checking for memcached.
+FR_SMART_CHECK_LIB([pthread], [pthread_once])
+
+smart_try_dir="$libmemcached_lib_dir"
+dnl # Use a libmemcached specific function which is only
+dnl # available in newer versions.
+FR_SMART_CHECK_LIB([memcached], [memcached])
+if test "x$ac_cv_lib_memcached_memcached" != "xyes"
+then
+ AC_MSG_WARN([libmemcached libraries not found. Use --with-libmemcached-lib-dir=<path>.])
+ FR_MODULE_FAIL([libmemcached])
+else
+ AC_CHECK_FUNCS(\
+ memcached \
+ memcached_free \
+ memcached_get \
+ memcached_set \
+ memcached_delete \
+ libmemcached_check_configuration \
+ ,[], [
+ FR_MODULE_FAIL([memached functions])
+ ])
+fi
+
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c
new file mode 100644
index 0000000..a8161cb
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c
@@ -0,0 +1,347 @@
+/*
+ * 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_cache_memcached.c
+ * @brief memcached based cache.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+#include <libmemcached/memcached.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "../../rlm_cache.h"
+#include "../../serialize.h"
+
+typedef struct rlm_cache_memcached_handle {
+ memcached_st *handle;
+} rlm_cache_memcached_handle_t;
+
+typedef struct rlm_cache_memcached {
+ char const *options; //!< Connection options
+ fr_connection_pool_t *pool;
+} rlm_cache_memcached_t;
+
+static const CONF_PARSER driver_config[] = {
+ { "options", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_cache_memcached_t, options), "--SERVER=localhost" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Free a connection handle
+ *
+ * @param mandle to free.
+ */
+static int _mod_conn_free(rlm_cache_memcached_handle_t *mandle)
+{
+ if (mandle->handle) memcached_free(mandle->handle);
+
+ return 0;
+}
+
+/** Create a new memcached handle
+ *
+ * @param ctx to allocate handle in.
+ * @param instance data.
+ */
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_cache_t *inst = instance;
+ rlm_cache_memcached_t *driver = inst->driver;
+ rlm_cache_memcached_handle_t *mandle;
+
+ memcached_st *sandle;
+ memcached_return_t ret;
+
+ sandle = memcached(driver->options, talloc_array_length(driver->options) -1);
+ if (!sandle) {
+ ERROR("rlm_cache_memcached: Failed creating memcached connection");
+
+ return NULL;
+ }
+
+ ret = memcached_version(sandle);
+ if (ret != MEMCACHED_SUCCESS) {
+ ERROR("rlm_cache_memcached: Failed getting server info: %s: %s", memcached_strerror(sandle, ret),
+ memcached_last_error_message(sandle));
+ memcached_free(sandle);
+ return NULL;
+ }
+
+ mandle = talloc_zero(ctx, rlm_cache_memcached_handle_t);
+ mandle->handle = sandle;
+ talloc_set_destructor(mandle, _mod_conn_free);
+
+ return mandle;
+}
+
+/** Cleanup a rlm_cache_memcached instance
+ *
+ * @param driver to free.
+ * @return 0
+ */
+static int _mod_detach(rlm_cache_memcached_t *driver)
+{
+ fr_connection_pool_free(driver->pool);
+ return 0;
+}
+
+/** Create a new rlm_cache_memcached instance
+ *
+ * @param conf memcached specific conf section.
+ * @param inst main rlm_cache instance.
+ * @return 0 on success, -1 on failure.
+ */
+static int mod_instantiate(CONF_SECTION *conf, rlm_cache_t *inst)
+{
+ rlm_cache_memcached_t *driver;
+ memcached_return_t ret;
+
+ char buffer[256];
+
+ static bool version_done;
+
+ buffer[0] = '\0';
+
+ /*
+ * Get version info from the libmemcached API.
+ */
+ if (!version_done) {
+ version_done = true;
+
+ INFO("rlm_cache_memcached: libmemcached version: %s", memcached_lib_version());
+ }
+
+ driver = talloc_zero(inst, rlm_cache_memcached_t);
+ talloc_set_destructor(driver, _mod_detach);
+
+ if (cf_section_parse(conf, driver, driver_config) < 0) return -1;
+
+ ret = libmemcached_check_configuration(driver->options, talloc_array_length(driver->options) -1,
+ buffer, sizeof(buffer));
+ if (ret != MEMCACHED_SUCCESS) {
+ ERROR("rlm_cache_memcached: Failed validating options string: %s", buffer);
+ return -1;
+ }
+
+ inst->driver = driver;
+
+ snprintf(buffer, sizeof(buffer), "rlm_cache (%s)", inst->name);
+
+ driver->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, buffer);
+ if (!driver->pool) return -1;
+
+ if (inst->max_entries > 0) WARN("rlm_cache_memcached: max_entries is not supported by this driver");
+
+ return 0;
+}
+
+static void cache_entry_free(rlm_cache_entry_t *c)
+{
+ talloc_free(c);
+}
+
+/** Locate a cache entry in memcached
+ *
+ * @param out Where to write the pointer to the cach entry.
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to memcached handle.
+ * @param key to search for.
+ * @return CACHE_OK on success CACHE_MISS if no entry found, CACHE_ERROR on error.
+ */
+static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, char const *key)
+{
+ rlm_cache_memcached_handle_t *mandle = *handle;
+
+ memcached_return_t mret;
+ size_t len;
+ int ret;
+ uint32_t flags;
+
+ char *from_store;
+
+ rlm_cache_entry_t *c;
+
+ from_store = memcached_get(mandle->handle, key, strlen(key), &len, &flags, &mret);
+ if (!from_store) {
+ if (mret == MEMCACHED_NOTFOUND) return CACHE_MISS;
+
+ RERROR("Failed retrieving entry for key \"%s\": %s: %s", key, memcached_strerror(mandle->handle, mret),
+ memcached_last_error_message(mandle->handle));
+
+ return CACHE_ERROR;
+ }
+ RDEBUG2("Retrieved %zu bytes from memcached", len);
+ RDEBUG2("%s", from_store);
+
+ c = talloc_zero(NULL, rlm_cache_entry_t);
+ ret = cache_deserialize(c, from_store, len);
+ free(from_store);
+ if (ret < 0) {
+ RERROR("%s", fr_strerror());
+ talloc_free(c);
+ return CACHE_ERROR;
+ }
+ c->key = talloc_strdup(c, key);
+ *out = c;
+
+ return CACHE_OK;
+}
+
+/** Insert a new entry into the data store
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to memcached handle.
+ * @param c entry to insert.
+ * @return CACHE_OK on success else CACHE_ERROR on error.
+ */
+static cache_status_t cache_entry_insert(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_memcached_handle_t *mandle = *handle;
+
+ memcached_return_t ret;
+
+ TALLOC_CTX *pool;
+ char *to_store;
+
+ pool = talloc_pool(NULL, 1024);
+ if (!pool) return CACHE_ERROR;
+
+ if (cache_serialize(pool, &to_store, c) < 0) {
+ talloc_free(pool);
+
+ return CACHE_ERROR;
+ }
+
+ ret = memcached_set(mandle->handle, c->key, talloc_array_length(c->key) - 1,
+ to_store ? to_store : "",
+ to_store ? talloc_array_length(to_store) - 1 : 0, c->expires, 0);
+ talloc_free(pool);
+ if (ret != MEMCACHED_SUCCESS) {
+ RERROR("Failed storing entry with key \"%s\": %s: %s", c->key,
+ memcached_strerror(mandle->handle, ret),
+ memcached_last_error_message(mandle->handle));
+
+ return CACHE_ERROR;
+ }
+
+ return CACHE_OK;
+}
+
+/** Call delete the cache entry from memcached
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to memcached handle.
+ * @param c entry to expire.
+ * @return CACHE_OK on success else CACHE_ERROR.
+ */
+static cache_status_t cache_entry_expire(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_memcached_handle_t *mandle = *handle;
+
+ memcached_return_t ret;
+
+ ret = memcached_delete(mandle->handle, c->key, talloc_array_length(c->key) - 1, 0);
+ if (ret != MEMCACHED_SUCCESS) {
+ RERROR("Failed deleting entry with key \"%s\": %s", c->key,
+ memcached_last_error_message(mandle->handle));
+
+ return CACHE_ERROR;
+ }
+
+ return CACHE_OK;
+}
+
+/** Get a memcached handle
+ *
+ * @param out Where to write the handle.
+ * @param inst rlm_cache instance.
+ * @param request The current request.
+ */
+static int mod_conn_get(rlm_cache_handle_t **out, rlm_cache_t *inst, UNUSED REQUEST *request)
+{
+ rlm_cache_memcached_t *driver = inst->driver;
+ rlm_cache_handle_t *mandle;
+
+ *out = NULL;
+
+ mandle = fr_connection_get(driver->pool);
+ if (!mandle) {
+ *out = NULL;
+ return -1;
+ }
+ *out = mandle;
+
+ return 0;
+}
+
+/** Release a socket
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to the handle to release (will be set to NULL).
+ */
+static void mod_conn_release(rlm_cache_t *inst, UNUSED REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rlm_cache_memcached_t *driver = inst->driver;
+
+ fr_connection_release(driver->pool, *handle);
+ *handle = NULL;
+}
+
+/** Reconnect a socket
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to the handle to reconnect (will be set to NULL if reconnection fails).
+ */
+static int mod_conn_reconnect(rlm_cache_t *inst, UNUSED REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rlm_cache_memcached_t *driver = inst->driver;
+ rlm_cache_handle_t *mandle;
+
+ mandle = fr_connection_reconnect(driver->pool, *handle);
+ if (!mandle) {
+ *handle = NULL;
+ return -1;
+ }
+ *handle = mandle;
+
+ return 0;
+}
+
+extern cache_module_t rlm_cache_memcached;
+cache_module_t rlm_cache_memcached = {
+ .name = "rlm_cache_memcached",
+ .instantiate = mod_instantiate,
+ .free = cache_entry_free,
+
+ .find = cache_entry_find,
+ .insert = cache_entry_insert,
+ .expire = cache_entry_expire,
+
+ .acquire = mod_conn_get,
+ .release = mod_conn_release,
+ .reconnect = mod_conn_reconnect
+};
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/all.mk b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/all.mk
new file mode 100644
index 0000000..21f6ba7
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/all.mk
@@ -0,0 +1,3 @@
+TARGET := rlm_cache_rbtree.a
+SOURCES := rlm_cache_rbtree.c
+TGT_LDLIBS := $(LIBS)
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c
new file mode 100644
index 0000000..2db7c93
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c
@@ -0,0 +1,351 @@
+/*
+ * 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_cache_rbtree.c
+ * @brief Simple rbtree based cache.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/heap.h>
+#include <freeradius-devel/rad_assert.h>
+#include "../../rlm_cache.h"
+
+#ifdef HAVE_PTHREAD_H
+# define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+# define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+# define PTHREAD_MUTEX_LOCK(_x)
+# define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+typedef struct rlm_cache_rbtree {
+ rbtree_t *cache; //!< Tree for looking up cache keys.
+ fr_heap_t *heap; //!< For managing entry expiry.
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex; //!< Protect the tree from multiple readers/writers.
+#endif
+} rlm_cache_rbtree_t;
+
+typedef struct rlm_cache_rbtree_entry {
+ rlm_cache_entry_t fields; //!< Entry data.
+ size_t offset; //!< Offset used for heap.
+} rlm_cache_rbtree_entry_t;
+
+/*
+ * Compare two entries by key. There may only be one entry with
+ * the same key.
+ */
+static int cache_entry_cmp(void const *one, void const *two)
+{
+ rlm_cache_entry_t const *a = one;
+ rlm_cache_entry_t const *b = two;
+
+ return strcmp(a->key, b->key);
+}
+
+/*
+ * Compare two entries by expiry time. There may be multiple
+ * entries with the same expiry time.
+ */
+static int cache_heap_cmp(void const *one, void const *two)
+{
+ rlm_cache_entry_t const *a = one;
+ rlm_cache_entry_t const *b = two;
+
+ if (a->expires < b->expires) return -1;
+ if (a->expires > b->expires) return +1;
+
+ return 0;
+}
+
+/** Walk over the cache rbtree
+ *
+ * Used to free any entries left in the tree on detach.
+ *
+ * @param ctx unused.
+ * @param data to free.
+ * @return 2
+ */
+static int _cache_entry_free(UNUSED void *ctx, void *data)
+{
+ talloc_free(data);
+
+ return 2;
+}
+
+/** Cleanup a cache_rbtree instance
+ *
+ * @param driver to free.
+ * @return 0
+ */
+static int _mod_detach(rlm_cache_rbtree_t *driver)
+{
+ if (driver->heap) fr_heap_delete(driver->heap);
+ if (driver->cache) {
+ rbtree_walk(driver->cache, RBTREE_DELETE_ORDER, _cache_entry_free, NULL);
+ rbtree_free(driver->cache);
+ }
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&driver->mutex);
+#endif
+ return 0;
+}
+
+/** Create a new cache_rbtree instance
+ *
+ * @param conf rbtree specific conf section.
+ * @param inst main rlm_cache instance.
+ * @return 0 on success, -1 on failure.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, rlm_cache_t *inst)
+{
+ rlm_cache_rbtree_t *driver;
+
+ driver = talloc_zero(inst, rlm_cache_rbtree_t);
+ talloc_set_destructor(driver, _mod_detach);
+ /*
+ * The cache.
+ */
+ driver->cache = rbtree_create(NULL, cache_entry_cmp, NULL, 0);
+ if (!driver->cache) {
+ ERROR("Failed to create cache");
+ return -1;
+ }
+ fr_link_talloc_ctx_free(driver, driver->cache);
+
+ /*
+ * The heap of entries to expire.
+ */
+ driver->heap = fr_heap_create(cache_heap_cmp, offsetof(rlm_cache_rbtree_entry_t, offset));
+ if (!driver->heap) {
+ ERROR("Failed to create heap for the cache");
+ return -1;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&driver->mutex, NULL) < 0) {
+ ERROR("Failed initializing mutex: %s", fr_syserror(errno));
+ return -1;
+ }
+#endif
+
+ inst->driver = driver;
+
+ return 0;
+}
+
+/** Custom allocation function for the driver
+ *
+ * Allows allocation of cache entry structures with additional fields.
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @return 0 on success, -1 on failure.
+ */
+static rlm_cache_entry_t *cache_entry_alloc(UNUSED rlm_cache_t *inst, REQUEST *request)
+{
+ rlm_cache_rbtree_entry_t *c;
+
+ c = talloc_zero(NULL, rlm_cache_rbtree_entry_t);
+ if (!c) {
+ REDEBUG("Failed allocating cache entry");
+ return NULL;
+ }
+
+ return (rlm_cache_entry_t *)c;
+}
+
+/** Locate a cache entry
+ *
+ * @param out Where to write the search result.
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Dummy handle (not used).
+ * @param key to search for.
+ * @return CACHE_OK on success CACHE_MISS if no entry found.
+ */
+static cache_status_t cache_entry_find(rlm_cache_entry_t **out, rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, char const *key)
+{
+ rlm_cache_rbtree_t *driver = inst->driver;
+
+ rlm_cache_entry_t *c, my_c;
+
+ rad_assert(*handle == request);
+
+ /*
+ * Clear out old entries
+ */
+ c = fr_heap_peek(driver->heap);
+ if (c && (c->expires < request->timestamp)) {
+ fr_heap_extract(driver->heap, c);
+ rbtree_deletebydata(driver->cache, c);
+ talloc_free(c);
+ }
+
+ /*
+ * Is there an entry for this key?
+ */
+ my_c.key = key;
+ c = rbtree_finddata(driver->cache, &my_c);
+ if (!c) {
+ *out = NULL;
+ return CACHE_MISS;
+ }
+ *out = c;
+
+ return CACHE_OK;
+}
+
+/** Insert a new entry into the data store
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Dummy handle (not used).
+ * @param c entry to insert.
+ * @return CACHE_OK on success else CACHE_ERROR on error.
+ */
+static cache_status_t cache_entry_insert(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_rbtree_t *driver = inst->driver;
+
+ rad_assert(*handle == request);
+
+ if (!rbtree_insert(driver->cache, c)) {
+ REDEBUG("Failed adding entry for key \"%s\"", c->key);
+
+ return CACHE_ERROR;
+ }
+
+ if (!fr_heap_insert(driver->heap, c)) {
+ rbtree_deletebydata(driver->cache, c);
+ REDEBUG("Failed adding entry for key \"%s\"", c->key);
+
+ return CACHE_ERROR;
+ }
+
+ return CACHE_OK;
+}
+
+/** Free an entry and remove it from the data store
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Dummy handle (not used).
+ * @param c entry to expire
+ * @return CACHE_OK.
+ */
+static cache_status_t cache_entry_expire(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_rbtree_t *driver = inst->driver;
+
+ rad_assert(*handle == request);
+
+ fr_heap_extract(driver->heap, c);
+ rbtree_deletebydata(driver->cache, c);
+ talloc_free(c);
+
+ return CACHE_OK;
+}
+
+/** Return the number of entries in the cache
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Dummy handle (not used).
+ * @return the number of entries in the cache.
+ */
+static uint32_t cache_entry_count(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rlm_cache_rbtree_t *driver = inst->driver;
+
+ rad_assert(*handle == request);
+
+ return rbtree_num_elements(driver->cache);
+}
+
+/** Lock the rbtree
+ *
+ * @param out Where to write the dummy handle.
+ * @param inst rlm_cache instance.
+ * @param request The current request.
+ */
+
+#ifdef HAVE_PTHREAD_H
+static int cache_acquire(rlm_cache_handle_t **out, rlm_cache_t *inst, REQUEST *request)
+#else
+static int cache_acquire(rlm_cache_handle_t **out, UNUSED rlm_cache_t *inst, REQUEST *request)
+#endif
+{
+#ifdef HAVE_PTHREAD_H
+ rlm_cache_rbtree_t *driver = inst->driver;
+#endif
+
+ PTHREAD_MUTEX_LOCK(&driver->mutex);
+
+ *out = request; /* handle is unused, this is just for sanity checking */
+
+ RDEBUG3("Mutex acquired");
+
+ return 0;
+}
+
+/** Release an entry unlocking any mutexes
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle The dummy handle created by cache_acquire.
+ */
+#ifdef HAVE_PTHREAD_H
+static void cache_release(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
+#else
+static void cache_release(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
+#endif
+{
+#ifdef HAVE_PTHREAD_H
+ rlm_cache_rbtree_t *driver = inst->driver;
+#endif
+
+ rad_assert(*handle == request);
+
+ PTHREAD_MUTEX_UNLOCK(&driver->mutex);
+
+ RDEBUG3("Mutex released");
+
+ *handle = NULL;
+}
+
+extern cache_module_t rlm_cache_rbtree;
+cache_module_t rlm_cache_rbtree = {
+ .name = "rlm_cache_rbtree",
+ .instantiate = mod_instantiate,
+ .alloc = cache_entry_alloc,
+
+ .find = cache_entry_find,
+ .insert = cache_entry_insert,
+ .expire = cache_entry_expire,
+ .count = cache_entry_count,
+
+ .acquire = cache_acquire,
+ .release = cache_release,
+};
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/.gitignore b/src/modules/rlm_cache/drivers/rlm_cache_redis/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/all.mk.in b/src/modules/rlm_cache/drivers/rlm_cache_redis/all.mk.in
new file mode 100644
index 0000000..8b720e2
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c ../../serialize.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/configure b/src/modules/rlm_cache/drivers/rlm_cache_redis/configure
new file mode 100755
index 0000000..b3f8451
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/configure
@@ -0,0 +1,4202 @@
+#! /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_cache_redis.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_cache_redis
+with_redis_include_dir
+with_redis_lib_dir
+with_redis_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_cache_redis
+ build without rlm_cache_redis
+ --with-redis-include-dir=DIR
+ Directory where the redis includes may be found
+ --with-redis-lib-dir=DIR
+ Directory where the redis libraries may be found
+ --with-redis-dir=DIR Base directory where redis is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_cache_redis
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_cache_redis was given.
+if test "${with_rlm_cache_redis+set}" = set; then :
+ withval=$with_rlm_cache_redis;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_cache_redis" != xno; then
+
+
+
+redis_include_dir=
+
+# Check whether --with-redis-include-dir was given.
+if test "${with_redis_include_dir+set}" = set; then :
+ withval=$with_redis_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+redis_lib_dir=
+
+# Check whether --with-redis-lib-dir was given.
+if test "${with_redis_lib_dir+set}" = set; then :
+ withval=$with_redis_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-redis-dir was given.
+if test "${with_redis_dir+set}" = set; then :
+ withval=$with_redis_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac
+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
+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
+
+
+
+smart_try_dir="${redis_include_dir}"
+
+
+
+ac_safe=`echo "hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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}/hiredis/hiredis.h" >&5
+$as_echo_n "checking for ${_prefix}/hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h" >&5
+$as_echo_n "checking for hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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_hiredis_hiredis_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&2;}
+
+fail="$fail hiredis.h"
+
+fi
+
+
+smart_try_dir="$redis_lib_dir"
+
+
+sm_lib_safe=`echo "hiredis" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "redisConnect" | 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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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 redisConnect in -lhiredis" >&5
+$as_echo_n "checking for redisConnect in -lhiredis... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ { $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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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_hiredis_redisConnect" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&2;}
+
+fail="$fail libhiredis"
+
+fi
+
+
+ targetname=rlm_cache_redis
+else
+ targetname=
+ echo \*\*\* module rlm_cache_redis is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_cache_redis to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_cache_redis." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_cache_redis." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_cache_redis requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_cache_redis requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/configure.ac b/src/modules/rlm_cache/drivers/rlm_cache_redis/configure.ac
new file mode 100644
index 0000000..2d2c5c3
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/configure.ac
@@ -0,0 +1,102 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_cache_redis.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_cache_redis])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-redis-include-dir=DIR
+redis_include_dir=
+AC_ARG_WITH(redis-include-dir,
+ [AS_HELP_STRING([--with-redis-include-dir=DIR],
+ [Directory where the redis includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-lib-dir=DIR
+redis_lib_dir=
+AC_ARG_WITH(redis-lib-dir,
+ [AS_HELP_STRING([--with-redis-lib-dir=DIR],
+ [Directory where the redis libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-dir=DIR
+AC_ARG_WITH(redis-dir,
+ [AS_HELP_STRING([--with-redis-dir=DIR],
+ [Base directory where redis is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for programs
+dnl ############################################################
+
+AC_PROG_CC
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="${redis_include_dir}"
+FR_SMART_CHECK_INCLUDE([hiredis/hiredis.h])
+if test "x$ac_cv_header_hiredis_hiredis_h" != "xyes"; then
+ AC_MSG_WARN([hiredis headers not found. Use --with-redis-include-dir=<path>.])
+ FR_MODULE_FAIL([hiredis.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+smart_try_dir="$redis_lib_dir"
+FR_SMART_CHECK_LIB(hiredis, redisConnect)
+if test "x$ac_cv_lib_hiredis_redisConnect" != "xyes"
+then
+ AC_MSG_WARN([hiredis libraries not found. Use --with-redis-lib-dir=<path>.])
+ FR_MODULE_FAIL([libhiredis])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c
new file mode 100644
index 0000000..3231faf
--- /dev/null
+++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c
@@ -0,0 +1,413 @@
+/*
+ * 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_cache_redis.c
+ * @brief redis based cache.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+
+#include <hiredis/hiredis.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "../../rlm_cache.h"
+#include "../../serialize.h"
+
+typedef struct rlm_cache_redis_handle {
+ redisContext *conn;
+} rlm_cache_redis_handle_t;
+
+typedef struct rlm_cache_redis {
+ fr_connection_pool_t *pool;
+ char const *hostname;
+ char const *password;
+ uint32_t database;
+ uint16_t port;
+ uint16_t query_timeout;
+} rlm_cache_redis_t;
+
+static const CONF_PARSER driver_config[] = {
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_cache_redis_t, hostname), NULL },
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, rlm_cache_redis_t, port), "6379" },
+ { "database", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_redis_t, database), "0" },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_cache_redis_t, password), NULL },
+ { "query_timeout", FR_CONF_OFFSET(PW_TYPE_SHORT, rlm_cache_redis_t, query_timeout), "5" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Free a connection handle
+ *
+ * @param randle to free.
+ */
+static int _mod_conn_free(rlm_cache_redis_handle_t *randle)
+{
+ if (randle->conn) {
+ redisFree(randle->conn);
+ randle->conn = NULL;
+ }
+
+ return 0;
+}
+
+/** Create a new redis handle
+ *
+ * @param ctx to allocate handle in.
+ * @param instance data.
+ */
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_cache_t *inst = instance;
+ rlm_cache_redis_t *driver = inst->driver;
+ rlm_cache_redis_handle_t *randle;
+ redisContext *conn;
+ redisReply *reply = NULL;
+ char buffer[1024];
+ struct timeval tv;
+
+ tv.tv_sec = driver->query_timeout;
+ tv.tv_usec = 0;
+ conn = redisConnectWithTimeout(driver->hostname, driver->port, tv);
+ if (!conn) {
+ ERROR("rlm_cache (%s): Failed calling redisConnectWithTimeout('%s', %d, %d)",
+ inst->name, driver->hostname, driver->port, driver->query_timeout);
+ return NULL;
+ }
+
+#ifndef redisReplyReaderGetError
+#define redisReplyReaderGetError redisReaderGetError
+#endif
+
+ if (conn && conn->err) {
+ ERROR("rlm_cache (%s): Problems with redisConnectWithTimeout('%s', %d, %d), %s",
+ inst->name, driver->hostname, driver->port, driver->query_timeout, redisReplyReaderGetError(conn));
+ redisFree(conn);
+ return NULL;
+ }
+
+ if (driver->password) {
+ snprintf(buffer, sizeof(buffer), "AUTH %s", driver->password);
+ reply = redisCommand(conn, buffer);
+ if (!reply) {
+ ERROR("rlm_redis (%s): Failed to run AUTH", inst->name);
+
+ do_close:
+ if (reply) freeReplyObject(reply);
+ redisFree(conn);
+ return NULL;
+ }
+
+ switch (reply->type) {
+ case REDIS_REPLY_STATUS:
+ if (strcmp(reply->str, "OK") != 0) {
+ ERROR("rlm_redis (%s): Failed authentication: reply %s",
+ inst->name, reply->str);
+ goto do_close;
+ }
+ break; /* else it's OK */
+
+ default:
+ ERROR("rlm_redis (%s): Unexpected reply to AUTH",
+ inst->name);
+ goto do_close;
+ }
+
+ freeReplyObject(reply);
+ }
+
+ randle = talloc_zero(ctx, rlm_cache_redis_handle_t);
+ randle->conn = conn;
+ talloc_set_destructor(randle, _mod_conn_free);
+
+ return randle;
+}
+
+/** Cleanup a rlm_cache_redis instance
+ *
+ * @param driver to free.
+ * @return 0
+ */
+static int _mod_detach(rlm_cache_redis_t *driver)
+{
+ fr_connection_pool_free(driver->pool);
+ return 0;
+}
+
+/** Create a new rlm_cache_redis instance
+ *
+ * @param conf redis specific conf section.
+ * @param inst main rlm_cache instance.
+ * @return 0 on success, -1 on failure.
+ */
+static int mod_instantiate(CONF_SECTION *conf, rlm_cache_t *inst)
+{
+ rlm_cache_redis_t *driver;
+ char buffer[256];
+ static bool version_done;
+
+ buffer[0] = '\0';
+
+ /*
+ * Get version info from the libredis API.
+ */
+ if (!version_done) {
+ version_done = true;
+ INFO("rlm_cache_redis: libhires version: %d.%d.%d", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
+ }
+
+ driver = talloc_zero(inst, rlm_cache_redis_t);
+ talloc_set_destructor(driver, _mod_detach);
+ if (cf_section_parse(conf, driver, driver_config) < 0) return -1;
+
+ inst->driver = driver;
+ snprintf(buffer, sizeof(buffer), "rlm_cache (%s)", inst->name);
+ driver->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, buffer);
+ if (!driver->pool) return -1;
+
+ if (inst->max_entries > 0) WARN("rlm_cache_redis: max_entries is not supported by this driver");
+
+ return 0;
+}
+
+static void cache_entry_free(rlm_cache_entry_t *c)
+{
+ talloc_free(c);
+}
+
+/** Locate a cache entry in redis
+ *
+ * @param out Where to write the pointer to the cach entry.
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to redis handle.
+ * @param key to search for.
+ * @return CACHE_OK on success CACHE_MISS if no entry found, CACHE_ERROR on error.
+ */
+static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, char const *key)
+{
+ rlm_cache_redis_handle_t *randle = *handle;
+ redisReply *reply;
+ rlm_cache_entry_t *c;
+ int ret;
+
+ reply = redisCommand(randle->conn,"GET %s", key);
+ if (!reply) {
+ RERROR("Failed retrieving entry for key \"%s\"", key);
+ return CACHE_ERROR;
+ }
+
+ c = talloc_zero(NULL, rlm_cache_entry_t);
+ switch (reply->type) {
+ case REDIS_REPLY_STRING:
+ ret = cache_deserialize(c, reply->str, reply->len);
+ if (ret < 0) {
+ RERROR("%s", fr_strerror());
+ error:
+ talloc_free(c);
+ freeReplyObject(reply);
+ return CACHE_ERROR;
+ }
+ break;
+ case REDIS_REPLY_NIL:
+ talloc_free(c);
+ freeReplyObject(reply);
+ return CACHE_MISS;
+ case REDIS_REPLY_ERROR:
+ RERROR("Failed retrieving entry for key \"%s\": %s", key, reply->str);
+ goto error;
+ default:
+ RERROR("Failed retrieving entry for key \"%s\": invalid type", key);
+ goto error;
+ }
+
+ freeReplyObject(reply);
+ c->key = talloc_strdup(c, key);
+ *out = c;
+
+ return CACHE_OK;
+}
+
+/** Insert a new entry into the data store
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to redis handle.
+ * @param c entry to insert.
+ * @return CACHE_OK on success else CACHE_ERROR on error.
+ */
+static cache_status_t cache_entry_insert(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_redis_handle_t *randle = *handle;
+ redisReply *reply = NULL;
+ TALLOC_CTX *pool;
+ char *to_store;
+
+ pool = talloc_pool(NULL, 1024);
+ if (!pool) return CACHE_ERROR;
+
+ if (cache_serialize(pool, &to_store, c) < 0) {
+ error:
+ if (reply) freeReplyObject(reply);
+ talloc_free(pool);
+ return CACHE_ERROR;
+ }
+
+ reply = redisCommand(
+ randle->conn,
+ "SET %b %b EX %d",
+ c->key,
+ talloc_array_length(c->key) - 1,
+ to_store ? to_store : "",
+ to_store ? talloc_array_length(to_store) - 1 : 0,
+ c->expires - c->created);
+
+ if (!reply) {
+ goto error;
+ }
+
+ switch (reply->type) {
+ case REDIS_REPLY_STATUS:
+ break;
+ case REDIS_REPLY_ERROR:
+ RERROR("Failed insert for key \"%s\": %s", c->key, reply->str);
+ goto error;
+ default:
+ RERROR("Failed insert for key \"%s\" %d", c->key, reply->type);
+ goto error;
+ }
+
+ freeReplyObject(reply);
+ talloc_free(pool);
+
+ return CACHE_OK;
+}
+
+/** Call delete the cache entry from redis
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to redis handle.
+ * @param c entry to expire.
+ * @return CACHE_OK on success else CACHE_ERROR.
+ */
+static cache_status_t cache_entry_expire(UNUSED rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ rlm_cache_entry_t *c)
+{
+ rlm_cache_redis_handle_t *randle = *handle;
+ redisReply *reply = NULL;
+
+ reply = redisCommand( randle->conn, "DEL %b", c->key, talloc_array_length(c->key) - 1);
+ if (!reply) {
+ RERROR("Failed expire for key \"%s\"", c->key);
+ error:
+ if (reply) freeReplyObject(reply);
+ return CACHE_ERROR;
+ }
+
+ switch (reply->type) {
+ default:
+ RERROR("Failed expire for key \"%s\"", c->key);
+ goto error;
+ case REDIS_REPLY_ERROR:
+ RERROR("Failed expire for key \"%s\": %s", c->key, reply->str);
+ goto error;
+ case REDIS_REPLY_INTEGER:
+ if (reply->integer == 0) RWARN("key \"%s\" is already expired", c->key);
+ break;
+ }
+
+ freeReplyObject(reply);
+
+ return CACHE_OK;
+}
+
+/** Get a redis handle
+ *
+ * @param out Where to write the handle.
+ * @param inst rlm_cache instance.
+ * @param request The current request.
+ */
+static int mod_conn_get(rlm_cache_handle_t **out, rlm_cache_t *inst, UNUSED REQUEST *request)
+{
+ rlm_cache_redis_t *driver = inst->driver;
+ rlm_cache_handle_t *randle;
+
+ *out = NULL;
+ randle = fr_connection_get(driver->pool);
+ if (!randle) {
+ *out = NULL;
+ return -1;
+ }
+
+ *out = randle;
+
+ return 0;
+}
+
+/** Release a socket
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to the handle to release (will be set to NULL).
+ */
+static void mod_conn_release(rlm_cache_t *inst, UNUSED REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rlm_cache_redis_t *driver = inst->driver;
+
+ fr_connection_release(driver->pool, *handle);
+ *handle = NULL;
+}
+
+/** Reconnect a socket
+ *
+ * @param inst main rlm_cache instance.
+ * @param request The current request.
+ * @param handle Pointer to the handle to reconnect (will be set to NULL if reconnection fails).
+ */
+static int mod_conn_reconnect(rlm_cache_t *inst, UNUSED REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rlm_cache_redis_t *driver = inst->driver;
+ rlm_cache_handle_t *randle;
+
+ randle = fr_connection_reconnect(driver->pool, *handle);
+ if (!randle) {
+ *handle = NULL;
+ return -1;
+ }
+
+ *handle = randle;
+
+ return 0;
+}
+
+extern cache_module_t rlm_cache_redis;
+cache_module_t rlm_cache_redis = {
+ .name = "rlm_cache_redis",
+ .instantiate = mod_instantiate,
+ .free = cache_entry_free,
+
+ .find = cache_entry_find,
+ .insert = cache_entry_insert,
+ .expire = cache_entry_expire,
+
+ .acquire = mod_conn_get,
+ .release = mod_conn_release,
+ .reconnect = mod_conn_reconnect
+};
diff --git a/src/modules/rlm_cache/rlm_cache.c b/src/modules/rlm_cache/rlm_cache.c
new file mode 100644
index 0000000..345bedd
--- /dev/null
+++ b/src/modules/rlm_cache/rlm_cache.c
@@ -0,0 +1,839 @@
+/*
+ * 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_cache.c
+ * @brief Cache values and merge them back into future requests.
+ *
+ * @copyright 2012-2014 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modcall.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "rlm_cache.h"
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "driver", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_cache_t, driver_name), "rlm_cache_rbtree" },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_cache_t, key), NULL },
+ { "ttl", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, ttl), "500" },
+ { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, max_entries), "0" },
+
+ /* Should be a type which matches time_t, @fixme before 2038 */
+ { "epoch", FR_CONF_OFFSET(PW_TYPE_SIGNED, rlm_cache_t, epoch), "0" },
+ { "add_stats", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_cache_t, stats), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int cache_acquire(rlm_cache_handle_t **out, rlm_cache_t *inst, REQUEST *request)
+{
+ if (!inst->module->acquire) return 0;
+
+ return inst->module->acquire(out, inst, request);
+}
+
+static void cache_release(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
+{
+ if (!inst->module->release) return;
+ if (!handle || !*handle) return;
+
+ inst->module->release(inst, request, handle);
+}
+
+static int cache_reconnect(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
+{
+ rad_assert(inst->module->reconnect);
+
+ return inst->module->reconnect(inst, request, handle);
+}
+
+/** Allocate a cache entry
+ *
+ * This is used so that drivers may use their own allocation functions
+ * to allocate structures larger than the normal rlm_cache_entry_t.
+ *
+ * If the driver doesn't specify a custom allocation function, the cache
+ * entry is talloced in the NULL ctx.
+ */
+static rlm_cache_entry_t *cache_alloc(rlm_cache_t *inst, REQUEST *request)
+{
+ if (inst->module->alloc) return inst->module->alloc(inst, request);
+
+ return talloc_zero(NULL, rlm_cache_entry_t);
+}
+
+/** Free memory associated with a cache entry
+ *
+ * This does not necessarily remove the entry from the cache, cache_expire
+ * should be used for that.
+ *
+ * This function should be called when an entry that is known to have been
+ * retrieved or inserted into a data store successfully, is no longer needed.
+ *
+ * Some drivers (like rlm_cache_rbtree) don't register a free function.
+ * This means that the cache entry never needs to be explicitly freed.
+ *
+ * @param c Cache entry to free.
+ * @param inst Module instance.
+ */
+static void cache_free(rlm_cache_t *inst, rlm_cache_entry_t **c)
+{
+ if (!c || !*c || !inst->module->free) return;
+
+ inst->module->free(*c);
+ *c = NULL;
+}
+
+/*
+ * Merge a cached entry into a REQUEST.
+ */
+static void CC_HINT(nonnull) cache_merge(rlm_cache_t *inst, REQUEST *request, rlm_cache_entry_t *c)
+{
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_find_by_num(request->config, PW_CACHE_MERGE, 0, TAG_ANY);
+ if (vp && (vp->vp_integer == 0)) {
+ RDEBUG2("Told not to merge entry into request");
+ return;
+ }
+
+ RDEBUG2("Merging cache entry into request");
+
+ if (c->packet && request->packet) {
+ rdebug_pair_list(L_DBG_LVL_2, request, c->packet, "&request:");
+ radius_pairmove(request, &request->packet->vps, fr_pair_list_copy(request->packet, c->packet), false);
+ }
+
+ if (c->reply && request->reply) {
+ rdebug_pair_list(L_DBG_LVL_2, request, c->reply, "&reply:");
+ radius_pairmove(request, &request->reply->vps, fr_pair_list_copy(request->reply, c->reply), false);
+ }
+
+ if (c->control) {
+ rdebug_pair_list(L_DBG_LVL_2, request, c->control, "&control:");
+ radius_pairmove(request, &request->config, fr_pair_list_copy(request, c->control), false);
+ }
+
+ if (c->state) {
+ rdebug_pair_list(L_DBG_LVL_2, request, c->state, "&session-state:");
+
+ fr_pair_list_mcopy_by_num(request->state_ctx, &request->state, &c->state, 0, 0, TAG_ANY);
+ }
+
+ if (inst->stats) {
+ rad_assert(request->packet != NULL);
+ vp = fr_pair_find_by_num(request->packet->vps, PW_CACHE_ENTRY_HITS, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(request->packet, PW_CACHE_ENTRY_HITS, 0);
+ rad_assert(vp != NULL);
+ fr_pair_add(&request->packet->vps, vp);
+ }
+ vp->vp_integer = c->hits;
+ }
+}
+
+
+/** Find a cached entry.
+ *
+ * @return RLM_MODULE_OK on success, RLM_MODULE_FAIL on failure, RLM_MODULE_NOTFOUND if notfound.
+ */
+static rlm_rcode_t cache_find(rlm_cache_entry_t **out, rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, char const *key)
+{
+ cache_status_t ret;
+
+ rlm_cache_entry_t *c;
+
+ *out = NULL;
+
+ for (;;) {
+ ret = inst->module->find(&c, inst, request, handle, key);
+ switch (ret) {
+ case CACHE_RECONNECT:
+ RDEBUG("Reconnecting...");
+ if (cache_reconnect(inst, request, handle) == 0) continue;
+ return RLM_MODULE_FAIL;
+
+ case CACHE_OK:
+ break;
+
+ case CACHE_MISS:
+ RDEBUG("No cache entry found for \"%s\"", key);
+ return RLM_MODULE_NOTFOUND;
+
+ /* FALL-THROUGH */
+ default:
+ return RLM_MODULE_FAIL;
+
+ }
+
+ break;
+ }
+
+ /*
+ * Yes, but it expired, OR the "forget all" epoch has
+ * passed. Delete it, and pretend it doesn't exist.
+ */
+ if ((c->expires < request->timestamp) || (c->created < inst->epoch)) {
+ RDEBUG("Removing expired entry");
+
+ inst->module->expire(inst, request, handle, c);
+ cache_free(inst, &c);
+ return RLM_MODULE_NOTFOUND; /* Couldn't find a non-expired entry */
+ }
+
+ RDEBUG("Found entry for \"%s\"", key);
+
+ c->hits++;
+ *out = c;
+
+ return RLM_MODULE_OK;
+}
+
+/** Expire a cache entry (removing it from the datastore)
+ *
+ */
+static void cache_expire(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle, rlm_cache_entry_t **c)
+{
+ rad_assert(*c);
+
+ for (;;) switch (inst->module->expire(inst, request, handle, *c)) {
+ case CACHE_RECONNECT:
+ if (cache_reconnect(inst, request, handle) == 0) continue;
+
+ /* FALL-THROUGH */
+ default:
+ cache_free(inst, c);
+ *c = NULL;
+ return;
+ }
+}
+
+/** Create and insert a cache entry.
+ *
+ * @return RLM_MODULE_OK on success, RLM_MODULE_UPDATED if we merged the cache entry and RLM_MODULE_FAIL on failure.
+ */
+static rlm_rcode_t cache_insert(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
+ char const *key, int ttl)
+{
+ VALUE_PAIR *vp, *to_cache;
+ vp_cursor_t src_list, packet, reply, control, state;
+
+ vp_map_t const *map;
+
+ bool merge = true;
+ rlm_cache_entry_t *c;
+
+ if ((inst->max_entries > 0) && inst->module->count &&
+ (inst->module->count(inst, request, handle) > inst->max_entries)) {
+ RWDEBUG("Cache is full: %d entries", inst->max_entries);
+ return RLM_MODULE_FAIL;
+ }
+
+ c = cache_alloc(inst, request);
+ if (!c) return RLM_MODULE_FAIL;
+
+ c->key = talloc_typed_strdup(c, key);
+ c->created = c->expires = request->timestamp;
+ c->expires += ttl;
+
+ RDEBUG("Creating new cache entry");
+
+ fr_cursor_init(&packet, &c->packet);
+ fr_cursor_init(&reply, &c->reply);
+ fr_cursor_init(&control, &c->control);
+ fr_cursor_init(&state, &c->state);
+
+ for (map = inst->maps; map != NULL; map = map->next) {
+ rad_assert(map->lhs && map->rhs);
+
+ if (map_to_vp(c, &to_cache, request, map, NULL) < 0) {
+ RDEBUG("Skipping %s", map->rhs->name);
+ continue;
+ }
+
+ for (vp = fr_cursor_init(&src_list, &to_cache);
+ vp;
+ vp = fr_cursor_next(&src_list)) {
+ VERIFY_VP(vp);
+
+ /*
+ * Prevent people from accidentally caching
+ * cache control attributes.
+ */
+ if (map->rhs->type == TMPL_TYPE_LIST) switch (vp->da->attr) {
+ case PW_CACHE_TTL:
+ case PW_CACHE_STATUS_ONLY:
+ case PW_CACHE_READ_ONLY:
+ case PW_CACHE_MERGE:
+ case PW_CACHE_ENTRY_HITS:
+ RDEBUG2("Skipping %s", vp->da->name);
+ continue;
+
+ default:
+ break;
+ }
+
+ RINDENT();
+ if (RDEBUG_ENABLED2) map_debug_log(request, map, vp);
+ REXDENT();
+
+ vp->op = map->op;
+
+ switch (map->lhs->tmpl_list) {
+ case PAIR_LIST_REQUEST:
+ fr_cursor_insert(&packet, vp);
+ break;
+
+ case PAIR_LIST_REPLY:
+ fr_cursor_insert(&reply, vp);
+ break;
+
+ case PAIR_LIST_CONTROL:
+ fr_cursor_insert(&control, vp);
+ break;
+
+ case PAIR_LIST_STATE:
+ fr_cursor_insert(&state, vp);
+ break;
+
+ default:
+ rad_assert(0); /* should have been caught by validation */
+ }
+ }
+ }
+
+ /*
+ * Check to see if we need to merge the entry into the request
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CACHE_MERGE, 0, TAG_ANY);
+ if (vp && (vp->vp_integer == 0)) merge = false;
+
+ if (merge) cache_merge(inst, request, c);
+
+ for (;;) {
+ cache_status_t ret;
+
+ ret = inst->module->insert(inst, request, handle, c);
+ switch (ret) {
+ case CACHE_RECONNECT:
+ if (cache_reconnect(inst, request, handle) == 0) continue;
+ return RLM_MODULE_FAIL;
+
+ case CACHE_OK:
+ RDEBUG("Committed entry, TTL %d seconds", ttl);
+ cache_free(inst, &c);
+ return RLM_MODULE_UPDATED;
+
+ default:
+ talloc_free(c); /* Failed insertion - use talloc_free not the driver free */
+ return RLM_MODULE_FAIL;
+ }
+ }
+}
+
+/** Verify that a map in the cache section makes sense
+ *
+ */
+static int cache_verify(vp_map_t *map, void *ctx)
+{
+ if (modcall_fixup_update(map, ctx) < 0) return -1;
+
+ if ((map->lhs->type != TMPL_TYPE_ATTR) &&
+ (map->lhs->type != TMPL_TYPE_LIST)) {
+ cf_log_err(map->ci, "Destination must be an attribute ref or a list");
+ return -1;
+ }
+
+ switch (map->lhs->tmpl_list) {
+ case PAIR_LIST_REQUEST:
+ case PAIR_LIST_REPLY:
+ case PAIR_LIST_CONTROL:
+ case PAIR_LIST_STATE:
+ break;
+
+ default:
+ cf_log_err(map->ci, "Destination list must be one of request, reply, control or session-state");
+ return -1;
+ }
+
+ if (map->lhs->tmpl_request != REQUEST_CURRENT) {
+ cf_log_err(map->ci, "Cached attributes can only be inserted into the current request");
+ return -1;
+ }
+
+ switch (map->rhs->type) {
+ case TMPL_TYPE_EXEC:
+ cf_log_err(map->ci, "Exec values are not allowed");
+ return -1;
+ /*
+ * Only =, :=, += and -= operators are supported for
+ * cache entries.
+ */
+ case TMPL_TYPE_LITERAL:
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_ATTR:
+ switch (map->op) {
+ case T_OP_SET:
+ case T_OP_EQ:
+ case T_OP_SUB:
+ case T_OP_ADD:
+ break;
+
+ default:
+ cf_log_err(map->ci, "Operator \"%s\" not allowed for %s values",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"),
+ fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
+ return -1;
+ }
+ break;
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ cf_log_err(map->ci, "Unknown attribute '%s'", map->rhs->name);
+ return -1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Do caching checks. Since we can update ANY VP list, we do
+ * exactly the same thing for all sections (autz / auth / etc.)
+ *
+ * If you want to cache something different in different sections,
+ * configure another cache module.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_cache_it(void *instance, REQUEST *request)
+{
+ rlm_cache_entry_t *c;
+ rlm_cache_t *inst = instance;
+
+ rlm_cache_handle_t *handle;
+
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ char buffer[1024];
+ rlm_rcode_t rcode;
+
+ int ttl = inst->ttl;
+
+ if (radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL) < 0) return RLM_MODULE_FAIL;
+
+ if (buffer[0] == '\0') {
+ REDEBUG("Zero length key string is invalid");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (cache_acquire(&handle, inst, request) < 0) return RLM_MODULE_FAIL;
+
+ rcode = cache_find(&c, inst, request, &handle, buffer);
+ if (rcode == RLM_MODULE_FAIL) goto finish;
+ rad_assert(handle);
+
+ /*
+ * If Cache-Status-Only == yes, only return whether we found a
+ * valid cache entry
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CACHE_STATUS_ONLY, 0, TAG_ANY);
+ if (vp && vp->vp_integer) {
+ rcode = c ? RLM_MODULE_OK:
+ RLM_MODULE_NOTFOUND;
+ goto finish;
+ }
+
+ /*
+ * Update the expiry time based on the TTL.
+ * A TTL of 0 means "delete from the cache".
+ * A TTL < 0 means "delete from the cache and recreate the entry".
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CACHE_TTL, 0, TAG_ANY);
+ if (vp) ttl = vp->vp_signed;
+
+ /*
+ * If there's no existing cache entry, go and create a new one.
+ */
+ if (!c) {
+ if (ttl == 0) {
+ ttl = inst->ttl;
+
+ } else if (ttl < 0) {
+ ttl = -ttl;
+ }
+ goto insert;
+ }
+
+ /*
+ * Expire the entry if requested to do so
+ */
+ if (vp) {
+ if (ttl == 0) {
+ cache_expire(inst, request, &handle, &c);
+ RDEBUG("Forcing expiry of entry");
+ rcode = RLM_MODULE_OK;
+ goto finish;
+ }
+
+ if (ttl < 0) {
+ RDEBUG("Forcing expiry of existing entry");
+ cache_expire(inst, request, &handle, &c);
+ ttl *= -1;
+ goto insert;
+ }
+ c->expires = request->timestamp + ttl;
+ RDEBUG("Setting TTL to %d", ttl);
+ }
+
+ /*
+ * Cache entry was still valid, so we merge it into the request
+ * and return. No need to add a new entry.
+ */
+ cache_merge(inst, request, c);
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+
+insert:
+ /*
+ * If Cache-Read-Only == yes, then we only allow already cached entries
+ * to be merged into the request
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CACHE_READ_ONLY, 0, TAG_ANY);
+ if (vp && vp->vp_integer) {
+ rcode = RLM_MODULE_NOTFOUND;
+ goto finish;
+ }
+
+ /*
+ * Create a new entry.
+ */
+ rcode = cache_insert(inst, request, &handle, buffer, ttl);
+ rad_assert(handle);
+
+finish:
+ cache_free(inst, &c);
+ cache_release(inst, request, &handle);
+
+ /*
+ * Clear control attributes
+ */
+ for (vp = fr_cursor_init(&cursor, &request->config);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->vendor == 0) switch (vp->da->attr) {
+ case PW_CACHE_TTL:
+ case PW_CACHE_STATUS_ONLY:
+ case PW_CACHE_READ_ONLY:
+ case PW_CACHE_MERGE:
+ vp = fr_cursor_remove(&cursor);
+ talloc_free(vp);
+ break;
+ }
+ }
+
+ return rcode;
+}
+
+static ssize_t CC_HINT(nonnull) cache_xlat(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t freespace);
+
+/*
+ * Allow single attribute values to be retrieved from the cache.
+ */
+static ssize_t cache_xlat(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t freespace)
+{
+ rlm_cache_entry_t *c = NULL;
+ rlm_cache_t *inst = instance;
+ rlm_cache_handle_t *handle = NULL;
+
+ VALUE_PAIR *vp, *vps;
+ pair_lists_t list;
+ DICT_ATTR const *target;
+ char const *p = fmt;
+ size_t len;
+ int ret = 0;
+
+ p += radius_list_name(&list, p, PAIR_LIST_REQUEST);
+ if (list == PAIR_LIST_UNKNOWN) {
+ REDEBUG("Unknown list qualifier in \"%s\"", fmt);
+ ret = -1;
+ goto finish;
+ }
+
+ target = dict_attrbyname(p);
+ if (!target) {
+ REDEBUG("Unknown attribute \"%s\"", p);
+ return -1;
+ }
+
+ if (cache_acquire(&handle, inst, request) < 0) return -1;
+
+ switch (cache_find(&c, inst, request, handle, fmt)) {
+ case RLM_MODULE_OK: /* found */
+ break;
+
+ case RLM_MODULE_NOTFOUND: /* not found */
+ *out = '\0';
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ switch (list) {
+ case PAIR_LIST_REQUEST:
+ vps = c->packet;
+ break;
+
+ case PAIR_LIST_REPLY:
+ vps = c->reply;
+ break;
+
+ case PAIR_LIST_CONTROL:
+ vps = c->control;
+ break;
+
+ case PAIR_LIST_STATE:
+ vps = c->state;
+ break;
+
+ default:
+ REDEBUG("Unsupported list \"%s\"", fr_int2str(pair_lists, list, "<UNKNOWN>"));
+ ret = -1;
+ goto finish;
+ }
+
+ vp = fr_pair_find_by_num(vps, target->attr, target->vendor, TAG_ANY);
+ if (!vp) {
+ RDEBUG("No instance of this attribute has been cached");
+ *out = '\0';
+ goto finish;
+ }
+
+ len = vp_prints_value(out, freespace, vp, 0);
+ if (is_truncated(len, freespace)) {
+ REDEBUG("Insufficient buffer space to write cached value");
+ ret = -1;
+ goto finish;
+ }
+
+finish:
+ cache_free(inst, &c);
+ cache_release(inst, request, &handle);
+
+ return ret;
+}
+
+/*
+ * 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_cache_t *inst = instance;
+
+ talloc_free(inst->maps);
+
+ /*
+ * We need to explicitly free all children, so if the driver
+ * parented any memory off the instance, their destructors
+ * run before we unload the bytecode for them.
+ *
+ * If we don't do this, we get a SEGV deep inside the talloc code
+ * when it tries to call a destructor that no longer exists.
+ */
+ talloc_free_children(inst);
+
+ /*
+ * Decrements the reference count. The driver object won't be unloaded
+ * until all instances of rlm_cache that use it have been destroyed.
+ */
+ if (inst->handle) dlclose(inst->handle);
+
+ return 0;
+}
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_cache_t *inst = instance;
+
+ inst->cs = conf;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+ /*
+ * Register the cache xlat function
+ */
+ xlat_register(inst->name, cache_xlat, NULL, inst);
+
+ return 0;
+}
+
+
+/*
+ * Instantiate the module.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_cache_t *inst = instance;
+ CONF_SECTION *update;
+
+ inst->cs = conf;
+
+ /*
+ * Sanity check for crazy people.
+ */
+ if (strncmp(inst->driver_name, "rlm_cache_", 10) != 0) {
+ cf_log_err_cs(conf, "\"%s\" is NOT an Cache driver!", inst->driver_name);
+ return -1;
+ }
+
+ /*
+ * Load the appropriate driver for our database
+ */
+ inst->handle = fr_dlopenext(inst->driver_name);
+ if (!inst->handle) {
+ cf_log_err_cs(conf, "Could not link driver %s: %s", inst->driver_name, dlerror());
+ cf_log_err_cs(conf, "Make sure it (and all its dependent libraries!) are in the search path"
+ " of your system's ld");
+ return -1;
+ }
+
+ inst->module = (cache_module_t *) dlsym(inst->handle, inst->driver_name);
+ if (!inst->module) {
+ cf_log_err_cs(conf, "Could not link symbol %s: %s", inst->driver_name, dlerror());
+ return -1;
+ }
+
+ DEBUG("rlm_cache (%s): Driver %s (module %s) loaded and linked", inst->name,
+ inst->driver_name, inst->module->name);
+
+ /*
+ * Non optional fields and callbacks
+ */
+ rad_assert(inst->module->name);
+ rad_assert(inst->module->find);
+ rad_assert(inst->module->insert);
+ rad_assert(inst->module->expire);
+
+ if (inst->module->instantiate) {
+ CONF_SECTION *cs;
+ char const *name;
+
+ name = strrchr(inst->driver_name, '_');
+ if (!name) {
+ name = inst->driver_name;
+ } else {
+ name++;
+ }
+
+ cs = cf_section_sub_find(conf, name);
+ if (!cs) {
+ cs = cf_section_alloc(conf, name, NULL);
+ if (!cs) return -1;
+ }
+
+ /*
+ * It's up to the driver to register a destructor (using talloc)
+ *
+ * Should write its instance data in inst->driver,
+ * and parent it off of inst.
+ */
+ if (inst->module->instantiate(cs, inst) < 0) return -1;
+ }
+
+ rad_assert(inst->key && *inst->key);
+
+ if (inst->ttl == 0) {
+ cf_log_err_cs(conf, "Must set 'ttl' to non-zero");
+ return -1;
+ }
+
+ if (inst->epoch != 0) {
+ cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files");
+ return -1;
+ }
+
+ update = cf_section_sub_find(inst->cs, "update");
+ if (!update) {
+ cf_log_err_cs(conf, "Must have an 'update' section in order to cache anything.");
+ return -1;
+ }
+
+ /*
+ * Make sure the users don't screw up too badly.
+ */
+ if (map_afrom_cs(&inst->maps, update,
+ PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, cache_verify, NULL, MAX_ATTRMAP) < 0) {
+ return -1;
+ }
+
+ if (!inst->maps) {
+ cf_log_err_cs(inst->cs, "Cache config must contain an update section, and "
+ "that section must not be empty");
+
+ return -1;
+ }
+ 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_cache;
+module_t rlm_cache = {
+ .magic = RLM_MODULE_INIT,
+ .name = "cache",
+ .inst_size = sizeof(rlm_cache_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_cache_it,
+ [MOD_AUTHENTICATE] = mod_cache_it,
+ [MOD_PREACCT] = mod_cache_it,
+ [MOD_ACCOUNTING] = mod_cache_it,
+ [MOD_PRE_PROXY] = mod_cache_it,
+ [MOD_POST_PROXY] = mod_cache_it,
+ [MOD_POST_AUTH] = mod_cache_it
+ },
+};
diff --git a/src/modules/rlm_cache/rlm_cache.h b/src/modules/rlm_cache/rlm_cache.h
new file mode 100644
index 0000000..10f6a4c
--- /dev/null
+++ b/src/modules/rlm_cache/rlm_cache.h
@@ -0,0 +1,112 @@
+/*
+ * 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_cache.h
+ * @brief Cache values and merge them back into future requests.
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ * @copyright 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSIDH(cache_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+typedef struct cache_module cache_module_t;
+
+typedef void rlm_cache_handle_t;
+
+#define MAX_ATTRMAP 128
+
+typedef enum {
+ CACHE_RECONNECT = -2, //!< Handle needs to be reconnected
+ CACHE_ERROR = -1, //!< Fatal error
+ CACHE_OK = 0, //!< Cache entry found/updated
+ CACHE_MISS = 1 //!< Cache entry notfound
+} cache_status_t;
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_cache_t {
+ char const *name; //!< Name of xlat function to register.
+
+ char const *driver_name; //!< Datastore name
+ void *handle; //!< Datastore handle.
+ cache_module_t *module; //!< Datastore
+ void *driver; //!< Driver module instance data.
+
+ char const *key;
+ uint32_t ttl; //!< How long an entry is valid for.
+ uint32_t max_entries; //!< Maximum entries allowed.
+ int32_t epoch; //!< Time after which entries are considered valid.
+ bool stats; //!< Generate statistics.
+
+ vp_map_t *maps; //!< Attribute map applied to users.
+ //!< and profiles.
+ CONF_SECTION *cs;
+} rlm_cache_t;
+
+typedef struct rlm_cache_entry_t {
+ char const *key; //!< Key used to identify entry.
+ long long int hits; //!< How many times the entry has been retrieved.
+ time_t created; //!< When the entry was created.
+ time_t expires; //!< When the entry expires.
+
+ VALUE_PAIR *control; //!< Cached control list.
+ VALUE_PAIR *packet; //!< Cached request list.
+ VALUE_PAIR *reply; //!< Cached reply list.
+ VALUE_PAIR *state; //!< Cached session-state list.
+} rlm_cache_entry_t;
+
+typedef int (*cache_instantiate_t)(CONF_SECTION *conf, rlm_cache_t *inst);
+typedef rlm_cache_entry_t *(*cache_entry_alloc_t)(rlm_cache_t *inst, REQUEST *request);
+typedef void (*cache_entry_free_t)(rlm_cache_entry_t *c);
+
+typedef cache_status_t (*cache_entry_find_t)(rlm_cache_entry_t **out, rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, char const *key);
+typedef cache_status_t (*cache_entry_insert_t)(rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, rlm_cache_entry_t *c);
+typedef cache_status_t (*cache_entry_expire_t)(rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle, rlm_cache_entry_t *entry);
+typedef uint32_t (*cache_entry_count_t)(rlm_cache_t *inst, REQUEST *request,
+ rlm_cache_handle_t **handle);
+
+typedef int (*cache_acquire_t)(rlm_cache_handle_t **out, rlm_cache_t *inst, REQUEST *request);
+typedef void (*cache_release_t)(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle);
+typedef int (*cache_reconnect_t)(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle);
+
+struct cache_module {
+ char const *name; //!< Driver name.
+
+ cache_instantiate_t instantiate; //!< (optional) Instantiate a driver.
+ cache_entry_alloc_t alloc; //!< (optional) Allocate a new entry.
+ cache_entry_free_t free; //!< (optional) Free memory used by an entry.
+
+ cache_entry_find_t find; //!< Retrieve an existing cache entry.
+ cache_entry_insert_t insert; //!< Add a new entry.
+ cache_entry_expire_t expire; //!< Remove an old entry.
+ cache_entry_count_t count; //!< Number of entries.
+
+ cache_acquire_t acquire; //!< (optional) Get a lock or connection handle.
+ cache_release_t release; //!< (optional) Release the lock or connection handle.
+ cache_reconnect_t reconnect; //!< (optional) Reconnect a handle.
+};
diff --git a/src/modules/rlm_cache/rlm_cache.mk b/src/modules/rlm_cache/rlm_cache.mk
new file mode 100644
index 0000000..5b1651a
--- /dev/null
+++ b/src/modules/rlm_cache/rlm_cache.mk
@@ -0,0 +1,3 @@
+TARGET := rlm_cache.a
+SOURCES := rlm_cache.c
+TGT_LDLIBS := $(LIBS)
diff --git a/src/modules/rlm_cache/serialize.c b/src/modules/rlm_cache/serialize.c
new file mode 100644
index 0000000..b1f8e0c
--- /dev/null
+++ b/src/modules/rlm_cache/serialize.c
@@ -0,0 +1,243 @@
+/*
+ * 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 serialize.c
+ * @brief Serialize and deserialise cache entries.
+ *
+ * @author Arran Cudbard-Bell
+ * @copyright 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include "rlm_cache.h"
+#include "serialize.h"
+
+/** Serialize a cache entry as a humanly readable string
+ *
+ * @param ctx to alloc new string in. Should be a talloc pool a little bigger
+ * than the maximum serialized size of the entry.
+ * @param out Where to write pointer to serialized cache entry.
+ * @param c Cache entry to serialize.
+ * @return 0 on success else -1.
+ */
+int cache_serialize(TALLOC_CTX *ctx, char **out, rlm_cache_entry_t *c)
+{
+ TALLOC_CTX *pairs = NULL;
+
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ char *to_store = NULL, *pair;
+
+ to_store = talloc_asprintf(ctx, "&Cache-Expires = %" PRIu64 "\n&Cache-Created = %" PRIu64 "\n",
+ (uint64_t)c->expires, (uint64_t)c->created);
+ if (!to_store) goto error;
+
+ /*
+ * It's valid to have an empty cache entry (save allocing the
+ * pairs pool)
+ */
+ if (!c->control && !c->packet && !c->reply) goto finish;
+
+ /*
+ * In the majority of cases using these pools reduces the number of mallocs
+ * to two, except in the case where the total serialized pairs length is
+ * greater than the pairs pool, or the total serialized string is greater
+ * than the store pool.
+ */
+ pairs = talloc_pool(ctx, 512);
+ if (!pairs) {
+ error:
+ talloc_free(pairs);
+ return -1;
+ }
+
+ if (c->control) {
+ for (vp = fr_cursor_init(&cursor, &c->control);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ pair = vp_aprints(pairs, vp, '\'');
+ if (!pair) goto error;
+
+ to_store = talloc_asprintf_append_buffer(to_store, "&control:%s\n", pair);
+ if (!to_store) goto error;
+ }
+ }
+
+ if (c->packet) {
+ for (vp = fr_cursor_init(&cursor, &c->packet);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ pair = vp_aprints(pairs, vp, '\'');
+ if (!pair) goto error;
+
+ to_store = talloc_asprintf_append_buffer(to_store, "&%s\n", pair);
+ if (!to_store) goto error;
+ }
+ }
+
+ if (c->reply) {
+ for (vp = fr_cursor_init(&cursor, &c->reply);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ pair = vp_aprints(pairs, vp, '\'');
+ if (!pair) goto error;
+
+ to_store = talloc_asprintf_append_buffer(to_store, "&reply:%s\n", pair);
+ if (!to_store) goto error;
+ }
+ }
+
+ if (c->state) {
+ for (vp = fr_cursor_init(&cursor, &c->state);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ pair = vp_aprints(pairs, vp, '\'');
+ if (!pair) goto error;
+
+ to_store = talloc_asprintf_append_buffer(to_store, "&session-state:%s\n", pair);
+ if (!to_store) goto error;
+ }
+ }
+
+finish:
+ talloc_free(pairs);
+ *out = to_store;
+
+ return 0;
+}
+
+/** Converts a serialized cache entry back into a structure
+ *
+ * @param c Cache entry to populate (should already be allocated)
+ * @param in String representation of cache entry.
+ * @param inlen Length of string. May be < 0 in which case strlen will be
+ * used to calculate the length of the string.
+ * @return 0 on success, -1 on error.
+ */
+int cache_deserialize(rlm_cache_entry_t *c, char *in, ssize_t inlen)
+{
+ vp_cursor_t packet, control, reply, state;
+
+ TALLOC_CTX *store = NULL;
+ char *p, *q;
+
+ store = talloc_pool(c, 1024);
+ if (!store) return -1;
+
+ if (inlen < 0) inlen = strlen(in);
+
+ fr_cursor_init(&packet, &c->packet);
+ fr_cursor_init(&control, &c->control);
+ fr_cursor_init(&reply, &c->reply);
+ fr_cursor_init(&state, &c->state);
+
+ p = in;
+
+ while (((size_t)(p - in)) < (size_t)inlen) {
+ vp_map_t *map = NULL;
+ VALUE_PAIR *vp = NULL;
+ ssize_t len;
+
+ q = strchr(p, '\n');
+ if (!q) break; /* List should also be terminated with a \n */
+ *q = '\0';
+
+ if (map_afrom_attr_str(store, &map, p,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ fr_strerror_printf("Failed parsing pair: %s", p);
+ goto error;
+ }
+
+ if (map->lhs->type != TMPL_TYPE_ATTR) {
+ fr_strerror_printf("Pair left hand side \"%s\" parsed as %s, needed attribute. "
+ "Check local dictionaries", map->lhs->name,
+ fr_int2str(tmpl_names, map->lhs->type, "<INVALID>"));
+ goto error;
+ }
+
+ if (map->rhs->type != TMPL_TYPE_LITERAL) {
+ fr_strerror_printf("Pair right hand side \"%s\" parsed as %s, needed literal. "
+ "Check serialized data quoting", map->rhs->name,
+ fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
+ goto error;
+ }
+
+ /*
+ * Convert literal to a type appropriate for the VP.
+ */
+ if (tmpl_cast_in_place(map->rhs, map->lhs->tmpl_da->type, map->lhs->tmpl_da) < 0) goto error;
+
+ vp = fr_pair_afrom_da(c, map->lhs->tmpl_da);
+ len = value_data_copy(vp, &vp->data, map->rhs->tmpl_data_type,
+ &map->rhs->tmpl_data_value, map->rhs->tmpl_data_length);
+ if (len < 0) goto error;
+ vp->vp_length = len;
+
+ /*
+ * Pull out the special attributes, and set the
+ * relevant cache entry fields.
+ */
+ if (vp->da->vendor == 0) switch (vp->da->attr) {
+ case PW_CACHE_CREATED:
+ c->created = vp->vp_date;
+ talloc_free(vp);
+ goto next;
+
+ case PW_CACHE_EXPIRES:
+ c->expires = vp->vp_date;
+ talloc_free(vp);
+ goto next;
+
+ default:
+ break;
+ }
+
+ switch (map->lhs->tmpl_list) {
+ case PAIR_LIST_REQUEST:
+ fr_cursor_insert(&packet, vp);
+ break;
+
+ case PAIR_LIST_CONTROL:
+ fr_cursor_insert(&control, vp);
+ break;
+
+ case PAIR_LIST_REPLY:
+ fr_cursor_insert(&reply, vp);
+ break;
+
+ case PAIR_LIST_STATE:
+ fr_cursor_insert(&state, vp);
+ break;
+
+ default:
+ fr_strerror_printf("Invalid cache list for pair: %s", p);
+ error:
+ talloc_free(vp);
+ talloc_free(map);
+ return -1;
+ }
+ next:
+ p = q + 1;
+ talloc_free(map);
+ }
+
+ return 0;
+}
diff --git a/src/modules/rlm_cache/serialize.h b/src/modules/rlm_cache/serialize.h
new file mode 100644
index 0000000..fdc34e9
--- /dev/null
+++ b/src/modules/rlm_cache/serialize.h
@@ -0,0 +1,29 @@
+/*
+ * 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 serialize.h
+ * @brief Serialize and deserialise cache entries.
+ *
+ * @author Arran Cudbard-Bell
+ * @copyright 2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSIDH(serialize_h, "$Id$")
+
+int cache_serialize(TALLOC_CTX *ctx, char **out, rlm_cache_entry_t *c);
+int cache_deserialize(rlm_cache_entry_t *c, char *in, ssize_t inlen);
diff --git a/src/modules/rlm_cache/stable b/src/modules/rlm_cache/stable
new file mode 100644
index 0000000..67a303e
--- /dev/null
+++ b/src/modules/rlm_cache/stable
@@ -0,0 +1,2 @@
+rlm_cache_memcached
+rlm_cache_redis
diff --git a/src/modules/rlm_chap/README.md b/src/modules/rlm_chap/README.md
new file mode 100644
index 0000000..0186535
--- /dev/null
+++ b/src/modules/rlm_chap/README.md
@@ -0,0 +1,9 @@
+# rlm_chap
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Performs Challenge Handshake Authentication Protocol (CHAP) authentication, as described by RFC 2865.
diff --git a/src/modules/rlm_chap/all.mk b/src/modules/rlm_chap/all.mk
new file mode 100644
index 0000000..c820e84
--- /dev/null
+++ b/src/modules/rlm_chap/all.mk
@@ -0,0 +1,4 @@
+TARGET := rlm_chap.a
+SOURCES := rlm_chap.c
+
+
diff --git a/src/modules/rlm_chap/rlm_chap.c b/src/modules/rlm_chap/rlm_chap.c
new file mode 100644
index 0000000..d0f3292
--- /dev/null
+++ b/src/modules/rlm_chap/rlm_chap.c
@@ -0,0 +1,162 @@
+/*
+ * 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_chap.c
+ * @brief Process chap authentication requests.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ if (!fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
+ return RLM_MODULE_NOOP;
+ }
+
+ if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY) != NULL) {
+ RWDEBUG2("&control:Auth-Type already set. Not setting to CHAP");
+ return RLM_MODULE_NOOP;
+ }
+
+ RINDENT();
+ RDEBUG("&control:Auth-Type := CHAP");
+ REXDENT();
+ pair_make_config("Auth-Type", "CHAP", T_OP_EQ);
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * 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_authenticate(UNUSED void *instance, REQUEST *request)
+{
+ VALUE_PAIR *password, *chap;
+ uint8_t pass_str[MAX_STRING_LEN];
+
+ if (!request->username) {
+ REDEBUG("&request:User-Name attribute is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ chap = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ if (!chap) {
+ REDEBUG("You set '&control:Auth-Type = CHAP' for a request that "
+ "does not contain a CHAP-Password attribute!");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (chap->vp_length == 0) {
+ REDEBUG("&request:CHAP-Password is empty");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (chap->vp_length != CHAP_VALUE_LENGTH + 1) {
+ REDEBUG("&request:CHAP-Password has invalid length");
+ return RLM_MODULE_INVALID;
+ }
+
+ password = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (password == NULL) {
+ if (fr_pair_find_by_num(request->config, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){
+ REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ REDEBUG("!!! Please update your configuration so that the \"known !!!");
+ REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!");
+ REDEBUG("!!! and NOT in User-Password. !!!");
+ REDEBUG("!!! !!!");
+ REDEBUG("!!! Authentication will fail because of this. !!!");
+ REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+
+ REDEBUG("&control:Cleartext-Password is required for authentication");
+ return RLM_MODULE_FAIL;
+ }
+
+ rad_chap_encode(request->packet, pass_str, chap->vp_octets[0], password);
+
+ if (RDEBUG_ENABLED3) {
+ uint8_t const *p;
+ size_t length;
+ VALUE_PAIR *vp;
+ char buffer[MAX_STRING_LEN * 2 + 1];
+
+ RDEBUG3("Comparing with \"known good\" &control:Cleartext-Password value \"%s\"",
+ password->vp_strvalue);
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
+ if (vp) {
+ RDEBUG2("Using challenge from &request:CHAP-Challenge");
+ p = vp->vp_octets;
+ length = vp->vp_length;
+ } else {
+ RDEBUG2("Using challenge from authenticator field");
+ p = request->packet->vector;
+ length = sizeof(request->packet->vector);
+ }
+
+ fr_bin2hex(buffer, p, length);
+ RINDENT();
+ RDEBUG3("CHAP challenge : %s", buffer);
+
+ fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH);
+ RDEBUG3("Client sent : %s", buffer);
+
+ fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH);
+ RDEBUG3("We calculated : %s", buffer);
+ REXDENT();
+ } else {
+ RDEBUG2("Comparing with \"known good\" Cleartext-Password");
+ }
+
+ if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) {
+ REDEBUG("Password comparison failed: password is incorrect");
+ return RLM_MODULE_REJECT;
+ }
+
+ RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue);
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * 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_chap;
+module_t rlm_chap = {
+ .magic = RLM_MODULE_INIT,
+ .name = "chap",
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ },
+};
diff --git a/src/modules/rlm_couchbase/.gitignore b/src/modules/rlm_couchbase/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_couchbase/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_couchbase/README.md b/src/modules/rlm_couchbase/README.md
new file mode 100644
index 0000000..087e22c
--- /dev/null
+++ b/src/modules/rlm_couchbase/README.md
@@ -0,0 +1,196 @@
+# rlm_couchbase
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Couchbase database driver for authentication and accounting.
+
+## General
+
+This module supports accounting, authorization, dynamic clients and simultaneous use checking. Accounting data is written directly to Couchbase as JSON documents and user authorization information is read from JSON documents stored within Couchbase. You should list the ```couchbase``` module in both the ```accounting``` and ```authorization``` sections of your site configuration if you are planning to use it for both purposes. You should also have ```pap``` enabled for authenticating users based on cleartext or hashed password attributes. To enable simultanous use checking you will need to list the ```couchbase``` module in the ```session``` and ```accounting``` sections of your site configuration.
+
+It was tested to handle thousands of RADIUS requests per second from several thousand Aerohive access points using a FreeRADIUS installation with this module for accounting and authorization.
+
+
+## Accounting
+
+You can use any RADIUS attribute available in the accounting request to build the key for storing the accounting documents. The default configuration will try to use 'Acct-Unique-Session-Id' and fallback to 'Acct-Session-Id' if 'Acct-Unique-Session-Id' is not present. You will need to have the ```acct_unique``` policy in the ```preacct``` section of your configuration to generate the unique id attribute. Different status types (start/stop/update) are merged into a single document to facilitate querying and reporting via views. When everything is configured correctly you will see accounting requests recorded as JSON documents in your Couchbase cluster. You have full control over what attributes are recorded and how those attributes are mapped to JSON element names via the module configuration.
+
+This example is from an Aerohive wireless access point.
+
+```
+{
+ "docType": "radacct",
+ "startTimestamp": "Jul 15 2013 13:22:07 CDT",
+ "stopTimestamp": "null",
+ "sessionId": "51D241D3-0000047A",
+ "lastStatus": 3,
+ "authentic": 1,
+ "userName": "mruser@blargs.com",
+ "nasIpAddress": "172.28.4.150",
+ "nasIdentifier": "air4.corp.blargs.com",
+ "nasPort": 0,
+ "calledStationId": "40-18-b1-01-3c-54",
+ "framedIpAddress": "172.27.2.87",
+ "callingStationId": "8C-2D-AA-72-36-BA",
+ "nasPortType": 19,
+ "connectInfo": "11ng",
+ "sessionTime": 5821,
+ "inputPackets": 5591,
+ "inputOctets": 681742,
+ "inputGigawords": 0,
+ "outputOctets": 536306,
+ "outputGigawords": 0,
+ "outputPackets": 1087,
+ "lastUpdated": "Jul 15 2013 14:59:08 CDT",
+ "uniqueId": "029d975fc48ecb41444da52a65e62a55",
+ "calledStationSSID": "BLARGS-WIFI",
+ "strippedUserName": "mruser",
+ "strippedUserDomain": "blargs.com"
+}
+```
+
+To generate the 'calledStationSSID' fields you will need to use the ```rewrite_called_station_id``` policy in the ```preacct``` section of your config. Similarly to get the 'Stripped-User-Name' and 'Stripped-User-Domain' attributes you can create a file in ```raddb/policy.d/``` with the following content:
+
+```
+## simple nt domain regex
+simple_nt_regexp = "^([^\\]*)\\(.*)$"
+
+## simple nai regex
+simple_nai_regexp = "^([^@]*)@(.*)$"
+
+## split user@domain and domain\user formats
+strip_user_domain {
+ if(User-Name && (User-Name =~ /${policy.simple_nt_regexp}/)){
+ update request {
+ &Stripped-User-Domain = "%{1}"
+ &Stripped-User-Name = "%{2}"
+ }
+ }
+ elsif(User-Name && (User-Name =~ /${policy.simple_nai_regexp}/)){
+ update request {
+ &Stripped-User-Name = "%{1}"
+ &Stripped-User-Domain = "%{2}"
+ }
+ }
+ else {
+ noop
+ }
+}
+```
+
+You can then reference this policy in both the ```preacct``` and ```authorization``` sections of your configuration before calling this module.
+
+
+## Authorization
+
+The authorization functionality relies on the user documents being stored with deterministic keys based on information available in the authorization request. The format of those keys may be specified in unlang like the example below:
+
+```
+user_key = "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}"
+```
+
+This will create an md5 hash of the lowercase 'Stripped-User-Name' attribute or the 'User-Name' attribute if 'Stripped-User-Name' doesn't exist. The module will then attempt to fetch the resulting key from the configured Couchbase bucket.
+
+The document structure is straight forward and flexible:
+
+```json
+{
+ "docType": "raduser",
+ "userName": "test",
+ "config": {
+ "SHA-Password": {
+ "value": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
+ "op": ":="
+ }
+ },
+ "reply": {
+ "Reply-Message": {
+ "value": "Hidey Ho!",
+ "op": "="
+ }
+ }
+}
+```
+
+You may specify any valid combination of attributes and operators in the JSON document ```config``` and ```reply``` sections. All other elements present in the user document will not be parsed and are ignored by the module.
+
+
+## Clients
+
+The client functionality depends on a combination of client documents and a simple view that returns those document keys. Client documents are only loaded ONCE on server startup so there should be no performance penalty using a view for this purpose.
+
+To enable the client loading functionality you will need to set the ```read_clients``` config option to 'yes' and specify a fully qualified view path in the ```client_view``` option.
+
+Example client document:
+
+```json
+{
+ "docType": "radclient",
+ "clientIdentifier": "13.0.0.0/8",
+ "clientSecret": "testing123"
+}
+```
+
+The element names and the client attributes to which they map are completely configurable. Elements present in the document that are not enumerated in the module configuration will be ignored. In addition to this document you will also need a view that returns the keys of all client documents you wish to load.
+
+Example client view:
+
+```js
+function (doc, meta) {
+ if (doc.docType && doc.docType == "radclient") {
+ emit(meta.id, null);
+ }
+}
+```
+
+This is the simplest possible view that would return all documents in the specified bucket having a ```docType``` element with ```radclient``` value. The module only reads the ```key``` (first emited field) and ```id``` elements in the returned view thus no additional output is needed and any additional output would be ignored. The ```key``` emitted here will be used as the client name inside the module.
+
+To have the module load only a subset of the client documents contained within the bucket you could add additional elements to the client documents and then filter based on those elements within your view.
+
+
+## Simultaneous Use
+
+The simultaneous use function relies on data stored in the accounting documents. When a user attempts to authenticate a view request is made to return all accounting type documents for the current user that do not contain a populated ```stopTimestamp``` value.
+
+Example check view:
+
+```js
+function (doc, meta) {
+ if (doc.docType && doc.docType == "radacct" && doc.userName && !doc.stopTimestamp) {
+ if (doc.strippedUserName) {
+ emit(doc.strippedUserName.toLowerCase(), null);
+ } else {
+ emit(doc.userName.toLowerCase(), null);
+ }
+ }
+}
+```
+
+The key (first emitted field) will need to match *EXACTLY* what you set for ```simul_vkey``` in the module configuration. The default xlat value will attempt to return the lower case 'Stripped-User-Name' attribute or 'User-Name' if the stripped version is not available.
+
+When the total number of keys (sessions) returned is greater than or equal to the ```Simultaneous-Use``` config section value of the current user, the user will be denied access. When verification is also enabled, each returned key will be fetched and the appropriate information will be passed on to the ```checkrad``` utillity to verify the session status. If ```checkrad``` determines the session is no longer valid (stale) the session will be updated and closed in Couchbase (if configured) and that session will not be counted against the users login limit. Further information is available in the module configuration.
+
+
+## To Use
+
+Until this module is added to the stable list you will need to explicitly add it to ```src/modules/stable``` before building the server.
+
+```
+echo rlm_couchbase >> src/modules/stable
+```
+
+You will also need the following libraries installed where they may be found by the server configuration script.
+
+* [libcouchbase](https://github.com/couchbase/libcouchbase) >= 2.0.0 with a valid libio module
+* [json-c](https://github.com/json-c/json-c) >= 0.9 (0.10+ HIGHLY encouraged)
+
+Once the above steps are complete, simply configure and install as usual.
+
+
+## Module Configuration
+
+Please see [/raddb/mods-available/couchbase](/raddb/mods-available/couchbase) for all available configuration options.
diff --git a/src/modules/rlm_couchbase/all.mk.in b/src/modules/rlm_couchbase/all.mk.in
new file mode 100644
index 0000000..1b52bcf
--- /dev/null
+++ b/src/modules/rlm_couchbase/all.mk.in
@@ -0,0 +1,13 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c mod.c jsonc_missing.c couchbase.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+# TODO: create man page
+#MAN := rlm_couchbase.8
diff --git a/src/modules/rlm_couchbase/config.h.in b/src/modules/rlm_couchbase/config.h.in
new file mode 100644
index 0000000..63a968f
--- /dev/null
+++ b/src/modules/rlm_couchbase/config.h.in
@@ -0,0 +1,25 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* 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_object_get_string_len' function. */
+#undef HAVE_JSON_OBJECT_GET_STRING_LEN
+
+/* Define to 1 if you have the `json_object_new_int64' function. */
+#undef HAVE_JSON_OBJECT_NEW_INT64
+
+/* Define to 1 if you have the `json_object_object_get_ex' function. */
+#undef HAVE_JSON_OBJECT_OBJECT_GET_EX
+
+/* Define to 1 if you have the `json_tokener_error_desc' function. */
+#undef HAVE_JSON_TOKENER_ERROR_DESC
+
+/* Define to 1 if you have the `json_tokener_get_error' function. */
+#undef HAVE_JSON_TOKENER_GET_ERROR
diff --git a/src/modules/rlm_couchbase/configure b/src/modules/rlm_couchbase/configure
new file mode 100755
index 0000000..4677477
--- /dev/null
+++ b/src/modules/rlm_couchbase/configure
@@ -0,0 +1,5276 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_couchbase.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_couchbase
+with_jsonc_include_dir
+with_jsonc_lib_dir
+with_jsonc_dir
+with_libcouchbase_include_dir
+with_libcouchbase_lib_dir
+with_libcouchbase_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+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_couchbase build without rlm_couchbase
+ --with-jsonc-include-dir=DIR
+ Directory where the json-c includes may be found
+ --with-jsonc-lib-dir=DIR
+ Directory where the json-c libraries may be found
+ --with-jsonc-dir=DIR Base directory where json-c is installed
+ --with-libcouchbase-include-dir=DIR
+ Directory where the libcouchbase includes may be
+ found
+ --with-libcouchbase-lib-dir=DIR
+ Directory where the libcouchbase libraries may be
+ found
+ --with-libcouchbase-dir=DIR
+ Base directory where libcouchbase is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_couchbase
+echo
+
+
+# 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_couchbase was given.
+if test "${with_rlm_couchbase+set}" = set; then :
+ withval=$with_rlm_couchbase;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_couchbase" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+jsonc_include_dir=
+
+# Check whether --with-jsonc-include-dir was given.
+if test "${with_jsonc_include_dir+set}" = set; then :
+ withval=$with_jsonc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+jsonc_lib_dir=
+
+# Check whether --with-jsonc-lib-dir was given.
+if test "${with_jsonc_lib_dir+set}" = set; then :
+ withval=$with_jsonc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-jsonc-dir was given.
+if test "${with_jsonc_dir+set}" = set; then :
+ withval=$with_jsonc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need json-c-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+have_json="yes"
+smart_try_dir="$jsonc_include_dir"
+
+
+
+ac_safe=`echo "json/json.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/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"
+ { $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;}
+
+fail="$fail libjson-c"
+
+ fi
+fi
+
+if test "x$have_json" = "xyes"; then
+ LDFLAGS="$SMART_LIBS"
+
+ for ac_func in \
+ json_c_version \
+ json_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_new_int64 \
+ json_tokener_error_desc \
+ json_tokener_get_error
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+else
+
+fail="$fail json-c"
+
+fi
+
+
+libcouchbase_include_dir=
+
+# Check whether --with-libcouchbase-include-dir was given.
+if test "${with_libcouchbase_include_dir+set}" = set; then :
+ withval=$with_libcouchbase_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+libcouchbase_lib_dir=
+
+# Check whether --with-libcouchbase-lib-dir was given.
+if test "${with_libcouchbase_lib_dir+set}" = set; then :
+ withval=$with_libcouchbase_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-libcouchbase-dir was given.
+if test "${with_libcouchbase_dir+set}" = set; then :
+ withval=$with_libcouchbase_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need libcouchbase-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval/lib"
+ libcouchbase_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir="$libcouchbase_include_dir"
+
+
+ac_safe=`echo "libcouchbase/couchbase.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 libcouchbase/couchbase.h in $try" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/libcouchbase/couchbase.h" >&5
+$as_echo_n "checking for ${_prefix}/libcouchbase/couchbase.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-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 libcouchbase/couchbase.h" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcouchbase/couchbase.h in $try" >&5
+$as_echo_n "checking for libcouchbase/couchbase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libcouchbase/couchbase.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ 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_libcouchbase_couchbase_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>." >&2;}
+
+fail="$fail couchbase.h"
+
+fi
+
+
+smart_try_dir="$libcouchbase_lib_dir"
+
+
+sm_lib_safe=`echo "couchbase" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "lcb_get_version" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcb_get_version in -lcouchbase in $try" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase in $try... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcb_get_version in -lcouchbase" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lcb_get_version in -lcouchbase in $try" >&5
+$as_echo_n "checking for lcb_get_version in -lcouchbase in $try... " >&6; }
+ LIBS="-lcouchbase $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char lcb_get_version();
+int
+main ()
+{
+lcb_get_version()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcouchbase"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_couchbase_lcb_get_version" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>." >&2;}
+
+fail="$fail libcouchbase"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL support" >&5
+$as_echo_n "checking for OpenSSL support... " >&6; }
+if test "x$OPENSSL_LIBS" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fail="$fail OpenSSL"
+
+fi
+
+
+
+ targetname=rlm_couchbase
+else
+ targetname=
+ echo \*\*\* module rlm_couchbase is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_couchbase to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_couchbase." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_couchbase." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_couchbase requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_couchbase requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_couchbase/configure.ac b/src/modules/rlm_couchbase/configure.ac
new file mode 100644
index 0000000..453b92a
--- /dev/null
+++ b/src/modules/rlm_couchbase/configure.ac
@@ -0,0 +1,220 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_couchbase.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_couchbase])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+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>.])
+ FR_MODULE_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"
+ AC_MSG_WARN([json-c libraries not found. Use --with-jsonc-lib-dir=<path>.])
+ FR_MODULE_FAIL([libjson-c])
+ fi
+fi
+
+if test "x$have_json" = "xyes"; then
+ dnl # Ensure we use the library we just found the rest of the checks
+ LDFLAGS="$SMART_LIBS"
+
+ dnl # Add any optional functions here
+ AC_CHECK_FUNCS(\
+ json_c_version \
+ json_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_new_int64 \
+ json_tokener_error_desc \
+ json_tokener_get_error
+ )
+else
+ FR_MODULE_FAIL([json-c])
+fi
+
+dnl ############################################################
+dnl # Check for libcouchbase
+dnl ############################################################
+
+dnl extra argument: --with-libcouchbase-include-dir=DIR
+libcouchbase_include_dir=
+AC_ARG_WITH(libcouchbase-include-dir,
+ [AS_HELP_STRING([--with-libcouchbase-include-dir=DIR],
+ [Directory where the libcouchbase includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-libcouchbase-lib-dir=DIR
+libcouchbase_lib_dir=
+AC_ARG_WITH(libcouchbase-lib-dir,
+[AS_HELP_STRING([--with-libcouchbase-lib-dir=DIR],
+ [Directory where the libcouchbase libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-libcouchbase-dir=DIR
+AC_ARG_WITH(libcouchbase-dir,
+[AS_HELP_STRING([--with-libcouchbase-dir=DIR],
+ [Base directory where libcouchbase is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need libcouchbase-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ libcouchbase_lib_dir="$withval/lib"
+ libcouchbase_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for libcouchbase header files
+dnl ############################################################
+
+smart_try_dir="$libcouchbase_include_dir"
+FR_SMART_CHECK_INCLUDE([libcouchbase/couchbase.h])
+if test "x$ac_cv_header_libcouchbase_couchbase_h" != "xyes"; then
+ AC_MSG_WARN([libcouchbase headers not found. Use --with-libcouchbase-include-dir=<path>.])
+ FR_MODULE_FAIL([couchbase.h])
+fi
+
+dnl ############################################################
+dnl # Check for libcouchbase libraries
+dnl ############################################################
+
+smart_try_dir="$libcouchbase_lib_dir"
+FR_SMART_CHECK_LIB([couchbase], [lcb_get_version])
+if test "x$ac_cv_lib_couchbase_lcb_get_version" != "xyes"; then
+ AC_MSG_WARN([libcouchbase libraries not found. Use --with-libcouchbase-lib-dir=<path>.])
+ FR_MODULE_FAIL([libcouchbase])
+fi
+
+dnl ############################################################
+dnl # Check for OpenSSL
+dnl ############################################################
+
+AC_MSG_CHECKING(for OpenSSL support)
+if test "x$OPENSSL_LIBS" != "x"; then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+ FR_MODULE_FAIL([OpenSSL])
+fi
+
+dnl ############################################################
+dnl # Checks done - set targetname
+dnl ############################################################
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_couchbase/couchbase.c b/src/modules/rlm_couchbase/couchbase.c
new file mode 100644
index 0000000..ab2d9d0
--- /dev/null
+++ b/src/modules/rlm_couchbase/couchbase.c
@@ -0,0 +1,412 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Wrapper functions around the libcouchbase Couchbase client driver.
+ * @file couchbase.c
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/** Couchbase callback for cluster statistics requests
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param error Couchbase error object.
+ * @param resp Couchbase statistics response object.
+ */
+void couchbase_stat_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_server_stat_resp_t *resp)
+{
+ if (error != LCB_SUCCESS) {
+ /* log error */
+ ERROR("rlm_couchbase: (stats_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ }
+ /* silent compiler */
+ (void)cookie;
+ (void)resp;
+}
+
+/** Couchbase callback for store (write) operations
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param operation Couchbase storage operation object.
+ * @param error Couchbase error object.
+ * @param resp Couchbase store operation response object.
+ */
+void couchbase_store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation,
+ lcb_error_t error, const lcb_store_resp_t *resp)
+{
+ if (error != LCB_SUCCESS) {
+ /* log error */
+ ERROR("rlm_couchbase: (store_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ }
+ /* silent compiler */
+ (void)cookie;
+ (void)operation;
+ (void)resp;
+}
+
+/** Couchbase callback for get (read) operations
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param error Couchbase error object.
+ * @param resp Couchbase get operation response object.
+ */
+void couchbase_get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp)
+{
+ cookie_u cu; /* union of const and non const pointers */
+ cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
+ cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
+ const char *bytes = resp->v.v0.bytes; /* the payload of this chunk */
+ lcb_size_t nbytes = resp->v.v0.nbytes; /* length of this data chunk */
+
+ /* check error */
+ switch (error) {
+ case LCB_SUCCESS:
+ /* check for valid bytes */
+ if (bytes && nbytes > 1) {
+ /* debug */
+ DEBUG("rlm_couchbase: (get_callback) got %zu bytes", nbytes);
+ /* parse string to json object */
+ c->jobj = json_tokener_parse_ex(c->jtok, bytes, nbytes);
+ /* switch on tokener error */
+ switch ((c->jerr = json_tokener_get_error(c->jtok))) {
+ case json_tokener_continue:
+ /* check object - should be null */
+ if (c->jobj != NULL) {
+ ERROR("rlm_couchbase: (get_callback) object not null on continue!");
+ }
+ break;
+ case json_tokener_success:
+ /* do nothing */
+ break;
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (get_callback) json parsing error: %s",
+ json_tokener_error_desc(c->jerr));
+ break;
+ }
+ }
+ break;
+
+ case LCB_KEY_ENOENT:
+ /* ignored */
+ DEBUG("rlm_couchbase: (get_callback) key does not exist");
+ break;
+
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (get_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ break;
+ }
+}
+
+/** Couchbase callback for http (view) operations
+ *
+ * @param request Couchbase http request object.
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param error Couchbase error object.
+ * @param resp Couchbase http response object.
+ */
+void couchbase_http_data_callback(lcb_http_request_t request, lcb_t instance, const void *cookie,
+ lcb_error_t error, const lcb_http_resp_t *resp)
+{
+ cookie_u cu; /* union of const and non const pointers */
+ cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
+ cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
+ const char *bytes = resp->v.v0.bytes; /* the payload of this chunk */
+ lcb_size_t nbytes = resp->v.v0.nbytes; /* length of this data chunk */
+
+ /* check error */
+ switch (error) {
+ case LCB_SUCCESS:
+ /* check for valid bytes */
+ if (bytes && nbytes > 1) {
+ /* debug */
+ DEBUG("rlm_couchbase: (http_data_callback) got %zu bytes", nbytes);
+ /* parse string to json object */
+ c->jobj = json_tokener_parse_ex(c->jtok, bytes, nbytes);
+ /* switch on tokener error */
+ switch ((c->jerr = json_tokener_get_error(c->jtok))) {
+ case json_tokener_continue:
+ /* check object - should be null */
+ if (c->jobj != NULL) {
+ ERROR("rlm_couchbase: (http_data_callback) object not null on continue!");
+ }
+ break;
+ case json_tokener_success:
+ /* do nothing */
+ break;
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (http_data_callback) json parsing error: %s",
+ json_tokener_error_desc(c->jerr));
+ break;
+ }
+ }
+ break;
+
+ default:
+ /* log error */
+ ERROR("rlm_couchbase: (http_data_callback) %s (0x%x)", lcb_strerror(instance, error), error);
+ break;
+ }
+ /* silent compiler */
+ (void)request;
+}
+
+/** Initialize a Couchbase connection instance
+ *
+ * Initialize all information relating to a Couchbase instance and configure available method callbacks.
+ * This function forces synchronous operation and will wait for a connection or timeout.
+ *
+ * @param instance Empty (un-allocated) Couchbase instance object.
+ * @param host The Couchbase server or list of servers.
+ * @param bucket The Couchbase bucket to associate with the instance.
+ * @param pass The Couchbase bucket password (NULL if none).
+ * @return Couchbase error object.
+ */
+lcb_error_t couchbase_init_connection(lcb_t *instance, const char *host, const char *bucket, const char *pass)
+{
+ lcb_error_t error; /* couchbase command return */
+ struct lcb_create_st options; /* init create struct */
+
+ /* init options */
+ memset(&options, 0, sizeof(options));
+
+ /* assign couchbase create options */
+ options.v.v0.host = host;
+ options.v.v0.bucket = bucket;
+
+ /* assign user and password if they were both passed */
+ if (bucket != NULL && pass != NULL) {
+ options.v.v0.user = bucket;
+ options.v.v0.passwd = pass;
+ }
+
+ /* create couchbase connection instance */
+ if ((error = lcb_create(instance, &options)) != LCB_SUCCESS) {
+ /* return error */
+ return error;
+ }
+
+ /* initiate connection */
+ if ((error = lcb_connect(*instance)) == LCB_SUCCESS) {
+ /* set general method callbacks */
+ lcb_set_stat_callback(*instance, couchbase_stat_callback);
+ lcb_set_store_callback(*instance, couchbase_store_callback);
+ lcb_set_get_callback(*instance, couchbase_get_callback);
+ lcb_set_http_data_callback(*instance, couchbase_http_data_callback);
+ /* wait on connection */
+ lcb_wait(*instance);
+ } else {
+ /* return error */
+ return error;
+ }
+
+ /* return instance */
+ return error;
+}
+
+/** Request Couchbase server statistics
+ *
+ * Setup and execute a request for cluster statistics and wait for the result.
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @return Couchbase error object.
+ */
+lcb_error_t couchbase_server_stats(lcb_t instance, const void *cookie)
+{
+ lcb_error_t error; /* couchbase command return */
+ lcb_server_stats_cmd_t cmd; /* server stats command stuct */
+ const lcb_server_stats_cmd_t *commands[1]; /* server stats commands array */
+
+ /* init commands */
+ commands[0] = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.name = "tap";
+ cmd.v.v0.nname = strlen(cmd.v.v0.name);
+
+ /* get statistics */
+ if ((error = lcb_server_stats(instance, cookie, 1, commands)) == LCB_SUCCESS) {
+ /* enter event look on success */
+ lcb_wait(instance);
+ }
+
+ /* return error */
+ return error;
+}
+
+/** Store a document by key in Couchbase
+ *
+ * Setup and execute a Couchbase set operation and wait for the result.
+ *
+ * @param instance Couchbase connection instance.
+ * @param key Document key to store in the database.
+ * @param document Document body to store in the database.
+ * @param expire Expiration time for the document (0 = never)
+ * @return Couchbase error object.
+ */
+lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire)
+{
+ lcb_error_t error; /* couchbase command return */
+ lcb_store_cmd_t cmd; /* store command stuct */
+ const lcb_store_cmd_t *commands[1]; /* store commands array */
+
+ /* init commands */
+ commands[0] = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.key = key;
+ cmd.v.v0.nkey = strlen(cmd.v.v0.key);
+ cmd.v.v0.bytes = document;
+ cmd.v.v0.nbytes = strlen(cmd.v.v0.bytes);
+ cmd.v.v0.exptime = expire;
+ cmd.v.v0.operation = LCB_SET;
+
+ /* store key/document in couchbase */
+ if ((error = lcb_store(instance, NULL, 1, commands)) == LCB_SUCCESS) {
+ /* enter event loop on success */
+ lcb_wait(instance);
+ }
+
+ /* return error */
+ return error;
+}
+
+/** Retrieve a document by key from Couchbase
+ *
+ * Setup and execute a Couchbase get request and wait for the result.
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param key Document key to fetch.
+ * @return Couchbase error object.
+ */
+lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key)
+{
+ cookie_u cu; /* union of const and non const pointers */
+ cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
+ cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
+ lcb_error_t error; /* couchbase command return */
+ lcb_get_cmd_t cmd; /* get command struct */
+ const lcb_get_cmd_t *commands[1]; /* get commands array */
+
+ /* init commands */
+ commands[0] = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.key = key;
+ cmd.v.v0.nkey = strlen(cmd.v.v0.key);
+
+ /* clear cookie */
+ memset(c, 0, sizeof(cookie_t));
+
+ /* init tokener error */
+ c->jerr = json_tokener_success;
+
+ /* create token */
+ c->jtok = json_tokener_new();
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: fetching document %s", key);
+
+ /* get document */
+ if ((error = lcb_get(instance, c, 1, commands)) == LCB_SUCCESS) {
+ /* enter event loop on success */
+ lcb_wait(instance);
+ }
+
+ /* free token */
+ json_tokener_free(c->jtok);
+
+ /* return error */
+ return error;
+}
+
+/** Query a Couchbase design document view
+ *
+ * Setup and execute a Couchbase view request and wait for the result.
+ *
+ * @param instance Couchbase connection instance.
+ * @param cookie Couchbase cookie for returning information from callbacks.
+ * @param path The fully qualified view path including the design document and view name.
+ * @param post The post payload (NULL for none).
+ * @return Couchbase error object.
+ */
+lcb_error_t couchbase_query_view(lcb_t instance, const void *cookie, const char *path, const char *post)
+{
+ cookie_u cu; /* union of const and non const pointers */
+ cu.cdata = cookie; /* set const union member to cookie passed from couchbase */
+ cookie_t *c = (cookie_t *) cu.data; /* set our cookie struct using non-const member */
+ lcb_error_t error; /* couchbase command return */
+ lcb_http_cmd_t cmd; /* http command struct */
+ const lcb_http_cmd_t *commands; /* http commands array */
+
+ commands = &cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* populate command struct */
+ cmd.v.v0.path = path;
+ cmd.v.v0.npath = strlen(cmd.v.v0.path);
+ cmd.v.v0.body = post;
+ cmd.v.v0.nbody = post ? strlen(post) : 0;
+ cmd.v.v0.method = post ? LCB_HTTP_METHOD_POST : LCB_HTTP_METHOD_GET;
+ cmd.v.v0.chunked = 1;
+ cmd.v.v0.content_type = "application/json";
+
+ /* clear cookie */
+ memset(c, 0, sizeof(cookie_t));
+
+ /* init tokener error */
+ c->jerr = json_tokener_success;
+
+ /* create token */
+ c->jtok = json_tokener_new();
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: fetching view %s", path);
+
+ /* query the view */
+ if ((error = lcb_make_http_request(instance, c, LCB_HTTP_TYPE_VIEW, commands, NULL)) == LCB_SUCCESS) {
+ /* enter event loop on success */
+ lcb_wait(instance);
+ }
+
+ /* free token */
+ json_tokener_free(c->jtok);
+
+ /* return error */
+ return error;
+}
diff --git a/src/modules/rlm_couchbase/couchbase.h b/src/modules/rlm_couchbase/couchbase.h
new file mode 100644
index 0000000..529bd72
--- /dev/null
+++ b/src/modules/rlm_couchbase/couchbase.h
@@ -0,0 +1,94 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Couchbase wrapper function prototypes and datatypes.
+ * @file couchbase.h
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+#ifndef _couchbase_h_
+#define _couchbase_h_
+
+RCSIDH(couchbase_h, "$Id$")
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#include <libcouchbase/couchbase.h>
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+#include "jsonc_missing.h"
+
+/** Information relating to the parsing of Couchbase document payloads
+ *
+ * This structure holds various references to json-c objects used when parsing
+ * Couchbase document payloads.
+ */
+typedef struct cookie_t {
+ json_object *jobj; //!< JSON objects handled by the json-c library.
+ json_tokener *jtok; //!< JSON tokener objects handled by the json-c library.
+ enum json_tokener_error jerr; //!< Error values produced by the json-c library.
+} cookie_t;
+
+/** Union of constant and non-constant pointers
+ *
+ * This is used to squelch compiler warnings about casting when passing data
+ * between functions expecting different data types.
+ */
+typedef union cookie_u {
+ const void *cdata; //!< Constant pointer to cookie payload (@p cookie_t).
+ void *data; //!< Non-constant pointer to data payload (@p cookie_t).
+} cookie_u;
+
+/* couchbase statistics callback */
+void couchbase_stat_callback(lcb_t instance, const void *cookie, lcb_error_t error,
+ const lcb_server_stat_resp_t *resp);
+
+/* store a key/document in couchbase */
+void couchbase_store_callback(lcb_t instance, const void *cookie, lcb_storage_t operation,
+ lcb_error_t error, const lcb_store_resp_t *item);
+
+/* get a document by key from couchbase */
+void couchbase_get_callback(lcb_t instance, const void *cookie, lcb_error_t error,
+ const lcb_get_resp_t *item);
+
+/* couchbase http callback for data chunks */
+void couchbase_http_data_callback(lcb_http_request_t request, lcb_t instance,
+ const void *cookie, lcb_error_t error, const lcb_http_resp_t *resp);
+
+/* create a couchbase instance and connect to the cluster */
+lcb_error_t couchbase_init_connection(lcb_t *instance, const char *host, const char *bucket, const char *pass);
+
+/* get server statistics */
+lcb_error_t couchbase_server_stats(lcb_t instance, const void *cookie);
+
+/* store document/key in couchbase */
+lcb_error_t couchbase_set_key(lcb_t instance, const char *key, const char *document, int expire);
+
+/* pull document from couchbase by key */
+lcb_error_t couchbase_get_key(lcb_t instance, const void *cookie, const char *key);
+
+/* query a couchbase view via http */
+lcb_error_t couchbase_query_view(lcb_t instance, const void *cookie, const char *path, const char *post);
+
+#endif /* _couchbase_h_ */
diff --git a/src/modules/rlm_couchbase/jsonc_missing.c b/src/modules/rlm_couchbase/jsonc_missing.c
new file mode 100644
index 0000000..dc3e7f6
--- /dev/null
+++ b/src/modules/rlm_couchbase/jsonc_missing.c
@@ -0,0 +1,82 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Workarounds for missing functions in older json-c libraries.
+ * @file jsonc_missing.c
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+RCSID("$Id$")
+
+#include <string.h>
+
+#include "jsonc_missing.h"
+
+#ifndef HAVE_JSON_C_VERSION
+ const char *json_c_version(void) {
+ return "Unknown (less than 0.10) - Please upgrade";
+ }
+#endif
+
+#ifndef HAVE_JSON_OBJECT_GET_STRING_LEN
+int json_object_get_string_len(json_object *obj) {
+ if ((obj == NULL) || (json_object_get_type(obj) != json_type_string))
+ return 0;
+ return (int)strlen(json_object_get_string(obj));
+}
+#endif
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+int json_object_object_get_ex(struct json_object *jso, const char *key, struct json_object **value) {
+ struct json_object *jobj;
+
+ if ((jso == NULL) || (key == NULL)) return 0;
+ if (value != NULL) *value = NULL;
+
+ switch (json_object_get_type(jso)) {
+ case json_type_object:
+ jobj = json_object_object_get(jso, key);
+ if (jobj == NULL) return 0;
+
+ if (value != NULL) *value = jobj;
+ return 1;
+
+ default:
+ if (value != NULL) *value = NULL;
+ return 0;
+ }
+}
+#endif
+
+#ifndef HAVE_JSON_TOKENER_GET_ERROR
+enum json_tokener_error json_tokener_get_error(json_tokener *tok) {
+ return tok->err;
+}
+#endif
+
+#ifndef HAVE_JSON_TOKENER_ERROR_DESC
+const char *json_tokener_error_desc(enum json_tokener_error jerr) {
+ int jerr_int = (int)jerr;
+ if (json_tokener_errors[jerr_int] == NULL)
+ return "Unknown error, invalid json_tokener_error value passed to json_tokener_error_desc()";
+ return json_tokener_errors[jerr_int];
+}
+#endif
diff --git a/src/modules/rlm_couchbase/jsonc_missing.h b/src/modules/rlm_couchbase/jsonc_missing.h
new file mode 100644
index 0000000..1100eff
--- /dev/null
+++ b/src/modules/rlm_couchbase/jsonc_missing.h
@@ -0,0 +1,89 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Function prototypes for missing functions in older json-c libraries.
+ * @file jsonc_missing.h
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+#ifndef _jsonc_missing_h_
+#define _jsonc_missing_h_
+
+RCSIDH(jsonc_missing_h, "$Id$")
+
+#include "config.h"
+
+#if defined(HAVE_JSONMC_JSON_H)
+# include <json-c/json.h>
+#elif defined(HAVE_JSON_JSON_H)
+# include <json/json.h>
+#endif
+
+#ifndef HAVE_JSON_C_VERSION
+const char *json_c_version(void);
+#endif
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+# include <json/json_object_private.h>
+#endif
+
+#ifndef HAVE_JSON_OBJECT_GET_STRING_LEN
+int json_object_get_string_len(struct json_object *obj);
+#endif
+
+#ifndef HAVE_JSON_OBJECT_OBJECT_GET_EX
+int json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value);
+#endif
+
+#ifndef HAVE_JSON_TOKENER_ERROR_DESC
+const char *json_tokener_error_desc(enum json_tokener_error jerr);
+#endif
+
+#ifndef HAVE_JSON_TOKENER_GET_ERROR
+enum json_tokener_error json_tokener_get_error(json_tokener *tok);
+#endif
+
+/* correct poor const handling within json-c library */
+#ifdef json_object_object_foreach
+# undef json_object_object_foreach
+#endif
+
+/* redefine with correct handling of const pointers */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+# define json_object_object_foreach(obj, key, val) \
+ char *key = NULL; \
+ struct json_object *val = NULL; \
+ union ctn_u {const void *cdata; void *data; } ctn; \
+ for (struct lh_entry *entry = json_object_get_object(obj)->head; \
+ ({ if (entry) { key = (char *)entry->k; ctn.cdata = entry->v; \
+ val = (struct json_object *)ctn.data; }; entry; }); \
+ entry = entry->next)
+#else /* ANSI C or MSC */
+# define json_object_object_foreach(obj,key,val) \
+ char const *key = NULL; \
+ struct json_object *val = NULL; \
+ struct lh_entry *entry; \
+ union ctn_u {const void *cdata; void *data; } ctn; \
+ for (entry = json_object_get_object(obj)->head; \
+ (entry ? (key = (char const *)entry->k, ctn.cdata = entry->v, \
+ val = (struct json_object *)ctn.data, entry) : 0); entry = entry->next)
+#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
+#endif /* _jsonc_missing_h_ */
diff --git a/src/modules/rlm_couchbase/mod.c b/src/modules/rlm_couchbase/mod.c
new file mode 100644
index 0000000..1d4e024
--- /dev/null
+++ b/src/modules/rlm_couchbase/mod.c
@@ -0,0 +1,767 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Utillity functions used in the module.
+ * @file mod.c
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include "mod.h"
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/** Delete a conneciton pool handle and free related resources
+ *
+ * Destroys the underlying Couchbase connection handle freeing any related
+ * resources and closes the socket connection.
+ *
+ * @param chandle The connection handle to destroy.
+ * @return Always returns 0 (success) in all conditions.
+ */
+static int _mod_conn_free(rlm_couchbase_handle_t *chandle)
+{
+ lcb_t cb_inst = chandle->handle; /* couchbase instance */
+
+ /* destroy/free couchbase instance */
+ lcb_destroy(cb_inst);
+
+ /* return */
+ return 0;
+}
+
+/** Create a new connection pool handle
+ *
+ * Create a new connection to Couchbase within the pool and initialize
+ * information associated with the connection instance.
+ *
+ * @param ctx The connection parent context.
+ * @param instance The module instance.
+ * @return The new connection handle or NULL on error.
+ */
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_couchbase_t *inst = instance; /* module instance pointer */
+ rlm_couchbase_handle_t *chandle = NULL; /* connection handle pointer */
+ cookie_t *cookie = NULL; /* couchbase cookie */
+ lcb_t cb_inst; /* couchbase connection instance */
+ lcb_error_t cb_error; /* couchbase error status */
+
+ /* create instance */
+ cb_error = couchbase_init_connection(&cb_inst, inst->server, inst->bucket, inst->password);
+
+ /* check couchbase instance */
+ if (cb_error != LCB_SUCCESS) {
+ ERROR("rlm_couchbase: failed to initiate couchbase connection: %s (0x%x)",
+ lcb_strerror(NULL, cb_error), cb_error);
+ /* destroy/free couchbase instance */
+ lcb_destroy(cb_inst);
+ /* fail */
+ return NULL;
+ }
+
+ /* allocate memory for couchbase connection instance abstraction */
+ chandle = talloc_zero(ctx, rlm_couchbase_handle_t);
+ talloc_set_destructor(chandle, _mod_conn_free);
+
+ /* allocate cookie off handle */
+ cookie = talloc_zero(chandle, cookie_t);
+
+ /* init tokener error and json object */
+ cookie->jerr = json_tokener_success;
+ cookie->jobj = NULL;
+
+ /* populate handle */
+ chandle->cookie = cookie;
+ chandle->handle = cb_inst;
+
+ /* return handle struct */
+ return chandle;
+}
+
+/** Build a JSON object map from the configuration "update" section
+ *
+ * Parse the "map" section from the module configuration file and store this
+ * as a JSON object (key/value list) in the module instance. This map will be
+ * used to lookup and map attributes for all incoming accounting requests.
+ *
+ * @param conf Configuration section.
+ * @param instance The module instance.
+ * @return Returns 0 on success, -1 on error.
+ */
+int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance)
+{
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ CONF_SECTION *cs; /* module config section */
+ CONF_ITEM *ci; /* config item */
+ CONF_PAIR *cp; /* conig pair */
+ const char *attribute, *element; /* attribute and element names */
+
+ /* find update section */
+ cs = cf_section_sub_find(conf, "update");
+
+ /* backwards compatibility */
+ if (!cs) {
+ cs = cf_section_sub_find(conf, "map");
+ WARN("rlm_couchbase: found deprecated 'map' section - please change to 'update'");
+ }
+
+ /* check section */
+ if (!cs) {
+ ERROR("rlm_couchbase: failed to find 'update' section in config");
+ /* fail */
+ return -1;
+ }
+
+ /* create attribute map object */
+ inst->map = json_object_new_object();
+
+ /* parse update section */
+ for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
+ /* validate item */
+ if (!cf_item_is_pair(ci)) {
+ ERROR("rlm_couchbase: failed to parse invalid item in 'update' section");
+ /* free map */
+ if (inst->map) {
+ json_object_put(inst->map);
+ }
+ /* fail */
+ return -1;
+ }
+
+ /* get value pair from item */
+ cp = cf_item_to_pair(ci);
+
+ /* get pair name (attribute name) */
+ attribute = cf_pair_attr(cp);
+
+ if (!dict_attrbyname(attribute)) {
+ ERROR("Unknown RADIUS attribute '%s'", attribute);
+ return -1;
+ }
+
+ /* get pair value (element name) */
+ element = cf_pair_value(cp);
+
+ /* add pair name and value */
+ json_object_object_add(inst->map, attribute, json_object_new_string(element));
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: added attribute '%s' to element '%s' mapping", attribute, element);
+ }
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: built attribute to element mapping %s", json_object_to_json_string(inst->map));
+
+ /* return */
+ return 0;
+}
+
+/** Map attributes to JSON element names
+ *
+ * Attempt to map the passed attribute name to the configured JSON element
+ * name using the JSON object map mod_build_attribute_element_map().
+ *
+ * @param name The character name of the requested attribute.
+ * @param map The JSON object map to use for the lookup.
+ * @param buf The buffer where the given element will be stored if found.
+ * @return Returns 0 on success, -1 on error.
+ */
+int mod_attribute_to_element(const char *name, json_object *map, void *buf)
+{
+ json_object *jval; /* json object values */
+
+ /* clear buffer */
+ memset((char *) buf, 0, MAX_KEY_SIZE);
+
+ /* attempt to map attribute */
+ if (json_object_object_get_ex(map, name, &jval)) {
+ /* copy and check size */
+ if (strlcpy(buf, json_object_get_string(jval), MAX_KEY_SIZE) >= MAX_KEY_SIZE) {
+ /* oops ... this value is bigger than our buffer ... error out */
+ ERROR("rlm_couchbase: json map value larger than MAX_KEY_SIZE - %d", MAX_KEY_SIZE);
+ /* return fail */
+ return -1;
+ }
+ /* looks good */
+ return 0;
+ }
+
+ /* debugging */
+ DEBUG("rlm_couchbase: skipping attribute with no map entry - %s", name);
+
+ /* default return */
+ return -1;
+}
+
+/** Build value pairs from the passed JSON object and add to the request
+ *
+ * Parse the passed JSON object and create value pairs that will be injected into
+ * the given request for authorization.
+ *
+ * Example JSON document structure:
+ * @code{.json}
+ * {
+ * "docType": "raduser",
+ * "userName": "test",
+ * "config": {
+ * "SHA-Password": {
+ * "value": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
+ * "op": ":="
+ * }
+ * },
+ * "reply": {
+ * "Reply-Message": {
+ * "value": "Hidey Ho!",
+ * "op": "="
+ * }
+ * }
+ * }
+ * @endcode
+ *
+ * @param json The JSON object representation of the user documnent.
+ * @param section The pair section ("config" or "reply").
+ * @param request The request to which the generated pairs should be added.
+ */
+void *mod_json_object_to_value_pairs(json_object *json, const char *section, REQUEST *request)
+{
+ json_object *jobj, *jval, *jop; /* json object pointers */
+ TALLOC_CTX *ctx; /* talloc context for fr_pair_make */
+ VALUE_PAIR *vp, **ptr; /* value pair and value pair pointer for fr_pair_make */
+
+ /* assign ctx and vps for fr_pair_make based on section */
+ if (strcmp(section, "config") == 0) {
+ ctx = request;
+ ptr = &(request->config);
+ } else if (strcmp(section, "reply") == 0) {
+ ctx = request->reply;
+ ptr = &(request->reply->vps);
+ } else {
+ /* log error - this shouldn't happen */
+ RERROR("invalid section passed for fr_pair_make");
+ /* return */
+ return NULL;
+ }
+
+ /* get config payload */
+ if (json_object_object_get_ex(json, section, &jobj)) {
+ /* make sure we have the correct type */
+ if ((jobj == NULL) || !json_object_is_type(jobj, json_type_object)) {
+ /* log error */
+ RERROR("invalid json type for '%s' section - sections must be json objects", section);
+ /* reuturn */
+ return NULL;
+ }
+ /* loop through object */
+ json_object_object_foreach(jobj, attribute, json_vp) {
+ /* check for appropriate type in value and op */
+ if ((jobj == NULL) || !json_object_is_type(json_vp, json_type_object)) {
+ /* log error */
+ RERROR("invalid json type for '%s' attribute - attributes must be json objects",
+ attribute);
+ /* return */
+ return NULL;
+ }
+ /* debugging */
+ RDEBUG("parsing '%s' attribute: %s => %s", section, attribute,
+ json_object_to_json_string(json_vp));
+ /* create pair from json object */
+ if (json_object_object_get_ex(json_vp, "value", &jval) &&
+ json_object_object_get_ex(json_vp, "op", &jop)) {
+ /* check for null before getting type */
+ if (jval == NULL) return NULL;
+ /* make correct pairs based on json object type */
+ switch (json_object_get_type(jval)) {
+ case json_type_double:
+ case json_type_int:
+ case json_type_string:
+ /* debugging */
+ RDEBUG("adding '%s' attribute to '%s' section", attribute, section);
+ /* add pair */
+ vp = fr_pair_make(ctx, ptr, attribute, json_object_get_string(jval),
+ fr_str2int(fr_tokens, json_object_get_string(jop), 0));
+ /* check pair */
+ if (!vp) {
+ RERROR("could not build value pair for '%s' attribute (%s)",
+ attribute, fr_strerror());
+ /* return */
+ return NULL;
+ }
+ break;
+
+ case json_type_object:
+ case json_type_array:
+ /* log error - we want to handle these eventually */
+ RERROR("skipping unhandled nested json object or array value pair object");
+ break;
+
+ default:
+ /* log error - this shouldn't ever happen */
+ RERROR("skipping unhandled json type in value pair object");
+ break;
+ }
+ } else {
+ /* log error */
+ RERROR("failed to get 'value' or 'op' element for '%s' attribute", attribute);
+ }
+ }
+ /* return NULL */
+ return NULL;
+ }
+
+ /* debugging */
+ RDEBUG("couldn't find '%s' section in json object - not adding value pairs for this section", section);
+
+ /* return NULL */
+ return NULL;
+}
+
+/** Convert value pairs to json objects
+ *
+ * Take the passed value pair and convert it to a json-c JSON object.
+ * This code is heavily based on the vp_prints_value_json() function
+ * from src/lib/print.c.
+ *
+ * @param request The request object.
+ * @param vp The value pair to convert.
+ * @param raw_value Print all values as raw, even if enum values exist.
+ * @return Returns a JSON object.
+ */
+json_object *mod_value_pair_to_json_object(REQUEST *request, VALUE_PAIR *vp, bool raw_value)
+{
+ char value[255]; /* radius attribute value */
+
+ /* add this attribute/value pair to our json output */
+ if (!vp->da->flags.has_tag) {
+ unsigned int i;
+
+ switch (vp->da->type) {
+ case PW_TYPE_INTEGER:
+ i = vp->vp_integer;
+ goto print_int;
+
+ case PW_TYPE_SHORT:
+ i = vp->vp_short;
+ goto print_int;
+
+ case PW_TYPE_BYTE:
+ i = vp->vp_byte;
+
+ print_int:
+ /* add a raw value to our json output - i.e. do not try resolve enum.
+ skip this if raw_value is false, and we have a value in the dictionary */
+ if (!raw_value && !vp->da->flags.has_value) break;
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for unsigned 32 bit int/byte/short '%s'", vp->da->name);
+ /* return as 64 bit int - JSON spec does not support unsigned ints */
+ return json_object_new_int64(i);
+#else
+ /* debug */
+ RDEBUG3("creating new int for unsigned 32 bit int/byte/short '%s'", vp->da->name);
+ /* return as 64 bit int - JSON spec does not support unsigned ints */
+ return json_object_new_int(i);
+#endif
+
+ case PW_TYPE_SIGNED:
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for signed 32 bit integer '%s'", vp->da->name);
+ /* return as 64 bit int - json-c represents all ints as 64 bits internally */
+ return json_object_new_int64(vp->vp_signed);
+#else
+ RDEBUG3("creating new int for signed 32 bit integer '%s'", vp->da->name);
+ /* return as signed int */
+ return json_object_new_int(vp->vp_signed);
+#endif
+
+ case PW_TYPE_INTEGER64:
+#ifdef HAVE_JSON_OBJECT_NEW_INT64
+ /* debug */
+ RDEBUG3("creating new int64 for 64 bit integer '%s'", vp->da->name);
+ /* return as 64 bit int - because it is a 64 bit int */
+ return json_object_new_int64(vp->vp_integer64);
+#else
+ /* warning */
+ RWARN("skipping 64 bit integer attribute '%s' - please upgrade json-c to 0.10+", vp->da->name);
+ break;
+#endif
+
+ default:
+ /* silence warnings - do nothing */
+ break;
+ }
+ }
+
+ /* keep going if not set above */
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ /* debug */
+ RDEBUG3("assigning string '%s' as string", vp->da->name);
+ /* return string value */
+ return json_object_new_string(vp->vp_strvalue);
+
+ default:
+ /* debug */
+ RDEBUG3("assigning unhandled '%s' as string", vp->da->name);
+ /* get standard value */
+ vp_prints_value(value, sizeof(value), vp, 0);
+ /* return string value from above */
+ return json_object_new_string(value);
+ }
+}
+
+/** Ensure accounting documents always contain a valid timestamp
+ *
+ * Inspect the given JSON object representation of an accounting document
+ * fetched from Couchbase and ensuse it contains a valid (non NULL) timestamp value.
+ *
+ * @param json JSON object representation of an accounting document.
+ * @param vps The value pairs associated with the current accounting request.
+ * @return Returns 0 on success, -1 on error.
+ */
+int mod_ensure_start_timestamp(json_object *json, VALUE_PAIR *vps)
+{
+ json_object *jval; /* json object value */
+ struct tm tm; /* struct to hold event time */
+ time_t ts = 0; /* values to hold time in seconds */
+ VALUE_PAIR *vp; /* values to hold value pairs */
+ char value[255]; /* store radius attribute values and our timestamp */
+
+ /* get our current start timestamp from our json body */
+ if (json_object_object_get_ex(json, "startTimestamp", &jval) == 0) {
+ /* debugging ... this shouldn't ever happen */
+ DEBUG("rlm_couchbase: failed to find 'startTimestamp' in current json body");
+ /* return */
+ return -1;
+ }
+
+ /* check for null value */
+ if (json_object_get_string(jval) != NULL) {
+ /* already set - nothing left to do */
+ return 0;
+ }
+
+ /* get current event timestamp */
+ if ((vp = fr_pair_find_by_num(vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* get seconds value from attribute */
+ ts = vp->vp_date;
+ } else {
+ /* debugging */
+ DEBUG("rlm_couchbase: failed to find event timestamp in current request");
+ /* return */
+ return -1;
+ }
+
+ /* clear value */
+ memset(value, 0, sizeof(value));
+
+ /* get elapsed session time */
+ if ((vp = fr_pair_find_by_num(vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY)) != NULL) {
+ /* calculate diff */
+ ts = (ts - vp->vp_integer);
+ /* calculate start time */
+ size_t length = strftime(value, sizeof(value), "%b %e %Y %H:%M:%S %Z", localtime_r(&ts, &tm));
+ /* check length */
+ if (length > 0) {
+ /* debugging */
+ DEBUG("rlm_couchbase: calculated start timestamp: %s", value);
+ /* store new value in json body */
+ json_object_object_add(json, "startTimestamp", json_object_new_string(value));
+ } else {
+ /* debugging */
+ DEBUG("rlm_couchbase: failed to format calculated timestamp");
+ /* return */
+ return -1;
+ }
+ }
+
+ /* default return */
+ return 0;
+}
+
+/** Handle client value processing for client_map_section()
+ *
+ * @param out Character output
+ * @param cp Configuration pair
+ * @param data The client data
+ * @return Returns 0 on success, -1 on error.
+ */
+static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
+{
+ json_object *jval;
+
+ if (!json_object_object_get_ex((json_object *)data, cf_pair_value(cp), &jval)) {
+ *out = NULL;
+ return 0;
+ }
+
+ if (!jval) return -1;
+
+ *out = talloc_strdup(NULL, json_object_get_string(jval));
+ if (!*out) return -1;
+
+ return 0;
+}
+
+/** Load client entries from Couchbase client documents on startup
+ *
+ * This function executes the view defined in the module configuration and loops
+ * through all returned rows. The view is called with "stale=false" to ensure the
+ * most accurate data available when the view is called. This will force an index
+ * rebuild on this design document in Couchbase. However, since this function is only
+ * run once at sever startup this should not be a concern.
+ *
+ * @param inst The module instance.
+ * @param tmpl Default values for new clients.
+ * @param map The client attribute configuration section.
+ * @return Returns 0 on success, -1 on error.
+ */
+int mod_load_client_documents(rlm_couchbase_t *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
+{
+ rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
+ char vpath[256], vid[MAX_KEY_SIZE], vkey[MAX_KEY_SIZE]; /* view path and fields */
+ char error[512]; /* view error return */
+ size_t idx = 0; /* row array index counter */
+ int retval = 0; /* return value */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+ json_object *json, *jval; /* json object holders */
+ json_object *jrows = NULL; /* json object to hold view rows */
+ CONF_SECTION *client; /* freeradius config section */
+ RADCLIENT *c; /* freeradius client */
+ int slen;
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return -1;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle->cookie;
+
+ /* build view path */
+ slen = snprintf(vpath, sizeof(vpath), "%s?stale=false", inst->client_view);
+ if (slen >= (int) sizeof(vpath) || slen < 0) {
+ ERROR("rlm_couchbase: view path too long");
+ retval=-1;
+ goto free_and_return;
+ }
+
+
+ /* query view for document */
+ cb_error = couchbase_query_view(cb_inst, cookie, vpath, NULL);
+
+ /* check error and object */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
+ /* log error */
+ ERROR("rlm_couchbase: failed to execute view request or parse return");
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: cookie->jobj == %s", json_object_to_json_string(cookie->jobj));
+
+ /* check for error in json object */
+ if (json_object_object_get_ex(cookie->jobj, "error", &json)) {
+ /* build initial error buffer */
+ strlcpy(error, json_object_get_string(json), sizeof(error));
+ /* get error reason */
+ if (json_object_object_get_ex(cookie->jobj, "reason", &json)) {
+ /* append divider */
+ strlcat(error, " - ", sizeof(error));
+ /* append reason */
+ strlcat(error, json_object_get_string(json), sizeof(error));
+ }
+ /* log error */
+ ERROR("rlm_couchbase: view request failed with error: %s", error);
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* check for document id in return */
+ if (!json_object_object_get_ex(cookie->jobj, "rows", &json)) {
+ /* log error */
+ ERROR("rlm_couchbase: failed to fetch rows from view payload");
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* get and hold rows */
+ jrows = json_object_get(json);
+
+ /* free cookie object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: jrows == %s", json_object_to_json_string(jrows));
+
+ /* check for valid row value */
+ if ((jrows == NULL) || !json_object_is_type(jrows, json_type_array) || json_object_array_length(jrows) < 1) {
+ /* log error */
+ ERROR("rlm_couchbase: no valid rows returned from view: %s", vpath);
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* loop across all row elements */
+ for (idx = 0; idx < (size_t)json_object_array_length(jrows); idx++) {
+ /* fetch current index */
+ json = json_object_array_get_idx(jrows, idx);
+
+ /* get view id */
+ if (json_object_object_get_ex(json, "id", &jval)) {
+ /* clear view id */
+ memset(vid, 0, sizeof(vid));
+ /* copy and check length */
+ if (strlcpy(vid, json_object_get_string(jval), sizeof(vid)) >= sizeof(vid)) {
+ ERROR("rlm_couchbase: id from row longer than MAX_KEY_SIZE (%d)",
+ MAX_KEY_SIZE);
+ continue;
+ }
+ } else {
+ WARN("rlm_couchbase: failed to fetch id from row - skipping");
+ continue;
+ }
+
+ /* get view key */
+ if (json_object_object_get_ex(json, "key", &jval)) {
+ /* clear view key */
+ memset(vkey, 0, sizeof(vkey));
+ /* copy and check length */
+ if (strlcpy(vkey, json_object_get_string(jval), sizeof(vkey)) >= sizeof(vkey)) {
+ ERROR("rlm_couchbase: key from row longer than MAX_KEY_SIZE (%d)",
+ MAX_KEY_SIZE);
+ continue;
+ }
+ } else {
+ WARN("rlm_couchbase: failed to fetch key from row - skipping");
+ continue;
+ }
+
+ /* fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, vid);
+
+ /* check error and object */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
+ /* log error */
+ ERROR("rlm_couchbase: failed to execute get request or parse return");
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* debugging */
+ DEBUG3("rlm_couchbase: cookie->jobj == %s", json_object_to_json_string(cookie->jobj));
+
+ /* allocate conf section */
+ client = tmpl ? cf_section_dup(NULL, tmpl, "client", vkey, true) :
+ cf_section_alloc(NULL, "client", vkey);
+
+ if (client_map_section(client, map, _get_client_value, cookie->jobj) < 0) {
+ /* free config setion */
+ talloc_free(client);
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /*
+ * @todo These should be parented from something.
+ */
+ c = client_afrom_cs(NULL, client, false, false);
+ if (!c) {
+ ERROR("rlm_couchbase: failed to allocate client");
+ /* free config setion */
+ talloc_free(client);
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /*
+ * Client parents the CONF_SECTION which defined it.
+ */
+ talloc_steal(c, client);
+
+ /* attempt to add client */
+ if (!client_add(NULL, c)) {
+ ERROR("rlm_couchbase: failed to add client '%s' from '%s', possible duplicate?", vkey, vid);
+ /* free client */
+ client_free(c);
+ /* set return */
+ retval = -1;
+ /* return */
+ goto free_and_return;
+ }
+
+ /* debugging */
+ DEBUG("rlm_couchbase: client '%s' added", c->longname);
+
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+ }
+
+ free_and_return:
+
+ /* free rows */
+ if (jrows) {
+ json_object_put(jrows);
+ }
+
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+
+ /* return */
+ return retval;
+}
diff --git a/src/modules/rlm_couchbase/mod.h b/src/modules/rlm_couchbase/mod.h
new file mode 100644
index 0000000..3cf9a31
--- /dev/null
+++ b/src/modules/rlm_couchbase/mod.h
@@ -0,0 +1,101 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Function prototypes and datatypes used in the module.
+ * @file mod.h
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+#ifndef _mod_h_
+#define _mod_h_
+
+RCSIDH(mod_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/* maximum size of a stored value */
+#define MAX_VALUE_SIZE 20480
+
+/* maximum length of a document key */
+#define MAX_KEY_SIZE 250
+
+/** The main module instance
+ *
+ * This struct contains the core module configuration.
+ */
+typedef struct rlm_couchbase_t {
+ char const *acct_key; //!< Accounting document key.
+ char const *doctype; //!< Value of accounting 'docType' element name.
+ uint32_t expire; //!< Accounting document expire time in seconds.
+
+ char const *server_raw; //!< Raw server string before parsing.
+ char const *server; //!< Couchbase server list.
+ char const *bucket; //!< Couchbase bucket.
+ char const *password; //!< Couchbase bucket password.
+
+ const char *user_key; //!< User document key.
+
+ bool read_clients; //!< Toggle for loading client records.
+ const char *client_view; //!< Couchbase view that returns client documents.
+
+ bool check_simul; //!< Toggle to enable simultaneous use checking.
+ const char *simul_view; //!< Couchbase view that returns accounting documents.
+
+ bool verify_simul; //!< Toggle to enable user login state verification.
+ const char *simul_vkey; //!< The query key to be used with simul_view.
+ bool delete_stale_sessions; //!< Toggle to trigger zapping of stale sessions.
+ bool raw_value; //!< Print raw values rather than resolving enums
+
+ json_object *map; //!< Json object to hold user defined attribute map.
+ fr_connection_pool_t *pool; //!< Connection pool.
+} rlm_couchbase_t;
+
+/** Couchbase instance specific information
+ *
+ * This struct contains the Couchbase connection handle as well as a
+ * cookie pointer to store fetched document payloads.
+ */
+typedef struct rlm_couchbase_handle_t {
+ void *handle; //!< Real couchbase instance.
+ void *cookie; //!< Couchbase cookie (@p cookie_u @p cookie_t).
+} rlm_couchbase_handle_t;
+
+/* define functions */
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
+
+int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance);
+
+int mod_attribute_to_element(const char *name, json_object *map, void *buf);
+
+void *mod_json_object_to_value_pairs(json_object *json, const char *section, REQUEST *request);
+
+json_object *mod_value_pair_to_json_object(REQUEST *request, VALUE_PAIR *vp, bool raw_value);
+
+int mod_ensure_start_timestamp(json_object *json, VALUE_PAIR *vps);
+
+int mod_client_map_section(CONF_SECTION *client, CONF_SECTION const *map, json_object *json, char const *docid);
+
+int mod_load_client_documents(rlm_couchbase_t *inst, CONF_SECTION *tmpl, CONF_SECTION *map);
+
+#endif /* _mod_h_ */
diff --git a/src/modules/rlm_couchbase/rlm_couchbase.c b/src/modules/rlm_couchbase/rlm_couchbase.c
new file mode 100644
index 0000000..8e8c813
--- /dev/null
+++ b/src/modules/rlm_couchbase/rlm_couchbase.c
@@ -0,0 +1,874 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @brief Integrate FreeRADIUS with the Couchbase document database.
+ * @file rlm_couchbase.c
+ *
+ * @author Aaron Hurt <ahurt@anbcs.com>
+ * @copyright 2013-2014 The FreeRADIUS Server Project.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "mod.h"
+#include "couchbase.h"
+#include "jsonc_missing.h"
+
+/**
+ * Client Configuration
+ */
+static const CONF_PARSER client_config[] = {
+ { "view", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, client_view), "_design/client/_view/by_name" },
+ CONF_PARSER_TERMINATOR
+};
+
+/**
+ * Module Configuration
+ */
+static const CONF_PARSER module_config[] = {
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_couchbase_t, server_raw), NULL },
+ { "bucket", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_couchbase_t, bucket), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, password), NULL },
+#ifdef WITH_ACCOUNTING
+ { "acct_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_couchbase_t, acct_key), "radacct_%{%{Acct-Unique-Session-Id}:-%{Acct-Session-Id}}" },
+ { "doctype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, doctype), "radacct" },
+ { "expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_couchbase_t, expire), 0 },
+#endif
+ { "user_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_couchbase_t, user_key), "raduser_%{md5:%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}}" },
+ { "read_clients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_couchbase_t, read_clients), NULL }, /* NULL defaults to "no" */
+ { "client", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) client_config },
+#ifdef WITH_SESSION_MGMT
+ { "check_simul", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_couchbase_t, check_simul), NULL }, /* NULL defaults to "no" */
+ { "simul_view", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_couchbase_t, simul_view), "_design/acct/_view/by_user" },
+ { "simul_vkey", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_couchbase_t, simul_vkey), "%{tolower:%{%{Stripped-User-Name}:-%{User-Name}}}" },
+ { "verify_simul", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_couchbase_t, verify_simul), NULL }, /* NULL defaults to "no" */
+#endif
+ { "raw_value", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_couchbase_t, raw_value), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Initialize the rlm_couchbase module
+ *
+ * Intialize the module and create the initial Couchbase connection pool.
+ *
+ * @param conf The module configuration.
+ * @param instance The module instance.
+ * @return Returns 0 on success, -1 on error.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ static bool version_done;
+
+ rlm_couchbase_t *inst = instance; /* our module instance */
+
+ if (!version_done) {
+ version_done = true;
+ INFO("rlm_couchbase: json-c version: %s", json_c_version());
+ INFO("rlm_couchbase: libcouchbase version: %s", lcb_get_version(NULL));
+ }
+
+ {
+ char *server, *p;
+ size_t len, i;
+ bool sep = false;
+
+ len = talloc_array_length(inst->server_raw);
+ server = p = talloc_array(inst, char, len);
+ for (i = 0; i < len; i++) {
+ switch (inst->server_raw[i]) {
+ case '\t':
+ case ' ':
+ case ',':
+ /* Consume multiple separators occurring in sequence */
+ if (sep == true) continue;
+
+ sep = true;
+ *p++ = ';';
+ break;
+
+ default:
+ sep = false;
+ *p++ = inst->server_raw[i];
+ break;
+ }
+ }
+
+ *p = '\0';
+ inst->server = server;
+ }
+
+ /* setup item map */
+ if (mod_build_attribute_element_map(conf, inst) != 0) {
+ /* fail */
+ return -1;
+ }
+
+ /* initiate connection pool */
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, NULL);
+
+ /* check connection pool */
+ if (!inst->pool) {
+ ERROR("rlm_couchbase: failed to initiate connection pool");
+ /* fail */
+ return -1;
+ }
+
+ /* load clients if requested */
+ if (inst->read_clients) {
+ CONF_SECTION *cs, *map, *tmpl; /* conf section */
+
+ /* attempt to find client section */
+ cs = cf_section_sub_find(conf, "client");
+ if (!cs) {
+ ERROR("rlm_couchbase: failed to find client section while loading clients");
+ /* fail */
+ return -1;
+ }
+
+ /* attempt to find attribute subsection */
+ map = cf_section_sub_find(cs, "attribute");
+ if (!map) {
+ ERROR("rlm_couchbase: failed to find attribute subsection while loading clients");
+ /* fail */
+ return -1;
+ }
+
+ tmpl = cf_section_sub_find(cs, "template");
+
+ /* debugging */
+ DEBUG("rlm_couchbase: preparing to load client documents");
+
+ /* attempt to load clients */
+ if (mod_load_client_documents(inst, tmpl, map) != 0) {
+ /* fail */
+ return -1;
+ }
+ }
+
+ /* return okay */
+ return 0;
+}
+
+/** Handle authorization requests using Couchbase document data
+ *
+ * Attempt to fetch the document assocaited with the requested user by
+ * using the deterministic key defined in the configuration. When a valid
+ * document is found it will be parsed and the containing value pairs will be
+ * injected into the request.
+ *
+ * @param instance The module instance.
+ * @param request The authorization request.
+ * @return Returns operation status (@p rlm_rcode_t).
+ */
+static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
+ char dockey[MAX_KEY_SIZE]; /* our document key */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+ rlm_rcode_t rcode = RLM_MODULE_OK; /* return code */
+
+ /* assert packet as not null */
+ rad_assert(request->packet != NULL);
+
+ /* attempt to build document key */
+ if (radius_xlat(dockey, sizeof(dockey), request, inst->user_key, NULL, NULL) < 0) {
+ /* log error */
+ RERROR("could not find user key attribute (%s) in packet", inst->user_key);
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return RLM_MODULE_FAIL;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle->cookie;
+
+ /* fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, dockey);
+
+ /* check error */
+ if (cb_error != LCB_SUCCESS || !cookie->jobj) {
+ /* log error */
+ RERROR("failed to fetch document or parse return");
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG3("parsed user document == %s", json_object_to_json_string(cookie->jobj));
+
+ /* inject config value pairs defined in this json oblect */
+ mod_json_object_to_value_pairs(cookie->jobj, "config", request);
+
+ /* inject reply value pairs defined in this json oblect */
+ mod_json_object_to_value_pairs(cookie->jobj, "reply", request);
+
+ finish:
+
+ /* free json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ /* release handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+
+ /* return */
+ return rcode;
+}
+
+#ifdef WITH_ACCOUNTING
+/** Write accounting data to Couchbase documents
+ *
+ * Handle accounting requests and store the associated data into JSON documents
+ * in couchbase mapping attribute names to JSON element names per the module configuration.
+ *
+ * When an existing document already exists for the same accounting section the new attributes
+ * will be merged with the currently existing data. When conflicts arrise the new attribute
+ * value will replace or be added to the existing value.
+ *
+ * @param instance The module instance.
+ * @param request The accounting request object.
+ * @return Returns operation status (@p rlm_rcode_t).
+ */
+static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
+ rlm_rcode_t rcode = RLM_MODULE_OK; /* return code */
+ VALUE_PAIR *vp; /* radius value pair linked list */
+ char dockey[MAX_KEY_SIZE]; /* our document key */
+ char document[MAX_VALUE_SIZE]; /* our document body */
+ char element[MAX_KEY_SIZE]; /* mapped radius attribute to element name */
+ int status = 0; /* account status type */
+ int docfound = 0; /* document found toggle */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+
+ /* assert packet as not null */
+ rad_assert(request->packet != NULL);
+
+ /* sanity check */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) {
+ /* log debug */
+ RDEBUG("could not find status type in packet");
+ /* return */
+ return RLM_MODULE_NOOP;
+ }
+
+ /* set status */
+ status = vp->vp_integer;
+
+ /* acknowledge the request but take no action */
+ if (status == PW_STATUS_ACCOUNTING_ON || status == PW_STATUS_ACCOUNTING_OFF) {
+ /* log debug */
+ RDEBUG("handling accounting on/off request without action");
+ /* return */
+ return RLM_MODULE_OK;
+ }
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return RLM_MODULE_FAIL;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle->cookie;
+
+ /* attempt to build document key */
+ if (radius_xlat(dockey, sizeof(dockey), request, inst->acct_key, NULL, NULL) < 0) {
+ /* log error */
+ RERROR("could not find accounting key attribute (%s) in packet", inst->acct_key);
+ /* set return */
+ rcode = RLM_MODULE_NOOP;
+ /* return */
+ goto finish;
+ }
+
+ /* attempt to fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, dockey);
+
+ /* check error and object */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
+ /* log error */
+ RERROR("failed to execute get request or parse returned json object");
+ /* free and reset json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+ /* check cookie json object */
+ } else if (cookie->jobj) {
+ /* set doc found */
+ docfound = 1;
+ /* debugging */
+ RDEBUG3("parsed json body from couchbase: %s", json_object_to_json_string(cookie->jobj));
+ }
+
+ /* start json document if needed */
+ if (docfound != 1) {
+ /* debugging */
+ RDEBUG("no existing document found - creating new json document");
+ /* create new json object */
+ cookie->jobj = json_object_new_object();
+ /* set 'docType' element for new document */
+ json_object_object_add(cookie->jobj, "docType", json_object_new_string(inst->doctype));
+ /* default startTimestamp and stopTimestamp to null values */
+ json_object_object_add(cookie->jobj, "startTimestamp", NULL);
+ json_object_object_add(cookie->jobj, "stopTimestamp", NULL);
+ }
+
+ /* status specific replacements for start/stop time */
+ switch (status) {
+ case PW_STATUS_START:
+ /* add start time */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* add to json object */
+ json_object_object_add(cookie->jobj, "startTimestamp",
+ mod_value_pair_to_json_object(request, vp, inst->raw_value));
+ }
+ break;
+
+ case PW_STATUS_STOP:
+ /* add stop time */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY)) != NULL) {
+ /* add to json object */
+ json_object_object_add(cookie->jobj, "stopTimestamp",
+ mod_value_pair_to_json_object(request, vp, inst->raw_value));
+ }
+ /* check start timestamp and adjust if needed */
+ mod_ensure_start_timestamp(cookie->jobj, request->packet->vps);
+ break;
+
+ case PW_STATUS_ALIVE:
+ /* check start timestamp and adjust if needed */
+ mod_ensure_start_timestamp(cookie->jobj, request->packet->vps);
+ break;
+
+ default:
+ /* don't doing anything */
+ rcode = RLM_MODULE_NOOP;
+ /* return */
+ goto finish;
+ }
+
+ /* loop through pairs and add to json document */
+ for (vp = request->packet->vps; vp; vp = vp->next) {
+ /* map attribute to element */
+ if (mod_attribute_to_element(vp->da->name, inst->map, &element) == 0) {
+ /* debug */
+ RDEBUG3("mapped attribute %s => %s", vp->da->name, element);
+ /* add to json object with mapped name */
+ json_object_object_add(cookie->jobj, element, mod_value_pair_to_json_object(request, vp, inst->raw_value));
+ }
+ }
+
+ /* copy json string to document and check size */
+ if (strlcpy(document, json_object_to_json_string(cookie->jobj), sizeof(document)) >= sizeof(document)) {
+ /* this isn't good */
+ RERROR("could not write json document - insufficient buffer space");
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG3("setting '%s' => '%s'", dockey, document);
+
+ /* store document/key in couchbase */
+ cb_error = couchbase_set_key(cb_inst, dockey, document, inst->expire);
+
+ /* check return */
+ if (cb_error != LCB_SUCCESS) {
+ RERROR("failed to store document (%s): %s (0x%x)", dockey, lcb_strerror(NULL, cb_error), cb_error);
+ }
+
+finish:
+ /* free and reset json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ /* release our connection handle */
+ if (handle) {
+ fr_connection_release(inst->pool, handle);
+ }
+
+ /* return */
+ return rcode;
+}
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/** Check if a given user is already logged in.
+ *
+ * Process accounting data to determine if a user is already logged in. Sets request->simul_count
+ * to the current session count for this user.
+ *
+ * Check twice. If on the first pass the user exceeds his maximum number of logins, do a second
+ * pass and validate all logins by querying the terminal server.
+ *
+ * @param instance The module instance.
+ * @param request The checksimul request object.
+ * @return Returns operation status (@p rlm_rcode_t).
+ */
+static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request) {
+ rlm_couchbase_t *inst = instance; /* our module instance */
+ rlm_rcode_t rcode = RLM_MODULE_OK; /* return code */
+ rlm_couchbase_handle_t *handle = NULL; /* connection pool handle */
+ char vpath[256], vkey[MAX_KEY_SIZE]; /* view path and query key */
+ char docid[MAX_KEY_SIZE]; /* document id returned from view */
+ char error[512]; /* view error return */
+ size_t idx = 0; /* row array index counter */
+ char element[MAX_KEY_SIZE]; /* mapped radius attribute to element name */
+ lcb_error_t cb_error = LCB_SUCCESS; /* couchbase error holder */
+ json_object *json, *jval; /* json object holders */
+ json_object *jrows = NULL; /* json object to hold view rows */
+ VALUE_PAIR *vp; /* value pair */
+ uint32_t client_ip_addr = 0; /* current client ip address */
+ char const *client_cs_id = NULL; /* current client calling station id */
+ char *user_name = NULL; /* user name from accounting document */
+ char *session_id = NULL; /* session id from accounting document */
+ char *cs_id = NULL; /* calling station id from accounting document */
+ fr_ipaddr_t nas_addr; /* nas address from accounting document */
+ uint32_t nas_port = 0; /* nas port from accounting document */
+ uint32_t framed_ip_addr = 0; /* framed ip address from accounting document */
+ char framed_proto = 0; /* framed proto from accounting document */
+ int session_time = 0; /* session time from accounting document */
+ int slen;
+
+ /* do nothing if this is not enabled */
+ if (inst->check_simul != true) {
+ RWDEBUG("Simultaneous-Use checking requires 'simul_count_query' to be configured");
+ return RLM_MODULE_NOOP;
+ }
+
+ /* ensure valid username in request */
+ if ((!request->username) || (request->username->vp_length == 0)) {
+ REDEBUG("Zero Length username not permitted");
+ return RLM_MODULE_INVALID;
+ }
+
+ /* attempt to build view key */
+ if (radius_xlat(vkey, sizeof(vkey), request, inst->simul_vkey, NULL, NULL) < 0) {
+ /* log error */
+ RERROR("could not find simultaneous use view key attribute (%s) in packet", inst->simul_vkey);
+ /* return */
+ return RLM_MODULE_FAIL;
+ }
+
+ /* get handle */
+ handle = fr_connection_get(inst->pool);
+
+ /* check handle */
+ if (!handle) return RLM_MODULE_FAIL;
+
+ /* set couchbase instance */
+ lcb_t cb_inst = handle->handle;
+
+ /* set cookie */
+ cookie_t *cookie = handle->cookie;
+
+ /* build view path */
+ slen = snprintf(vpath, sizeof(vpath), "%s?key=\"%s\"&stale=update_after",
+ inst->simul_view, vkey);
+ if (slen >= (int) sizeof(vpath) || slen < 0) {
+ RERROR("view path is too long");
+ return RLM_MODULE_FAIL;
+ }
+
+ /* query view for document */
+ cb_error = couchbase_query_view(cb_inst, cookie, vpath, NULL);
+
+ /* check error and object */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
+ /* log error */
+ RERROR("failed to execute view request or parse return");
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG3("cookie->jobj == %s", json_object_to_json_string(cookie->jobj));
+
+ /* check for error in json object */
+ if (json_object_object_get_ex(cookie->jobj, "error", &json)) {
+ /* build initial error buffer */
+ strlcpy(error, json_object_get_string(json), sizeof(error));
+ /* get error reason */
+ if (json_object_object_get_ex(cookie->jobj, "reason", &json)) {
+ /* append divider */
+ strlcat(error, " - ", sizeof(error));
+ /* append reason */
+ strlcat(error, json_object_get_string(json), sizeof(error));
+ }
+ /* log error */
+ RERROR("view request failed with error: %s", error);
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* check for document id in return */
+ if (!json_object_object_get_ex(cookie->jobj, "rows", &json)) {
+ /* log error */
+ RERROR("failed to fetch rows from view payload");
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* get and hold rows */
+ jrows = json_object_get(json);
+
+ /* free cookie object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ /* check for valid row value */
+ if (!jrows || !json_object_is_type(jrows, json_type_array)) {
+ /* log error */
+ RERROR("no valid rows returned from view: %s", vpath);
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG3("jrows == %s", json_object_to_json_string(jrows));
+
+ /* set the count */
+ request->simul_count = json_object_array_length(jrows);
+
+ /* debugging */
+ RDEBUG("found %d open sessions for %s", request->simul_count, request->username->vp_strvalue);
+
+ /* check count */
+ if (request->simul_count < request->simul_max) {
+ rcode = RLM_MODULE_OK;
+ goto finish;
+ }
+
+ /*
+ * Current session count exceeds configured maximum.
+ * Continue on to verify the sessions if configured otherwise stop here.
+ */
+ if (inst->verify_simul != true) {
+ rcode = RLM_MODULE_OK;
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG("verifying session count");
+
+ /* reset the count */
+ request->simul_count = 0;
+
+ /* get client ip address for MPP detection below */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
+ client_ip_addr = vp->vp_ipaddr;
+ }
+
+ /* get calling station id for MPP detection below */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
+ client_cs_id = vp->vp_strvalue;
+ }
+
+ /* loop across all row elements */
+ for (idx = 0; idx < (size_t)json_object_array_length(jrows); idx++) {
+ /* clear docid */
+ memset(docid, 0, sizeof(docid));
+
+ /* fetch current index */
+ json = json_object_array_get_idx(jrows, idx);
+
+ /* get document id */
+ if (json_object_object_get_ex(json, "id", &jval)) {
+ /* copy and check length */
+ if (strlcpy(docid, json_object_get_string(jval), sizeof(docid)) >= sizeof(docid)) {
+ RERROR("document id from row longer than MAX_KEY_SIZE (%d)", MAX_KEY_SIZE);
+ continue;
+ }
+ }
+
+ /* check for valid doc id */
+ if (docid[0] == 0) {
+ RWARN("failed to fetch document id from row - skipping");
+ continue;
+ }
+
+ /* fetch document */
+ cb_error = couchbase_get_key(cb_inst, cookie, docid);
+
+ /* check error and object */
+ if (cb_error != LCB_SUCCESS || cookie->jerr != json_tokener_success || !cookie->jobj) {
+ /* log error */
+ RERROR("failed to execute get request or parse return");
+ /* set return */
+ rcode = RLM_MODULE_FAIL;
+ /* return */
+ goto finish;
+ }
+
+ /* debugging */
+ RDEBUG3("cookie->jobj == %s", json_object_to_json_string(cookie->jobj));
+
+ /* get element name for User-Name attribute */
+ if (mod_attribute_to_element("User-Name", inst->map, &element) == 0) {
+ /* get and check username element */
+ if (!json_object_object_get_ex(cookie->jobj, element, &jval)){
+ RDEBUG("cannot zap stale entry without username");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ /* copy json string value to user_name */
+ user_name = talloc_typed_strdup(request, json_object_get_string(jval));
+ } else {
+ RDEBUG("failed to find map entry for User-Name attribute");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* get element name for Acct-Session-Id attribute */
+ if (mod_attribute_to_element("Acct-Session-Id", inst->map, &element) == 0) {
+ /* get and check session id element */
+ if (!json_object_object_get_ex(cookie->jobj, element, &jval)){
+ RDEBUG("cannot zap stale entry without session id");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ /* copy json string value to session_id */
+ session_id = talloc_typed_strdup(request, json_object_get_string(jval));
+ } else {
+ RDEBUG("failed to find map entry for Acct-Session-Id attribute");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* get element name for NAS-IP-Address attribute */
+ if (mod_attribute_to_element("NAS-IP-Address", inst->map, &element) == 0) {
+ /* attempt to get and nas address element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)){
+ nas_addr.af = AF_INET;
+ nas_addr.ipaddr.ip4addr.s_addr = inet_addr(json_object_get_string(jval));
+ }
+ }
+
+ /* get element name for NAS-Port attribute */
+ if (mod_attribute_to_element("NAS-Port", inst->map, &element) == 0) {
+ /* attempt to get nas port element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ nas_port = (uint32_t) json_object_get_int(jval);
+ }
+ }
+
+ /* check terminal server */
+ int check = rad_check_ts(&nas_addr, nas_port, NULL, user_name, session_id);
+
+ /* take action based on check return */
+ if (check == 0) {
+ /* stale record - zap it if enabled */
+ if (inst->delete_stale_sessions) {
+ /* get element name for Framed-IP-Address attribute */
+ if (mod_attribute_to_element("Framed-IP-Address", inst->map, &element) == 0) {
+ /* attempt to get framed ip address element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ framed_ip_addr = inet_addr(json_object_get_string(jval));
+ }
+ }
+
+ /* get element name for Framed-Port attribute */
+ if (mod_attribute_to_element("Framed-Port", inst->map, &element) == 0) {
+ /* attempt to get framed port element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ if (strcmp(json_object_get_string(jval), "PPP") == 0) {
+ framed_proto = 'P';
+ } else if (strcmp(json_object_get_string(jval), "SLIP") == 0) {
+ framed_proto = 'S';
+ }
+ }
+ }
+
+ /* get element name for Acct-Session-Time attribute */
+ if (mod_attribute_to_element("Acct-Session-Time", inst->map, &element) == 0) {
+ /* attempt to get session time element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ session_time = json_object_get_int(jval);
+ }
+ }
+
+ /* zap session */
+ session_zap(request, &nas_addr, nas_port, NULL, user_name, session_id,
+ framed_ip_addr, framed_proto, session_time);
+ }
+ } else if (check == 1) {
+ /* user is still logged in - increase count */
+ ++request->simul_count;
+
+ /* get element name for Framed-IP-Address attribute */
+ if (mod_attribute_to_element("Framed-IP-Address", inst->map, &element) == 0) {
+ /* attempt to get framed ip address element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ framed_ip_addr = inet_addr(json_object_get_string(jval));
+ } else {
+ /* ensure 0 if not found */
+ framed_ip_addr = 0;
+ }
+ }
+
+ /* get element name for Calling-Station-Id attribute */
+ if (mod_attribute_to_element("Calling-Station-Id", inst->map, &element) == 0) {
+ /* attempt to get framed ip address element */
+ if (json_object_object_get_ex(cookie->jobj, element, &jval)) {
+ /* copy json string value to cs_id */
+ cs_id = talloc_typed_strdup(request, json_object_get_string(jval));
+ } else {
+ /* ensure null if not found */
+ cs_id = NULL;
+ }
+ }
+
+ /* Does it look like a MPP attempt? */
+ if (client_ip_addr && framed_ip_addr && framed_ip_addr == client_ip_addr) {
+ request->simul_mpp = 2;
+ } else if (client_cs_id && cs_id && !strncmp(cs_id, client_cs_id, 16)) {
+ request->simul_mpp = 2;
+ }
+
+ } else {
+ /* check failed - return error */
+ REDEBUG("failed to check the terminal server for user '%s'", user_name);
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* free and reset document user name talloc */
+ if (user_name) TALLOC_FREE(user_name);
+
+ /* free and reset document calling station id talloc */
+ if (cs_id) TALLOC_FREE(cs_id);
+
+ /* free and reset document session id talloc */
+ if (session_id) TALLOC_FREE(session_id);
+
+ /* free and reset json object before fetching next row */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+ }
+
+ /* debugging */
+ RDEBUG("Retained %d open sessions for %s after verification",
+ request->simul_count, request->username->vp_strvalue);
+
+finish:
+ if (user_name) talloc_free(user_name);
+ if (cs_id) talloc_free(cs_id);
+ if (session_id) talloc_free(session_id);
+
+ /* free rows */
+ if (jrows) json_object_put(jrows);
+
+ /* free and reset json object */
+ if (cookie->jobj) {
+ json_object_put(cookie->jobj);
+ cookie->jobj = NULL;
+ }
+
+ if (handle) fr_connection_release(inst->pool, handle);
+
+ /*
+ * The Auth module apparently looks at request->simul_count,
+ * not the return value of this module when deciding to deny
+ * a call for too many sessions.
+ */
+ return rcode;
+}
+#endif
+
+/** Detach the module
+ *
+ * Detach the module instance and free any allocated resources.
+ *
+ * @param instance The module instance.
+ * @return Returns 0 (success) in all conditions.
+ */
+static int mod_detach(void *instance)
+{
+ rlm_couchbase_t *inst = instance;
+
+ if (inst->map) json_object_put(inst->map);
+ if (inst->pool) fr_connection_pool_free(inst->pool);
+
+ return 0;
+}
+
+/*
+ * Hook into the FreeRADIUS module system.
+ */
+extern module_t rlm_couchbase;
+module_t rlm_couchbase = {
+ .magic = RLM_MODULE_INIT,
+ .name = "couchbase",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_couchbase_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_ACCOUNTING
+ [MOD_ACCOUNTING] = mod_accounting,
+#endif
+#ifdef WITH_SESSION_MGMT
+ [MOD_SESSION] = mod_checksimul
+#endif
+ },
+};
diff --git a/src/modules/rlm_counter/.gitignore b/src/modules/rlm_counter/.gitignore
new file mode 100644
index 0000000..e936973
--- /dev/null
+++ b/src/modules/rlm_counter/.gitignore
@@ -0,0 +1,2 @@
+config.h
+all.mk
diff --git a/src/modules/rlm_counter/README.md b/src/modules/rlm_counter/README.md
new file mode 100644
index 0000000..4b461f6
--- /dev/null
+++ b/src/modules/rlm_counter/README.md
@@ -0,0 +1,12 @@
+# rlm_counter
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Provides a way to count items, one counter per unique key. For
+example with User-Name for the key and Acct-Session-Time as the
+count attribute, the length of time each user may use per day
+could be limited.
diff --git a/src/modules/rlm_counter/all.mk.in b/src/modules/rlm_counter/all.mk.in
new file mode 100644
index 0000000..5570dd4
--- /dev/null
+++ b/src/modules/rlm_counter/all.mk.in
@@ -0,0 +1,17 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TARGETNAME)" ""
+install: $(R)$(bindir)/rad_counter
+
+$(R)$(bindir)/rad_counter: src/modules/rlm_counter/rad_counter | $(R)$(bindir)
+ @$(INSTALL) -m 755 src/modules/rlm_counter/rad_counter $(R)$(bindir)/
+endif
diff --git a/src/modules/rlm_counter/config.h.in b/src/modules/rlm_counter/config.h.in
new file mode 100644
index 0000000..1952812
--- /dev/null
+++ b/src/modules/rlm_counter/config.h.in
@@ -0,0 +1,9 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* do we have gdbm_fdesc */
+#undef HAVE_GDBM_FDESC
+
+/* do we need GDBM_SYNC */
+#undef NEED_GDBM_SYNC
+
+
diff --git a/src/modules/rlm_counter/configure b/src/modules/rlm_counter/configure
new file mode 100755
index 0000000..59b66ea
--- /dev/null
+++ b/src/modules/rlm_counter/configure
@@ -0,0 +1,4672 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_counter.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_counter
+'
+ 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_counter build without rlm_counter
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_counter
+echo
+
+
+# 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_counter was given.
+if test "${with_rlm_counter+set}" = set; then :
+ withval=$with_rlm_counter;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_counter" != 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
+
+
+
+
+
+ac_safe=`echo "gdbm.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 gdbm.h in $try" >&5
+$as_echo_n "checking for gdbm.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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}/gdbm.h" >&5
+$as_echo_n "checking for ${_prefix}/gdbm.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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 gdbm.h" >&5
+$as_echo_n "checking for gdbm.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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 gdbm.h in $try" >&5
+$as_echo_n "checking for gdbm.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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=
+
+
+
+sm_lib_safe=`echo "gdbm" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "gdbm_open" | 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 gdbm_open in -lgdbm in $try" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm in $try... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ 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 gdbm_open in -lgdbm" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ { $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 gdbm_open in -lgdbm in $try" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm in $try... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ 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_gdbm_gdbm_open" != "xyes"; then
+
+fail="$fail libgdbm"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+
+if test x"$fail" = x""; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see GDBM_SYNC status" >&5
+$as_echo_n "checking to see GDBM_SYNC status... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <gdbm.h>
+#ifdef GDBM_SYNC
+ found-gdbm-sync!
+#else
+ not found. this version must use sync by default.
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "found-gdbm-sync" >/dev/null 2>&1; then :
+
+
+$as_echo "#define NEED_GDBM_SYNC yes" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: needs it." >&5
+$as_echo "needs it." >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: SYNCs by default." >&5
+$as_echo "SYNCs by default." >&6; }
+
+
+fi
+rm -f conftest*
+
+
+fi
+
+
+old_LIBS=$LIBS
+LIBS="$LIBS $SMART_LIBS"
+ac_fn_c_check_func "$LINENO" "gdbm_fdesc" "ac_cv_func_gdbm_fdesc"
+if test "x$ac_cv_func_gdbm_fdesc" = xyes; then :
+
+fi
+
+if test "x$ac_cv_func_gdbm_fdesc" = "xyes";
+then
+
+$as_echo "#define HAVE_GDBM_FDESC /**/" >>confdefs.h
+
+fi
+LIBS=$old_LIBS
+
+
+ targetname=rlm_counter
+else
+ targetname=
+ echo \*\*\* module rlm_counter is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_counter to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_counter." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_counter." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_counter requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_counter requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_counter/configure.ac b/src/modules/rlm_counter/configure.ac
new file mode 100644
index 0000000..d5889d8
--- /dev/null
+++ b/src/modules/rlm_counter/configure.ac
@@ -0,0 +1,55 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_counter.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_counter])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_SMART_CHECK_INCLUDE(gdbm.h)
+FR_SMART_CHECK_LIB(gdbm, gdbm_open)
+if test "x$ac_cv_lib_gdbm_gdbm_open" != "xyes"; then
+ FR_MODULE_FAIL([libgdbm])
+fi
+
+FR_MODULE_TEST_PASS_DO([
+ AC_MSG_CHECKING(to see GDBM_SYNC status)
+ AC_EGREP_CPP(found-gdbm-sync, [
+#include <gdbm.h>
+#ifdef GDBM_SYNC
+ found-gdbm-sync!
+#else
+ not found. this version must use sync by default.
+#endif
+ ], [
+ AC_DEFINE(NEED_GDBM_SYNC, yes, [do we need GDBM_SYNC])
+ AC_MSG_RESULT(needs it.)
+ ], [
+ AC_MSG_RESULT(SYNCs by default.)
+ ]
+ )
+])
+
+old_LIBS=$LIBS
+LIBS="$LIBS $SMART_LIBS"
+AC_CHECK_FUNC(gdbm_fdesc)
+if test "x$ac_cv_func_gdbm_fdesc" = "xyes";
+then
+ AC_DEFINE(HAVE_GDBM_FDESC, [], [do we have gdbm_fdesc])
+fi
+LIBS=$old_LIBS
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_counter/rad_counter b/src/modules/rlm_counter/rad_counter
new file mode 100755
index 0000000..8de31a1
--- /dev/null
+++ b/src/modules/rlm_counter/rad_counter
@@ -0,0 +1,113 @@
+#!/usr/bin/perl
+#
+# $Id$
+#
+use warnings ;
+use GDBM_File ;
+use Fcntl ;
+use Getopt::Long;
+use File::Basename;
+
+my $user = '';
+my $divisor = 1;
+my $reset = 0;
+my $match = '.*';
+my $help = 0;
+
+#
+# This should be fixed...
+#
+$filename = '';
+
+sub show_help {
+ my $progname = basename($0);
+ print <<EOF;
+Usage: $progname --file=<counter filename> [OPTION...]
+Query and maintain FreeRADIUS rlm_counter DB file.
+
+Arguments:
+--file=<filename> Counter DB filename.
+
+Options:
+--user=<username> Information for specific user.
+--match=<regexp> Information for matching users.
+--reset=<number> Reset counter to <number>.
+ If divisor is set use it,
+ else <number> means seconds.
+--help Show this help screen.
+--(hours|minutes|seconds) Specify information divisor.
+EOF
+ exit 0;
+}
+
+#
+# Print out only one user,
+#
+# Or specify printing in hours, minutes, or seconds (default)
+#
+GetOptions ('user=s' => \$user,
+ 'match=s' => \$match,
+ 'file=s' => \$filename,
+ 'reset=i' => \$reset,
+ 'help' => \$help,
+ 'hours' => sub { $divisor = 3600 },
+ 'minutes' => sub { $divisor = 60 },
+ 'seconds' => sub { $divisor = 1 } );
+
+show_help if ($help || $filename eq '');
+
+#
+# Open the file.
+#
+if ($reset){
+ my $db = tie(%hash, 'GDBM_File', $filename, O_RDWR, 0666) or die "Cannot open $filename: $!\n";
+}else{
+ my $db = tie(%hash, 'GDBM_File', $filename, O_RDONLY, 0666) or die "Cannot open $filename: $!\n";
+}
+
+#
+# If given one name, give the seconds
+#
+if ($user ne '') {
+ if (defined($hash{$user})){
+ print $user, "\t\t", int ( unpack('L',$hash{$user}) / $divisor), "\n";
+ if ($reset){
+ my $uniqueid = (unpack('L A32',$hash{$user}))[1];
+ $hash{$user} = pack('L A32',$reset * $divisor,$uniqueid);
+ print $user, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
+ }
+ }else{
+ print $user, "\t\t", "Not found\n";
+ }
+
+ undef $db;
+ untie %hash;
+ exit 0;
+}
+
+#
+# This may be faster, but unordered.
+#while (($key,$val) = each %hash) {
+#
+foreach $key (sort keys %hash) {
+ #
+ # These are special.
+ next if ($key eq "DEFAULT1");
+ next if ($key eq "DEFAULT2");
+
+ #
+ # Allow user names matching a regex.
+ #
+ next if ($key !~ /$match/);
+
+ #
+ # Print out the names...
+ print $key, "\t\t", int ( unpack('L',$hash{$key}) / $divisor), "\n";
+ if ($reset){
+ my $uniqueid = (unpack('L A32',$hash{$key}))[1];
+ $hash{$key} = pack('L A32',$reset * $divisor,$uniqueid);
+ print $key, "\t\t", "Counter reset to ", $reset * $divisor, "\n";
+ }
+}
+undef $db;
+untie %hash;
diff --git a/src/modules/rlm_counter/rlm_counter.c b/src/modules/rlm_counter/rlm_counter.c
new file mode 100644
index 0000000..ff46aef
--- /dev/null
+++ b/src/modules/rlm_counter/rlm_counter.c
@@ -0,0 +1,891 @@
+/*
+ * 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_counter.c
+ * @brief Provides a packet counter to track data usage and other values.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2001 Alan DeKok <aland@ox.org>
+ * @copyright 2001-2003 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include "config.h"
+
+#include <gdbm.h>
+
+#ifdef NEEDS_GDBM_SYNC
+# define GDBM_SYNCOPT GDBM_SYNC
+#else
+# define GDBM_SYNCOPT 0
+#endif
+
+#ifdef GDBM_NOLOCK
+#define GDBM_COUNTER_OPTS (GDBM_SYNCOPT | GDBM_NOLOCK)
+#else
+#define GDBM_COUNTER_OPTS (GDBM_SYNCOPT)
+#endif
+
+#ifndef HAVE_GDBM_FDESC
+#define gdbm_fdesc(foo) (-1)
+#endif
+
+#define UNIQUEID_MAX_LEN 32
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_counter_t {
+ char const *filename; /* name of the database file */
+ char const *reset; /* daily, weekly, monthly, never or user defined */
+ char const *key_name; /* User-Name */
+ char const *count_attribute; /* Acct-Session-Time */
+ char const *counter_name; /* Daily-Session-Time */
+ char const *check_name; /* Daily-Max-Session */
+ char const *reply_name; /* Session-Timeout */
+ char const *service_type; /* Service-Type to search for */
+
+ uint32_t cache_size;
+ uint32_t service_val;
+
+ DICT_ATTR const *key_attr;
+ DICT_ATTR const *count_attr;
+ DICT_ATTR const *check_attr;
+ DICT_ATTR const *reply_attr;
+ DICT_ATTR const *dict_attr; /* attribute number for the counter. */
+
+ time_t reset_time; /* The time of the next reset. */
+ time_t last_reset; /* The time of the last reset. */
+
+ GDBM_FILE gdbm; /* The gdbm file handle */
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t mutex; /* A mutex to lock the gdbm file for only one reader/writer */
+#endif
+} rlm_counter_t;
+
+#ifndef HAVE_PTHREAD_H
+/*
+ * This is a lot simpler than putting ifdef's around
+ * every use of the pthread functions.
+ */
+#define pthread_mutex_lock(a)
+#define pthread_mutex_unlock(a)
+#define pthread_mutex_init(a,b)
+#define pthread_mutex_destroy(a)
+#endif
+
+typedef struct rad_counter {
+ unsigned int user_counter;
+ char uniqueid[UNIQUEID_MAX_LEN];
+} rad_counter;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_counter_t, filename), NULL },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, key_name), NULL },
+ { "reset", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, reset), NULL },
+
+ { "count-attribute", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, count_attribute), NULL },
+ { "count_attribute", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, count_attribute), NULL },
+
+ { "counter-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, counter_name), NULL },
+ { "counter_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, counter_name), NULL },
+
+ { "check-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, check_name), NULL },
+ { "check_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_counter_t, check_name), NULL },
+
+ { "reply-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, reply_name), NULL },
+ { "reply_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_counter_t, reply_name), NULL },
+
+ { "allowed-servicetype", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_counter_t, service_type), NULL },
+ { "allowed_service_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_counter_t, service_type), NULL },
+
+ { "cache-size", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_counter_t, cache_size), NULL },
+ { "cache_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_counter_t, cache_size), "1000" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Work around compiler "const" issues.
+ */
+#define ASSIGN(_x,_y) memcpy(&_x, &_y, sizeof(_x))
+
+
+/*
+ * See if the counter matches.
+ */
+static int counter_cmp(void *instance, UNUSED REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ rlm_counter_t *inst = instance;
+ datum key_datum;
+ datum count_datum;
+ VALUE_PAIR *key_vp;
+ rad_counter counter;
+
+ /*
+ * Find the key attribute.
+ */
+ key_vp = fr_pair_find_by_da(request, inst->key_attr, TAG_ANY);
+ if (!key_vp) {
+ return RLM_MODULE_NOOP;
+ }
+
+ ASSIGN(key_datum.dptr,key_vp->vp_strvalue);
+ key_datum.dsize = key_vp->vp_length;
+
+ count_datum = gdbm_fetch(inst->gdbm, key_datum);
+
+ if (!count_datum.dptr) {
+ return -1;
+ }
+ memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
+ free(count_datum.dptr);
+
+ return counter.user_counter - check->vp_integer;
+}
+
+
+static rlm_rcode_t add_defaults(rlm_counter_t *inst)
+{
+ datum key_datum;
+ datum time_datum;
+ static char const *default1 = "DEFAULT1";
+ static char const *default2 = "DEFAULT2";
+
+ DEBUG2("rlm_counter: add_defaults: Start");
+
+ memcpy(&key_datum.dptr, &default1, sizeof(key_datum.dptr));
+ key_datum.dsize = strlen(key_datum.dptr);
+ time_datum.dptr = (char *) &inst->reset_time;
+ time_datum.dsize = sizeof(time_t);
+
+ if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0) {
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ return RLM_MODULE_FAIL;
+ }
+ DEBUG2("rlm_counter: DEFAULT1 set to %u", (unsigned int) inst->reset_time);
+
+ memcpy(&key_datum.dptr, &default2, sizeof(key_datum.dptr));
+ key_datum.dsize = strlen(key_datum.dptr);
+ key_datum.dsize = strlen(default2);
+ time_datum.dptr = (char *) &inst->last_reset;
+ time_datum.dsize = sizeof(time_t);
+
+ if (gdbm_store(inst->gdbm, key_datum, time_datum, GDBM_REPLACE) < 0) {
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ return RLM_MODULE_FAIL;
+ }
+ DEBUG2("rlm_counter: DEFAULT2 set to %u", (unsigned int) inst->last_reset);
+ DEBUG2("rlm_counter: add_defaults: End");
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t reset_db(rlm_counter_t *inst)
+{
+ int cache_size = inst->cache_size;
+ rlm_rcode_t rcode;
+
+ DEBUG2("rlm_counter: reset_db: Closing database");
+ gdbm_close(inst->gdbm);
+
+ /*
+ * Open a completely new database.
+ */
+ {
+ char *filename;
+
+ memcpy(&filename, &inst->filename, sizeof(filename));
+ inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
+ }
+ if (!inst->gdbm) {
+ ERROR("rlm_counter: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
+ return RLM_MODULE_FAIL;
+ }
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(cache_size)) == -1) {
+ ERROR("rlm_counter: Failed to set cache size");
+ }
+
+ DEBUG2("rlm_counter: reset_db: Opened new database");
+
+ /*
+ * Add defaults
+ */
+ rcode = add_defaults(inst);
+ if (rcode != RLM_MODULE_OK)
+ return rcode;
+
+ DEBUG2("rlm_counter: reset_db ended");
+
+ return RLM_MODULE_OK;
+}
+
+static int find_next_reset(rlm_counter_t *inst, time_t timeval)
+{
+ int ret = 0;
+ size_t len;
+ unsigned int num = 1;
+ char last = '\0';
+ struct tm *tm, s_tm;
+ char sCurrentTime[40], sNextTime[40];
+
+ tm = localtime_r(&timeval, &s_tm);
+ len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);
+ if (len == 0) *sCurrentTime = '\0';
+ tm->tm_sec = tm->tm_min = 0;
+
+ if (!inst->reset)
+ return -1;
+ if (isdigit((uint8_t) inst->reset[0])) {
+ len = strlen(inst->reset);
+ if (len == 0)
+ return -1;
+ last = inst->reset[len - 1];
+ if (!isalpha((uint8_t) last))
+ last = 'd';
+ num = atoi(inst->reset);
+ DEBUG("rlm_counter: num=%d, last=%c",num,last);
+ }
+ if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
+ /*
+ * Round up to the next nearest hour.
+ */
+ tm->tm_hour += num;
+ inst->reset_time = mktime(tm);
+ } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
+ /*
+ * Round up to the next nearest day.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday += num;
+ inst->reset_time = mktime(tm);
+ } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
+ /*
+ * Round up to the next nearest week.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
+ inst->reset_time = mktime(tm);
+ } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
+ tm->tm_hour = 0;
+ tm->tm_mday = 1;
+ tm->tm_mon += num;
+ inst->reset_time = mktime(tm);
+ } else if (strcmp(inst->reset, "never") == 0) {
+ inst->reset_time = 0;
+ } else {
+ ERROR("rlm_counter: Unknown reset timer \"%s\"",
+ inst->reset);
+ return -1;
+ }
+
+ len = strftime(sNextTime, sizeof(sNextTime), "%Y-%m-%d %H:%M:%S", tm);
+ if (len == 0) *sNextTime = '\0';
+ DEBUG2("rlm_counter: Current Time: %" PRId64 " [%s], Next reset %" PRId64 " [%s]",
+ (int64_t) timeval, sCurrentTime, (int64_t) inst->reset_time, sNextTime);
+
+ return ret;
+}
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_counter_t *inst = instance;
+ ATTR_FLAGS flags;
+ DICT_ATTR const *da;
+
+ memset(&flags, 0, sizeof(flags));
+ flags.compare = 1; /* ugly hack */
+ da = dict_attrbyname(inst->counter_name);
+ if (da && (da->type != PW_TYPE_INTEGER)) {
+ cf_log_err_cs(conf, "Counter attribute %s MUST be integer", inst->counter_name);
+ return -1;
+ }
+
+ if (!da && (dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER, flags) < 0)) {
+ cf_log_err_cs(conf, "Failed to create counter attribute %s: %s", inst->counter_name, fr_strerror());
+ return -1;
+ }
+
+ if (paircompare_register_byname(inst->counter_name, NULL, true, counter_cmp, inst) < 0) {
+ cf_log_err_cs(conf, "Failed to create counter attribute %s: %s", inst->counter_name, fr_strerror());
+ return -1;
+ }
+
+
+ da = dict_attrbyname(inst->counter_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Failed to find counter attribute %s", inst->counter_name);
+ return -1;
+ }
+ inst->dict_attr = da;
+
+ /*
+ * Create a new attribute for the check item.
+ */
+ flags.compare = 0;
+ if (dict_addattr(inst->check_name, -1, 0, PW_TYPE_INTEGER, flags) < 0) {
+ cf_log_err_cs(conf, "Failed to create check attribute %s: %s", inst->counter_name, fr_strerror());
+ return -1;
+
+ }
+
+ da = dict_attrbyname(inst->check_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Failed to find check attribute %s", inst->counter_name);
+ return -1;
+ }
+ inst->check_attr = da;
+
+ 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_counter_t *inst = instance;
+ DICT_ATTR const *da;
+ DICT_VALUE *dval;
+ time_t now;
+ int cache_size;
+ int ret;
+ datum key_datum;
+ datum time_datum;
+ char const *default1 = "DEFAULT1";
+ char const *default2 = "DEFAULT2";
+
+ cache_size = inst->cache_size;
+
+ da = dict_attrbyname(inst->key_name);
+ rad_assert(da != NULL);
+ inst->key_attr = da;
+
+ /*
+ * Discover the attribute number of the counter.
+ */
+ da = dict_attrbyname(inst->count_attribute);
+ rad_assert(da != NULL);
+ inst->count_attr = da;
+
+ /*
+ * Discover the attribute number of the reply attribute.
+ */
+ if (inst->reply_name != NULL) {
+ da = dict_attrbyname(inst->reply_name);
+ if (!da) {
+ cf_log_err_cs(conf, "No such attribute %s", inst->reply_name);
+ return -1;
+ }
+ if (da->type != PW_TYPE_INTEGER) {
+ cf_log_err_cs(conf, "Reply attribute' %s' is not of type integer", inst->reply_name);
+ return -1;
+ }
+ inst->reply_attr = da;
+ } else {
+ inst->reply_attr = NULL;
+ }
+
+ /*
+ * Find the attribute for the allowed protocol
+ */
+ if (inst->service_type != NULL) {
+ if ((dval = dict_valbyname(PW_SERVICE_TYPE, 0, inst->service_type)) == NULL) {
+ ERROR("rlm_counter: Failed to find attribute number for %s", inst->service_type);
+ return -1;
+ }
+ inst->service_val = dval->value;
+ }
+
+ /*
+ * Find when to reset the database.
+ */
+ rad_assert(inst->reset && *inst->reset);
+ now = time(NULL);
+ inst->reset_time = 0;
+ inst->last_reset = now;
+
+ if (find_next_reset(inst,now) == -1) {
+ ERROR("rlm_counter: find_next_reset() returned -1. Exiting");
+ return -1;
+ }
+
+ {
+ char *filename;
+
+ memcpy(&filename, &inst->filename, sizeof(filename));
+ inst->gdbm = gdbm_open(filename, sizeof(int), GDBM_NEWDB | GDBM_COUNTER_OPTS, 0600, NULL);
+ }
+ if (!inst->gdbm) {
+ ERROR("rlm_counter: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
+ return -1;
+ }
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(cache_size)) == -1) {
+ ERROR("rlm_counter: Failed to set cache size");
+ }
+
+ /*
+ * Look for the DEFAULT1 entry. This entry if it exists contains the
+ * time of the next database reset. This time is set each time we reset
+ * the database. If next_reset < now then we reset the database.
+ * That way we can overcome the problem where radiusd is down during a database
+ * reset time. If we did not keep state information in the database then the reset
+ * would be extended and that would create problems.
+ *
+ * We also store the time of the last reset in the DEFAULT2 entry.
+ *
+ * If DEFAULT1 and DEFAULT2 do not exist (new database) we add them to the database
+ */
+
+ memcpy(&key_datum.dptr, &default1, sizeof(key_datum.dptr));
+ key_datum.dsize = strlen(key_datum.dptr);
+
+ time_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (time_datum.dptr != NULL) {
+ time_t next_reset = 0;
+
+ memcpy(&next_reset, time_datum.dptr, sizeof(time_t));
+ free(time_datum.dptr);
+ time_datum.dptr = NULL;
+ if (next_reset && next_reset <= now) {
+
+ inst->last_reset = now;
+ ret = reset_db(inst);
+ if (ret != RLM_MODULE_OK) {
+ ERROR("rlm_counter: reset_db() failed");
+ return -1;
+ }
+ } else {
+ inst->reset_time = next_reset;
+ }
+
+ memcpy(&key_datum.dptr, &default2, sizeof(key_datum.dptr));
+ key_datum.dsize = strlen(key_datum.dptr);
+
+ time_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (time_datum.dptr != NULL) {
+ memcpy(&inst->last_reset, time_datum.dptr, sizeof(time_t));
+ free(time_datum.dptr);
+ }
+ } else {
+ ret = add_defaults(inst);
+ if (ret != RLM_MODULE_OK) {
+ ERROR("rlm_counter: add_defaults() failed");
+ return -1;
+ }
+ }
+
+ /*
+ * Init the mutex
+ */
+ pthread_mutex_init(&inst->mutex, NULL);
+
+ return 0;
+}
+
+/*
+ * Write accounting information to this modules database.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_counter_t *inst = instance;
+ datum key_datum;
+ datum count_datum;
+ VALUE_PAIR *key_vp, *count_vp, *proto_vp, *uniqueid_vp;
+ rad_counter counter;
+ rlm_rcode_t rcode;
+ int ret;
+ int acctstatustype = 0;
+ time_t diff;
+
+ if ((key_vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL)
+ acctstatustype = key_vp->vp_integer;
+ else {
+ DEBUG("rlm_counter: Could not find account status type in packet");
+ return RLM_MODULE_NOOP;
+ }
+ if (acctstatustype != PW_STATUS_STOP) {
+ DEBUG("rlm_counter: We only run on Accounting-Stop packets");
+ return RLM_MODULE_NOOP;
+ }
+ uniqueid_vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0, TAG_ANY);
+ if (uniqueid_vp != NULL)
+ DEBUG("rlm_counter: Packet Unique ID = '%s'",uniqueid_vp->vp_strvalue);
+
+ /*
+ * Before doing anything else, see if we have to reset
+ * the counters.
+ */
+ if (inst->reset_time && (inst->reset_time <= request->timestamp)) {
+ DEBUG("rlm_counter: Time to reset the database");
+ inst->last_reset = inst->reset_time;
+ find_next_reset(inst,request->timestamp);
+ pthread_mutex_lock(&inst->mutex);
+ rcode = reset_db(inst);
+ pthread_mutex_unlock(&inst->mutex);
+ if (rcode != RLM_MODULE_OK)
+ return rcode;
+ }
+ /*
+ * Check if we need to watch out for a specific service-type. If yes then check it
+ */
+ if (inst->service_type != NULL) {
+ if ((proto_vp = fr_pair_find_by_num(request->packet->vps, PW_SERVICE_TYPE, 0, TAG_ANY)) == NULL) {
+ DEBUG("rlm_counter: Could not find Service-Type attribute in the request. Returning NOOP");
+ return RLM_MODULE_NOOP;
+ }
+ if ((unsigned)proto_vp->vp_integer != inst->service_val) {
+ DEBUG("rlm_counter: This Service-Type is not allowed. Returning NOOP");
+ return RLM_MODULE_NOOP;
+ }
+ }
+ /*
+ * Check if request->timestamp - {Acct-Delay-Time} < last_reset
+ * If yes reject the packet since it is very old
+ */
+ key_vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
+ if (key_vp != NULL) {
+ if ((key_vp->vp_integer != 0) && (request->timestamp - (time_t) key_vp->vp_integer) < inst->last_reset) {
+ DEBUG("rlm_counter: This packet is too old. Returning NOOP");
+ return RLM_MODULE_NOOP;
+ }
+ }
+
+
+
+ /*
+ * Look for the key. User-Name is special. It means
+ * The REAL username, after stripping.
+ */
+ key_vp = (inst->key_attr->attr == PW_USER_NAME) ? request->username :
+ fr_pair_find_by_da(request->packet->vps, inst->key_attr, TAG_ANY);
+ if (!key_vp) {
+ DEBUG("rlm_counter: Could not find the key-attribute in the request. Returning NOOP");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Look for the attribute to use as a counter.
+ */
+ count_vp = fr_pair_find_by_da(request->packet->vps, inst->count_attr, TAG_ANY);
+ if (!count_vp) {
+ DEBUG("rlm_counter: Could not find the count_attribute in the request");
+ return RLM_MODULE_NOOP;
+ }
+
+ ASSIGN(key_datum.dptr, key_vp->vp_strvalue);
+ key_datum.dsize = key_vp->vp_length;
+
+ DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue);
+ pthread_mutex_lock(&inst->mutex);
+ count_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (!count_datum.dptr) {
+ DEBUG("rlm_counter: Could not find the requested key in the database");
+ counter.user_counter = 0;
+ if (uniqueid_vp != NULL)
+ strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue, sizeof(counter.uniqueid));
+ else
+ memset((char *)counter.uniqueid,0,UNIQUEID_MAX_LEN);
+ } else {
+ DEBUG("rlm_counter: Key found");
+ memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
+ free(count_datum.dptr);
+ DEBUG("rlm_counter: Counter Unique ID = '%s'",counter.uniqueid);
+ if (uniqueid_vp != NULL) {
+ if (strncmp(uniqueid_vp->vp_strvalue,counter.uniqueid, UNIQUEID_MAX_LEN - 1) == 0) {
+ DEBUG("rlm_counter: Unique IDs for user match. Droping the request");
+ pthread_mutex_unlock(&inst->mutex);
+ return RLM_MODULE_NOOP;
+ }
+ strlcpy(counter.uniqueid,uniqueid_vp->vp_strvalue, sizeof(counter.uniqueid));
+ }
+ DEBUG("rlm_counter: User=%s, Counter=%d.",request->username->vp_strvalue,counter.user_counter);
+ }
+
+ if (inst->count_attr->attr == PW_ACCT_SESSION_TIME) {
+ /*
+ * If session time < diff then the user got in after the
+ * last reset. So add his session time, otherwise add the
+ * diff.
+ *
+ * That way if he logged in at 23:00 and we reset the
+ * daily counter at 24:00 and he logged out at 01:00
+ * then we will only count one hour (the one in the new
+ * day). That is the right thing
+ */
+ diff = request->timestamp - inst->last_reset;
+ counter.user_counter += ((time_t) count_vp->vp_integer < diff) ? count_vp->vp_integer : diff;
+
+ } else if (count_vp->da->type == PW_TYPE_INTEGER) {
+ /*
+ * Integers get counted, without worrying about
+ * reset dates.
+ */
+ counter.user_counter += count_vp->vp_integer;
+
+ } else {
+ /*
+ * The attribute is NOT an integer, just count once
+ * more that we've seen it.
+ */
+ counter.user_counter++;
+ }
+
+ DEBUG("rlm_counter: User=%s, New Counter=%d.",request->username->vp_strvalue,counter.user_counter);
+ count_datum.dptr = (char *) &counter;
+ count_datum.dsize = sizeof(rad_counter);
+
+ DEBUG("rlm_counter: Storing new value in database");
+ ret = gdbm_store(inst->gdbm, key_datum, count_datum, GDBM_REPLACE);
+ pthread_mutex_unlock(&inst->mutex);
+ if (ret < 0) {
+ ERROR("rlm_counter: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ return RLM_MODULE_FAIL;
+ }
+ DEBUG("rlm_counter: New value stored successfully");
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * 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_counter_t *inst = instance;
+ rlm_rcode_t rcode = RLM_MODULE_NOOP;
+ datum key_datum;
+ datum count_datum;
+ rad_counter counter;
+ VALUE_PAIR *key_vp, *check_vp;
+ VALUE_PAIR *reply_item;
+ char msg[128];
+
+ /*
+ * Before doing anything else, see if we have to reset
+ * the counters.
+ */
+ if (inst->reset_time && (inst->reset_time <= request->timestamp)) {
+ rlm_rcode_t rcode2;
+
+ inst->last_reset = inst->reset_time;
+ find_next_reset(inst,request->timestamp);
+ pthread_mutex_lock(&inst->mutex);
+ rcode2 = reset_db(inst);
+ pthread_mutex_unlock(&inst->mutex);
+ if (rcode2 != RLM_MODULE_OK) {
+ return rcode2;
+ }
+ }
+
+
+ /*
+ * Look for the key. User-Name is special. It means
+ * The REAL username, after stripping.
+ */
+ DEBUG2("rlm_counter: Entering module authorize code");
+ key_vp = (inst->key_attr->attr == PW_USER_NAME) ? request->username :
+ fr_pair_find_by_da(request->packet->vps, inst->key_attr, TAG_ANY);
+ if (!key_vp) {
+ DEBUG2("rlm_counter: Could not find Key value pair");
+ return rcode;
+ }
+
+ /*
+ * Look for the check item
+ */
+ if ((check_vp = fr_pair_find_by_da(request->config, inst->check_attr, TAG_ANY)) == NULL) {
+ DEBUG2("rlm_counter: Could not find Check item value pair");
+ return rcode;
+ }
+
+ ASSIGN(key_datum.dptr, key_vp->vp_strvalue);
+ key_datum.dsize = key_vp->vp_length;
+
+
+ /*
+ * Init to be sure
+ */
+
+ counter.user_counter = 0;
+
+ DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue);
+ pthread_mutex_lock(&inst->mutex);
+ count_datum = gdbm_fetch(inst->gdbm, key_datum);
+ pthread_mutex_unlock(&inst->mutex);
+ if (count_datum.dptr != NULL) {
+ DEBUG("rlm_counter: Key Found");
+ memcpy(&counter, count_datum.dptr, sizeof(rad_counter));
+ free(count_datum.dptr);
+ }
+ else
+ DEBUG("rlm_counter: Could not find the requested key in the database");
+
+ /*
+ * Check if check item > counter
+ */
+ DEBUG("rlm_counter: Check item = %d, Count = %d",check_vp->vp_integer,counter.user_counter);
+ if (check_vp->vp_integer > counter.user_counter) {
+ unsigned int res;
+
+ res = check_vp->vp_integer - counter.user_counter;
+
+ DEBUG("rlm_counter: res is greater than zero");
+ if (inst->count_attr->attr == PW_ACCT_SESSION_TIME) {
+ /*
+ * Do the following only if the count attribute is
+ * AcctSessionTime
+ */
+
+ /*
+ * We are assuming that simultaneous-use=1. But
+ * even if that does not happen then our user
+ * could login at max for 2*max-usage-time Is
+ * that acceptable?
+ */
+
+ /*
+ * User is allowed, but set Session-Timeout.
+ * Stolen from main/auth.c
+ */
+
+ /*
+ * If we are near a reset then add the next
+ * limit, so that the user will not need to
+ * login again
+ * Before that set the return value to the time
+ * remaining to next reset
+ */
+ if (inst->reset_time && (res >= (inst->reset_time - request->timestamp))) {
+ res = inst->reset_time - request->timestamp;
+ res += check_vp->vp_integer;
+ }
+
+ reply_item = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (reply_item) {
+ if (reply_item->vp_integer > res) {
+ reply_item->vp_integer = res;
+ }
+ } else {
+ reply_item = radius_pair_create(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ reply_item->vp_integer = res;
+ }
+ } else if (inst->reply_attr) {
+ reply_item = fr_pair_find_by_da(request->reply->vps, inst->reply_attr, TAG_ANY);
+ if (reply_item) {
+ if (reply_item->vp_integer > res) {
+ reply_item->vp_integer = res;
+ }
+ } else {
+ reply_item = radius_pair_create(request->reply, &request->reply->vps, inst->reply_attr->attr,
+ inst->reply_attr->vendor);
+ reply_item->vp_integer = res;
+ }
+ }
+
+ rcode = RLM_MODULE_OK;
+
+ DEBUG2("rlm_counter: (Check item - counter) is greater than zero");
+ DEBUG2("rlm_counter: Authorized user %s, check_item=%d, counter=%d",
+ key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter);
+ DEBUG2("rlm_counter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d", key_vp->vp_strvalue,res);
+ } else {
+ /*
+ * User is denied access, send back a reply message
+ */
+ sprintf(msg, "Your maximum %s usage time has been reached", inst->reset);
+ pair_make_reply("Reply-Message", msg, T_OP_EQ);
+
+ REDEBUG("Maximum %s usage time reached", inst->reset);
+ rcode = RLM_MODULE_REJECT;
+
+ DEBUG2("rlm_counter: Rejected user %s, check_item=%d, counter=%d",
+ key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter);
+ }
+
+ return rcode;
+}
+
+static int mod_detach(void *instance)
+{
+ rlm_counter_t *inst = instance;
+
+ if (inst->gdbm) {
+ gdbm_close(inst->gdbm);
+ }
+
+ pthread_mutex_destroy(&inst->mutex);
+
+ 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_counter;
+module_t rlm_counter = {
+ .magic = RLM_MODULE_INIT,
+ .name = "counter",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_counter_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_ACCOUNTING] = mod_accounting
+ },
+};
diff --git a/src/modules/rlm_date/README.md b/src/modules/rlm_date/README.md
new file mode 100644
index 0000000..2145c2f
--- /dev/null
+++ b/src/modules/rlm_date/README.md
@@ -0,0 +1,9 @@
+# rlm_date
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Converts date strings between user configurable formats.
diff --git a/src/modules/rlm_date/all.mk b/src/modules/rlm_date/all.mk
new file mode 100644
index 0000000..94c83a6
--- /dev/null
+++ b/src/modules/rlm_date/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_date.a
+SOURCES := rlm_date.c
diff --git a/src/modules/rlm_date/rlm_date.c b/src/modules/rlm_date/rlm_date.c
new file mode 100644
index 0000000..79191e7
--- /dev/null
+++ b/src/modules/rlm_date/rlm_date.c
@@ -0,0 +1,141 @@
+/*
+ * 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
+ */
+
+/**
+ * @file rlm_date.c
+ * @brief Translates timestrings between formats.
+ *
+ * @author Artur Malinowski <artur@wow.com>
+ *
+ * @copyright 2013 Artur Malinowski <artur@wow.com>
+ * @copyright 1999-2013 The FreeRADIUS Server Project.
+ */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <ctype.h>
+#include <time.h>
+
+typedef struct rlm_date_t {
+ char const *xlat_name;
+ char const *fmt;
+ bool utc;
+} rlm_date_t;
+
+static const CONF_PARSER module_config[] = {
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_date_t, fmt), "%b %e %Y %H:%M:%S %Z" },
+ { "utc", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_date_t, utc), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+DIAG_OFF(format-nonliteral)
+static ssize_t xlat_date_convert(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ rlm_date_t *inst = instance;
+ time_t date = 0;
+ struct tm tminfo;
+ VALUE_PAIR *vp;
+
+ memset(&tminfo, 0, sizeof(tminfo));
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ switch (vp->da->type) {
+ /*
+ * These are 'to' types, i.e. we'll convert the integers
+ * to a time structure, and then output it in the specified
+ * format as a string.
+ */
+ case PW_TYPE_DATE:
+ date = vp->vp_date;
+ goto encode;
+
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_INTEGER64:
+ date = (time_t) vp->vp_integer;
+
+ encode:
+ if (!inst->utc) {
+ if (localtime_r(&date, &tminfo) == NULL) {
+ REDEBUG("Failed converting time string to localtime");
+ goto error;
+ }
+ } else {
+ if (gmtime_r(&date, &tminfo) == NULL) {
+ REDEBUG("Failed converting time string to gmtime");
+ goto error;
+ }
+ }
+ return strftime(out, outlen, inst->fmt, &tminfo);
+
+ /*
+ * These are 'from' types, i.e. we'll convert the input string
+ * into a time structure, and then output it as an integer
+ * unix timestamp.
+ */
+ case PW_TYPE_STRING:
+ if (strptime(vp->vp_strvalue, inst->fmt, &tminfo) == NULL) {
+ REDEBUG("Failed to parse time string \"%s\" as format '%s'", vp->vp_strvalue, inst->fmt);
+ goto error;
+ }
+
+ if (!inst->utc) {
+ date = mktime(&tminfo);
+ } else {
+ date = timegm(&tminfo);
+ }
+ if (date < 0) {
+ REDEBUG("Failed converting parsed time into unix time");
+
+ }
+ return snprintf(out, outlen, "%" PRIu64, (uint64_t) date);
+
+ default:
+ REDEBUG("Can't convert type %s into date", fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
+ }
+
+ error:
+ *out = '\0';
+ return -1;
+}
+DIAG_ON(format-nonliteral)
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_date_t *inst = instance;
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) {
+ inst->xlat_name = cf_section_name1(conf);
+ }
+
+ xlat_register(inst->xlat_name, xlat_date_convert, NULL, inst);
+
+ return 0;
+}
+
+extern module_t rlm_date;
+module_t rlm_date = {
+ .magic = RLM_MODULE_INIT,
+ .name = "date",
+ .inst_size = sizeof(rlm_date_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap
+};
+
diff --git a/src/modules/rlm_detail/README.md b/src/modules/rlm_detail/README.md
new file mode 100644
index 0000000..3d3aaaf
--- /dev/null
+++ b/src/modules/rlm_detail/README.md
@@ -0,0 +1,9 @@
+# rlm_detail
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Writes attributes from a request list to a flat text file in 'detail' format.
diff --git a/src/modules/rlm_detail/all.mk b/src/modules/rlm_detail/all.mk
new file mode 100644
index 0000000..ba646ca
--- /dev/null
+++ b/src/modules/rlm_detail/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_detail.a
+SOURCES := rlm_detail.c
diff --git a/src/modules/rlm_detail/rlm_detail.c b/src/modules/rlm_detail/rlm_detail.c
new file mode 100644
index 0000000..036549f
--- /dev/null
+++ b/src/modules/rlm_detail/rlm_detail.c
@@ -0,0 +1,564 @@
+/*
+ * 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_detail.c
+ * @brief Write plaintext versions of packets to flatfiles.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/detail.h>
+#include <freeradius-devel/exfile.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_FNMATCH_H
+# include <fnmatch.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+# include <grp.h>
+#endif
+
+#define DIRLEN 8192 //!< Maximum path length.
+
+/** Instance configuration for rlm_detail
+ *
+ * Holds the configuration and preparsed data for a instance of rlm_detail.
+ */
+typedef struct detail_instance {
+ char const *name; //!< Instance name.
+ char const *filename; //!< File/path to write to.
+ uint32_t perm; //!< Permissions to use for new files.
+ char const *group; //!< Group to use for new files.
+
+ char const *header; //!< Header format.
+ bool locking; //!< Whether the file should be locked.
+
+ bool log_srcdst; //!< Add IP src/dst attributes to entries.
+
+ bool escape; //!< do filename escaping, yes / no
+
+ xlat_escape_t escape_func; //!< escape function
+
+ exfile_t *ef; //!< Log file handler
+
+ fr_hash_table_t *ht; //!< Holds suppressed attributes.
+} rlm_detail_t;
+
+static const CONF_PARSER module_config[] = {
+ { "detailfile", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, rlm_detail_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_detail_t, filename), "%{radacctdir}/%{Client-IP-Address}/detail" },
+ { "header", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_detail_t, header), "%t" },
+ { "detailperm", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_detail_t, perm), NULL },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_detail_t, perm), "0600" },
+ { "group", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_detail_t, group), NULL },
+ { "locking", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_detail_t, locking), "no" },
+ { "escape_filenames", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_detail_t, escape), "no" },
+ { "log_packet_header", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_detail_t, log_srcdst), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Clean up.
+ */
+static int mod_detach(void *instance)
+{
+ rlm_detail_t *inst = instance;
+ if (inst->ht) fr_hash_table_free(inst->ht);
+ return 0;
+}
+
+
+static uint32_t detail_hash(void const *data)
+{
+ DICT_ATTR const *da = data;
+ return fr_hash(&da, sizeof(da));
+}
+
+static int detail_cmp(void const *a, void const *b)
+{
+ DICT_ATTR const *one = a;
+ DICT_ATTR const *two = b;
+
+ return one - two;
+}
+
+/*
+ * (Re-)read radiusd.conf into memory.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_detail_t *inst = instance;
+ CONF_SECTION *cs;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ /*
+ * Escape filenames only if asked.
+ */
+ if (inst->escape) {
+ inst->escape_func = rad_filename_escape;
+ } else {
+ inst->escape_func = rad_filename_make_safe;
+ }
+
+ inst->ef = exfile_init(inst, 256, 30, inst->locking);
+ if (!inst->ef) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
+ /*
+ * Suppress certain attributes.
+ */
+ cs = cf_section_sub_find(conf, "suppress");
+ if (cs) {
+ CONF_ITEM *ci;
+
+ inst->ht = fr_hash_table_create(detail_hash, detail_cmp, NULL);
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ char const *attr;
+ DICT_ATTR const *da;
+
+ if (!cf_item_is_pair(ci)) continue;
+
+ attr = cf_pair_attr(cf_item_to_pair(ci));
+ if (!attr) continue; /* pair-anoia */
+
+ da = dict_attrbyname(attr);
+ if (!da) {
+ cf_log_err_cs(conf, "No such attribute '%s'", attr);
+ return -1;
+ }
+
+ /*
+ * Be kind to minor mistakes.
+ */
+ if (fr_hash_table_finddata(inst->ht, da)) {
+ WARN("rlm_detail (%s): Ignoring duplicate entry '%s'", inst->name, attr);
+ continue;
+ }
+
+
+ if (!fr_hash_table_insert(inst->ht, da)) {
+ ERROR("rlm_detail (%s): Failed inserting '%s' into suppression table",
+ inst->name, attr);
+ return -1;
+ }
+
+ DEBUG("rlm_detail (%s): '%s' suppressed, will not appear in detail output", inst->name, attr);
+ }
+
+ /*
+ * If we didn't suppress anything, delete the hash table.
+ */
+ if (fr_hash_table_num_elements(inst->ht) == 0) {
+ fr_hash_table_free(inst->ht);
+ inst->ht = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Wrapper for VPs allocated on the stack.
+ */
+static void detail_vp_print(TALLOC_CTX *ctx, FILE *out, VALUE_PAIR const *stacked)
+{
+ VALUE_PAIR *vp;
+
+ vp = talloc(ctx, VALUE_PAIR);
+ if (!vp) return;
+
+ memcpy(vp, stacked, sizeof(*vp));
+ vp->op = T_OP_EQ;
+ vp_print(out, vp);
+ talloc_free(vp);
+}
+
+
+/** Write a single detail entry to file pointer
+ *
+ * @param[in] out Where to write entry.
+ * @param[in] inst Instance of rlm_detail.
+ * @param[in] request The current request.
+ * @param[in] packet associated with the request (request, reply, proxy-request, proxy-reply...).
+ * @param[in] compat Write out entry in compatibility mode.
+ */
+static int detail_write(FILE *out, rlm_detail_t *inst, REQUEST *request, RADIUS_PACKET *packet, bool compat)
+{
+ VALUE_PAIR *vp;
+ char timestamp[256];
+
+ if ((packet->code == PW_CODE_ACCOUNTING_REQUEST) && !packet->vps) {
+ RWDEBUG("Skipping empty packet");
+ return 0;
+ }
+
+ if (radius_xlat(timestamp, sizeof(timestamp), request, inst->header, NULL, NULL) < 0) {
+ return -1;
+ }
+
+#define WRITE(fmt, ...) do {\
+ if (fprintf(out, fmt, ## __VA_ARGS__) < 0) {\
+ RERROR("Failed writing to detail file: %s", fr_syserror(errno));\
+ return -1;\
+ }\
+} while(0)
+
+ WRITE("%s\n", timestamp);
+
+ /*
+ * Write the information to the file.
+ */
+ if (!compat) {
+ /*
+ * Print out names, if they're OK.
+ * Numbers, if not.
+ */
+ if (is_radius_code(packet->code)) {
+ WRITE("\tPacket-Type = %s\n", fr_packet_codes[packet->code]);
+ } else {
+ WRITE("\tPacket-Type = %u\n", packet->code);
+ }
+ }
+
+ if (inst->log_srcdst) {
+ VALUE_PAIR src_vp, dst_vp;
+
+ memset(&src_vp, 0, sizeof(src_vp));
+ memset(&dst_vp, 0, sizeof(dst_vp));
+
+ switch (packet->src_ipaddr.af) {
+ case AF_INET:
+ src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_IP_ADDRESS, 0);
+ src_vp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+
+ dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_IP_ADDRESS, 0);
+ dst_vp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+ break;
+
+ case AF_INET6:
+ src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_IPV6_ADDRESS, 0);
+ memcpy(&src_vp.vp_ipv6addr, &packet->src_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->src_ipaddr.ipaddr.ip6addr));
+ dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_IPV6_ADDRESS, 0);
+ memcpy(&dst_vp.vp_ipv6addr, &packet->dst_ipaddr.ipaddr.ip6addr,
+ sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
+ break;
+
+ default:
+ break;
+ }
+
+ detail_vp_print(request, out, &src_vp);
+ detail_vp_print(request, out, &dst_vp);
+
+ src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_PORT, 0);
+ src_vp.vp_integer = packet->src_port;
+ dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_PORT, 0);
+ dst_vp.vp_integer = packet->dst_port;
+
+ detail_vp_print(request, out, &src_vp);
+ detail_vp_print(request, out, &dst_vp);
+ }
+
+ {
+ vp_cursor_t cursor;
+ /* Write each attribute/value to the log file */
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ FR_TOKEN op;
+
+ if (inst->ht && fr_hash_table_finddata(inst->ht, vp->da)) continue;
+
+ /*
+ * Don't print passwords in old format...
+ */
+ if (compat && !vp->da->vendor && (vp->da->attr == PW_USER_PASSWORD)) continue;
+
+ /*
+ * Print all of the attributes, operator should always be '='.
+ */
+ op = vp->op;
+ vp->op = T_OP_EQ;
+ vp_print(out, vp);
+ vp->op = op;
+ }
+ }
+
+ /*
+ * Add non-protocol attributes.
+ */
+ if (compat) {
+#ifdef WITH_PROXY
+ if (request->proxy) {
+ char proxy_buffer[128];
+
+ inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr,
+ proxy_buffer, sizeof(proxy_buffer));
+ WRITE("\tFreeradius-Proxied-To = %s\n", proxy_buffer);
+ }
+#endif
+ }
+ WRITE("\tTimestamp = %ld\n", (unsigned long) request->timestamp);
+
+ WRITE("\n");
+
+ return 0;
+}
+
+/*
+ * Do detail, compatible with old accounting
+ */
+static rlm_rcode_t CC_HINT(nonnull) detail_do(void *instance, REQUEST *request, RADIUS_PACKET *packet, bool compat)
+{
+ int outfd, dupfd;
+ char buffer[DIRLEN];
+
+ FILE *outfp;
+
+#ifdef HAVE_GRP_H
+ gid_t gid;
+ char *endptr;
+#endif
+
+ rlm_detail_t *inst = instance;
+
+ /*
+ * Generate the path for the detail file. Use the same
+ * format, but truncate at the last /. Then feed it
+ * through radius_xlat() to expand the variables.
+ */
+ if (radius_xlat(buffer, sizeof(buffer), request, inst->filename, inst->escape_func, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ RDEBUG2("%s expands to %s", inst->filename, buffer);
+
+#ifdef WITH_ACCOUNTING
+#if defined(HAVE_FNMATCH_H) && defined(FNM_FILE_NAME)
+ /*
+ * If we read it from a detail file, and we're about to
+ * write it back to the SAME detail file directory, then
+ * suppress the write. This check prevents an infinite
+ * loop.
+ */
+ if (request->listener && (request->listener->type == RAD_LISTEN_DETAIL) &&
+ (fnmatch(((listen_detail_t *)request->listener->data)->filename,
+ buffer, FNM_FILE_NAME | FNM_PERIOD ) == 0)) {
+ RWDEBUG2("Suppressing infinite loop");
+ return RLM_MODULE_NOOP;
+ }
+#endif
+#endif
+
+ outfd = exfile_open(inst->ef, buffer, inst->perm, NULL);
+ if (outfd < 0) {
+ RERROR("Couldn't open file %s: %s", buffer, fr_strerror());
+ return RLM_MODULE_FAIL;
+ }
+
+ if (inst->group != NULL) {
+ gid = strtol(inst->group, &endptr, 10);
+ if (*endptr != '\0') {
+ if (rad_getgid(request, &gid, inst->group) < 0) {
+ RDEBUG2("Unable to find system group '%s'", inst->group);
+ goto skip_group;
+ }
+ }
+
+ if (chown(buffer, -1, gid) == -1) {
+ RDEBUG2("Unable to change system group of '%s'", buffer);
+ }
+ }
+
+skip_group:
+ /*
+ * Open the output fp for buffering.
+ */
+ outfp = NULL;
+ dupfd = dup(outfd);
+ if (dupfd < 0) {
+ RERROR("Failed to dup() file descriptor for detail file");
+ goto fail;
+ }
+
+ if ((outfp = fdopen(dupfd, "a")) == NULL) {
+ RERROR("Couldn't open file %s: %s", buffer, fr_syserror(errno));
+ fail:
+ if (outfp) fclose(outfp);
+ exfile_close(inst->ef, outfd);
+ return RLM_MODULE_FAIL;
+ }
+
+ if (detail_write(outfp, inst, request, packet, compat) < 0) goto fail;
+
+ /*
+ * Flush everything
+ */
+ fclose(outfp);
+ exfile_close(inst->ef, outfd);
+
+ /*
+ * And everything is fine.
+ */
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Accounting - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+#ifdef WITH_DETAIL
+ if (request->listener->type == RAD_LISTEN_DETAIL &&
+ strcmp(((rlm_detail_t *)instance)->filename,
+ ((listen_detail_t *)request->listener->data)->filename) == 0) {
+ RDEBUG("Suppressing writes to detail file as the request was just read from a detail file");
+ return RLM_MODULE_NOOP;
+ }
+#endif
+
+ return detail_do(instance, request, request->packet, true);
+}
+
+/*
+ * Incoming Access Request - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ return detail_do(instance, request, request->packet, false);
+}
+
+/*
+ * Outgoing Access-Request Reply - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ return detail_do(instance, request, request->reply, false);
+}
+
+#ifdef WITH_COA
+/*
+ * Incoming CoA - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
+{
+ return detail_do(instance, request, request->packet, false);
+}
+
+/*
+ * Outgoing CoA - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_send_coa(void *instance, REQUEST *request)
+{
+ return detail_do(instance, request, request->reply, false);
+}
+#endif
+
+/*
+ * Outgoing Access-Request to home server - write the detail files.
+ */
+#ifdef WITH_PROXY
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ if (request->proxy && request->proxy->vps) {
+ return detail_do(instance, request, request->proxy, false);
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+
+/*
+ * Outgoing Access-Request Reply - write the detail files.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
+{
+ if (request->proxy_reply && request->proxy_reply->vps) {
+ return detail_do(instance, request, request->proxy_reply, false);
+ }
+
+ /*
+ * No reply: we must be doing Post-Proxy-Type = Fail.
+ *
+ * Note that we just call the normal accounting function,
+ * to minimize the amount of code, and to highlight that
+ * it's doing normal accounting.
+ */
+ if (!request->proxy_reply) {
+ rlm_rcode_t rcode;
+
+ rcode = mod_accounting(instance, request);
+ if (rcode == RLM_MODULE_OK) {
+ request->reply->code = PW_CODE_ACCOUNTING_RESPONSE;
+ }
+ return rcode;
+ }
+
+ return RLM_MODULE_NOOP;
+}
+#endif
+
+/* globally exported name */
+extern module_t rlm_detail;
+module_t rlm_detail = {
+ .magic = RLM_MODULE_INIT,
+ .name = "detail",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_detail_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_accounting,
+ [MOD_ACCOUNTING] = mod_accounting,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ },
+};
+
diff --git a/src/modules/rlm_digest/README.md b/src/modules/rlm_digest/README.md
new file mode 100644
index 0000000..c21c0a6
--- /dev/null
+++ b/src/modules/rlm_digest/README.md
@@ -0,0 +1,11 @@
+# rlm_digest
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+The digest module performs HTTP digest authentication, usually for
+a SIP server. See draft-sterman-aaa-sip-00.txt for details. The
+module does not support RFC 5090.
diff --git a/src/modules/rlm_digest/all.mk b/src/modules/rlm_digest/all.mk
new file mode 100644
index 0000000..a02e547
--- /dev/null
+++ b/src/modules/rlm_digest/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_digest.a
+SOURCES := rlm_digest.c
diff --git a/src/modules/rlm_digest/rlm_digest.c b/src/modules/rlm_digest/rlm_digest.c
new file mode 100644
index 0000000..572e04d
--- /dev/null
+++ b/src/modules/rlm_digest/rlm_digest.c
@@ -0,0 +1,601 @@
+/*
+ * 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_digest.c
+ * @brief Handles SIP digest authentication requests from Cisco SIP servers.
+ *
+ * @copyright 2002,2006 The FreeRADIUS server project
+ * @copyright 2002 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/md5.h>
+
+static int digest_fix(REQUEST *request)
+{
+ VALUE_PAIR *first, *i;
+ vp_cursor_t cursor;
+
+ /*
+ * We need both of these attributes to do the authentication.
+ */
+ first = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_RESPONSE, 0, TAG_ANY);
+ if (!first) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Check the sanity of the attribute.
+ */
+ if (first->vp_length != 32) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Check for proper format of the Digest-Attributes
+ */
+ RDEBUG("Checking for correctly formatted Digest-Attributes");
+
+ first = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY);
+ if (!first) {
+ return RLM_MODULE_NOOP;
+ }
+
+ fr_cursor_init(&cursor, &first);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
+ int length = i->vp_length;
+ int attrlen;
+ uint8_t const *p = i->vp_octets;
+
+ /*
+ * Until this stupidly encoded attribute is exhausted.
+ */
+ while (length > 0) {
+ /*
+ * The attribute type must be valid
+ */
+ if ((p[0] == 0) || (p[0] > 10)) {
+ RDEBUG("Not formatted as Digest-Attributes: TLV type (%u) invalid", (unsigned int) p[0]);
+ return RLM_MODULE_NOOP;
+ }
+
+ attrlen = p[1]; /* stupid VSA format */
+
+ /*
+ * Too short.
+ */
+ if (attrlen < 3) {
+ RDEBUG("Not formatted as Digest-Attributes: TLV too short");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Too long.
+ */
+ if (attrlen > length) {
+ RDEBUG("Not formatted as Digest-Attributes: TLV too long)");
+ return RLM_MODULE_NOOP;
+ }
+
+ length -= attrlen;
+ p += attrlen;
+ } /* loop over this one attribute */
+ }
+
+ /*
+ * Convert them to something sane.
+ */
+ RDEBUG("Digest-Attributes look OK. Converting them to something more useful");
+ fr_cursor_first(&cursor);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY))) {
+ int length = i->vp_length;
+ int attrlen;
+ uint8_t const *p = &i->vp_octets[0];
+ VALUE_PAIR *sub;
+
+ /*
+ * Until this stupidly encoded attribute is exhausted.
+ */
+ while (length > 0) {
+ /*
+ * The attribute type must be valid
+ */
+ if ((p[0] == 0) || (p[0] > 10)) {
+ REDEBUG("Received Digest-Attributes with invalid sub-attribute %d", p[0]);
+ return RLM_MODULE_INVALID;
+ }
+
+ attrlen = p[1]; /* stupid VSA format */
+
+ /*
+ * Too short.
+ */
+ if (attrlen < 3) {
+ REDEBUG("Received Digest-Attributes with short sub-attribute %d, of length %d", p[0], attrlen);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Too long.
+ */
+ if (attrlen > length) {
+ REDEBUG("Received Digest-Attributes with long sub-attribute %d, of length %d", p[0], attrlen);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Create a new attribute, broken out of
+ * the stupid sub-attribute crap.
+ *
+ * Didn't they know that VSA's exist?
+ */
+ sub = radius_pair_create(request->packet, &request->packet->vps,
+ PW_DIGEST_REALM - 1 + p[0], 0);
+ fr_pair_value_bstrncpy(sub, p + 2, attrlen - 2);
+
+ if ((rad_debug_lvl > 1) && fr_log_fp) {
+ vp_print(fr_log_fp, sub);
+ }
+
+ /*
+ * FIXME: Check for the existence
+ * of the necessary attributes!
+ */
+
+ length -= attrlen;
+ p += attrlen;
+ } /* loop over this one attribute */
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode;
+
+ /*
+ * Double-check and fix the attributes.
+ */
+ rcode = digest_fix(request);
+ if (rcode != RLM_MODULE_OK) return rcode;
+
+
+ if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY)) {
+ RWDEBUG2("Auth-Type already set. Not setting to DIGEST");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Everything's OK, add a digest authentication type.
+ */
+ RDEBUG("Adding Auth-Type = DIGEST");
+ pair_make_config("Auth-Type", "DIGEST", T_OP_EQ);
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Perform all of the wondrous variants of digest authentication.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
+{
+ int i;
+ size_t a1_len, a2_len, kd_len;
+ uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
+ uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
+ uint8_t kd[(MAX_STRING_LEN + 1) * 5];
+ uint8_t hash[16]; /* MD5 output */
+ VALUE_PAIR *vp, *passwd, *algo;
+ VALUE_PAIR *qop, *nonce;
+
+ /*
+ * We require access to the plain-text password, or to the
+ * Digest-HA1 parameter.
+ */
+ passwd = fr_pair_find_by_num(request->config, PW_DIGEST_HA1, 0, TAG_ANY);
+ if (passwd) {
+ if (passwd->vp_length != 32) {
+ RAUTH("Digest-HA1 has invalid length, authentication failed");
+ return RLM_MODULE_INVALID;
+ }
+ } else {
+ passwd = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ }
+ if (!passwd) {
+ RAUTH("Cleartext-Password or Digest-HA1 is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * We need these, too.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0, TAG_ANY);
+ if (!vp) {
+ error:
+ REDEBUG("You set 'Auth-Type = Digest' for a request that does not contain any digest attributes!");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Look for the "internal" FreeRADIUS Digest attributes.
+ * If they don't exist, it means that someone forced
+ * Auth-Type = digest, without putting "digest" into the
+ * "authorize" section. In that case, try to decode the
+ * attributes here.
+ */
+ if (!fr_pair_find_by_num(request->packet->vps, PW_DIGEST_NONCE, 0, TAG_ANY)) {
+ int rcode;
+
+ rcode = digest_fix(request);
+
+ /*
+ * NOOP means "couldn't find the attributes".
+ * That's bad.
+ */
+ if (rcode == RLM_MODULE_NOOP) goto error;
+
+ if (rcode != RLM_MODULE_OK) return rcode;
+ }
+
+ /*
+ * We require access to the Digest-Nonce-Value
+ */
+ nonce = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_NONCE, 0, TAG_ANY);
+ if (!nonce) {
+ REDEBUG("No Digest-Nonce: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * A1 = Digest-User-Name ":" Realm ":" Password
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-User-Name: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a1[0], vp->vp_octets, vp->vp_length);
+ a1_len = vp->vp_length;
+
+ a1[a1_len] = ':';
+ a1_len++;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_REALM, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-Realm: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a1[a1_len], vp->vp_octets, vp->vp_length);
+ a1_len += vp->vp_length;
+
+ a1[a1_len] = ':';
+ a1_len++;
+
+ if (passwd->da->attr == PW_CLEARTEXT_PASSWORD) {
+ memcpy(&a1[a1_len], passwd->vp_octets, passwd->vp_length);
+ a1_len += passwd->vp_length;
+ a1[a1_len] = '\0';
+ RDEBUG2("A1 = %s", a1);
+ } else {
+ a1[a1_len] = '\0';
+ RDEBUG2("A1 = %s (using Digest-HA1)", a1);
+ a1_len = 16;
+ }
+
+ /*
+ * See which variant we calculate.
+ * Assume MD5 if no Digest-Algorithm attribute received
+ */
+ algo = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_ALGORITHM, 0, TAG_ANY);
+ if ((!algo) ||
+ (strcasecmp(algo->vp_strvalue, "MD5") == 0)) {
+ /*
+ * Set A1 to Digest-HA1 if no User-Password found
+ */
+ if (passwd->da->attr == PW_DIGEST_HA1) {
+ if (fr_hex2bin(&a1[0], sizeof(a1), passwd->vp_strvalue, passwd->vp_length) != 16) {
+ RDEBUG2("Invalid text in Digest-HA1");
+ return RLM_MODULE_INVALID;
+ }
+ }
+
+ } else if (strcasecmp(algo->vp_strvalue, "MD5-sess") == 0) {
+ /*
+ * K1 = H(A1) : Digest-Nonce ... : H(A2)
+ *
+ * If we find Digest-HA1, we assume it contains
+ * H(A1).
+ */
+ if (passwd->da->attr == PW_CLEARTEXT_PASSWORD) {
+ fr_md5_calc(hash, &a1[0], a1_len);
+ fr_bin2hex((char *) &a1[0], hash, 16);
+ } else { /* MUST be Digest-HA1 */
+ memcpy(&a1[0], passwd->vp_strvalue, 32);
+ }
+ a1_len = 32;
+
+ a1[a1_len] = ':';
+ a1_len++;
+
+ /*
+ * Tack on the Digest-Nonce. Length must be even
+ */
+ if ((nonce->vp_length & 1) != 0) {
+ REDEBUG("Received Digest-Nonce hex string with invalid length: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a1[a1_len], nonce->vp_octets, nonce->vp_length);
+ a1_len += nonce->vp_length;
+
+ a1[a1_len] = ':';
+ a1_len++;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_CNONCE, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-CNonce: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Digest-CNonce length must be even
+ */
+ if ((vp->vp_length & 1) != 0) {
+ REDEBUG("Received Digest-CNonce hex string with invalid length: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a1[a1_len], vp->vp_octets, vp->vp_length);
+ a1_len += vp->vp_length;
+
+ } else if (strcasecmp(algo->vp_strvalue, "MD5") != 0) {
+ /*
+ * We check for "MD5-sess" and "MD5".
+ * Anything else is an error.
+ */
+ REDEBUG("Unknown Digest-Algorithm \"%s\": Cannot perform Digest authentication", vp->vp_strvalue);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * A2 = Digest-Method ":" Digest-URI
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_METHOD, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-Method: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a2[0], vp->vp_octets, vp->vp_length);
+ a2_len = vp->vp_length;
+
+ a2[a2_len] = ':';
+ a2_len++;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_URI, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-URI: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&a2[a2_len], vp->vp_octets, vp->vp_length);
+ a2_len += vp->vp_length;
+
+ /*
+ * QOP is "auth-int", tack on ": Digest-Body-Digest"
+ */
+ qop = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_QOP, 0, TAG_ANY);
+ if (qop) {
+ if (strcasecmp(qop->vp_strvalue, "auth-int") == 0) {
+ VALUE_PAIR *body;
+
+ /*
+ * Add in Digest-Body-Digest
+ */
+ a2[a2_len] = ':';
+ a2_len++;
+
+ /*
+ * Must be a hex representation of an MD5 digest.
+ */
+ body = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_BODY_DIGEST, 0, TAG_ANY);
+ if (!body) {
+ REDEBUG("No Digest-Body-Digest: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ if ((a2_len + body->vp_length) > sizeof(a2)) {
+ REDEBUG("Digest-Body-Digest is too long");
+ return RLM_MODULE_INVALID;
+ }
+
+ memcpy(a2 + a2_len, body->vp_octets, body->vp_length);
+ a2_len += body->vp_length;
+
+ } else if (strcasecmp(qop->vp_strvalue, "auth") != 0) {
+ REDEBUG("Unknown Digest-QOP \"%s\": Cannot perform Digest authentication", qop->vp_strvalue);
+ return RLM_MODULE_INVALID;
+ }
+ }
+
+ a2[a2_len] = '\0';
+ RDEBUG2("A2 = %s", a2);
+
+ /*
+ * KD = H(A1) : Digest-Nonce ... : H(A2).
+ * Compute MD5 if Digest-Algorithm == "MD5-Sess",
+ * or if we found a User-Password.
+ */
+ if (((algo != NULL) &&
+ (strcasecmp(algo->vp_strvalue, "MD5-Sess") == 0)) ||
+ (passwd->da->attr == PW_CLEARTEXT_PASSWORD)) {
+ a1[a1_len] = '\0';
+ fr_md5_calc(&hash[0], &a1[0], a1_len);
+ } else {
+ memcpy(&hash[0], &a1[0], a1_len);
+ }
+ fr_bin2hex((char *) kd, hash, sizeof(hash));
+
+#ifndef NRDEBUG
+ if (rad_debug_lvl > 1) {
+ fr_printf_log("H(A1) = ");
+ for (i = 0; i < 16; i++) {
+ fr_printf_log("%02x", hash[i]);
+ }
+ fr_printf_log("\n");
+ }
+#endif
+ kd_len = 32;
+
+ kd[kd_len] = ':';
+ kd_len++;
+
+ memcpy(&kd[kd_len], nonce->vp_octets, nonce->vp_length);
+ kd_len += nonce->vp_length;
+
+ /*
+ * No QOP defined. Do RFC 2069 compatibility.
+ */
+ if (!qop) {
+ /*
+ * Do nothing here.
+ */
+
+ } else { /* Digest-QOP MUST be "auth" or "auth-int" */
+ /*
+ * Tack on ":" Digest-Nonce-Count ":" Digest-CNonce
+ * ":" Digest-QOP
+ */
+ kd[kd_len] = ':';
+ kd_len++;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_NONCE_COUNT, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-Nonce-Count: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&kd[kd_len], vp->vp_octets, vp->vp_length);
+ kd_len += vp->vp_length;
+
+ kd[kd_len] = ':';
+ kd_len++;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_CNONCE, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-CNonce: Cannot perform Digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+ memcpy(&kd[kd_len], vp->vp_octets, vp->vp_length);
+ kd_len += vp->vp_length;
+
+ kd[kd_len] = ':';
+ kd_len++;
+
+ memcpy(&kd[kd_len], qop->vp_octets, qop->vp_length);
+ kd_len += qop->vp_length;
+ }
+
+ /*
+ * Tack on ":" H(A2)
+ */
+ kd[kd_len] = ':';
+ kd_len++;
+
+ fr_md5_calc(&hash[0], &a2[0], a2_len);
+
+ fr_bin2hex((char *) kd + kd_len, hash, sizeof(hash));
+
+#ifndef NRDEBUG
+ if (rad_debug_lvl > 1) {
+ fr_printf_log("H(A2) = ");
+ for (i = 0; i < 16; i++) {
+ fr_printf_log("%02x", hash[i]);
+ }
+ fr_printf_log("\n");
+ }
+#endif
+ kd_len += 32;
+
+ kd[kd_len] = 0;
+
+ RDEBUG2("KD = %s\n", &kd[0]);
+
+ /*
+ * Take the hash of KD.
+ */
+ fr_md5_calc(&hash[0], &kd[0], kd_len);
+ memcpy(&kd[0], &hash[0], 16);
+
+ /*
+ * Get the binary value of Digest-Response
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_DIGEST_RESPONSE, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG("No Digest-Response attribute in the request. Cannot perform digest authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (fr_hex2bin(&hash[0], sizeof(hash), vp->vp_strvalue, vp->vp_length) != (vp->vp_length >> 1)) {
+ RDEBUG2("Invalid text in Digest-Response");
+ return RLM_MODULE_INVALID;
+ }
+
+#ifndef NRDEBUG
+ if (rad_debug_lvl > 1) {
+ fr_printf_log("EXPECTED ");
+ for (i = 0; i < 16; i++) {
+ fr_printf_log("%02x", kd[i]);
+ }
+ fr_printf_log("\n");
+
+ fr_printf_log("RECEIVED ");
+ for (i = 0; i < 16; i++) {
+ fr_printf_log("%02x", hash[i]);
+ }
+ fr_printf_log("\n");
+ }
+#endif
+
+ /*
+ * And finally, compare the digest in the packet with KD.
+ */
+ if (memcmp(&kd[0], &hash[0], 16) == 0) {
+ return RLM_MODULE_OK;
+ }
+
+ RDEBUG("FAILED authentication");
+ return RLM_MODULE_REJECT;
+}
+
+/*
+ * 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_digest;
+module_t rlm_digest = {
+ .magic = RLM_MODULE_INIT,
+ .name = "digest",
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_dynamic_clients/README.md b/src/modules/rlm_dynamic_clients/README.md
new file mode 100644
index 0000000..bb73eb8
--- /dev/null
+++ b/src/modules/rlm_dynamic_clients/README.md
@@ -0,0 +1,10 @@
+# rlm_dynamic_clients
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Provides a way to load RADIUS clients as needed, rather than when
+the server starts.
diff --git a/src/modules/rlm_dynamic_clients/all.mk b/src/modules/rlm_dynamic_clients/all.mk
new file mode 100644
index 0000000..c93bee8
--- /dev/null
+++ b/src/modules/rlm_dynamic_clients/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_dynamic_clients.a
+SOURCES := rlm_dynamic_clients.c
diff --git a/src/modules/rlm_dynamic_clients/rlm_dynamic_clients.c b/src/modules/rlm_dynamic_clients/rlm_dynamic_clients.c
new file mode 100644
index 0000000..299ac11
--- /dev/null
+++ b/src/modules/rlm_dynamic_clients/rlm_dynamic_clients.c
@@ -0,0 +1,119 @@
+/*
+ * 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_dynamic_clients.c
+ * @brief Reads client definitions from flat files as required.
+ *
+ * @copyright 2008 The FreeRADIUS server project
+ * @copyright 2008 Alan DeKok <aland@deployingradius.com>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#ifdef WITH_DYNAMIC_CLIENTS
+/*
+ * Find the client definition.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance,
+ REQUEST *request)
+{
+ size_t length;
+ char const *value;
+ CONF_PAIR *cp;
+ RADCLIENT *c;
+ char buffer[2048];
+
+ /*
+ * Ensure we're only being called from the main thread,
+ * with fake packets.
+ */
+ if ((request->packet->vps != NULL) || (request->parent != NULL)) {
+ RDEBUG("Cannot use `dynamic_clients` for normal packets");
+ return RLM_MODULE_NOOP;
+ }
+
+ if (!request->client || !request->client->cs) {
+ RDEBUG("Unknown client definition");
+ return RLM_MODULE_NOOP;
+ }
+
+ cp = cf_pair_find(request->client->cs, "directory");
+ if (!cp) {
+ RDEBUG("No directory configuration in the client");
+ return RLM_MODULE_NOOP;
+ }
+
+ value = cf_pair_value(cp);
+ if (!value) {
+ RDEBUG("No value given for the directory entry in the client");
+ return RLM_MODULE_NOOP;
+ }
+
+ length = strlen(value);
+ if (length > (sizeof(buffer) - 256)) {
+ RDEBUG("Directory name too long");
+ return RLM_MODULE_NOOP;
+ }
+
+ memcpy(buffer, value, length + 1);
+ ip_ntoh(&request->packet->src_ipaddr,
+ buffer + length, sizeof(buffer) - length - 1);
+
+ /*
+ * Read the buffer and generate the client.
+ */
+ c = client_read(buffer, (request->client->server != NULL), true);
+ if (!c) return RLM_MODULE_FAIL;
+
+ /*
+ * Replace the client. This is more than a bit of a
+ * hack.
+ */
+ request->client = c;
+ c->dynamic = true;
+
+ return RLM_MODULE_OK;
+}
+#else
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ RDEBUG("Dynamic clients are unsupported in this build");
+ return RLM_MODULE_FAIL;
+}
+#endif
+
+/*
+ * 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_dynamic_clients;
+module_t rlm_dynamic_clients = {
+ .magic = RLM_MODULE_INIT,
+ .name = "dynamic_clients",
+ .type = RLM_TYPE_THREAD_SAFE, /* type */
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_eap/.gitignore b/src/modules/rlm_eap/.gitignore
new file mode 100644
index 0000000..e713fa7
--- /dev/null
+++ b/src/modules/rlm_eap/.gitignore
@@ -0,0 +1 @@
+radeapclient
diff --git a/src/modules/rlm_eap/README.md b/src/modules/rlm_eap/README.md
new file mode 100644
index 0000000..54cce8f
--- /dev/null
+++ b/src/modules/rlm_eap/README.md
@@ -0,0 +1,11 @@
+# rlm_eap
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Implements the base protocol for EAP (Extensible Authentication Protocol).
+
+EAP is commonly used to authenticate 802.1X and PPP (Point to Point Protocol) sessions.
diff --git a/src/modules/rlm_eap/all.mk b/src/modules/rlm_eap/all.mk
new file mode 100644
index 0000000..f2cb44b
--- /dev/null
+++ b/src/modules/rlm_eap/all.mk
@@ -0,0 +1 @@
+SUBMAKEFILES := libeap/all.mk rlm_eap.mk types/all.mk radeapclient.mk
diff --git a/src/modules/rlm_eap/configure b/src/modules/rlm_eap/configure
new file mode 100755
index 0000000..a87f8b0
--- /dev/null
+++ b/src/modules/rlm_eap/configure
@@ -0,0 +1,3557 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap.c"
+enable_option_checking=no
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+eaptypes
+mod_cflags
+mod_ldflags
+targetname
+subdirs
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+ac_subdirs_all='$eapsubdirs'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap build without rlm_eap
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap was given.
+if test "${with_rlm_eap+set}" = set; then :
+ withval=$with_rlm_eap;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+eapsubdirs=
+for foo in `find ./types -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ eapsubdirs="$eapsubdirs $bar"
+done
+
+ln -s ../../../install-sh install-sh
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+
+subdirs="$subdirs $eapsubdirs"
+
+rm install-sh
+
+
+ targetname=rlm_eap
+else
+ targetname=
+ echo \*\*\* module rlm_eap is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+if test x"$fail" != x""; then :
+ eapsubdirs=""
+fi
+
+
+eaptypes=types
+if test x"$eapsubdirs" = x""; then
+ eaptypes=""
+fi
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+ # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+ # so they do not pile up.
+ ac_sub_configure_args=
+ ac_prev=
+ eval "set x $ac_configure_args"
+ shift
+ for ac_arg
+ do
+ if test -n "$ac_prev"; then
+ ac_prev=
+ continue
+ fi
+ case $ac_arg in
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
+ | --c=*)
+ ;;
+ --config-cache | -C)
+ ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ ;;
+ --disable-option-checking)
+ ;;
+ *)
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+ esac
+ done
+
+ # Always prepend --prefix to ensure using the same prefix
+ # in subdir configurations.
+ ac_arg="--prefix=$prefix"
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+ # Pass --silent
+ if test "$silent" = yes; then
+ ac_sub_configure_args="--silent $ac_sub_configure_args"
+ fi
+
+ # Always prepend --disable-option-checking to silence warnings, since
+ # different subdirs can have different --enable and --with options.
+ ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+ ac_popdir=`pwd`
+ for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+ # Do not complain, so a configure script can configure whichever
+ # parts of a large source tree are present.
+ test -d "$srcdir/$ac_dir" || continue
+
+ ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+ $as_echo "$ac_msg" >&6
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ cd "$ac_dir"
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ ac_sub_configure=$ac_srcdir/configure.gnu
+ elif test -f "$ac_srcdir/configure"; then
+ ac_sub_configure=$ac_srcdir/configure
+ elif test -f "$ac_srcdir/configure.in"; then
+ # This should be Cygnus configure.
+ ac_sub_configure=$ac_aux_dir/configure
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+ ac_sub_configure=
+ fi
+
+ # The recursion is here.
+ if test -n "$ac_sub_configure"; then
+ # Make the cache file name correct relative to the subdirectory.
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+ *) # Relative name.
+ ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+ # The eval makes quoting arguments work.
+ eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+ as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+ fi
+
+ cd "$ac_popdir"
+ done
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/configure.ac b/src/modules/rlm_eap/configure.ac
new file mode 100644
index 0000000..dfa13e9
--- /dev/null
+++ b/src/modules/rlm_eap/configure.ac
@@ -0,0 +1,42 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+
+eapsubdirs=
+for foo in `find ./types -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ eapsubdirs="$eapsubdirs $bar"
+done
+
+dnl # don't ask... this is done to avoid autoconf stupidities.
+ln -s ../../../install-sh install-sh
+
+AC_CONFIG_SUBDIRS($eapsubdirs)
+rm install-sh
+
+FR_MODULE_END_TESTS
+
+FR_MODULE_TEST_FAIL_DO([eapsubdirs=""])
+
+eaptypes=types
+if test x"$eapsubdirs" = x""; then
+ eaptypes=""
+fi
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+AC_SUBST(eaptypes)
+
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/eap.c b/src/modules/rlm_eap/eap.c
new file mode 100644
index 0000000..1ece323
--- /dev/null
+++ b/src/modules/rlm_eap/eap.c
@@ -0,0 +1,1270 @@
+/*
+ * eap.c rfc2284 & rfc2869 implementation
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2003,2006 The FreeRADIUS server project
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ */
+/*
+ * EAP PACKET FORMAT
+ * --- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data ...
+ * +-+-+-+-+
+ *
+ *
+ * EAP Request and Response Packet Format
+ * --- ------- --- -------- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Type-Data ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ *
+ *
+ * EAP Success and Failure Packet Format
+ * --- ------- --- ------- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+#include <freeradius-devel/modpriv.h>
+
+RCSID("$Id$")
+
+#include "rlm_eap.h"
+#include <ctype.h>
+
+static char const *eap_codes[] = {
+ "", /* 0 is invalid */
+ "Request",
+ "Response",
+ "Success",
+ "Failure"
+};
+
+static int _eap_module_free(eap_module_t *inst)
+{
+ /*
+ * We have to check inst->type as it's only allocated
+ * if we loaded the eap method.
+ */
+ if (inst->type && inst->type->detach) (inst->type->detach)(inst->instance);
+
+#ifndef NDEBUG
+ /*
+ * Don't dlclose() modules if we're doing memory
+ * debugging. This removes the symbols needed by
+ * valgrind.
+ */
+ if (!main_config.debug_memory)
+#endif
+ if (inst->handle) dlclose(inst->handle);
+
+ return 0;
+}
+
+/** Load required EAP sub-modules (methods)
+ *
+ */
+int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **m_inst, eap_type_t num, CONF_SECTION *cs)
+{
+ eap_module_t *method;
+ char *mod_name, *p;
+
+ /* Make room for the EAP-Type */
+ *m_inst = method = talloc_zero(cs, eap_module_t);
+ if (!inst) return -1;
+
+ talloc_set_destructor(method, _eap_module_free);
+
+ /* fill in the structure */
+ method->cs = cs;
+ method->name = eap_type2name(num);
+
+ /*
+ * The name of the module were trying to load
+ */
+ mod_name = talloc_typed_asprintf(method, "rlm_eap_%s", method->name);
+
+ /*
+ * dlopen is case sensitive
+ */
+ p = mod_name;
+ while (*p) {
+ *p = tolower((uint8_t) *p);
+ p++;
+ }
+
+ /*
+ * Link the loaded EAP-Type
+ */
+ method->handle = fr_dlopenext(mod_name);
+ if (!method->handle) {
+ ERROR("rlm_eap (%s): Failed to link %s: %s", inst->xlat_name, mod_name, fr_strerror());
+
+ return -1;
+ }
+
+ method->type = dlsym(method->handle, mod_name);
+ if (!method->type) {
+ ERROR("rlm_eap (%s): Failed linking to structure in %s: %s", inst->xlat_name,
+ method->name, dlerror());
+
+ return -1;
+ }
+
+ cf_log_module(cs, "Linked to sub-module %s", mod_name);
+
+ /*
+ * Call the attach num in the EAP num module
+ */
+ if ((method->type->instantiate) && ((method->type->instantiate)(method->cs, &(method->instance)) < 0)) {
+ ERROR("rlm_eap (%s): Failed to initialise %s", inst->xlat_name, mod_name);
+
+ if (method->instance) {
+ (void) talloc_steal(method, method->instance);
+ }
+
+ return -1;
+ }
+
+ if (method->instance) {
+ (void) talloc_steal(method, method->instance);
+ }
+
+ return 0;
+}
+
+/*
+ * Call the appropriate handle with the right eap_method.
+ */
+static int eap_module_call(eap_module_t *module, eap_handler_t *handler)
+{
+ int rcode = 1;
+ REQUEST *request = handler->request;
+
+ char const *caller = request->module;
+
+ rad_assert(module != NULL);
+
+ RDEBUG2("Calling submodule %s to process data", module->type->name);
+
+ request->module = module->type->name;
+
+ switch (handler->stage) {
+ case INITIATE:
+ if (!module->type->session_init(module->instance, handler)) {
+ rcode = 0;
+ }
+
+ break;
+
+ case PROCESS:
+ /*
+ * The called function updates the EAP reply packet.
+ */
+ if (!module->type->process ||
+ !module->type->process(module->instance, handler)) {
+ rcode = 0;
+ }
+
+ break;
+
+ default:
+ /* Should never enter here */
+ RDEBUG("Internal sanity check failed on EAP");
+ rcode = 0;
+ break;
+ }
+
+ request->module = caller;
+ return rcode;
+}
+
+/** Process NAK data from EAP peer
+ *
+ */
+static eap_type_t eap_process_nak(rlm_eap_t *inst, REQUEST *request,
+ eap_type_t type,
+ eap_type_data_t *nak)
+{
+ unsigned int i;
+ VALUE_PAIR *vp;
+ eap_type_t method = PW_EAP_INVALID;
+
+ /*
+ * The NAK data is the preferred EAP type(s) of
+ * the client.
+ *
+ * RFC 3748 says to list one or more proposed
+ * alternative types, one per octet, or to use
+ * 0 for no alternative.
+ */
+ if (!nak->data) {
+ REDEBUG("Peer sent empty (invalid) NAK. "
+ "Can't select method to continue with");
+
+ return PW_EAP_INVALID;
+ }
+
+ /*
+ * Pick one type out of the one they asked for,
+ * as they may have asked for many.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_EAP_TYPE, 0, TAG_ANY);
+ for (i = 0; i < nak->length; i++) {
+ /*
+ * Type 0 is valid, and means there are no
+ * common choices.
+ */
+ if (nak->data[i] == 0) {
+ RDEBUG("Peer NAK'd indicating it is not willing to "
+ "continue ");
+
+ return PW_EAP_INVALID;
+ }
+
+ /*
+ * It is invalid to request identity,
+ * notification & nak in nak.
+ */
+ if (nak->data[i] < PW_EAP_MD5) {
+ REDEBUG("Peer NAK'd asking for bad "
+ "type %s (%d)",
+ eap_type2name(nak->data[i]),
+ nak->data[i]);
+
+ return PW_EAP_INVALID;
+ }
+
+ if ((nak->data[i] >= PW_EAP_MAX_TYPES) ||
+ !inst->methods[nak->data[i]]) {
+ RDEBUG2("Peer NAK'd asking for "
+ "unsupported EAP type %s (%d), skipping...",
+ eap_type2name(nak->data[i]),
+ nak->data[i]);
+
+ continue;
+ }
+
+ /*
+ * Prevent a firestorm if the client is confused.
+ */
+ if (type == nak->data[i]) {
+ RDEBUG2("Peer NAK'd our request for "
+ "%s (%d) with a request for "
+ "%s (%d), skipping...",
+ eap_type2name(nak->data[i]),
+ nak->data[i],
+ eap_type2name(nak->data[i]),
+ nak->data[i]);
+
+ RWARN("!!! We requested to use an EAP type as normal.");
+ RWARN("!!! The supplicant rejected that, and requested to use the same EAP type.");
+ RWARN("!!! i.e. the supplicant said 'I don't like X, please use X instead.");
+ RWARN("!!! The supplicant software is broken and does not work properly.");
+ RWARN("!!! Please upgrade it to software that works.");
+
+ continue;
+ }
+
+ /*
+ * Enforce per-user configuration of EAP
+ * types.
+ */
+ if (vp && (vp->vp_integer != nak->data[i])) {
+ RDEBUG2("Peer wants %s (%d), while we "
+ "require %s (%d), skipping",
+ eap_type2name(nak->data[i]),
+ nak->data[i],
+ eap_type2name(vp->vp_integer),
+ vp->vp_integer);
+
+ continue;
+ }
+
+ RDEBUG("Found mutually acceptable type %s (%d)",
+ eap_type2name(nak->data[i]), nak->data[i]);
+
+ method = nak->data[i];
+
+ break;
+ }
+
+ if (method == PW_EAP_INVALID) {
+ REDEBUG("No mutually acceptable types found");
+ }
+
+ return method;
+}
+
+/** Select the correct callback based on a response
+ *
+ * Based on the EAP response from the supplicant, call the appropriate
+ * method callback.
+ *
+ * Default to the configured EAP-Type for all Unsupported EAP-Types.
+ *
+ * @param inst Configuration data for this instance of rlm_eap.
+ * @param handler State data that persists over multiple rounds of EAP.
+ * @return a status code.
+ */
+eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler)
+{
+ eap_type_data_t *type = &handler->eap_ds->response->type;
+ REQUEST *request = handler->request;
+
+ eap_type_t next = inst->default_method;
+ VALUE_PAIR *vp;
+
+ /*
+ * Don't trust anyone.
+ */
+ if ((type->num == 0) || (type->num >= PW_EAP_MAX_TYPES)) {
+ REDEBUG("Peer sent EAP method number %d, which is outside known range", type->num);
+
+ return EAP_INVALID;
+ }
+
+ /*
+ * Multiple levels of TLS nesting are invalid. But if
+ * the parent has a home_server defined, then this
+ * request is being processed through a virtual
+ * server... so that's OK.
+ *
+ * i.e. we're inside an EAP tunnel, which means we have a
+ * parent. If the outer session exists, and doesn't have
+ * a home server, then it's multiple layers of tunneling.
+ */
+ if (handler->request->parent &&
+ handler->request->parent->parent &&
+ !handler->request->parent->parent->home_server) {
+ RERROR("Multiple levels of TLS nesting are invalid");
+
+ return EAP_INVALID;
+ }
+
+ RDEBUG2("Peer sent packet with method EAP %s (%d)", eap_type2name(type->num), type->num);
+ /*
+ * Figure out what to do.
+ */
+ switch (type->num) {
+ case PW_EAP_IDENTITY:
+ /*
+ * Allow per-user configuration of EAP types.
+ */
+ vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TYPE, 0,
+ TAG_ANY);
+ if (vp) next = vp->vp_integer;
+
+ /*
+ * Ensure it's valid.
+ */
+ if ((next < PW_EAP_MD5) ||
+ (next >= PW_EAP_MAX_TYPES) ||
+ (!inst->methods[next])) {
+ REDEBUG2("Tried to start unsupported EAP type %s (%d)",
+ eap_type2name(next), next);
+
+ return EAP_INVALID;
+ }
+
+ do_initiate:
+ /*
+ * If any of these fail, we messed badly somewhere
+ */
+ rad_assert(next >= PW_EAP_MD5);
+ rad_assert(next < PW_EAP_MAX_TYPES);
+ rad_assert(inst->methods[next]);
+
+ handler->stage = INITIATE;
+ handler->type = next;
+
+ if (eap_module_call(inst->methods[next], handler) == 0) {
+ REDEBUG2("Failed starting EAP %s (%d) session. EAP sub-module failed",
+ eap_type2name(next), next);
+
+ return EAP_INVALID;
+ }
+ break;
+
+ case PW_EAP_NAK:
+ /*
+ * Delete old data, if necessary.
+ */
+ if (handler->opaque && handler->free_opaque) {
+ handler->free_opaque(handler->opaque);
+ handler->free_opaque = NULL;
+ handler->opaque = NULL;
+ }
+
+ /*
+ * We got a NAK after the peer started doing a
+ * particular EAP type. That's rude, tell the
+ * peer to go away.
+ */
+ if (handler->started) return EAP_INVALID;
+
+ next = eap_process_nak(inst, handler->request,
+ handler->type, type);
+
+ /*
+ * We probably want to return 'fail' here...
+ */
+ if (!next) {
+ return EAP_INVALID;
+ }
+
+ goto do_initiate;
+
+ /*
+ * Key off of the configured sub-modules.
+ */
+ default:
+ /*
+ * We haven't configured it, it doesn't exist.
+ */
+ if (!inst->methods[type->num]) {
+ REDEBUG2("Client asked for unsupported EAP type %s (%d)",
+ eap_type2name(type->num),
+ type->num);
+
+ return EAP_INVALID;
+ }
+
+ rad_assert(handler->stage == PROCESS);
+ handler->type = type->num;
+ if (eap_module_call(inst->methods[type->num],
+ handler) == 0) {
+ REDEBUG2("Failed continuing EAP %s (%d) session. EAP sub-module failed",
+ eap_type2name(type->num),
+ type->num);
+
+ return EAP_INVALID;
+ }
+ handler->started = true;
+ break;
+ }
+
+ return EAP_OK;
+}
+
+
+/*
+ * compose EAP reply packet in EAP-Message attr of RADIUS.
+ *
+ * Set the RADIUS reply codes based on EAP request codes. Append
+ * any additonal VPs to RADIUS reply
+ */
+rlm_rcode_t eap_compose(eap_handler_t *handler)
+{
+ VALUE_PAIR *vp;
+ eap_packet_raw_t *eap_packet;
+ REQUEST *request;
+ EAP_DS *eap_ds;
+ eap_packet_t *reply;
+ int rcode;
+
+#ifndef NDEBUG
+ handler = talloc_get_type_abort(handler, eap_handler_t);
+ request = talloc_get_type_abort(handler->request, REQUEST);
+ eap_ds = talloc_get_type_abort(handler->eap_ds, EAP_DS);
+ reply = talloc_get_type_abort(eap_ds->request, eap_packet_t);
+#else
+ request = handler->request;
+ eap_ds = handler->eap_ds;
+ reply = eap_ds->request;
+#endif
+
+ /*
+ * The Id for the EAP packet to the NAS wasn't set.
+ * Do so now.
+ */
+ if (!eap_ds->set_request_id) {
+ /*
+ * Id serves to suppport request/response
+ * retransmission in the EAP layer and as such
+ * must be different for 'adjacent' packets
+ * except in case of success/failure-replies.
+ *
+ * RFC2716 (EAP-TLS) requires this to be
+ * incremented, RFC2284 only makes the above-
+ * mentioned restriction.
+ */
+ reply->id = handler->eap_ds->response->id;
+
+ switch (reply->code) {
+ /*
+ * The Id is a simple "ack" for success
+ * and failure.
+ *
+ * RFC 3748 section 4.2 says
+ *
+ * ... The Identifier field MUST match
+ * the Identifier field of the Response
+ * packet that it is sent in response
+ * to.
+ */
+ case PW_EAP_SUCCESS:
+ case PW_EAP_FAILURE:
+ break;
+
+ /*
+ * We've sent a response to their
+ * request, the Id is incremented.
+ */
+ default:
+ ++reply->id;
+ }
+ }
+
+ /*
+ * For Request & Response packets, set the EAP sub-type,
+ * if the EAP sub-module didn't already set it.
+ *
+ * This allows the TLS module to be "morphic", and means
+ * that the TTLS and PEAP modules can call it to do most
+ * of their dirty work.
+ */
+ if (((eap_ds->request->code == PW_EAP_REQUEST) ||
+ (eap_ds->request->code == PW_EAP_RESPONSE)) &&
+ (eap_ds->request->type.num == 0)) {
+ rad_assert(handler->type >= PW_EAP_MD5);
+ rad_assert(handler->type < PW_EAP_MAX_TYPES);
+
+ eap_ds->request->type.num = handler->type;
+ }
+
+ if (eap_wireformat(reply) == EAP_INVALID) {
+ return RLM_MODULE_INVALID;
+ }
+ eap_packet = (eap_packet_raw_t *)reply->packet;
+
+ vp = radius_pair_create(request->reply, &request->reply->vps, PW_EAP_MESSAGE, 0);
+ if (!vp) return RLM_MODULE_INVALID;
+
+ vp->vp_length = eap_packet->length[0] * 256 + eap_packet->length[1];
+ vp->vp_octets = talloc_steal(vp, reply->packet);
+ reply->packet = NULL;
+
+ /*
+ * EAP-Message is always associated with
+ * Message-Authenticator but not vice-versa.
+ *
+ * Don't add a Message-Authenticator if it's already
+ * there.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(request->reply, PW_MESSAGE_AUTHENTICATOR, 0);
+ vp->vp_length = AUTH_VECTOR_LEN;
+ vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length);
+ fr_pair_add(&(request->reply->vps), vp);
+ }
+
+ /* Set request reply code, but only if it's not already set. */
+ rcode = RLM_MODULE_OK;
+ if (!request->reply->code) switch (reply->code) {
+ case PW_EAP_RESPONSE:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ rcode = RLM_MODULE_REJECT;
+ break;
+ case PW_EAP_SUCCESS:
+ request->reply->code = PW_CODE_ACCESS_ACCEPT;
+ rcode = RLM_MODULE_OK;
+ break;
+ case PW_EAP_FAILURE:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ rcode = RLM_MODULE_REJECT;
+ break;
+ case PW_EAP_REQUEST:
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ rcode = RLM_MODULE_HANDLED;
+ break;
+ default:
+ /*
+ * When we're pulling MS-CHAPv2 out of EAP-MS-CHAPv2,
+ * we do so WITHOUT setting a reply code, as the
+ * request is being proxied.
+ */
+ if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) {
+ return RLM_MODULE_HANDLED;
+ }
+
+ /* Should never enter here */
+ REDEBUG("Reply code %d is unknown, rejecting the request", reply->code);
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ reply->code = PW_EAP_FAILURE;
+ rcode = RLM_MODULE_REJECT;
+ break;
+ }
+
+ RDEBUG2("Sending EAP %s (code %i) ID %d length %i",
+ eap_codes[eap_packet->code], eap_packet->code, reply->id,
+ eap_packet->length[0] * 256 + eap_packet->length[1]);
+
+ return rcode;
+}
+
+/*
+ * Radius criteria, EAP-Message is invalid without Message-Authenticator
+ * For EAP_START, send Access-Challenge with EAP Identity request.
+ */
+int eap_start(rlm_eap_t *inst, REQUEST *request)
+{
+ VALUE_PAIR *vp, *proxy;
+ VALUE_PAIR *eap_msg;
+
+ eap_msg = fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (!eap_msg) {
+ RDEBUG2("No EAP-Message, not doing EAP");
+ return EAP_NOOP;
+ }
+
+ /*
+ * Look for EAP-Type = None (FreeRADIUS specific attribute)
+ * this allows you to NOT do EAP for some users.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY);
+ if (vp && vp->vp_integer == 0) {
+ RDEBUG2("Found EAP-Message, but EAP-Type = None, so we're not doing EAP");
+ return EAP_NOOP;
+ }
+
+ /*
+ * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message
+ *
+ * Checks for Message-Authenticator are handled by rad_recv().
+ */
+
+ /*
+ * Check for a Proxy-To-Realm. Don't get excited over LOCAL
+ * realms (sigh).
+ */
+ proxy = fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+ if (proxy) {
+ REALM *realm;
+
+ /*
+ * If it's a LOCAL realm, then we're not proxying
+ * to it.
+ */
+ realm = realm_find(proxy->vp_strvalue);
+ if (!realm || (realm && (!realm->auth_pool))) {
+ proxy = NULL;
+ }
+ }
+
+ /*
+ * Check the length before de-referencing the contents.
+ *
+ * Lengths of zero are required by the RFC for EAP-Start,
+ * but we've never seen them in practice.
+ *
+ * Lengths of two are what we see in practice as
+ * EAP-Starts.
+ */
+ if ((eap_msg->vp_length == 0) || (eap_msg->vp_length == 2)) {
+ uint8_t *p;
+
+ /*
+ * It's a valid EAP-Start, but the request
+ * was marked as being proxied. So we don't
+ * do EAP, as the home server will do it.
+ */
+ if (proxy) {
+ do_proxy:
+ RDEBUG2("Request is supposed to be proxied to "
+ "Realm %s. Not doing EAP.", proxy->vp_strvalue);
+ return EAP_NOOP;
+ }
+
+ RDEBUG2("Got EAP_START message");
+ vp = fr_pair_afrom_num(request->reply, PW_EAP_MESSAGE, 0);
+ if (!vp) return EAP_FAIL;
+ fr_pair_add(&request->reply->vps, vp);
+
+ /*
+ * Manually create an EAP Identity request
+ */
+ vp->vp_length = 5;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+
+ p[0] = PW_EAP_REQUEST;
+ p[1] = 0; /* ID */
+ p[2] = 0;
+ p[3] = 5; /* length */
+ p[4] = PW_EAP_IDENTITY;
+
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ return EAP_FOUND;
+ } /* end of handling EAP-Start */
+
+ /*
+ * The EAP packet header is 4 bytes, plus one byte of
+ * EAP sub-type. Short packets are discarded, unless
+ * we're proxying.
+ */
+ if (eap_msg->vp_length < (EAP_HEADER_LEN + 1)) {
+ if (proxy) goto do_proxy;
+
+ RDEBUG2("Ignoring EAP-Message which is too short to be meaningful");
+ return EAP_FAIL;
+ }
+
+ /*
+ * Create an EAP-Type containing the EAP-type
+ * from the packet.
+ */
+ vp = fr_pair_afrom_num(request->packet, PW_EAP_TYPE, 0);
+ if (vp) {
+ vp->vp_integer = eap_msg->vp_octets[4];
+ fr_pair_add(&(request->packet->vps), vp);
+ }
+
+ /*
+ * If the request was marked to be proxied, do it now.
+ * This is done after checking for a valid length
+ * (which may not be good), and after adding the EAP-Type
+ * attribute. This lets other modules selectively cancel
+ * proxying based on EAP-Type.
+ */
+ if (proxy) goto do_proxy;
+
+ /*
+ * From now on, we're supposed to be handling the
+ * EAP packet. We better understand it...
+ */
+
+ /*
+ * We're allowed only a few codes. Request, Response,
+ * Success, or Failure.
+ */
+ if ((eap_msg->vp_octets[0] == 0) ||
+ (eap_msg->vp_octets[0] >= PW_EAP_MAX_CODES)) {
+ RDEBUG2("Peer sent EAP packet with unknown code %i", eap_msg->vp_octets[0]);
+ } else {
+ RDEBUG2("Peer sent EAP %s (code %i) ID %d length %zu",
+ eap_codes[eap_msg->vp_octets[0]],
+ eap_msg->vp_octets[0],
+ eap_msg->vp_octets[1],
+ eap_msg->vp_length);
+ }
+
+ /*
+ * We handle request and responses. The only other defined
+ * codes are success and fail. The client SHOULD NOT be
+ * sending success/fail packets to us, as it doesn't make
+ * sense.
+ */
+ if ((eap_msg->vp_octets[0] != PW_EAP_REQUEST) &&
+ (eap_msg->vp_octets[0] != PW_EAP_RESPONSE)) {
+ RDEBUG2("Ignoring EAP packet which we don't know how to handle");
+ return EAP_FAIL;
+ }
+
+ /*
+ * We've been told to ignore unknown EAP types, AND it's
+ * an unknown type. Return "NOOP", which will cause the
+ * mod_authorize() to return NOOP.
+ *
+ * EAP-Identity, Notification, and NAK are all handled
+ * internally, so they never have handlers.
+ */
+ if ((eap_msg->vp_octets[4] >= PW_EAP_MD5) &&
+ inst->ignore_unknown_types &&
+ ((eap_msg->vp_octets[4] == 0) ||
+ (eap_msg->vp_octets[4] >= PW_EAP_MAX_TYPES) ||
+ (!inst->methods[eap_msg->vp_octets[4]]))) {
+ RDEBUG2("Ignoring Unknown EAP type");
+ return EAP_NOOP;
+ }
+
+ /*
+ * They're NAKing the EAP type we wanted to use, and
+ * asking for one which we don't support.
+ *
+ * NAK is code + id + length1 + length + NAK
+ * + requested EAP type(s).
+ *
+ * We know at this point that we can't handle the
+ * request. We could either return an EAP-Fail here, but
+ * it's not too critical.
+ *
+ * By returning "noop", we can ensure that authorize()
+ * returns NOOP, and another module may choose to proxy
+ * the request.
+ */
+ if ((eap_msg->vp_octets[4] == PW_EAP_NAK) &&
+ (eap_msg->vp_length >= (EAP_HEADER_LEN + 2)) &&
+ inst->ignore_unknown_types &&
+ ((eap_msg->vp_octets[5] == 0) ||
+ (eap_msg->vp_octets[5] >= PW_EAP_MAX_TYPES) ||
+ (!inst->methods[eap_msg->vp_octets[5]]))) {
+ RDEBUG2("Ignoring NAK with request for unknown EAP type");
+ return EAP_NOOP;
+ }
+
+ if ((eap_msg->vp_octets[4] == PW_EAP_TTLS) ||
+ (eap_msg->vp_octets[4] == PW_EAP_PEAP)) {
+ RDEBUG2("Continuing tunnel setup");
+ return EAP_OK;
+ }
+ /*
+ * We return ok in response to EAP identity
+ * This means we can write:
+ *
+ * eap {
+ * ok = return
+ * }
+ * ldap
+ * sql
+ *
+ * ...in the inner-tunnel, to avoid expensive and unnecessary SQL/LDAP lookups
+ */
+ if (eap_msg->vp_octets[4] == PW_EAP_IDENTITY) {
+ RDEBUG2("EAP-Identity reply, returning 'ok' so we can short-circuit the rest of authorize");
+ return EAP_OK;
+ }
+
+ /*
+ * Later EAP messages are longer than the 'start'
+ * message, so if everything is OK, this function returns
+ * 'no start found', so that the rest of the EAP code can
+ * use the State attribute to match this EAP-Message to
+ * an ongoing conversation.
+ */
+ RDEBUG2("No EAP Start, assuming it's an on-going EAP conversation");
+
+ return EAP_NOTFOUND;
+}
+
+/*
+ * compose EAP FAILURE packet in EAP-Message
+ */
+void eap_fail(eap_handler_t *handler)
+{
+ /*
+ * Delete any previous replies.
+ */
+ fr_pair_delete_by_num(&handler->request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&handler->request->reply->vps, PW_STATE, 0, TAG_ANY);
+
+ talloc_free(handler->eap_ds->request);
+ handler->eap_ds->request = talloc_zero(handler->eap_ds, eap_packet_t);
+ handler->eap_ds->request->code = PW_EAP_FAILURE;
+ handler->finished = true;
+ eap_compose(handler);
+}
+
+/*
+ * compose EAP SUCCESS packet in EAP-Message
+ */
+void eap_success(eap_handler_t *handler)
+{
+ handler->eap_ds->request->code = PW_EAP_SUCCESS;
+ handler->finished = true;
+ eap_compose(handler);
+}
+
+/*
+ * Basic EAP packet verfications & validations
+ */
+static int eap_validation(REQUEST *request, eap_packet_raw_t **eap_packet_p)
+{
+ uint16_t len;
+ eap_packet_raw_t *eap_packet = *eap_packet_p;
+
+ memcpy(&len, eap_packet->length, sizeof(uint16_t));
+ len = ntohs(len);
+
+ /*
+ * High level EAP packet checks
+ */
+ if (len <= EAP_HEADER_LEN) {
+ RAUTH("EAP packet is too small: Ignoring it.");
+ return EAP_INVALID;
+ }
+
+ if (eap_packet->code == PW_EAP_REQUEST) {
+ VALUE_PAIR *vp;
+ RAUTH("Unexpected EAP-Request. NAKing it.");
+
+ vp = pair_make_reply("EAP-Message", "123456", T_OP_SET);
+ if (vp) {
+ uint8_t buffer[6];
+
+ buffer[0] = PW_EAP_RESPONSE;
+ buffer[1] = eap_packet->id;
+ buffer[2] = 0;
+ buffer[3] = 6;
+ buffer[4] = PW_EAP_NAK;
+ buffer[5] = 0; /* no overlapping EAP types */
+
+ fr_pair_value_memcpy(vp, buffer, 6);
+ }
+
+ /*
+ * Ensure that the Access-Reject has a Message-Authenticator
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(request->reply, PW_MESSAGE_AUTHENTICATOR, 0);
+ vp->vp_length = AUTH_VECTOR_LEN;
+ vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length);
+ fr_pair_add(&(request->reply->vps), vp);
+ }
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+
+ return EAP_INVALID;
+ }
+
+ /*
+ * We only allow responses from the peer. The peer
+ * CANNOT ask us to authenticate outselves.
+ */
+ if (eap_packet->code != PW_EAP_RESPONSE) {
+ RAUTH("Unexpected packet code %02x: Ignoring it.", eap_packet->code);
+ return EAP_INVALID;
+ }
+
+ if ((eap_packet->data[0] <= 0) ||
+ (eap_packet->data[0] >= PW_EAP_MAX_TYPES)) {
+ /*
+ * Handle expanded types by smashing them to
+ * normal types.
+ */
+ if (eap_packet->data[0] == PW_EAP_EXPANDED_TYPE) {
+ uint8_t *p, *q;
+
+ if (len <= (EAP_HEADER_LEN + 1 + 3 + 4)) {
+ RAUTH("Expanded EAP type is too short: ignoring the packet");
+ return EAP_INVALID;
+ }
+
+ if ((eap_packet->data[1] != 0) ||
+ (eap_packet->data[2] != 0) ||
+ (eap_packet->data[3] != 0)) {
+ RAUTH("Expanded EAP type has unknown Vendor-ID: ignoring the packet");
+ return EAP_INVALID;
+ }
+
+ if ((eap_packet->data[4] != 0) ||
+ (eap_packet->data[5] != 0) ||
+ (eap_packet->data[6] != 0)) {
+ RAUTH("Expanded EAP type has unknown Vendor-Type: ignoring the packet");
+ return EAP_INVALID;
+ }
+
+ if ((eap_packet->data[7] == 0) ||
+ (eap_packet->data[7] >= PW_EAP_MAX_TYPES)) {
+ RAUTH("Unsupported Expanded EAP type %s (%u): ignoring the packet",
+ eap_type2name(eap_packet->data[7]), eap_packet->data[7]);
+ return EAP_INVALID;
+ }
+
+ if (eap_packet->data[7] == PW_EAP_NAK) {
+ RAUTH("Unsupported Expanded EAP-NAK: ignoring the packet");
+ return EAP_INVALID;
+ }
+
+ /*
+ * Re-write the EAP packet to NOT have the expanded type.
+ */
+ q = (uint8_t *) eap_packet;
+ memmove(q + EAP_HEADER_LEN, q + EAP_HEADER_LEN + 7, len - 7 - EAP_HEADER_LEN);
+
+ p = talloc_realloc(talloc_parent(eap_packet), eap_packet, uint8_t, len - 7);
+ if (!p) {
+ RAUTH("Unsupported EAP type %s (%u): ignoring the packet",
+ eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
+ return EAP_INVALID;
+ }
+
+ len -= 7;
+ p[2] = (len >> 8) & 0xff;
+ p[3] = len & 0xff;
+
+ *eap_packet_p = (eap_packet_raw_t *) p;
+ RWARN("Converting Expanded EAP to normal EAP.");
+ RWARN("Unnecessary use of Expanded EAP types is not recommended.");
+
+ return EAP_VALID;
+ }
+
+ RAUTH("Unsupported EAP type %s (%u): ignoring the packet",
+ eap_type2name(eap_packet->data[0]), eap_packet->data[0]);
+ return EAP_INVALID;
+ }
+
+ /* we don't expect notification, but we send it */
+ if (eap_packet->data[0] == PW_EAP_NOTIFICATION) {
+ RAUTH("Got NOTIFICATION, "
+ "Ignoring the packet");
+ return EAP_INVALID;
+ }
+
+ return EAP_VALID;
+}
+
+
+/*
+ * Get the user Identity only from EAP-Identity packets
+ */
+static char *eap_identity(REQUEST *request, eap_handler_t *handler, eap_packet_raw_t *eap_packet)
+{
+ int size;
+ uint16_t len;
+ char *identity;
+
+ if ((!eap_packet) ||
+ (eap_packet->code != PW_EAP_RESPONSE) ||
+ (eap_packet->data[0] != PW_EAP_IDENTITY)) {
+ return NULL;
+ }
+
+ memcpy(&len, eap_packet->length, sizeof(uint16_t));
+ len = ntohs(len);
+
+ if ((len <= 5) || (eap_packet->data[1] == 0x00)) {
+ REDEBUG("EAP-Identity Unknown");
+ return NULL;
+ }
+
+ if (len > 1024) {
+ REDEBUG("EAP-Identity too long");
+ return NULL;
+ }
+
+ size = len - 5;
+ identity = talloc_array(handler, char, size + 1);
+ memcpy(identity, &eap_packet->data[1], size);
+ identity[size] = '\0';
+
+ return identity;
+}
+
+
+/*
+ * Create our Request-Response data structure with the eap packet
+ */
+static EAP_DS *eap_buildds(eap_handler_t *handler,
+ eap_packet_raw_t **eap_packet_p)
+{
+ EAP_DS *eap_ds = NULL;
+ eap_packet_raw_t *eap_packet = *eap_packet_p;
+ int typelen;
+ uint16_t len;
+
+ if ((eap_ds = eap_ds_alloc(handler)) == NULL) {
+ return NULL;
+ }
+
+ eap_ds->response->packet = (uint8_t *) eap_packet;
+ (void) talloc_steal(eap_ds, eap_packet);
+ eap_ds->response->code = eap_packet->code;
+ eap_ds->response->id = eap_packet->id;
+ eap_ds->response->type.num = eap_packet->data[0];
+
+ memcpy(&len, eap_packet->length, sizeof(uint16_t));
+ len = ntohs(len);
+ eap_ds->response->length = len;
+
+ /*
+ * We've eaten the eap packet into the eap_ds.
+ */
+ *eap_packet_p = NULL;
+
+ /*
+ * First 5 bytes in eap, are code + id + length(2) + type.
+ *
+ * The rest is type-specific data. We skip type while
+ * getting typedata from data.
+ */
+ typelen = len - 5/*code + id + length + type */;
+ if (typelen > 0) {
+ /*
+ * Since the packet contains the complete
+ * eap_packet, typedata will be a ptr in packet
+ * to its typedata
+ */
+ eap_ds->response->type.data = eap_ds->response->packet + 5/*code+id+length+type*/;
+ eap_ds->response->type.length = typelen;
+ } else {
+ eap_ds->response->type.length = 0;
+ eap_ds->response->type.data = NULL;
+ }
+
+ return eap_ds;
+}
+
+
+/*
+ * If identity response then create a fresh handler & fill the identity
+ * else handler MUST be in our list, get that.
+ * This handler creation cannot fail
+ *
+ * username contains REQUEST->username which might have been stripped.
+ * identity contains the one sent in EAP-Identity response
+ */
+eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_packet_p,
+ REQUEST *request)
+{
+ eap_handler_t *handler = NULL;
+ eap_packet_raw_t *eap_packet;
+ VALUE_PAIR *vp;
+
+ /*
+ * Ensure it's a valid EAP-Request, or EAP-Response.
+ */
+ if (eap_validation(request, eap_packet_p) == EAP_INVALID) {
+ error:
+ talloc_free(*eap_packet_p);
+ *eap_packet_p = NULL;
+ return NULL;
+ }
+
+ eap_packet = *eap_packet_p;
+
+ /*
+ * eap_handler_t MUST be found in the list if it is not
+ * EAP-Identity response
+ */
+ if (eap_packet->data[0] != PW_EAP_IDENTITY) {
+ handler = eaplist_find(inst, request, eap_packet);
+ if (!handler) {
+ /* Either send EAP_Identity or EAP-Fail */
+ RDEBUG("Either EAP-request timed out OR EAP-response to an unknown EAP-request");
+ goto error;
+ }
+
+ /*
+ * Even more paranoia. Without this, some weird
+ * clients could do crazy things.
+ *
+ * It's ok to send EAP sub-type NAK in response
+ * to a request for a particular type, but it's NOT
+ * OK to blindly return data for another type.
+ */
+ if ((eap_packet->data[0] != PW_EAP_NAK) &&
+ (eap_packet->data[0] != handler->type)) {
+ RERROR("Response appears to match a previous request, but the EAP type is wrong");
+ RERROR("We expected EAP type %s, but received type %s",
+ eap_type2name(handler->type),
+ eap_type2name(eap_packet->data[0]));
+ RERROR("Your Supplicant or NAS is probably broken");
+ goto error;
+ }
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ /*
+ * NAS did not set the User-Name
+ * attribute, so we set it here and
+ * prepend it to the beginning of the
+ * request vps so that autz's work
+ * correctly
+ */
+ RDEBUG2("Broken NAS did not set User-Name, setting from EAP Identity");
+ vp = fr_pair_make(request->packet, &request->packet->vps, "User-Name", handler->identity, T_OP_EQ);
+ if (!vp) {
+ goto error;
+ }
+ } else {
+ /*
+ * A little more paranoia. If the NAS
+ * *did* set the User-Name, and it doesn't
+ * match the identity, (i.e. If they
+ * change their User-Name part way through
+ * the EAP transaction), then reject the
+ * request as the NAS is doing something
+ * funny.
+ */
+ if (strncmp(handler->identity, vp->vp_strvalue,
+ MAX_STRING_LEN) != 0) {
+ RDEBUG("Identity does not match User-Name. Authentication failed");
+ goto error;
+ }
+ }
+ } else { /* packet was EAP identity */
+ handler = eap_handler_alloc(inst);
+ if (!handler) {
+ goto error;
+ }
+
+ /*
+ * All fields in the handler are set to zero.
+ */
+ handler->identity = eap_identity(request, handler, eap_packet);
+ if (!handler->identity) {
+ RDEBUG("Identity Unknown, authentication failed");
+ error2:
+ talloc_free(handler);
+ goto error;
+ }
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ /*
+ * NAS did not set the User-Name
+ * attribute, so we set it here and
+ * prepend it to the beginning of the
+ * request vps so that autz's work
+ * correctly
+ */
+ RWDEBUG2("NAS did not set User-Name. Setting it locally from EAP Identity");
+ vp = fr_pair_make(request->packet, &request->packet->vps, "User-Name", handler->identity, T_OP_EQ);
+ if (!vp) {
+ goto error2;
+ }
+ } else {
+ /*
+ * Paranoia. If the NAS *did* set the
+ * User-Name, and it doesn't match the
+ * identity, the NAS is doing something
+ * funny, so reject the request.
+ */
+ if (strncmp(handler->identity, vp->vp_strvalue,
+ MAX_STRING_LEN) != 0) {
+ RDEBUG("Identity does not match User-Name, setting from EAP Identity");
+ goto error2;
+ }
+ }
+ }
+
+ handler->eap_ds = eap_buildds(handler, eap_packet_p);
+ if (!handler->eap_ds) {
+ goto error2;
+ }
+
+ handler->timestamp = request->timestamp;
+ handler->request = request;
+ return handler;
+}
diff --git a/src/modules/rlm_eap/eap.h b/src/modules/rlm_eap/eap.h
new file mode 100644
index 0000000..b487c08
--- /dev/null
+++ b/src/modules/rlm_eap/eap.h
@@ -0,0 +1,154 @@
+/*
+ * eap.h Header file containing the interfaces for all EAP types.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_H
+#define _EAP_H
+
+RCSIDH(eap_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "eap_types.h"
+
+/* TLS configuration name */
+#define TLS_CONFIG_SECTION "tls-config"
+
+/*
+ * EAP_DS contains all the received/sending information
+ * response = Received EAP packet
+ * request = Sending EAP packet
+ *
+ * Note: We are authentication server,
+ * we get ONLY EAP-Responses and
+ * we send EAP-Request/EAP-success/EAP-failure
+ */
+typedef struct eap_ds {
+ eap_packet_t *response;
+ eap_packet_t *request;
+ int set_request_id;
+} EAP_DS;
+
+/*
+ * Currently there are only 2 types
+ * of operations defined,
+ * apart from attach & detach for each EAP-Type.
+ */
+typedef enum operation_t {
+ INITIATE = 0,
+ PROCESS
+} operation_t;
+
+
+/*
+ * eap_handler_t is the interface for any EAP-Type.
+ * Each handler contains information for one specific EAP-Type.
+ * This way we don't need to change any interfaces in future.
+ * It is also a list of EAP-request handlers waiting for EAP-response
+ * eap_id = copy of the eap packet we sent to the
+ *
+ * next = pointer to next
+ * state = state attribute from the reply we sent
+ * state_len = length of data in the state attribute.
+ * src_ipaddr = client which sent us the RADIUS request containing
+ * this EAP conversation.
+ * eap_id = copy of EAP id we sent to the client.
+ * timestamp = timestamp when this handler was last used.
+ * identity = Identity, as obtained, from EAP-Identity response.
+ * request = RADIUS request data structure
+ * prev_eapds = Previous EAP request, for which eap_ds contains the response.
+ * eap_ds = Current EAP response.
+ * opaque = EAP-Type holds some data that corresponds to the current
+ * EAP-request/response
+ * free_opaque = To release memory held by opaque,
+ * when this handler is timedout & needs to be deleted.
+ * It is the responsibility of the specific EAP-TYPE
+ * to avoid any memory leaks in opaque
+ * Hence this pointer should be provided by the EAP-Type
+ * if opaque is not NULL
+ * status = finished/onhold/..
+ */
+#define EAP_STATE_LEN (AUTH_VECTOR_LEN)
+typedef struct _eap_handler {
+ struct _eap_handler *prev, *next;
+ uint8_t state[EAP_STATE_LEN];
+ fr_ipaddr_t src_ipaddr;
+
+ uint8_t eap_id; //!< EAP Identifier used to match
+ //!< requests and responses.
+ eap_type_t type; //!< EAP type number.
+
+ time_t timestamp;
+
+ REQUEST *request;
+
+ char *identity; //!< User name from EAP-Identity
+
+ EAP_DS *prev_eapds;
+ EAP_DS *eap_ds;
+
+ void *opaque;
+ void (*free_opaque)(void *opaque);
+ void *inst_holder;
+
+ int status;
+
+ int stage;
+
+ int trips;
+
+ bool tls;
+ bool started;
+ bool finished;
+ VALUE_PAIR *certs;
+} eap_handler_t;
+
+/*
+ * Interface to call EAP sub mdoules
+ */
+typedef struct rlm_eap_module {
+ char const *name; //!< The name of the sub-module
+ //!< (without rlm_ prefix).
+ int (*instantiate)(CONF_SECTION *conf, void **instance); //!< Create a new submodule instance.
+ int (*session_init)(void *instance, eap_handler_t *handler); //!< Initialise a new EAP session.
+ int (*process)(void *instance, eap_handler_t *handler); //!< Continue an EAP session.
+ int (*detach)(void *instance); //!< Destroy a submodule instance.
+} rlm_eap_module_t;
+
+#define REQUEST_DATA_EAP_HANDLER (1)
+#define REQUEST_DATA_EAP_TUNNEL_CALLBACK PW_EAP_MESSAGE
+#define REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK ((PW_EAP_MESSAGE << 16) | PW_EAP_MSCHAPV2)
+#define RAD_REQUEST_OPTION_PROXY_EAP (1 << 16)
+
+/*
+ * This is for tunneled callbacks
+ */
+typedef int (*eap_tunnel_callback_t)(eap_handler_t *handler, void *tls_session);
+
+typedef struct eap_tunnel_data_t {
+ void *tls_session;
+ eap_tunnel_callback_t callback;
+} eap_tunnel_data_t;
+
+#endif /*_EAP_H*/
diff --git a/src/modules/rlm_eap/libeap/all.mk b/src/modules/rlm_eap/libeap/all.mk
new file mode 100644
index 0000000..6a32129
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/all.mk
@@ -0,0 +1,10 @@
+TARGET := libfreeradius-eap.a
+
+SOURCES := eapcommon.c eapcrypto.c eap_chbind.c eapsimlib.c fips186prf.c comp128.c
+ifneq (${OPENSSL_LIBS},)
+SOURCES += eap_tls.c mppe_keys.c
+endif
+
+SRC_CFLAGS := -DEAPLIB
+
+SRC_INCDIRS := . ..
diff --git a/src/modules/rlm_eap/libeap/comp128.c b/src/modules/rlm_eap/libeap/comp128.c
new file mode 100644
index 0000000..e624877
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/comp128.c
@@ -0,0 +1,460 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file comp128.c
+ * @brief Implementations of comp128v1, comp128v2, comp128v3 algorithms
+ *
+ * Comp128v1 was inspired by code from:
+ * Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>,
+ * and David Wagner <daw@cs.berkeley.edu>
+ *
+ * But it has been fully rewritten (Sylvain Munaut <tnt@246tNt.com>) from various PDFs found online
+ * describing the algorithm because the licence of the code referenced above was unclear.
+ * A comment snippet from the original code is included below, it describes where the doc came
+ * from and how the algorithm was reverse engineered.
+ *
+ * Comp128v2 & v3 is a port of the python code from:
+ * http://www.hackingprojects.net/
+ * The author of the original code is Tamas Jos <tamas.jos@skelsec.com>
+ *
+ * @note The above GPL license only applies to comp128v1, the license for comp128v2 and comp128v3 is unknown.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Hacking projects [http://www.hackingprojects.net/]
+ * @copyright 2009 Sylvain Munaut <tnt@246tNt.com>
+ */
+
+#include "comp128.h"
+#include <stdio.h>
+/* 512 bytes */
+static uint8_t const comp128v1_t0[] = {
+ 102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188,
+ 109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161,
+ 252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70,
+ 67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116,
+ 247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225,
+ 182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48,
+ 149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176,
+ 250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121,
+ 61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196,
+ 56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231,
+ 174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255,
+ 239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82,
+ 104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5,
+ 57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226,
+ 184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23,
+ 80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119,
+ 177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246,
+ 213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108,
+ 37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59,
+ 26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207,
+ 194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215,
+ 243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245,
+ 90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137,
+ 27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32,
+ 103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172,
+ 197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210,
+ 165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125,
+ 54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192,
+ 170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198,
+ 254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147,
+ 218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154,
+ 159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253};
+
+/* 256 bytes */
+static uint8_t const comp128v1_t1[] = {
+ 19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43,
+ 27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5,
+ 35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6,
+ 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20,
+ 90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78,
+ 76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51,
+ 57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67,
+ 12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75,
+ 95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29,
+ 82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114,
+ 82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74,
+ 113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73,
+ 118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83,
+ 104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126,
+ 31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52,
+ 101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35};
+
+/* 128 bytes */
+static uint8_t const comp128v1_t2[] = {
+ 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43,
+ 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18,
+ 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59,
+ 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56,
+ 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61,
+ 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0,
+ 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27,
+ 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7};
+
+/* 64 bytes */
+static uint8_t const comp128v1_t3[] = {
+ 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31,
+ 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9,
+ 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10,
+ 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19};
+
+/* 32 bytes */
+static uint8_t const comp128v1_t4[] = {
+ 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8,
+ 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12};
+
+static uint8_t const *_comp128_table[] = { comp128v1_t0, comp128v1_t1, comp128v1_t2, comp128v1_t3, comp128v1_t4 };
+
+/* 256 bytes */
+static uint8_t const comp128v23_t0[] = {
+ 197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203,
+ 61, 126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33,
+ 160, 184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46,
+ 113, 187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222,
+ 137, 233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231,
+ 54, 209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30,
+ 2, 155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112,
+ 56, 173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175,
+ 67, 128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145,
+ 138, 7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169,
+ 213, 88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86,
+ 226, 141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242,
+ 206, 97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251,
+ 29, 216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204,
+ 43, 247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250,
+ 139, 19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26};
+
+/* 256 bytes */
+static uint8_t const comp128v23_t1[] = {
+ 170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129,
+ 216, 79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235,
+ 6, 20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18,
+ 224, 171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178,
+ 156, 52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222,
+ 76, 139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138,
+ 31, 56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154,
+ 179, 131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245,
+ 193, 78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169,
+ 68, 101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59,
+ 21, 92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82,
+ 54, 237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207,
+ 181, 29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148,
+ 209, 98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80,
+ 196, 33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149,
+ 226, 218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112};
+
+static inline void _comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl)
+{
+ int i, j, m, a, b, y, z;
+ m = 4 - n;
+ for (i = 0; i < (1 << n); i++) {
+ for (j = 0; j < (1 << m); j++) {
+ a = j + i * (2 << m);
+ b = a + (1 << m);
+ y = (x[a] + (x[b] << 1)) & ((32 << m) - 1);
+ z = ((x[a] << 1) + x[b]) & ((32 << m) - 1);
+ x[a] = tbl[y];
+ x[b] = tbl[z];
+ }
+ }
+}
+
+static inline void _comp128_compression(uint8_t *x)
+{
+ int n;
+ for (n = 0; n < 5; n++) {
+ _comp128_compression_round(x, n, _comp128_table[n]);
+ }
+}
+
+static inline void _comp128_bitsfrombytes(uint8_t *x, uint8_t *bits)
+{
+ int i;
+
+ memset(bits, 0x00, 128);
+ for (i = 0; i < 128; i++) {
+ if (x[i >> 2] & (1 << (3 - (i & 3)))) {
+ bits[i] = 1;
+ }
+ }
+}
+
+static inline void _comp128_permutation(uint8_t *x, uint8_t *bits)
+{
+ int i;
+ memset(&x[16], 0x00, 16);
+ for (i = 0; i < 128; i++) {
+ x[(i >> 3) + 16] |= bits[(i * 17) & 127] << (7 - (i & 7));
+ }
+}
+
+/** Calculate comp128v1 sres and kc from ki and rand
+ *
+ * This code derived from a leaked document from the GSM standards.
+ * Some missing pieces were filled in by reverse-engineering a working SIM.
+ * We have verified that this is the correct COMP128 algorithm.
+ *
+ * The first page of the document identifies it as
+ * _Technical Information: GSM System Security Study_.
+ * 10-1617-01, 10th June 1988.
+ * The bottom of the title page is marked
+ * Racal Research Ltd.
+ * Worton Drive, Worton Grange Industrial Estate,
+ * Reading, Berks. RG2 0SB, England.
+ * Telephone: Reading (0734) 868601 Telex: 847152
+ * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy!
+ *
+ * Note: There are three typos in the spec (discovered by reverse-engineering).
+ * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read
+ * "z = (2 * x[m] + x[n]) mod 2^(9-j)".
+ * Second, the "k" loop in the "Form bits from bytes" section is severely
+ * botched: the k index should run only from 0 to 3, and clearly the range
+ * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8,
+ * to be consistent with the subsequent section).
+ * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as
+ * claimed in the document. (And the document doesn't specify how Kc is
+ * derived, but that was also easily discovered with reverse engineering.)
+ * All of these typos have been corrected in the following code.
+ *
+ * @param[out] sres 4 byte value derived from ki and rand.
+ * @param[out] kc 12 byte value derived from ki and rand.
+ * @param[in] ki known only by the SIM and AuC (us in this case).
+ * @param[in] rand 16 bytes of randomness.
+ */
+void comp128v1(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand)
+{
+ int i;
+ uint8_t x[32], bits[128];
+
+ /* x[16-31] = RAND */
+ memcpy(&x[16], rand, 16);
+
+ /*
+ * Round 1-7
+ */
+ for (i=0; i < 7; i++) {
+ /* x[0-15] = Ki */
+ memcpy(x, ki, 16);
+
+ /* Compression */
+ _comp128_compression(x);
+
+ /* FormBitFromBytes */
+ _comp128_bitsfrombytes(x, bits);
+
+ /* Permutation */
+ _comp128_permutation(x, bits);
+ }
+
+ /*
+ * Round 8 (final)
+ * x[0-15] = Ki
+ */
+ memcpy(x, ki, 16);
+
+ /* Compression */
+ _comp128_compression(x);
+
+ /* Output stage */
+ for (i = 0; i < 8; i += 2) {
+ sres[i >> 1] = x[i] << 4 | x[i + 1];
+ }
+
+ for (i = 0; i < 12; i += 2) {
+ kc[i>>1] = (x[i + 18] << 6) |
+ (x[i + 19] << 2) |
+ (x[i + 20] >> 2);
+ }
+
+ kc[6] = (x[30] << 6) | (x[31] << 2);
+ kc[7] = 0;
+}
+
+static void _comp128v23(uint8_t *rand, uint8_t const *kxor)
+{
+ uint8_t temp[16];
+ uint8_t km_rm[32];
+
+ int j, i, k, z;
+
+ memset(&temp, 0, sizeof(temp));
+ memcpy(km_rm, rand, 16);
+ memcpy(km_rm + 16, kxor, 16);
+ memset(rand, 0, 16);
+
+ for (i = 0; i < 5; i++) {
+ j = 0;
+
+ for (z = 0; z < 16; z++) {
+ temp[z] = comp128v23_t0[comp128v23_t1[km_rm[16 + z]] ^ km_rm[z]];
+ }
+
+ while ((1 << i) > j) {
+ k = 0;
+
+ while ((1 << (4 - i)) > k) {
+ km_rm[(((2 * k) + 1) << i) + j] =
+ comp128v23_t0[comp128v23_t1[temp[(k << i) + j]] ^ (km_rm[(k << i) + 16 + j])];
+ km_rm[(k << (i + 1)) + j] = temp[(k << i) + j];
+ k++;
+ }
+ j++;
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 8; j++) {
+ rand[i] = rand[i] ^ (((km_rm[(19 * (j + 8 * i) + 19) % 256 / 8] >> (3 * j + 3) % 8) & 1) << j);
+ }
+ }
+}
+
+/** Calculate comp128v2 or comp128v3 sres and kc from ki and rand
+ *
+ * @param[out] sres 4 byte value derived from ki and rand.
+ * @param[out] kc 8 byte value derived from ki and rand.
+ * @param[in] ki known only by the SIM and AuC (us in this case).
+ * @param[in] rand 16 bytes of randomness.
+ * @param[in] v2 if true we use version comp128-2 else we use comp128-3.
+
+ */
+void comp128v23(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand, bool v2)
+{
+ uint8_t k_mix[16];
+ uint8_t rand_mix[16];
+ uint8_t katyvasz[16];
+ uint8_t buffer[16];
+
+ /* Every day IM suffling... */
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ k_mix[i] = ki[15 - i];
+ k_mix[15 - i] = ki[i];
+ }
+
+ for (i = 0; i < 8; i++) {
+ rand_mix[i] = rand[15 - i];
+ rand_mix[15 - i] = rand[i];
+ }
+
+ for (i = 0; i < 16; i++) {
+ katyvasz[i] = k_mix[i] ^ rand_mix[i];
+ }
+
+ for (i = 0; i < 8; i++) {
+ _comp128v23(rand_mix, katyvasz);
+ }
+
+ for (i = 0; i < 16; i++) {
+ buffer[i] = rand_mix[15 - i];
+ }
+
+ if (v2) {
+ buffer[15] = 0x00;
+ buffer[14] = 4 * (buffer[14] >> 2);
+ }
+
+ for (i = 0; i < 4; i++) {
+ buffer[8 + i - 4] = buffer[8 + i];
+ buffer[8 + i] = buffer[8 + i + 4];
+ }
+
+ /*
+ * The algorithm uses 16 bytes until this point, but only 12 bytes are effective
+ * also 12 bytes coming out from the SIM card.
+ */
+ memcpy(sres, buffer, 4);
+ memcpy(kc, buffer + 4, 8);
+}
+
+#if 0
+#include <stdlib.h>
+#include <ctype.h>
+static int hextoint(char x)
+{
+ x = toupper(x);
+ if (x >= 'A' && x <= 'F') {
+ return x-'A' + 10;
+ } else if (x >= '0' && x <= '9') {
+ return x-'0';
+ }
+
+ fprintf(stderr, "Bad input.\n");
+
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ uint8_t rand[16], key[16], sres[4], kc[8];
+ int version;
+ int i;
+
+ if ((argc != 4) ||
+ (strlen(argv[1]) != 34) || (strlen(argv[2]) != 34) ||
+ (strncmp(argv[1], "0x", 2) != 0) || (strncmp(argv[2], "0x", 2) != 0) ||
+ !(version = atoi(argv[3]))) {
+ error:
+ fprintf(stderr, "Usage: %s 0x<key> 0x<rand> [1|2|3]\n", argv[0]);
+ exit(1);
+ }
+
+ for (i = 0; i < 16; i++) {
+ key[i] = (hextoint(argv[1][(2 * i) + 2]) << 4) | hextoint(argv[1][(2 * i) + 3]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ rand[i] = (hextoint(argv[2][(2 * i) + 2]) << 4) | hextoint(argv[2][(2 * i) + 3]);
+ }
+
+ switch (version) {
+ case 3:
+ comp128v23(sres, kc, key, rand, false);
+ break;
+ case 2:
+ comp128v23(sres, kc, key, rand, true);
+ break;
+ case 1:
+ comp128v1(sres, kc, key, rand);
+ break;
+ default:
+ fprintf(stderr, "Invalid version, must be 1,2 or 3");
+ goto error;
+ }
+
+ /* Output in vector format <Ki>,<rand>,<sres><Kc> */
+ for (i = 0; i < 16; i++) {
+ printf("%02X", key[i]);
+ }
+ printf(",");
+ for (i = 0; i < 16; i++) {
+ printf("%02X", rand[i]);
+ }
+ printf(",");
+ for (i = 0; i < 4; i++) {
+ printf("%02X", sres[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ printf("%02X", kc[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
+#endif
diff --git a/src/modules/rlm_eap/libeap/comp128.h b/src/modules/rlm_eap/libeap/comp128.h
new file mode 100644
index 0000000..4cd2199
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/comp128.h
@@ -0,0 +1,11 @@
+#ifndef _COMP128_H
+#define _COMP128_H
+
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+void comp128v1(uint8_t *sres, uint8_t *kc, const uint8_t *ki, const uint8_t *rand);
+void comp128v23(uint8_t *sres, uint8_t *kc, uint8_t const *ki, uint8_t const *rand, bool v2);
+
+#endif
diff --git a/src/modules/rlm_eap/libeap/eap_chbind.c b/src/modules/rlm_eap/libeap/eap_chbind.c
new file mode 100644
index 0000000..21b2584
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_chbind.c
@@ -0,0 +1,290 @@
+/*
+ * eap_chbind.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2014 Network RADIUS SARL
+ * Copyright 2014 The FreeRADIUS server project
+ */
+
+
+RCSID("$Id$")
+
+#include "eap_chbind.h"
+
+static bool chbind_build_response(REQUEST *request, CHBIND_REQ *chbind)
+{
+ int length;
+ size_t total;
+ uint8_t *ptr, *end;
+ VALUE_PAIR const *vp;
+ vp_cursor_t cursor;
+
+ total = 0;
+ for (vp = fr_cursor_init(&cursor, &request->reply->vps);
+ vp != NULL;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Skip things which shouldn't be in channel bindings.
+ */
+ if (vp->da->flags.encrypt != FLAG_ENCRYPT_NONE) continue;
+ if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) continue;
+
+ total += 2 + vp->vp_length;
+ }
+
+ /*
+ * No attributes: just send a 1-byte response code.
+ */
+ if (!total) {
+ ptr = talloc_zero_array(chbind, uint8_t, 1);
+ } else {
+ ptr = talloc_zero_array(chbind, uint8_t, total + 4);
+ }
+ if (!ptr) return false;
+ chbind->response = (chbind_packet_t *) ptr;
+
+ /*
+ * Set the response code. Default to "fail" if none was
+ * specified.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CHBIND_RESPONSE_CODE, 0, TAG_ANY);
+ if (vp) {
+ ptr[0] = vp->vp_integer;
+ } else {
+ ptr[0] = CHBIND_CODE_FAILURE;
+ }
+
+ if (!total) return true; /* nothing to encode */
+
+ /* Write the length field into the header */
+ ptr[1] = (total >> 8) & 0xff;
+ ptr[2] = total & 0xff;
+ ptr[3] = CHBIND_NSID_RADIUS;
+
+ RDEBUG("Sending chbind response: code %i", (int )(ptr[0]));
+ rdebug_pair_list(L_DBG_LVL_1, request, request->reply->vps, NULL);
+
+ /* Encode the chbind attributes into the response */
+ ptr += 4;
+ end = ptr + total;
+ for (vp = fr_cursor_init(&cursor, &request->reply->vps);
+ vp != NULL;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Skip things which shouldn't be in channel bindings.
+ */
+ if (vp->da->flags.encrypt != FLAG_ENCRYPT_NONE) continue;
+ if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) continue;
+
+ length = rad_vp2attr(NULL, NULL, NULL, &vp, ptr, end - ptr);
+ if (length < 0) continue;
+ ptr += length;
+ }
+
+ return true;
+}
+
+
+/*
+ * Parse channel binding packet to obtain data for a specific
+ * NSID.
+ *
+ * See:
+ * http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.2
+ */
+static size_t chbind_get_data(chbind_packet_t const *packet,
+ int desired_nsid,
+ uint8_t const **data)
+{
+ uint8_t const *ptr;
+ uint8_t const *end;
+
+ if (packet->code != CHBIND_CODE_REQUEST) {
+ return 0;
+ }
+
+ ptr = (uint8_t const *) packet;
+ end = ptr + talloc_array_length((uint8_t const *) packet);
+
+ ptr++; /* skip the code at the start of the packet */
+ while (ptr < end) {
+ uint8_t nsid;
+ size_t length;
+
+ /*
+ * Need room for length(2) + NSID + data.
+ */
+ if ((end - ptr) < 4) return 0;
+
+ length = (ptr[0] << 8) | ptr[1];
+ if (length == 0) return 0;
+
+ if ((ptr + length + 3) > end) return 0;
+
+ nsid = ptr[2];
+ if (nsid == desired_nsid) {
+ ptr += 3;
+ *data = ptr;
+ return length;
+ }
+
+ ptr += 3 + length;
+ }
+
+ return 0;
+}
+
+
+PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind)
+{
+ PW_CODE rcode;
+ REQUEST *fake = NULL;
+ VALUE_PAIR *vp = NULL;
+ uint8_t const *attr_data;
+ size_t data_len = 0;
+
+ /* check input parameters */
+ rad_assert((request != NULL) &&
+ (chbind != NULL) &&
+ (chbind->request != NULL) &&
+ (chbind->response == NULL));
+
+ /* Set-up the fake request */
+ fake = request_alloc_fake(request);
+ fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+ /* Add the username to the fake request */
+ if (chbind->username) {
+ vp = fr_pair_copy(fake->packet, chbind->username);
+ fr_pair_add(&fake->packet->vps, vp);
+ fake->username = vp;
+ }
+
+ /*
+ * Maybe copy the State over, too?
+ */
+
+ /* Add the channel binding attributes to the fake packet */
+ data_len = chbind_get_data(chbind->request, CHBIND_NSID_RADIUS, &attr_data);
+ if (data_len) {
+ rad_assert(data_len <= talloc_array_length((uint8_t const *) chbind->request));
+
+ while (data_len > 0) {
+ int attr_len = rad_attr2vp(fake->packet, NULL, NULL, NULL, attr_data, data_len, &vp);
+ if (attr_len <= 0) {
+ /* If radaddr2vp fails, return NULL string for
+ channel binding response */
+ talloc_free(fake);
+ return PW_CODE_ACCESS_ACCEPT;
+ }
+ if (vp) {
+ fr_pair_add(&fake->packet->vps, vp);
+ }
+ attr_data += attr_len;
+ data_len -= attr_len;
+ }
+ }
+
+ /*
+ * Set virtual server based on configuration for channel
+ * bindings, this is hard-coded for now.
+ */
+ fake->server = "channel_bindings";
+ fake->packet->code = PW_CODE_ACCESS_REQUEST;
+
+ switch (rad_virtual_server(fake)) {
+ /* If rad_authenticate succeeded, build a reply */
+ case RLM_MODULE_OK:
+ case RLM_MODULE_HANDLED:
+ if (chbind_build_response(fake, chbind)) {
+ rcode = PW_CODE_ACCESS_ACCEPT;
+ break;
+ }
+ /* FALL-THROUGH */
+
+ /* If we got any other response from rad_authenticate, it maps to a reject */
+ default:
+ rcode = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+
+ talloc_free(fake);
+
+ return rcode;
+}
+
+/*
+ * Handles multiple EAP-channel-binding Message attrs
+ * ie concatenates all to get the complete EAP-channel-binding packet.
+ */
+chbind_packet_t *eap_chbind_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
+{
+ size_t length;
+ uint8_t *ptr;
+ VALUE_PAIR *first, *vp;
+ chbind_packet_t *packet;
+ vp_cursor_t cursor;
+
+ first = fr_pair_find_by_num(vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY);
+ if (!first) return NULL;
+
+ /*
+ * Compute the total length of the channel binding data.
+ */
+ length = 0;
+ fr_cursor_init(&cursor, &first);
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY))) {
+ length += vp->vp_length;
+ }
+
+ if (length < 4) {
+ DEBUG("Invalid length %u for channel binding data", (unsigned int) length);
+ return NULL;
+ }
+
+ /*
+ * Now that we know the length, allocate memory for the packet.
+ */
+ ptr = talloc_zero_array(ctx, uint8_t, length);
+ if (!ptr) return NULL;
+
+ /*
+ * Copy the data over to our packet.
+ */
+ packet = (chbind_packet_t *) ptr;
+ fr_cursor_init(&cursor, &first);
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY))) {
+ memcpy(ptr, vp->vp_octets, vp->vp_length);
+ ptr += vp->vp_length;
+ }
+
+ return packet;
+}
+
+VALUE_PAIR *eap_chbind_packet2vp(RADIUS_PACKET *packet, chbind_packet_t *chbind)
+{
+ VALUE_PAIR *vp;
+
+ if (!chbind) return NULL; /* don't produce garbage */
+
+ vp = fr_pair_afrom_num(packet, PW_UKERNA_CHBIND, VENDORPEC_UKERNA);
+ if (!vp) return NULL;
+ fr_pair_value_memcpy(vp, (uint8_t *) chbind, talloc_array_length((uint8_t *)chbind));
+
+ return vp;
+}
diff --git a/src/modules/rlm_eap/libeap/eap_chbind.h b/src/modules/rlm_eap/libeap/eap_chbind.h
new file mode 100644
index 0000000..346b712
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_chbind.h
@@ -0,0 +1,64 @@
+/*
+ * eap_chbind.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2014 Network RADIUS SARL
+ * Copyright 2014 The FreeRADIUS server project
+ */
+
+#ifndef _EAP_CHBIND_H
+#define _EAP_CHBIND_H
+
+RCSIDH(eap_chbind_h, "$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#include <freeradius-devel/radiusd.h>
+
+#include "eap.h"
+
+/* Structure to represent eap channel binding packet format */
+typedef struct chbind_packet_t {
+ uint8_t code;
+ uint8_t data[1];
+} chbind_packet_t;
+
+/* Structure to hold channel bindings req/resp information */
+typedef struct CHBIND_REQ {
+ VALUE_PAIR *username; /* the username */
+ chbind_packet_t *request; /* channel binding request buffer */
+ chbind_packet_t *response; /* channel binding response buffer */
+} CHBIND_REQ;
+
+/* Protocol constants */
+#define CHBIND_NSID_RADIUS 1
+
+#define CHBIND_CODE_REQUEST 1
+#define CHBIND_CODE_SUCCESS 2
+#define CHBIND_CODE_FAILURE 3
+
+/* Channel binding function prototypes */
+PW_CODE chbind_process(REQUEST *request, CHBIND_REQ *chbind_req);
+
+VALUE_PAIR *eap_chbind_packet2vp(RADIUS_PACKET *packet, chbind_packet_t *chbind);
+chbind_packet_t *eap_chbind_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps);
+
+#endif /*_EAP_CHBIND_H*/
diff --git a/src/modules/rlm_eap/libeap/eap_sim.h b/src/modules/rlm_eap/libeap/eap_sim.h
new file mode 100644
index 0000000..0d92f67
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_sim.h
@@ -0,0 +1,122 @@
+/*
+ * eap_sim.h Header file containing the EAP-SIM types
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * Copyright 2006 The FreeRADIUS server project
+ *
+ */
+#ifndef _EAP_SIM_H
+#define _EAP_SIM_H
+
+RCSIDH(eap_sim_h, "$Id$")
+
+#include "eap_types.h"
+
+#define EAP_SIM_VERSION 0x0001
+
+enum eapsim_subtype {
+ EAPSIM_START = 10,
+ EAPSIM_CHALLENGE = 11,
+ EAPSIM_NOTIFICATION = 12,
+ EAPSIM_REAUTH = 13,
+ EAPSIM_CLIENT_ERROR = 14,
+ EAPSIM_MAX_SUBTYPE = 15
+};
+
+enum eapsim_clientstates {
+ EAPSIM_CLIENT_INIT = 0,
+ EAPSIM_CLIENT_START = 1,
+ EAPSIM_CLIENT_MAXSTATES
+};
+
+/* server states
+ *
+ * in server_start, we send a EAP-SIM Start message.
+ *
+ */
+enum eapsim_serverstates {
+ EAPSIM_SERVER_START = 0,
+ EAPSIM_SERVER_CHALLENGE = 1,
+ EAPSIM_SERVER_SUCCESS = 10,
+ EAPSIM_SERVER_MAXSTATES
+};
+
+
+/*
+ * interfaces in eapsimlib.c
+ */
+int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep);
+char const *sim_state2name(enum eapsim_clientstates state, char *buf, int buflen);
+char const *sim_subtype2name(enum eapsim_subtype subtype, char *buf, int buflen);
+int unmap_eapsim_basictypes(RADIUS_PACKET *r, uint8_t *attr, unsigned int attrlen);
+
+
+/************************/
+/* CRYPTO FUNCTIONS */
+/************************/
+
+/*
+ * key derivation functions/structures
+ *
+ */
+
+#define EAPSIM_SRES_SIZE 4
+#define EAPSIM_RAND_SIZE 16
+#define EAPSIM_KC_SIZE 8
+#define EAPSIM_CALCMAC_SIZE 20
+#define EAPSIM_NONCEMT_SIZE 16
+#define EAPSIM_AUTH_SIZE 16
+
+struct eapsim_keys {
+ /* inputs */
+ uint8_t identity[MAX_STRING_LEN];
+ unsigned int identitylen;
+ uint8_t nonce_mt[EAPSIM_NONCEMT_SIZE];
+ uint8_t rand[3][EAPSIM_RAND_SIZE];
+ uint8_t sres[3][EAPSIM_SRES_SIZE];
+ uint8_t Kc[3][EAPSIM_KC_SIZE];
+ uint8_t versionlist[MAX_STRING_LEN];
+ uint8_t versionlistlen;
+ uint8_t versionselect[2];
+
+ /* outputs */
+ uint8_t master_key[20];
+ uint8_t K_aut[EAPSIM_AUTH_SIZE];
+ uint8_t K_encr[16];
+ uint8_t msk[64];
+ uint8_t emsk[64];
+};
+
+
+/*
+ * interfaces in eapsimlib.c
+ */
+int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps,
+ uint8_t key[EAPSIM_AUTH_SIZE],
+ uint8_t *extra, int extralen,
+ uint8_t calcmac[20]);
+
+/*
+ * in eapcrypto.c
+ */
+void eapsim_calculate_keys(struct eapsim_keys *ek);
+void eapsim_dump_mk(struct eapsim_keys *ek);
+
+
+#endif /* _EAP_SIM_H */
diff --git a/src/modules/rlm_eap/libeap/eap_tls.c b/src/modules/rlm_eap/libeap/eap_tls.c
new file mode 100644
index 0000000..2f37663
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_tls.c
@@ -0,0 +1,1206 @@
+
+/*
+ * eap_tls.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+/*
+ *
+ * TLS Packet Format in EAP
+ * --- ------ ------ -- ---
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | TLS Message Length
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TLS Message Length | TLS Data...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <assert.h>
+
+#include "eap_tls.h"
+/*
+ * Send an initial eap-tls request to the peer.
+ *
+ * Frame eap reply packet.
+ * len = header + type + tls_typedata
+ * tls_typedata = flags(Start (S) bit set, and no data)
+ *
+ * Once having received the peer's Identity, the EAP server MUST
+ * respond with an EAP-TLS/Start packet, which is an
+ * EAP-Request packet with EAP-Type=EAP-TLS, the Start (S) bit
+ * set, and no data. The EAP-TLS conversation will then begin,
+ * with the peer sending an EAP-Response packet with
+ * EAP-Type = EAP-TLS. The data field of that packet will
+ * be the TLS data.
+ *
+ * Fragment length is Framed-MTU - 4.
+ */
+tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_conf, bool client_cert, bool allow_tls13)
+{
+ tls_session_t *ssn;
+ REQUEST *request = handler->request;
+
+ handler->tls = true;
+
+ /*
+ * Every new session is started only from EAP-TLS-START.
+ * Before Sending EAP-TLS-START, open a new SSL session.
+ * Create all the required data structures & store them
+ * in Opaque. So that we can use these data structures
+ * when we get the response
+ */
+ ssn = tls_new_session(handler, tls_conf, request, client_cert, allow_tls13);
+ if (!ssn) {
+ return NULL;
+ }
+
+ /*
+ * Create a structure for all the items required to be
+ * verified for each client and set that as opaque data
+ * structure.
+ *
+ * NOTE: If we want to set each item sepearately then
+ * this index should be global.
+ */
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_HANDLER, (void *)handler);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF, (void *)tls_conf);
+ SSL_set_ex_data(ssn->ssl, fr_tls_ex_index_certs, (void *)&(handler->certs));
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_IDENTITY, (void *)&(handler->identity));
+#ifdef HAVE_OPENSSL_OCSP_H
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_STORE, (void *)tls_conf->ocsp_store);
+#endif
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_SSN, (void *)ssn);
+ SSL_set_ex_data(ssn->ssl, FR_TLS_EX_INDEX_TALLOC, handler);
+
+ return talloc_steal(handler, ssn); /* ssn */
+}
+
+/*
+ The S flag is set only within the EAP-TLS start message
+ sent from the EAP server to the peer.
+*/
+int eaptls_start(EAP_DS *eap_ds, int peap_flag)
+{
+ EAPTLS_PACKET reply;
+
+ reply.code = FR_TLS_START;
+ reply.length = TLS_HEADER_LEN + 1/*flags*/;
+
+ reply.flags = peap_flag;
+ reply.flags = SET_START(reply.flags);
+
+ reply.data = NULL;
+ reply.dlen = 0;
+
+ eaptls_compose(eap_ds, &reply);
+
+ return 1;
+}
+
+
+/** Send an EAP-TLS success
+ *
+ * Composes an EAP-TLS-Success. This is a message with code EAP_TLS_ESTABLISHED.
+ * It contains no cryptographic material, and is not protected.
+ *
+ * We add the MPPE keys here. These are used by the NAS. The supplicant
+ * will derive the same keys separately.
+ *
+ * @param handler handler of eap session that completed successfully.
+ * @param peap_flag to indicate PEAP version
+ * @return
+ * - 1 on success.
+ */
+int eaptls_success(eap_handler_t *handler, int peap_flag)
+{
+ EAPTLS_PACKET reply;
+ REQUEST *request = handler->request;
+ tls_session_t *tls_session = handler->opaque;
+
+ handler->finished = true;
+ reply.code = FR_TLS_SUCCESS;
+ reply.length = TLS_HEADER_LEN;
+ reply.flags = peap_flag;
+ reply.data = NULL;
+ reply.dlen = 0;
+
+ tls_success(tls_session, request);
+
+ /*
+ * Call compose AFTER checking for cached data.
+ */
+ eaptls_compose(handler->eap_ds, &reply);
+
+ /*
+ * Automatically generate MPPE keying material.
+ */
+ if (tls_session->label) {
+ uint8_t const *context = NULL;
+ size_t context_size = 0;
+#ifdef TLS1_3_VERSION
+ uint8_t const context_tls13[] = { handler->type };
+#endif
+
+ switch (SSL_version(tls_session->ssl)) {
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ context = context_tls13;
+ context_size = sizeof(context_tls13);
+ tls_session->label = "EXPORTER_EAP_TLS_Key_Material";
+ break;
+#endif
+ case TLS1_2_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_VERSION:
+ break;
+ case SSL2_VERSION:
+ case SSL3_VERSION:
+ default:
+ /* Should never happen */
+ rad_assert(0);
+ return 0;
+ break;
+ }
+ eaptls_gen_mppe_keys(request,
+ tls_session->ssl, tls_session->label,
+ context, context_size);
+ } else if (handler->type != PW_EAP_FAST) {
+ RWDEBUG("(TLS) EAP Not adding MPPE keys because there is no PRF label");
+ }
+
+ eaptls_gen_eap_key(handler);
+
+ return 1;
+}
+
+int eaptls_fail(eap_handler_t *handler, int peap_flag)
+{
+ EAPTLS_PACKET reply;
+ tls_session_t *tls_session = handler->opaque;
+
+ handler->finished = true;
+ reply.code = FR_TLS_FAIL;
+ reply.length = TLS_HEADER_LEN;
+ reply.flags = peap_flag;
+ reply.data = NULL;
+ reply.dlen = 0;
+
+ tls_fail(tls_session);
+
+ eaptls_compose(handler->eap_ds, &reply);
+
+ return 1;
+}
+
+/*
+ A single TLS record may be up to 16384 octets in length, but a TLS
+ message may span multiple TLS records, and a TLS certificate message
+ may in principle be as long as 16MB.
+*/
+
+/*
+ * Frame the Dirty data that needs to be send to the client in an
+ * EAP-Request. We always embed the TLS-length in all EAP-TLS
+ * packets that we send, for easy reference purpose. Handle
+ * fragmentation and sending the next fragment etc.
+ */
+int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn)
+{
+ EAPTLS_PACKET reply;
+ unsigned int size;
+ unsigned int nlen;
+ unsigned int lbit = 0;
+
+ /* This value determines whether we set (L)ength flag for
+ EVERY packet we send and add corresponding
+ "TLS Message Length" field.
+
+ length_flag = true;
+ This means we include L flag and "TLS Msg Len" in EVERY
+ packet we send out.
+
+ length_flag = false;
+ This means we include L flag and "TLS Msg Len" **ONLY**
+ in First packet of a fragment series. We do not use
+ it anywhere else.
+
+ Having L flag in every packet is prefered.
+
+ */
+ if (ssn->length_flag) {
+ lbit = 4;
+ }
+ if (ssn->fragment == 0) {
+ ssn->tls_msg_len = ssn->dirty_out.used;
+ }
+
+ reply.code = FR_TLS_REQUEST;
+ reply.flags = ssn->peap_flag;
+
+ /* Send data, NOT more than the FRAGMENT size */
+ if (ssn->dirty_out.used > ssn->mtu) {
+ size = ssn->mtu;
+ reply.flags = SET_MORE_FRAGMENTS(reply.flags);
+ /* Length MUST be included if it is the First Fragment */
+ if (ssn->fragment == 0) {
+ lbit = 4;
+ }
+ ssn->fragment = 1;
+ } else {
+ size = ssn->dirty_out.used;
+ ssn->fragment = 0;
+ }
+
+ reply.dlen = lbit + size;
+ reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen;
+
+ reply.data = talloc_array(eap_ds, uint8_t, reply.length);
+ if (!reply.data) return 0;
+
+ if (lbit) {
+ nlen = htonl(ssn->tls_msg_len);
+ memcpy(reply.data, &nlen, lbit);
+ reply.flags = SET_LENGTH_INCLUDED(reply.flags);
+ }
+ (ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size);
+
+ eaptls_compose(eap_ds, &reply);
+ talloc_free(reply.data);
+ reply.data = NULL;
+
+ return 1;
+}
+
+
+/*
+ * Similarly, when the EAP server receives an EAP-Response with
+ * the M bit set, it MUST respond with an EAP-Request with
+ * EAP-Type=EAP-TLS and no data. This serves as a fragment ACK.
+ *
+ * In order to prevent errors in the processing of fragments, the
+ * EAP server MUST use increment the Identifier value for each
+ * fragment ACK contained within an EAP-Request, and the peer
+ * MUST include this Identifier value in the subsequent fragment
+ * contained within an EAP- Reponse.
+ *
+ * EAP server sends an ACK when it determines there are More
+ * fragments to receive to make the complete
+ * TLS-record/TLS-Message
+ */
+static int eaptls_send_ack(eap_handler_t *handler, int peap_flag)
+{
+ EAPTLS_PACKET reply;
+ REQUEST *request = handler->request;
+
+ RDEBUG2("(TLS) EAP ACKing fragment, the peer should send more data.");
+ reply.code = FR_TLS_ACK;
+ reply.length = TLS_HEADER_LEN + 1/*flags*/;
+ reply.flags = peap_flag;
+ reply.data = NULL;
+ reply.dlen = 0;
+
+ eaptls_compose(handler->eap_ds, &reply);
+
+ return 1;
+}
+
+/*
+ * The S flag is set only within the EAP-TLS start message sent
+ * from the EAP server to the peer.
+ *
+ * Similarly, when the EAP server receives an EAP-Response with
+ * the M bit set, it MUST respond with an EAP-Request with
+ * EAP-Type=EAP-TLS and no data. This serves as a fragment
+ * ACK. The EAP peer MUST wait.
+ */
+static fr_tls_status_t eaptls_verify(eap_handler_t *handler)
+{
+ EAP_DS *eap_ds = handler->eap_ds;
+ tls_session_t *tls_session = handler->opaque;
+ EAP_DS *prev_eap_ds = handler->prev_eapds;
+ eaptls_packet_t *eaptls_packet, *eaptls_prev = NULL;
+ REQUEST *request = handler->request;
+ size_t frag_len;
+
+ /*
+ * We don't check ANY of the input parameters. It's all
+ * code which works together, so if something is wrong,
+ * we SHOULD core dump.
+ *
+ * e.g. if eap_ds is NULL, of if eap_ds->response is
+ * NULL, of if it's NOT an EAP-Response, or if the packet
+ * is too short. See eap_validation()., in ../../eap.c
+ *
+ * Also, eap_method_select() takes care of selecting the
+ * appropriate type, so we don't need to check
+ * eap_ds->response->type.num == PW_EAP_TLS, or anything
+ * else.
+ */
+ eaptls_packet = (eaptls_packet_t *)eap_ds->response->type.data;
+ if (prev_eap_ds && prev_eap_ds->response)
+ eaptls_prev = (eaptls_packet_t *)prev_eap_ds->response->type.data;
+
+ if (eaptls_packet) {
+ /*
+ * First output the flags (for debugging)
+ */
+ RDEBUG3("(TLS) EAP Peer sent flags %c%c%c",
+ TLS_START(eaptls_packet->flags) ? 'S' : '-',
+ TLS_MORE_FRAGMENTS(eaptls_packet->flags) ? 'M' : '-',
+ TLS_LENGTH_INCLUDED(eaptls_packet->flags) ? 'L' : '-');
+ }
+
+ /*
+ * check for ACK
+ *
+ * If there's no TLS data, or there's 1 byte of TLS data,
+ * with the flags set to zero, then it's an ACK.
+ *
+ * Find if this is a reply to the previous request sent
+ */
+ if ((!eaptls_packet) ||
+ ((eap_ds->response->length == EAP_HEADER_LEN + 2) &&
+ ((eaptls_packet->flags & 0xc0) == 0x00))) {
+
+ if (prev_eap_ds && (prev_eap_ds->request->id == eap_ds->response->id)) {
+ return tls_ack_handler(handler->opaque, request);
+ } else {
+ REDEBUG("(TLS) EAP Received Unexpected ACK - rejection the connection");
+ return FR_TLS_INVALID;
+ }
+ }
+
+ /*
+ * We send TLS_START, but do not receive it.
+ */
+ if (TLS_START(eaptls_packet->flags)) {
+ REDEBUG("(TLS) EAP Peer sent EAP-TLS Start message (only the server is allowed to do this)");
+ return FR_TLS_INVALID;
+ }
+
+ /*
+ * Calculate this fragment's length
+ */
+ frag_len = eap_ds->response->length -
+ (EAP_HEADER_LEN + (TLS_LENGTH_INCLUDED(eaptls_packet->flags) ? 6 : 2));
+
+ /*
+ * The L bit (length included) is set to indicate the
+ * presence of the four octet TLS Message Length field,
+ * and MUST be set for the first fragment of a fragmented
+ * TLS message or set of messages.
+ *
+ * The M bit (more fragments) is set on all but the last
+ * fragment.
+ *
+ * The S bit (EAP-TLS start) is set in an EAP-TLS Start
+ * message. This differentiates the EAP-TLS Start message
+ * from a fragment acknowledgement.
+ */
+ if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) {
+ size_t total_len = eaptls_packet->data[2] * 256 | eaptls_packet->data[3];
+
+ if (frag_len > total_len) {
+ RWDEBUG("(TLS) EAP Fragment length (%zu bytes) is greater than TLS record length (%zu bytes)", frag_len,
+ total_len);
+ }
+
+ RDEBUG2("(TLS) EAP Peer says that the final record size will be %zu bytes", total_len);
+ if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {
+ /*
+ * The supplicant is free to send fragments of wildly varying
+ * lengths, but the vast majority won't.
+ *
+ * In this calculation we take into account the fact that the future
+ * fragments are likely to be 4 bytes larger than the initial one
+ * as they won't contain the length field.
+ */
+ if (frag_len + 4) { /* check for wrap, else clang scan gets excited */
+ RDEBUG2("(TLS) EAP Expecting %i fragments",
+ (int)((((total_len - frag_len) + ((frag_len + 4) - 1)) / (frag_len + 4)) + 1));
+ }
+
+ /*
+ * FIRST_FRAGMENT is identified
+ * 1. If there is no previous EAP-response received.
+ * 2. If EAP-response received, then its M bit not set.
+ * (It is because Last fragment will not have M bit set)
+ */
+ if (!prev_eap_ds || (!prev_eap_ds->response) || (!eaptls_prev) ||
+ !TLS_MORE_FRAGMENTS(eaptls_prev->flags)) {
+ RDEBUG2("(TLS) EAP Got first TLS fragment (%zu bytes). Peer says more fragments "
+ "will follow", frag_len);
+ tls_session->tls_record_in_total_len = total_len;
+ tls_session->tls_record_in_recvd_len = frag_len;
+
+ return FR_TLS_FIRST_FRAGMENT;
+ }
+
+ RDEBUG2("(TLS) EAP Got additional fragment with length (%zu bytes). "
+ "Peer says more fragments will follow", frag_len);
+
+ /*
+ * Check we've not exceeded the originally indicated TLS record size.
+ */
+ tls_session->tls_record_in_recvd_len += frag_len;
+ if (tls_session->tls_record_in_recvd_len > tls_session->tls_record_in_total_len) {
+ RWDEBUG("(TLS) EAP Total received fragments (%zu bytes), exceeds "
+ "total data length (%zu bytes)", frag_len, total_len);
+ }
+
+ return FR_TLS_MORE_FRAGMENTS_WITH_LENGTH;
+ }
+
+ /*
+ * If it's a complete record, our fragment size should match the
+ * value of the four octet TLS length field.
+ */
+ if (total_len != frag_len) {
+ RWDEBUG("(TLS) EAP Peer says no more fragments, but expected data length (%zu bytes) "
+ "does not match expected data length (%zu bytes)", total_len, frag_len);
+ }
+
+ tls_session->tls_record_in_total_len = total_len;
+ tls_session->tls_record_in_recvd_len = frag_len;
+ RDEBUG2("(TLS) EAP Got all data (%zu bytes)", frag_len);
+ return FR_TLS_LENGTH_INCLUDED;
+ }
+
+ /*
+ * The previous packet had the M flags set, but this one doesn't,
+ * this must be the final record fragment
+ */
+ if ((eaptls_prev && TLS_MORE_FRAGMENTS(eaptls_prev->flags)) && !TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {
+ RDEBUG2("(TLS) EAP Got final fragment (%zu bytes)", frag_len);
+ tls_session->tls_record_in_recvd_len += frag_len;
+ if (tls_session->tls_record_in_recvd_len != tls_session->tls_record_in_total_len) {
+ RWDEBUG("(TLS) EAP Total received record fragments (%zu bytes), does not equal expected "
+ "expected data length (%zu bytes)",
+ tls_session->tls_record_in_recvd_len, tls_session->tls_record_in_total_len);
+ }
+ }
+
+ if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {
+ RDEBUG2("(TLS) EAP Got additional fragment (%zu bytes). Peer says more fragments will follow",
+ frag_len);
+ tls_session->tls_record_in_recvd_len += frag_len;
+ if (tls_session->tls_record_in_recvd_len > tls_session->tls_record_in_total_len) {
+ RWDEBUG("(TLS) EAP Total received fragments (%zu bytes), exceeds "
+ "expected length (%zu bytes)",
+ tls_session->tls_record_in_recvd_len, tls_session->tls_record_in_total_len);
+ }
+ return FR_TLS_MORE_FRAGMENTS;
+ }
+
+ /*
+ * None of the flags are set, but it's still a valid EAP-TLS packet.
+ */
+ return FR_TLS_OK;
+}
+
+/*
+ * EAPTLS_PACKET
+ * code = EAP-code
+ * id = EAP-id
+ * length = code + id + length + flags + tlsdata
+ * = 1 + 1 + 2 + 1 + X
+ * length = EAP-length - 1(EAP-Type = 1 octet)
+ * flags = EAP-typedata[0] (1 octet)
+ * dlen = EAP-typedata[1-4] (4 octets), if L flag set
+ * = length - 5(code+id+length+flags), otherwise
+ * data = EAP-typedata[5-n], if L flag set
+ * = EAP-typedata[1-n], otherwise
+ * packet = EAP-typedata (complete typedata)
+ *
+ * Points to consider during EAP-TLS data extraction
+ * 1. In the received packet, No data will be present incase of ACK-NAK
+ * 2. Incase if more fragments need to be received then ACK after retreiving this fragment.
+ *
+ * RFC 2716 Section 4.2. PPP EAP TLS Request Packet
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | TLS Message Length
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | TLS Message Length | TLS Data...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * The Length field is two octets and indicates the length of the EAP
+ * packet including the Code, Identifir, Length, Type, and TLS data
+ * fields.
+ */
+static EAPTLS_PACKET *eaptls_extract(REQUEST *request, EAP_DS *eap_ds, fr_tls_status_t status)
+{
+ EAPTLS_PACKET *tlspacket;
+ uint32_t data_len = 0;
+ uint32_t len = 0;
+ uint8_t *data = NULL;
+
+ if (status == FR_TLS_INVALID) return NULL;
+
+ /*
+ * The main EAP code & eaptls_verify() take care of
+ * ensuring that the packet is OK, and that we can
+ * extract the various fields we want.
+ *
+ * e.g. a TLS packet with zero data is allowed as an ACK,
+ * but we will never see it here, as we will simply
+ * send another fragment, instead of trying to extract
+ * the data.
+ *
+ * MUST have TLS type octet, followed by flags, followed
+ * by data.
+ */
+ assert(eap_ds->response->length > 2);
+
+ tlspacket = talloc(eap_ds, EAPTLS_PACKET);
+ if (!tlspacket) return NULL;
+
+ /*
+ * Code & id for EAPTLS & EAP are same
+ * but eaptls_length = eap_length - 1(EAP-Type = 1 octet)
+ *
+ * length = code + id + length + type + tlsdata
+ * = 1 + 1 + 2 + 1 + X
+ */
+ tlspacket->code = eap_ds->response->code;
+ tlspacket->id = eap_ds->response->id;
+ tlspacket->length = eap_ds->response->length - 1; /* EAP type */
+ tlspacket->flags = eap_ds->response->type.data[0];
+
+ /*
+ * A quick sanity check of the flags. If we've been told
+ * that there's a length, and there isn't one, then stop.
+ */
+ if (TLS_LENGTH_INCLUDED(tlspacket->flags) &&
+ (tlspacket->length < 5)) { /* flags + TLS message length */
+ REDEBUG("(TLS) EAP Invalid packet received: Length bit is set,"
+ "but packet too short to contain length field");
+ talloc_free(tlspacket);
+ return NULL;
+ }
+
+ /*
+ * If the final TLS packet is larger than we can handle, die
+ * now.
+ *
+ * Likewise, if the EAP packet says N bytes, and the TLS
+ * packet says there's fewer bytes, it's a problem.
+ */
+ if (TLS_LENGTH_INCLUDED(tlspacket->flags)) {
+ memcpy(&data_len, &eap_ds->response->type.data[1], 4);
+ data_len = ntohl(data_len);
+ if (data_len > MAX_RECORD_SIZE) {
+ REDEBUG("(TLS) EAP Reassembled data will be %u bytes, "
+ "greater than the size that we can handle (" STRINGIFY(MAX_RECORD_SIZE) " bytes)",
+ data_len);
+ talloc_free(tlspacket);
+ return NULL;
+ }
+ }
+
+ switch (status) {
+ /*
+ * The TLS Message Length field is four octets, and
+ * provides the total length of the TLS message or set of
+ * messages that is being fragmented; this simplifies
+ * buffer allocation.
+ *
+ * Dynamic allocation of buffers as & when we know the
+ * length should solve the problem.
+ */
+ case FR_TLS_FIRST_FRAGMENT:
+ case FR_TLS_LENGTH_INCLUDED:
+ case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH:
+ if (tlspacket->length < 5) { /* flags + TLS message length */
+ REDEBUG("(TLS) EAP Invalid packet received: Expected length, got none");
+ talloc_free(tlspacket);
+ return NULL;
+ }
+
+ /*
+ * Extract all the TLS fragments from the
+ * previous eap_ds Start appending this
+ * fragment to the above ds
+ */
+ memcpy(&data_len, &eap_ds->response->type.data[1], sizeof(uint32_t));
+ data_len = ntohl(data_len);
+ data = (eap_ds->response->type.data + 5/*flags+TLS-Length*/);
+ len = eap_ds->response->type.length - 5/*flags+TLS-Length*/;
+
+ /*
+ * Hmm... this should be an error, too.
+ */
+ if (data_len > len) {
+ data_len = len;
+ }
+ break;
+
+ /*
+ * Data length is implicit, from the EAP header.
+ */
+ case FR_TLS_MORE_FRAGMENTS:
+ case FR_TLS_OK:
+ data_len = eap_ds->response->type.length - 1/*flags*/;
+ data = eap_ds->response->type.data + 1/*flags*/;
+ break;
+
+ default:
+ REDEBUG("(TLS) EAP Invalid packet received");
+ talloc_free(tlspacket);
+ return NULL;
+ }
+
+ tlspacket->dlen = data_len;
+ if (data_len) {
+ tlspacket->data = talloc_array(tlspacket, uint8_t,
+ data_len);
+ if (!tlspacket->data) {
+ talloc_free(tlspacket);
+ return NULL;
+ }
+ memcpy(tlspacket->data, data, data_len);
+ }
+
+ return tlspacket;
+}
+
+
+
+/*
+ * To process the TLS,
+ * INCOMING DATA:
+ * 1. EAP-TLS should get the compelete TLS data from the peer.
+ * 2. Store that data in a data structure with any other required info
+ * 3. Handle that data structure to the TLS module.
+ * 4. TLS module will perform its operations on the data and
+ * handle back to EAP-TLS
+ *
+ * OUTGOING DATA:
+ * 1. EAP-TLS if necessary will fragment it and send it to the
+ * destination.
+ *
+ * During EAP-TLS initialization, TLS Context object will be
+ * initialized and stored. For every new authentication
+ * requests, TLS will open a new session object and that session
+ * object should be maintained even after the session is
+ * completed for session resumption. (Probably later as a feature
+ * as we donot know who maintains these session objects ie,
+ * SSL_CTX (internally) or TLS module(explicitly). If TLS module,
+ * then how to let SSL API know about these sessions.)
+ */
+static fr_tls_status_t eaptls_operation(fr_tls_status_t status, eap_handler_t *handler)
+{
+ REQUEST *request = handler->request;
+ tls_session_t *tls_session = handler->opaque;
+
+ if ((status == FR_TLS_MORE_FRAGMENTS) ||
+ (status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) ||
+ (status == FR_TLS_FIRST_FRAGMENT)) {
+ /*
+ * Send the ACK.
+ */
+ eaptls_send_ack(handler, tls_session->peap_flag);
+ return FR_TLS_HANDLED;
+
+ }
+
+ /*
+ * We have the complete TLS-data or TLS-message.
+ *
+ * Clean the dirty message.
+ *
+ * Authenticate the user and send
+ * Success/Failure.
+ *
+ * If more info
+ * is required then send another request.
+ */
+ if (!tls_handshake_recv(handler->request, tls_session)) {
+ REDEBUG("(TLS) EAP Receive handshake failed during operation");
+ tls_fail(tls_session);
+ return FR_TLS_FAIL;
+ }
+
+#ifdef TLS1_3_VERSION
+ /*
+ * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+ *
+ * We need to signal the other end that TLS negotiation
+ * is done. We can't send a zero-length application data
+ * message, so we send application data which is one byte
+ * of zero.
+ *
+ * Note this is only done for when there is no application
+ * data to be sent. So this is done always for EAP-TLS but
+ * notibly not for PEAP even on resumption.
+ */
+ if ((SSL_version(tls_session->ssl) == TLS1_3_VERSION) &&
+ (tls_session->client_cert_ok || tls_session->authentication_success || SSL_session_reused(tls_session->ssl))) {
+ if ((handler->type == PW_EAP_TLS) || SSL_session_reused(tls_session->ssl)) {
+ tls_session->authentication_success = true;
+
+ RDEBUG("(TLS) EAP Sending final Commitment Message.");
+ tls_session->record_plus(&tls_session->clean_in, "\0", 1);
+ }
+
+ tls_handshake_send(request, tls_session);
+ }
+#endif
+
+ /*
+ * FIXME: return success/fail.
+ *
+ * TLS proper can decide what to do, then.
+ */
+ if (tls_session->dirty_out.used > 0) {
+ eaptls_request(handler->eap_ds, tls_session);
+ return FR_TLS_HANDLED;
+ }
+
+ /*
+ * If there is no data to send i.e
+ * dirty_out.used <=0 and if the SSL
+ * handshake is finished.
+ */
+ if (tls_session->is_init_finished) return FR_TLS_SUCCESS;
+
+ /*
+ * If session is established, skip round-trip and
+ * try to process any inner tunnel data if present.
+ *
+ * This occurs for EAP-TTLS/PAP with TLSv1.3.
+ */
+ if (!tls_session->is_init_finished && SSL_is_init_finished(tls_session->ssl)) {
+ /*
+ * Don't set is_init_finished, as that causes the
+ * rest of the code to make too many assumptions.
+ */
+ return FR_TLS_OK;
+ }
+
+ /*
+ * Who knows what happened...
+ */
+ REDEBUG("(TLS) Cannot continue, as the peer is misbehaving.");
+ return FR_TLS_FAIL;
+}
+
+
+/*
+ * In the actual authentication first verify the packet and then create the data structure
+ */
+/*
+ * To process the TLS,
+ * INCOMING DATA:
+ * 1. EAP-TLS should get the compelete TLS data from the peer.
+ * 2. Store that data in a data structure with any other required info
+ * 3. Hand this data structure to the TLS module.
+ * 4. TLS module will perform its operations on the data and hands back to EAP-TLS
+ * OUTGOING DATA:
+ * 1. EAP-TLS if necessary will fragment it and send it to the destination.
+ *
+ * During EAP-TLS initialization, TLS Context object will be
+ * initialized and stored. For every new authentication
+ * requests, TLS will open a new session object and that
+ * session object SHOULD be maintained even after the session
+ * is completed, for session resumption. (Probably later as a
+ * feature, as we do not know who maintains these session
+ * objects ie, SSL_CTX (internally) or TLS module (explicitly). If
+ * TLS module, then how to let SSL API know about these
+ * sessions.)
+ */
+
+/*
+ * Process an EAP request
+ */
+fr_tls_status_t eaptls_process(eap_handler_t *handler)
+{
+ tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+ EAPTLS_PACKET *tlspacket;
+ fr_tls_status_t status;
+ REQUEST *request = handler->request;
+
+ if (!request) return FR_TLS_FAIL;
+
+ RDEBUG3("(TLS) EAP Continuing ...");
+
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
+
+ if (handler->certs) fr_pair_add(&request->packet->vps,
+ fr_pair_list_copy(request->packet, handler->certs));
+
+ /*
+ * This case is when SSL generates Alert then we
+ * send that alert to the client and then send the EAP-Failure
+ */
+ status = eaptls_verify(handler);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("(TLS) EAP Verification failed with %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("(TLS) EAP Verification says %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+
+ switch (status) {
+ default:
+ case FR_TLS_INVALID:
+ case FR_TLS_FAIL:
+
+ /*
+ * Success means that we're done the initial
+ * handshake. For TTLS, this means send stuff
+ * back to the client, and the client sends us
+ * more tunneled data.
+ */
+ case FR_TLS_SUCCESS:
+ goto done;
+
+ /*
+ * Normal TLS request, continue with the "get rest
+ * of fragments" phase.
+ */
+ case FR_TLS_REQUEST:
+ eaptls_request(handler->eap_ds, tls_session);
+ status = FR_TLS_HANDLED;
+ goto done;
+
+ /*
+ * The handshake is done, and we're in the "tunnel
+ * data" phase.
+ */
+ case FR_TLS_OK:
+ RDEBUG2("(TLS) EAP Done initial handshake");
+
+ /*
+ * Get the rest of the fragments.
+ */
+ case FR_TLS_FIRST_FRAGMENT:
+ case FR_TLS_MORE_FRAGMENTS:
+ case FR_TLS_LENGTH_INCLUDED:
+ case FR_TLS_MORE_FRAGMENTS_WITH_LENGTH:
+ break;
+ }
+
+ /*
+ * Extract the TLS packet from the buffer.
+ */
+ if ((tlspacket = eaptls_extract(request, handler->eap_ds, status)) == NULL) {
+ REDEBUG("(TLS) EAP Failed extracting TLS packet from EAP-Message");
+ status = FR_TLS_FAIL;
+ goto done;
+ }
+
+ /*
+ * Get the session struct from the handler
+ *
+ * update the dirty_in buffer
+ *
+ * NOTE: This buffer will contain partial data when M bit is set.
+ *
+ * CAUTION while reinitializing this buffer, it should be
+ * reinitialized only when this M bit is NOT set.
+ */
+ if (tlspacket->dlen !=
+ (tls_session->record_plus)(&tls_session->dirty_in, tlspacket->data, tlspacket->dlen)) {
+ talloc_free(tlspacket);
+ REDEBUG("(TLS) EAP Exceeded maximum record size");
+ status = FR_TLS_FAIL;
+ goto done;
+ }
+
+ /*
+ * No longer needed.
+ */
+ talloc_free(tlspacket);
+
+ /*
+ * SSL initalization is done. Return.
+ *
+ * The TLS data will be in the tls_session structure.
+ */
+ if (tls_session->is_init_finished) {
+ /*
+ * The initialization may be finished, but if
+ * there more fragments coming, then send ACK,
+ * and get the caller to continue the
+ * conversation.
+ */
+ if ((status == FR_TLS_MORE_FRAGMENTS) ||
+ (status == FR_TLS_MORE_FRAGMENTS_WITH_LENGTH) ||
+ (status == FR_TLS_FIRST_FRAGMENT)) {
+ /*
+ * Send the ACK.
+ */
+ eaptls_send_ack(handler, tls_session->peap_flag);
+ RDEBUG2("(TLS) EAP Init is done, but tunneled data is fragmented");
+ status = FR_TLS_HANDLED;
+ goto done;
+ }
+
+ status = tls_application_data(tls_session, request);
+ goto done;
+ }
+
+ /*
+ * Continue the handshake.
+ */
+ status = eaptls_operation(status, handler);
+ if (status == FR_TLS_SUCCESS) {
+#define MAX_SESSION_SIZE (256)
+ VALUE_PAIR *vps;
+ char buffer[2 * MAX_SESSION_SIZE + 1];
+
+ /*
+ * Restore the cached VPs before processing the
+ * application data.
+ */
+ tls_session_id(tls_session->ssl_session, buffer, MAX_SESSION_SIZE);
+
+ vps = SSL_SESSION_get_ex_data(tls_session->ssl_session, fr_tls_ex_index_vps);
+ if (!vps) {
+ RWDEBUG("(TLS) EAP No information in cached session %s", buffer);
+ } else {
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ fr_tls_server_conf_t *conf;
+
+ RDEBUG("(TLS) EAP Adding cached attributes from session %s", buffer);
+
+ conf = (fr_tls_server_conf_t *)SSL_get_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_CONF);
+ rad_assert(conf != NULL);
+
+ /*
+ * The cbtls_get_session() function doesn't have
+ * access to sock->certs or handler->certs, which
+ * is where the certificates normally live. So
+ * the certs are all in the VPS list here, and
+ * have to be manually extracted.
+ */
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (conf->cache_ht && fr_hash_table_finddata(conf->cache_ht, vp->da)) {
+ rdebug_pair(L_DBG_LVL_2, request, vp, "&session-state:");
+ fr_pair_add(&request->state, fr_pair_copy(request->state_ctx, vp));
+ continue;
+ }
+
+ /*
+ * TLS-* attrs get added back to
+ * the request list.
+ */
+ if ((vp->da->vendor == 0) &&
+ (vp->da->attr >= PW_TLS_CERT_SERIAL) &&
+ (vp->da->attr <= PW_TLS_CLIENT_CERT_SUBJECT_ALT_NAME_UPN)) {
+ /*
+ * Certs already exist. Don't re-add them.
+ */
+ if (!handler->certs) {
+ rdebug_pair(L_DBG_LVL_2, request, vp, "&request:");
+ fr_pair_add(&request->packet->vps, fr_pair_copy(request->packet, vp));
+ }
+
+ } else if ((vp->da->vendor == 0) &&
+ (vp->da->attr == PW_EAP_TYPE)) {
+ /*
+ * EAP-Type gets added to
+ * the control list, so
+ * that we can sanity check it.
+ */
+ rdebug_pair(L_DBG_LVL_2, request, vp, "&control:");
+ fr_pair_add(&request->config, fr_pair_copy(request, vp));
+
+ } else {
+
+ rdebug_pair(L_DBG_LVL_2, request, vp, "&reply:");
+ fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
+ }
+ }
+ REXDENT();
+ }
+ }
+
+ done:
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
+
+ return status;
+}
+
+
+/*
+ * compose the TLS reply packet in the EAP reply typedata
+ */
+int eaptls_compose(EAP_DS *eap_ds, EAPTLS_PACKET *reply)
+{
+ uint8_t *ptr;
+
+ /*
+ * Don't set eap_ds->request->type.num, as the main EAP
+ * handler will do that for us. This allows the TLS
+ * module to be called from TTLS & PEAP.
+ */
+
+ /*
+ * When the EAP server receives an EAP-Response with the
+ * M bit set, it MUST respond with an EAP-Request with
+ * EAP-Type=EAP-TLS and no data. This serves as a
+ * fragment ACK. The EAP peer MUST wait until it receives
+ * the EAP-Request before sending another fragment.
+ *
+ * In order to prevent errors in the processing of
+ * fragments, the EAP server MUST use increment the
+ * Identifier value for each fragment ACK contained
+ * within an EAP-Request, and the peer MUST include this
+ * Identifier value in the subsequent fragment contained
+ * within an EAP- Reponse.
+ */
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t,
+ reply->length - TLS_HEADER_LEN + 1);
+ if (!eap_ds->request->type.data) return 0;
+
+ /* EAPTLS Header length is excluded while computing EAP typelen */
+ eap_ds->request->type.length = reply->length - TLS_HEADER_LEN;
+
+ ptr = eap_ds->request->type.data;
+ *ptr++ = (uint8_t)(reply->flags & 0xFF);
+
+ if (reply->dlen) memcpy(ptr, reply->data, reply->dlen);
+
+ switch (reply->code) {
+ case FR_TLS_ACK:
+ case FR_TLS_START:
+ case FR_TLS_REQUEST:
+ eap_ds->request->code = PW_EAP_REQUEST;
+ break;
+
+ case FR_TLS_SUCCESS:
+ eap_ds->request->code = PW_EAP_SUCCESS;
+ break;
+
+ case FR_TLS_FAIL:
+ eap_ds->request->code = PW_EAP_FAILURE;
+ break;
+
+ default:
+ /* Should never enter here */
+ rad_assert(0);
+ break;
+ }
+
+ return 1;
+}
+
+/*
+ * Parse TLS configuration
+ *
+ * If the option given by 'attr' is set, we find the config section
+ * of that name and use that for the TLS configuration. If not, we
+ * fall back to compatibility mode and read the TLS options from
+ * the 'tls' section.
+ */
+fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *attr)
+{
+ char const *tls_conf_name;
+ CONF_PAIR *cp;
+ CONF_SECTION *parent;
+ CONF_SECTION *tls_cs;
+ fr_tls_server_conf_t *tls_conf;
+
+ if (!cs)
+ return NULL;
+
+ rad_assert(attr != NULL);
+
+ parent = cf_item_parent(cf_section_to_item(cs));
+
+ cp = cf_pair_find(cs, attr);
+ if (cp) {
+ tls_conf_name = cf_pair_value(cp);
+
+ tls_cs = cf_section_sub_find_name2(parent, TLS_CONFIG_SECTION, tls_conf_name);
+
+ if (!tls_cs) {
+ ERROR("Cannot find tls config \"%s\"", tls_conf_name);
+ return NULL;
+ }
+ } else {
+ /*
+ * If we can't find the section given by the 'attr', we
+ * fall-back to looking for the "tls" section, as in
+ * previous versions.
+ *
+ * We don't fall back if the 'attr' is specified, but we can't
+ * find the section - that is just a config error.
+ */
+ INFO("TLS section \"%s\" missing, trying to use legacy configuration", attr);
+ tls_cs = cf_section_sub_find(parent, "tls");
+ }
+
+ if (!tls_cs)
+ return NULL;
+
+ tls_conf = tls_server_conf_parse(tls_cs);
+
+ if (!tls_conf)
+ return NULL;
+
+ /*
+ * The EAP RFC's say 1020, but we're less picky.
+ */
+ if (tls_conf->fragment_size < 100) {
+ ERROR("Configured fragment size is too small, must be >= 100");
+ return NULL;
+ }
+
+ /*
+ * The maximum size for a RADIUS packet is 4096,
+ * minus the header (20), Message-Authenticator (18),
+ * and State (18), etc. results in about 4000 bytes of data
+ * that can be devoted *solely* to EAP.
+ */
+ if (tls_conf->fragment_size > 4000) {
+ ERROR("Configured fragment size is too large, must be <= 4000");
+ return NULL;
+ }
+
+ /*
+ * Account for the EAP header (4), and the EAP-TLS header
+ * (6), as per Section 4.2 of RFC 2716. What's left is
+ * the maximum amount of data we read from a TLS buffer.
+ */
+ tls_conf->fragment_size -= 10;
+
+ return tls_conf;
+}
+
diff --git a/src/modules/rlm_eap/libeap/eap_tls.h b/src/modules/rlm_eap/libeap/eap_tls.h
new file mode 100644
index 0000000..8e5fc77
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_tls.h
@@ -0,0 +1,109 @@
+/*
+ * eap_tls.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_TLS_H
+#define _EAP_TLS_H
+
+RCSIDH(eap_tls_h, "$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <ctype.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/tls.h>
+
+#include "eap.h"
+
+/*
+ * Externally exported TLS functions.
+ */
+fr_tls_status_t eaptls_process(eap_handler_t *handler);
+
+int eaptls_success(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
+int eaptls_fail(eap_handler_t *handler, int peap_flag) CC_HINT(nonnull);
+int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) CC_HINT(nonnull);
+
+
+void T_PRF(unsigned char const *secret, unsigned int secret_len, char const *prf_label, unsigned char const *seed, unsigned int seed_len, unsigned char *out, unsigned int out_len) CC_HINT(nonnull(1,3,6));
+void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, size_t context_size);
+void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size);
+void eaptls_gen_eap_key(eap_handler_t *handler);
+void eap_fast_tls_gen_challenge(SSL *ssl, int version, uint8_t *buffer, size_t size, char const *prf_label) CC_HINT(nonnull);
+
+#define BUFFER_SIZE 1024
+
+typedef enum tls_op {
+ EAP_TLS_START = 1,
+ EAP_TLS_ACK = 2,
+ EAP_TLS_SUCCESS = 3,
+ EAP_TLS_FAIL = 4,
+ EAP_TLS_ALERT = 9
+} tls_op_t;
+
+#define TLS_HEADER_LEN 4
+
+typedef struct tls_packet_t {
+ uint8_t flags;
+ uint8_t data[1];
+} eaptls_packet_t;
+
+typedef struct tls_packet {
+ uint8_t code;
+ uint8_t id;
+ uint32_t length;
+ uint8_t flags;
+ uint8_t *data;
+ uint32_t dlen;
+
+ //uint8_t *packet; /* Wired EAP-TLS packet as found in typdedata of eap_packet_t */
+} EAPTLS_PACKET;
+
+
+/* EAP-TLS framework */
+EAPTLS_PACKET *eaptls_alloc(void);
+void eaptls_free(EAPTLS_PACKET **eaptls_packet_ptr);
+tls_session_t *eaptls_session(eap_handler_t *handler, fr_tls_server_conf_t *tls_conf, bool client_cert, bool allow_tls13);
+int eaptls_start(EAP_DS *eap_ds, int peap);
+int eaptls_compose(EAP_DS *eap_ds, EAPTLS_PACKET *reply);
+
+fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *key);
+
+#endif /*_EAP_TLS_H*/
diff --git a/src/modules/rlm_eap/libeap/eap_types.h b/src/modules/rlm_eap/libeap/eap_types.h
new file mode 100644
index 0000000..c6568ff
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eap_types.h
@@ -0,0 +1,162 @@
+/*
+ * eap_types.h Header file containing the interfaces for all EAP types.
+ *
+ * most contents moved from modules/rlm_eap/eap.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_TYPES_H
+#define _EAP_TYPES_H
+
+RCSIDH(eap_methods_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+/* Code (1) + Identifier (1) + Length (2) */
+#define EAP_HEADER_LEN 4
+
+typedef enum eap_code {
+ PW_EAP_REQUEST = 1,
+ PW_EAP_RESPONSE,
+ PW_EAP_SUCCESS,
+ PW_EAP_FAILURE,
+ PW_EAP_MAX_CODES
+} eap_code_t;
+
+typedef enum eap_method {
+ PW_EAP_INVALID = 0, /* 0 */
+ PW_EAP_IDENTITY, /* 1 */
+ PW_EAP_NOTIFICATION, /* 2 */
+ PW_EAP_NAK, /* 3 */
+ PW_EAP_MD5, /* 4 */
+ PW_EAP_OTP, /* 5 */
+ PW_EAP_GTC, /* 6 */
+ PW_EAP_7, /* 7 - unused */
+ PW_EAP_8, /* 8 - unused */
+ PW_EAP_RSA_PUBLIC_KEY, /* 9 */
+ PW_EAP_DSS_UNILATERAL, /* 10 */
+ PW_EAP_KEA, /* 11 */
+ PW_EAP_KEA_VALIDATE, /* 12 */
+ PW_EAP_TLS, /* 13 */
+ PW_EAP_DEFENDER_TOKEN, /* 14 */
+ PW_EAP_RSA_SECURID, /* 15 */
+ PW_EAP_ARCOT_SYSTEMS, /* 16 */
+ PW_EAP_LEAP, /* 17 */
+ PW_EAP_SIM, /* 18 */
+ PW_EAP_SRP_SHA1, /* 19 */
+ PW_EAP_20, /* 20 - unassigned */
+ PW_EAP_TTLS, /* 21 */
+ PW_EAP_REMOTE_ACCESS_SERVICE, /* 22 */
+ PW_EAP_AKA, /* 23 */
+ PW_EAP_3COM, /* 24 - should this be EAP-HP now? */
+ PW_EAP_PEAP, /* 25 */
+ PW_EAP_MSCHAPV2, /* 26 */
+ PW_EAP_MAKE, /* 27 */
+ PW_EAP_CRYPTOCARD, /* 28 */
+ PW_EAP_CISCO_MSCHAPV2, /* 29 */
+ PW_EAP_DYNAMID, /* 30 */
+ PW_EAP_ROB, /* 31 */
+ PW_EAP_POTP, /* 32 */
+ PW_EAP_MS_ATLV, /* 33 */
+ PW_EAP_SENTRINET, /* 34 */
+ PW_EAP_ACTIONTEC, /* 35 */
+ PW_EAP_COGENT_BIOMETRIC, /* 36 */
+ PW_EAP_AIRFORTRESS, /* 37 */
+ PW_EAP_TNC, /* 38 - fixme conflicts with HTTP DIGEST */
+// PW_EAP_HTTP_DIGEST, /* 38 */
+ PW_EAP_SECURISUITE, /* 39 */
+ PW_EAP_DEVICECONNECT, /* 40 */
+ PW_EAP_SPEKE, /* 41 */
+ PW_EAP_MOBAC, /* 42 */
+ PW_EAP_FAST, /* 43 */
+ PW_EAP_ZONELABS, /* 44 */
+ PW_EAP_LINK, /* 45 */
+ PW_EAP_PAX, /* 46 */
+ PW_EAP_PSK, /* 47 */
+ PW_EAP_SAKE, /* 48 */
+ PW_EAP_IKEV2, /* 49 */
+ PW_EAP_AKA2, /* 50 */
+ PW_EAP_GPSK, /* 51 */
+ PW_EAP_PWD, /* 52 */
+ PW_EAP_EKE, /* 53 */
+ PW_EAP_MAX_TYPES /* 54 - for validation */
+} eap_type_t;
+
+#define PW_EAP_EXPANDED_TYPE (254)
+
+typedef enum eap_rcode {
+ EAP_NOTFOUND, //!< EAP handler data not found.
+ EAP_FOUND, //!< EAP handler data found, continue.
+ EAP_OK, //!< Ok, continue.
+ EAP_FAIL, //!< Failed, don't reply.
+ EAP_NOOP, //!< Succeeded without doing anything.
+ EAP_INVALID, //!< Invalid, don't reply.
+ EAP_VALID, //!< Valid, continue.
+ EAP_MAX_RCODES
+} eap_rcode_t;
+
+extern const FR_NAME_NUMBER eap_rcode_table[];
+
+/** EAP-Type specific data
+ */
+typedef struct eap_type_data {
+ eap_type_t num;
+ size_t length;
+ uint8_t *data;
+} eap_type_data_t;
+
+/** Structure to hold EAP data
+ *
+ * length = code + id + length + type + type.data
+ * = 1 + 1 + 2 + 1 + X
+ */
+typedef struct eap_packet {
+ eap_code_t code;
+ uint8_t id;
+ size_t length;
+ eap_type_data_t type;
+
+ uint8_t *packet;
+} eap_packet_t;
+
+/** Structure to represent packet format of eap *on wire*
+ */
+typedef struct eap_packet_raw {
+ uint8_t code;
+ uint8_t id;
+ uint8_t length[2];
+ uint8_t data[1];
+} eap_packet_raw_t;
+
+
+/*
+ * interfaces in eapcommon.c
+ */
+eap_type_t eap_name2type(char const *name);
+char const *eap_type2name(eap_type_t method);
+int eap_wireformat(eap_packet_t *reply);
+int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply);
+VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *reply);
+eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps);
+void eap_add_reply(REQUEST *request, char const *name, uint8_t const *value, int len);
+
+#endif /* _EAP_TYPES_H */
diff --git a/src/modules/rlm_eap/libeap/eapclient.h b/src/modules/rlm_eap/libeap/eapclient.h
new file mode 100644
index 0000000..594007f
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eapclient.h
@@ -0,0 +1,8 @@
+/*
+ * some of this seems like a repeat of rlm_eap, and needs to be better
+ * integrated, but as a client library, it deals with Request/Replies
+ * rather than with Replies -> new requests.
+ *
+ * Bare with me for a bit.
+ *
+ */
diff --git a/src/modules/rlm_eap/libeap/eapcommon.c b/src/modules/rlm_eap/libeap/eapcommon.c
new file mode 100644
index 0000000..96db30b
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eapcommon.c
@@ -0,0 +1,401 @@
+/*
+ * eapcommon.c rfc2284 & rfc2869 implementation
+ *
+ * code common to clients and to servers.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2003,2006 The FreeRADIUS server project
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ */
+/*
+ * EAP PACKET FORMAT
+ * --- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data ...
+ * +-+-+-+-+
+ *
+ *
+ * EAP Request and Response Packet Format
+ * --- ------- --- -------- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Type-Data ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+ *
+ *
+ * EAP Success and Failure Packet Format
+ * --- ------- --- ------- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/rad_assert.h>
+#include "eap_types.h"
+
+const FR_NAME_NUMBER eap_rcode_table[] = {
+ { "notfound", EAP_NOTFOUND },
+ { "found", EAP_OK },
+ { "ok", EAP_FAIL },
+ { "fail", EAP_NOOP },
+ { "noop", EAP_INVALID },
+ { "invalid", EAP_VALID },
+ { "valid", EAP_MAX_RCODES },
+
+ { NULL , -1 }
+};
+
+/** Return an EAP-Type for a particular name
+ *
+ * Converts a name into an IANA EAP type.
+ *
+ * @param name to convert.
+ * @return The IANA EAP type or PW_EAP_INVALID if the name doesn't match any
+ * known types.
+ */
+eap_type_t eap_name2type(char const *name)
+{
+ DICT_VALUE *dv;
+
+ dv = dict_valbyname(PW_EAP_TYPE, 0, name);
+ if (!dv) return PW_EAP_INVALID;
+
+ if (dv->value >= PW_EAP_MAX_TYPES) return PW_EAP_INVALID;
+
+ return dv->value;
+}
+
+/** Return an EAP-name for a particular type
+ *
+ * Resolve
+ */
+char const *eap_type2name(eap_type_t method)
+{
+ DICT_VALUE *dv;
+
+ dv = dict_valbyattr(PW_EAP_TYPE, 0, method);
+ if (dv) {
+ return dv->name;
+ }
+
+ return "unknown";
+}
+
+/*
+ * EAP packet format to be sent over the wire
+ *
+ * i.e. code+id+length+data where data = null/type+typedata
+ * based on code.
+ *
+ * INPUT to function is reply->code
+ * reply->id
+ * reply->type - setup with data
+ *
+ * OUTPUT reply->packet is setup with wire format, and will
+ * be allocated to the right size.
+ *
+ */
+int eap_wireformat(eap_packet_t *reply)
+{
+ eap_packet_raw_t *header;
+ uint16_t total_length = 0;
+
+ if (!reply) return EAP_INVALID;
+
+ /*
+ * If reply->packet is set, then the wire format
+ * has already been calculated, just succeed.
+ */
+ if(reply->packet != NULL) return EAP_VALID;
+
+ total_length = EAP_HEADER_LEN;
+ if (reply->code < 3) {
+ total_length += 1/* EAP Method */;
+ if (reply->type.data && reply->type.length > 0) {
+ total_length += reply->type.length;
+ }
+ }
+
+ reply->packet = talloc_array(reply, uint8_t, total_length);
+ header = (eap_packet_raw_t *)reply->packet;
+ if (!header) {
+ return EAP_INVALID;
+ }
+
+ header->code = (reply->code & 0xFF);
+ header->id = (reply->id & 0xFF);
+
+ total_length = htons(total_length);
+ memcpy(header->length, &total_length, sizeof(total_length));
+
+ /*
+ * Request and Response packets are special.
+ */
+ if ((reply->code == PW_EAP_REQUEST) ||
+ (reply->code == PW_EAP_RESPONSE)) {
+ header->data[0] = (reply->type.num & 0xFF);
+
+ /*
+ * Here since we cannot know the typedata format and length
+ *
+ * Type_data is expected to be wired by each EAP-Type
+ *
+ * Zero length/No typedata is supported as long as
+ * type is defined
+ */
+ if (reply->type.data && reply->type.length > 0) {
+ memcpy(&header->data[1], reply->type.data, reply->type.length);
+ talloc_free(reply->type.data);
+ reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/;
+ }
+ }
+
+ return EAP_VALID;
+}
+
+
+/*
+ * compose EAP reply packet in EAP-Message attr of RADIUS. If
+ * EAP exceeds 253, frame it in multiple EAP-Message attrs.
+ */
+int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply)
+{
+ VALUE_PAIR *vp;
+ eap_packet_raw_t *eap_packet;
+ int rcode;
+
+ if (eap_wireformat(reply) == EAP_INVALID) {
+ return RLM_MODULE_INVALID;
+ }
+ eap_packet = (eap_packet_raw_t *)reply->packet;
+
+ fr_pair_delete_by_num(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY);
+
+ vp = eap_packet2vp(packet, eap_packet);
+ if (!vp) return RLM_MODULE_INVALID;
+ fr_pair_add(&(packet->vps), vp);
+
+ /*
+ * EAP-Message is always associated with
+ * Message-Authenticator but not vice-versa.
+ *
+ * Don't add a Message-Authenticator if it's already
+ * there.
+ */
+ vp = fr_pair_find_by_num(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ if (!vp) {
+ vp = fr_pair_afrom_num(packet, PW_MESSAGE_AUTHENTICATOR, 0);
+ vp->vp_length = AUTH_VECTOR_LEN;
+ vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length);
+
+ fr_pair_add(&(packet->vps), vp);
+ }
+
+ /* Set request reply code, but only if it's not already set. */
+ rcode = RLM_MODULE_OK;
+ if (!packet->code) switch (reply->code) {
+ case PW_EAP_RESPONSE:
+ case PW_EAP_SUCCESS:
+ packet->code = PW_CODE_ACCESS_ACCEPT;
+ rcode = RLM_MODULE_HANDLED;
+ break;
+ case PW_EAP_FAILURE:
+ packet->code = PW_CODE_ACCESS_REJECT;
+ rcode = RLM_MODULE_REJECT;
+ break;
+ case PW_EAP_REQUEST:
+ packet->code = PW_CODE_ACCESS_CHALLENGE;
+ rcode = RLM_MODULE_HANDLED;
+ break;
+ default:
+ /* Should never enter here */
+ ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
+ packet->code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+
+ return rcode;
+}
+
+
+VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *eap)
+{
+ int total, size;
+ uint8_t const *ptr;
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR *vp;
+ vp_cursor_t out;
+
+ total = eap->length[0] * 256 + eap->length[1];
+
+ if (total == 0) {
+ DEBUG("Asked to encode empty EAP-Message!");
+ return NULL;
+ }
+
+ ptr = (uint8_t const *) eap;
+
+ fr_cursor_init(&out, &head);
+ do {
+ size = total;
+ if (size > 253) size = 253;
+
+ vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0);
+ if (!vp) {
+ fr_pair_list_free(&head);
+ return NULL;
+ }
+ fr_pair_value_memcpy(vp, ptr, size);
+
+ fr_cursor_insert(&out, vp);
+
+ ptr += size;
+ total -= size;
+ } while (total > 0);
+
+ return head;
+}
+
+
+/*
+ * Handles multiple EAP-Message attrs
+ * ie concatenates all to get the complete EAP packet.
+ *
+ * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
+ * refer fragmentation in rfc2869.
+ */
+eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
+{
+ VALUE_PAIR *first, *i;
+ eap_packet_raw_t *eap_packet;
+ unsigned char *ptr;
+ uint16_t len;
+ int total_len;
+ vp_cursor_t cursor;
+
+ /*
+ * Get only EAP-Message attribute list
+ */
+ first = fr_pair_find_by_num(vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (!first) {
+ fr_strerror_printf("EAP-Message not found");
+ return NULL;
+ }
+
+ /*
+ * Sanity check the length before doing anything.
+ */
+ if (first->vp_length < 4) {
+ fr_strerror_printf("EAP packet is too short");
+ return NULL;
+ }
+
+ /*
+ * Get the Actual length from the EAP packet
+ * First EAP-Message contains the EAP packet header
+ */
+ memcpy(&len, first->vp_strvalue + 2, sizeof(len));
+ len = ntohs(len);
+
+ /*
+ * Take out even more weird things.
+ */
+ if (len < 4) {
+ fr_strerror_printf("EAP packet has invalid length (less than 4 bytes)");
+ return NULL;
+ }
+
+ /*
+ * Sanity check the length, BEFORE allocating memory.
+ */
+ total_len = 0;
+ fr_cursor_init(&cursor, &first);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
+ total_len += i->vp_length;
+
+ if (total_len > len) {
+ fr_strerror_printf("Malformed EAP packet. Length in packet header %i, "
+ "does not match actual length %i", len, total_len);
+ return NULL;
+ }
+ }
+
+ /*
+ * If the length is SMALLER, die, too.
+ */
+ if (total_len < len) {
+ fr_strerror_printf("Malformed EAP packet. Length in packet header does not "
+ "match actual length");
+ return NULL;
+ }
+
+ /*
+ * Now that we know the lengths are OK, allocate memory.
+ */
+ eap_packet = (eap_packet_raw_t *) talloc_zero_array(ctx, uint8_t, len);
+ if (!eap_packet) {
+ return NULL;
+ }
+
+ /*
+ * Copy the data from EAP-Message's over to our EAP packet.
+ */
+ ptr = (unsigned char *)eap_packet;
+
+ /* RADIUS ensures order of attrs, so just concatenate all */
+ fr_cursor_first(&cursor);
+ while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
+ memcpy(ptr, i->vp_strvalue, i->vp_length);
+ ptr += i->vp_length;
+ }
+
+ return eap_packet;
+}
+
+/*
+ * Add raw hex data to the reply.
+ */
+void eap_add_reply(REQUEST *request,
+ char const *name, uint8_t const *value, int len)
+{
+ VALUE_PAIR *vp;
+
+ vp = pair_make_reply(name, NULL, T_OP_EQ);
+ if (!vp) {
+ REDEBUG("Did not create attribute %s: %s\n",
+ name, fr_strerror());
+ return;
+ }
+
+ fr_pair_value_memcpy(vp, value, len);
+}
diff --git a/src/modules/rlm_eap/libeap/eapcrypto.c b/src/modules/rlm_eap/libeap/eapcrypto.c
new file mode 100644
index 0000000..f57714b
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eapcrypto.c
@@ -0,0 +1,301 @@
+/*
+ * eapcrypto.c Common key derivation routines for EAP/SIM.
+ *
+ * The development of the EAP/SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * Copyright 2003,2006 The FreeRADIUS server project
+ *
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "eap_types.h"
+#include "eap_sim.h"
+#include <freeradius-devel/sha1.h>
+
+void eapsim_calculate_keys(struct eapsim_keys *ek)
+{
+ fr_sha1_ctx context;
+ uint8_t fk[160];
+ unsigned char buf[256];
+ unsigned char *p;
+ unsigned int blen;
+
+ p = buf;
+ memcpy(p, ek->identity, ek->identitylen); p = p+ek->identitylen;
+ memcpy(p, ek->Kc[0], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
+ memcpy(p, ek->Kc[1], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
+ memcpy(p, ek->Kc[2], EAPSIM_KC_SIZE); p = p+EAPSIM_KC_SIZE;
+ memcpy(p, ek->nonce_mt, sizeof(ek->nonce_mt)); p=p+sizeof(ek->nonce_mt);
+ memcpy(p, ek->versionlist, ek->versionlistlen);p=p+ek->versionlistlen;
+ memcpy(p, ek->versionselect, sizeof(ek->versionselect)); p=p+sizeof(ek->versionselect);
+ /* *p++ = ek->versionselect[1]; */
+
+ blen = p - buf;
+
+#if defined(TEST_CASE) || defined(DUMP_EAPSIM_KEYS)
+ {
+ unsigned int i, j, k;
+
+ j=0; k=0;
+
+ printf("SHA1buffer was: ");
+ for (i = 0; i < blen; i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ if(k==20) {
+ printf("\n ");
+ k=0;
+ j=0;
+ }
+ j++;
+ k++;
+
+ printf("%02x", buf[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+
+ /* do the master key first */
+ fr_sha1_init(&context);
+ fr_sha1_update(&context, buf, blen);
+ fr_sha1_final(ek->master_key, &context);
+
+ /*
+ * now use the PRF to expand it, generated K_aut, K_encr,
+ * MSK and EMSK.
+ */
+ fips186_2prf(ek->master_key, fk);
+
+ /* split up the result */
+ memcpy(ek->K_encr, fk + 0, 16); /* 128 bits for encryption */
+ memcpy(ek->K_aut, fk + 16, EAPSIM_AUTH_SIZE); /*128 bits for auth */
+ memcpy(ek->msk, fk + 32, 64); /* 64 bytes for Master Session Key */
+ memcpy(ek->emsk, fk + 96, 64); /* 64- extended Master Session Key */
+}
+
+
+void eapsim_dump_mk(struct eapsim_keys *ek)
+{
+ unsigned int i, j, k;
+
+ printf("Input was: \n");
+ printf(" identity: (len=%u)", ek->identitylen);
+ for (i = 0; i < ek->identitylen; i++) {
+ printf("%02x", ek->identity[i]);
+ }
+
+ printf("\n nonce_mt: ");
+ for (i = 0; i < EAPSIM_NONCEMT_SIZE; i++) {
+ printf("%02x", ek->nonce_mt[i]);
+ }
+
+ for (k = 0; k<3; k++) {
+ printf("\n rand%u: ", k);
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ printf("%02x", ek->rand[k][i]);
+ }
+ }
+
+ for (k = 0; k<3; k++) {
+ printf("\n sres%u: ", k);
+ for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
+ printf("%02x", ek->sres[k][i]);
+ }
+ }
+
+ for (k = 0; k<3; k++) {
+ printf("\n Kc%u: ", k);
+ for (i = 0; i < EAPSIM_KC_SIZE; i++) {
+ printf("%02x", ek->Kc[k][i]);
+ }
+ }
+
+ printf("\n versionlist[%d]: ",ek->versionlistlen);
+ for (i = 0; i < ek->versionlistlen; i++) {
+ printf("%02x", ek->versionlist[i]);
+ }
+
+ printf("\n select %02x %02x\n",
+ ek->versionselect[0],
+ ek->versionselect[1]);
+
+ printf("\n\nOutput\n");
+
+ printf("mk: ");
+ j=0;
+ for (i = 0; i < sizeof(ek->master_key); i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", ek->master_key[i]);
+ }
+
+ printf("\nK_aut: ");
+ j=0;
+ for (i = 0; i < sizeof(ek->K_aut); i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", ek->K_aut[i]);
+ }
+
+ printf("\nK_encr: ");
+ j=0;
+ for (i = 0; i < sizeof(ek->K_encr); i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", ek->K_encr[i]);
+ }
+
+ printf("\nmsk: ");
+ j=0; k=0;
+ for (i = 0; i < sizeof(ek->msk); i++) {
+ if(k==20) {
+ printf("\n ");
+ k=0;
+ j=0;
+ }
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ k++;
+ j++;
+
+ printf("%02x", ek->msk[i]);
+ }
+ printf("\nemsk: ");
+ j=0; k=0;
+ for (i = 0; i < sizeof(ek->emsk); i++) {
+ if(k==20) {
+ printf("\n ");
+ k=0;
+ j=0;
+ }
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ k++;
+ j++;
+
+ printf("%02x", ek->emsk[i]);
+ }
+ printf("\n");
+}
+
+#ifdef TEST_CASE
+
+#include <assert.h>
+
+struct eapsim_keys inputkey1 = {
+ {'e', 'a', 'p', 's','i','m' },
+ 6,
+ 0x4d, 0x6c, 0x40, 0xde, 0x48, 0x3a, 0xdd, 0x99, /* nonce_mt */
+ 0x50, 0x90, 0x2c, 0x40, 0x24, 0xce, 0x76, 0x5e,
+ 0x89, 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, /* chalX */
+ 0x89, 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef,
+ 0x9a, 0xbc, 0xde, 0xf8, 0x9a, 0xbc, 0xde, 0xf8,
+ 0x9a, 0xbc, 0xde, 0xf8, 0x9a, 0xbc, 0xde, 0xf8,
+ 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, 0x89,
+ 0xab, 0xcd, 0xef, 0x89, 0xab, 0xcd, 0xef, 0x89,
+ 0x12, 0x34, 0xab, 0xcd, /* sresX */
+ 0x12, 0x34, 0xab, 0xcd,
+ 0x23, 0x4a, 0xbc, 0xd1,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* Kc */
+ 0x10, 0x21, 0x32, 0x43, 0x54, 0x65, 0x76, 0x87,
+ 0x30, 0x41, 0x52, 0x63, 0x74, 0x85, 0x96, 0xa7,
+ {0x00, 0x02, 0x00, 0x01},
+ 4,
+ 0x00, 0x01 ,
+};
+
+struct eapsim_keys inputkey2 = {
+ {'1','2','4','4','0','7','0','1','0','0','0','0','0','0','0','1','@','e','a','p','s','i','m','.','f','o','o'},
+ 27,
+ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, /* nonce_mt */
+ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* chalX */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+
+ 0xd1, 0xd2, 0xd3, 0xd4, /* SRES 1 */
+ 0xe1, 0xe2, 0xe3, 0xe4,
+ 0xf1, 0xf2, 0xf3, 0xf4,
+
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* Kc */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ /* {0x00, 0x02, 0x00, 0x01}, */
+ {0x00, 0x01},
+ 2,
+ 0x00, 0x01 ,
+};
+
+
+
+main(int argc, char *argv[])
+{
+ struct eapsim_keys *ek;
+
+ ek = &inputkey1;
+
+ eapsim_calculate_keys(ek);
+ eapsim_dump_mk(ek);
+
+ ek = &inputkey2;
+
+ eapsim_calculate_keys(ek);
+ eapsim_dump_mk(ek);
+}
+#endif
+
+
+
+
+
+
+/*
+ * Local Variables:
+ * c-style: bsd
+ * End:
+ */
diff --git a/src/modules/rlm_eap/libeap/eapsimlib.c b/src/modules/rlm_eap/libeap/eapsimlib.c
new file mode 100644
index 0000000..67e21b2
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/eapsimlib.c
@@ -0,0 +1,508 @@
+/*
+ * eapsimlib.c based upon draft-haverinen-pppext-eap-sim-11.txt.
+ *
+ * The development of the EAP/SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * code common to EAP-SIM clients and to servers.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000-2003,2006 The FreeRADIUS server project
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ */
+
+/*
+ * EAP-SIM PACKET FORMAT
+ * ------- ------ ------
+ *
+ * EAP Request and Response Packet Format
+ * --- ------- --- -------- ------ ------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | SIM-Type | SIM-Length | value ... |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * with SIM-Type/SIM-Length/Value... repeating. SIM-Length is in units
+ * of 32 bits, and includes the Sim-Type/Sim-Length fields.
+ *
+ * The SIM-Type's are mapped to PW_EAP_SIM_BASE+Sim-type and
+ * unmapped by these functions.
+ *
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include "eap_types.h"
+#include "eap_sim.h"
+#include <freeradius-devel/sha1.h>
+
+/*
+ * given a radius request with many attributes in the EAP-SIM range, build
+ * them all into a single EAP-SIM body.
+ *
+ */
+int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep)
+{
+ VALUE_PAIR *vp;
+ int encoded_size;
+ uint8_t *encodedmsg, *attr;
+ unsigned int id, eapcode;
+ uint8_t *macspace;
+ uint8_t const *append;
+ int appendlen;
+ unsigned char subtype;
+ vp_cursor_t cursor;
+
+ macspace = NULL;
+ append = NULL;
+ appendlen = 0;
+
+ /*
+ * encodedmsg is now an EAP-SIM message.
+ * it might be too big for putting into an EAP-Type-SIM
+ *
+ */
+ subtype = (vp = fr_pair_find_by_num(r->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) ?
+ vp->vp_integer : EAPSIM_START;
+
+ id = (vp = fr_pair_find_by_num(r->vps, PW_EAP_ID, 0, TAG_ANY)) ?
+ vp->vp_integer : ((int)getpid() & 0xff);
+
+ eapcode = (vp = fr_pair_find_by_num(r->vps, PW_EAP_CODE, 0, TAG_ANY)) ?
+ vp->vp_integer : PW_EAP_REQUEST;
+
+ /*
+ * take a walk through the attribute list to see how much space
+ * that we need to encode all of this.
+ */
+ encoded_size = 0;
+ for (vp = fr_cursor_init(&cursor, &r->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ int roundedlen;
+ int vplen;
+
+ if ((vp->da->attr < PW_EAP_SIM_BASE) || (vp->da->attr >= (PW_EAP_SIM_BASE + 256))) {
+ continue;
+ }
+
+ vplen = vp->vp_length;
+
+ /*
+ * the AT_MAC attribute is a bit different, when we get to this
+ * attribute, we pull the contents out, save it for later
+ * processing, set the size to 16 bytes (plus 2 bytes padding).
+ *
+ * At this point, we only care about the size.
+ */
+ if(vp->da->attr == PW_EAP_SIM_MAC) {
+ vplen = 18;
+ }
+
+ /* round up to next multiple of 4, after taking in
+ * account the type and length bytes
+ */
+ roundedlen = (vplen + 2 + 3) & ~3;
+ encoded_size += roundedlen;
+ }
+
+ if (ep->code != PW_EAP_SUCCESS) {
+ ep->code = eapcode;
+ }
+
+ ep->id = (id & 0xff);
+ ep->type.num = PW_EAP_SIM;
+
+ /*
+ * if no attributes were found, do very little.
+ *
+ */
+ if (encoded_size == 0) {
+ encodedmsg = talloc_array(ep, uint8_t, 3);
+ /* FIX: could be NULL */
+
+ encodedmsg[0] = subtype;
+ encodedmsg[1] = 0;
+ encodedmsg[2] = 0;
+
+ ep->type.length = 3;
+ ep->type.data = encodedmsg;
+
+ return 1;
+ }
+
+
+ /*
+ * figured out the length, so allocate some space for the results.
+ *
+ * Note that we do not bother going through an "EAP" stage, which
+ * is a bit strange compared to the unmap, which expects to see
+ * an EAP-SIM virtual attributes.
+ *
+ * EAP is 1-code, 1-identifier, 2-length, 1-type = 5 overhead.
+ *
+ * SIM code adds a subtype, and 2 bytes of reserved = 3.
+ *
+ */
+ encoded_size += 3;
+ encodedmsg = talloc_array(ep, uint8_t, encoded_size);
+ if (!encodedmsg) {
+ return 0;
+ }
+ memset(encodedmsg, 0, encoded_size);
+
+ /*
+ * now walk the attributes again, sticking them in.
+ *
+ * we go three bytes into the encoded message, because there are two
+ * bytes of reserved, and we will fill the "subtype" in later.
+ *
+ */
+ attr = encodedmsg+3;
+
+ for (vp = fr_cursor_first(&cursor); vp; vp = fr_cursor_next(&cursor)) {
+ int roundedlen;
+
+ if(vp->da->attr < PW_EAP_SIM_BASE ||
+ vp->da->attr >= PW_EAP_SIM_BASE + 256) {
+ continue;
+ }
+
+ /*
+ * the AT_MAC attribute is a bit different, when we get to this
+ * attribute, we pull the contents out, save it for later
+ * processing, set the size to 16 bytes (plus 2 bytes padding).
+ *
+ * At this point, we put in zeros, and remember where the
+ * sixteen bytes go.
+ */
+ if(vp->da->attr == PW_EAP_SIM_MAC) {
+ roundedlen = 20;
+ memset(&attr[2], 0, 18);
+ macspace = &attr[4];
+ append = vp->vp_octets;
+ appendlen = vp->vp_length;
+ } else {
+ roundedlen = (vp->vp_length + 2 + 3) & ~3;
+ memset(attr, 0, roundedlen);
+ memcpy(&attr[2], vp->vp_strvalue, vp->vp_length);
+ }
+ attr[0] = vp->da->attr - PW_EAP_SIM_BASE;
+ attr[1] = roundedlen >> 2;
+
+ attr += roundedlen;
+ }
+
+ encodedmsg[0] = subtype;
+
+ ep->type.length = encoded_size;
+ ep->type.data = encodedmsg;
+
+ /*
+ * if macspace was set and we have a key,
+ * then we should calculate the HMAC-SHA1 of the resulting EAP-SIM
+ * packet, appended with the value of append.
+ */
+ vp = fr_pair_find_by_num(r->vps, PW_EAP_SIM_KEY, 0, TAG_ANY);
+ if(macspace != NULL && vp != NULL) {
+ unsigned char *buffer;
+ eap_packet_raw_t *hdr;
+ uint16_t hmaclen, total_length = 0;
+ unsigned char sha1digest[20];
+
+ total_length = EAP_HEADER_LEN + 1 + encoded_size;
+ hmaclen = total_length + appendlen;
+ buffer = talloc_array(r, uint8_t, hmaclen);
+ hdr = (eap_packet_raw_t *) buffer;
+ if (!hdr) {
+ talloc_free(encodedmsg);
+ return 0;
+ }
+
+ hdr->code = eapcode & 0xFF;
+ hdr->id = (id & 0xFF);
+ total_length = htons(total_length);
+ memcpy(hdr->length, &total_length, sizeof(total_length));
+
+ hdr->data[0] = PW_EAP_SIM;
+
+ /* copy the data */
+ memcpy(&hdr->data[1], encodedmsg, encoded_size);
+
+ /* copy the nonce */
+ memcpy(&hdr->data[encoded_size+1], append, appendlen);
+
+ /* HMAC it! */
+ fr_hmac_sha1(sha1digest, buffer, hmaclen, vp->vp_octets, vp->vp_length);
+
+ /* done with the buffer, free it */
+ talloc_free(buffer);
+
+ /* now copy the digest to where it belongs in the AT_MAC */
+ /* note that it is truncated to 128-bits */
+ memcpy(macspace, sha1digest, 16);
+ }
+
+ /* if we had an AT_MAC and no key, then fail */
+ if ((macspace != NULL) && !vp) {
+ if (encodedmsg != NULL) {
+ talloc_free(encodedmsg);
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * given a radius request with an EAP-SIM body, decode it into TLV pairs
+ *
+ * return value is true if it succeeded, false if there was something
+ * wrong and the packet should be discarded.
+ *
+ */
+int unmap_eapsim_basictypes(RADIUS_PACKET *r,
+ uint8_t *attr, unsigned int attrlen)
+{
+ VALUE_PAIR *newvp;
+ int eapsim_attribute;
+ unsigned int eapsim_len;
+ int es_attribute_count;
+
+ es_attribute_count = 0;
+
+ /* big enough to have even a single attribute */
+ if (attrlen < 5) {
+ fr_strerror_printf("EAP-Sim attribute too short: %d < 5", attrlen);
+ return 0;
+ }
+
+ newvp = fr_pair_afrom_num(r, PW_EAP_SIM_SUBTYPE, 0);
+ if (!newvp) {
+ fr_strerror_printf("Failed creating EAP-SIM-Subtype");
+ return 0;
+ }
+
+ newvp->vp_integer = attr[0];
+ newvp->vp_length = 1;
+ fr_pair_add(&(r->vps), newvp);
+
+ /*
+ * EAP-SIM has a 1 octet of subtype, and 2 octets
+ * reserved.
+ */
+ attr += 3;
+ attrlen -= 3;
+
+ /*
+ * Loop over each attribute. The format is:
+ *
+ * 1 octet of type
+ * 1 octet of length (value 1..255)
+ * ((4 * length) - 2) octets of data.
+ */
+ while (attrlen > 0) {
+ uint8_t *p;
+
+ if (attrlen < 2) {
+ fr_strerror_printf("EAP-Sim attribute %d too short: %d < 2", es_attribute_count, attrlen);
+ return 0;
+ }
+
+ if (!attr[1]) {
+ fr_strerror_printf("EAP-Sim attribute %d (no.%d) has no data", attr[0],
+ es_attribute_count);
+ return 0;
+ }
+
+ eapsim_attribute = attr[0];
+ eapsim_len = attr[1] * 4;
+
+ /*
+ * The length includes the 2-byte header.
+ */
+ if (eapsim_len > attrlen) {
+ fr_strerror_printf("EAP-Sim attribute %d (no.%d) has length longer than data (%d > %d)",
+ eapsim_attribute, es_attribute_count, eapsim_len, attrlen);
+ return 0;
+ }
+
+ newvp = fr_pair_afrom_num(r, eapsim_attribute + PW_EAP_SIM_BASE, 0);
+ if (!newvp) {
+ /*
+ * RFC 4186 Section 8.1 says 0..127 are
+ * "non-skippable". If one such
+ * attribute is found and we don't
+ * understand it, the server has to send:
+ *
+ * EAP-Request/SIM/Notification packet with an
+ * (AT_NOTIFICATION code, which implies general failure ("General
+ * failure after authentication" (0), or "General failure" (16384),
+ * depending on the phase of the exchange), which terminates the
+ * authentication exchange.
+ */
+ if (eapsim_attribute <= 127) {
+ fr_strerror_printf("Unknown mandatory attribute %d, failing",
+ eapsim_attribute);
+ return 0;
+ }
+
+ } else {
+ /*
+ * It's known, ccount for header, and
+ * copy the value over.
+ */
+ newvp->vp_length = eapsim_len - 2;
+
+ newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length);
+ memcpy(p, &attr[2], newvp->vp_length);
+ fr_pair_add(&(r->vps), newvp);
+ }
+
+ /* advance pointers, decrement length */
+ attr += eapsim_len;
+ attrlen -= eapsim_len;
+ es_attribute_count++;
+ }
+
+ return 1;
+}
+
+/*
+ * calculate the MAC for the EAP message, given the key.
+ * The "extra" will be appended to the EAP message and included in the
+ * HMAC.
+ *
+ */
+int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, uint8_t key[EAPSIM_AUTH_SIZE], uint8_t *extra, int extralen,
+ uint8_t calcmac[20])
+{
+ int ret;
+ eap_packet_raw_t *e;
+ uint8_t *buffer;
+ int elen,len;
+ VALUE_PAIR *mac;
+
+ mac = fr_pair_find_by_num(rvps, PW_EAP_SIM_MAC, 0, TAG_ANY);
+
+ if(!mac || mac->vp_length != 18) {
+ /* can't check a packet with no AT_MAC attribute */
+ return 0;
+ }
+
+ /* get original copy of EAP message, note that it was sanitized
+ * to have a valid length, which we depend upon.
+ */
+ e = eap_vp2packet(ctx, rvps);
+ if (!e) return 0;
+
+ /* make copy big enough for everything */
+ elen = (e->length[0] * 256) + e->length[1];
+ len = elen + extralen;
+
+ buffer = talloc_array(ctx, uint8_t, len);
+ if (!buffer) {
+ talloc_free(e);
+ return 0;
+ }
+
+ memcpy(buffer, e, elen);
+ memcpy(buffer + elen, extra, extralen);
+
+ /*
+ * now look for the AT_MAC attribute in the copy of the buffer
+ * and make sure that the checksum is zero.
+ *
+ */
+ {
+ uint8_t *attr;
+
+ /* first attribute is 8 bytes into the EAP packet.
+ * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved.
+ */
+ attr = buffer+8;
+ while(attr < (buffer+elen)) {
+ if (attr[0] == (PW_EAP_SIM_MAC - PW_EAP_SIM_BASE)) {
+ /* zero the data portion, after making sure
+ * the size is >=5. Maybe future versions.
+ * will use more bytes, so be liberal.
+ */
+ if(attr[1] < 5) {
+ ret = 0;
+ goto done;
+ }
+ memset(&attr[4], 0, (attr[1]-1)*4);
+ }
+ /* advance the pointer */
+ attr += attr[1]*4;
+ }
+ }
+
+ /* now, HMAC-SHA1 it with the key. */
+ fr_hmac_sha1(calcmac, buffer, len, key, 16);
+
+ ret = memcmp(&mac->vp_strvalue[2], calcmac, 16) == 0 ? 1 : 0;
+ done:
+ talloc_free(e);
+ talloc_free(buffer);
+ return(ret);
+}
+
+/*
+ * definitions changed to take a buffer for unknowns
+ * as this is more thread safe.
+ */
+static char const *simstates[] = { "init", "start", NULL };
+
+char const *sim_state2name(enum eapsim_clientstates state,
+ char *statenamebuf,
+ int statenamebuflen)
+{
+ if(state >= EAPSIM_CLIENT_MAXSTATES) {
+ snprintf(statenamebuf, statenamebuflen, "eapstate:%d", state);
+ return statenamebuf;
+ }
+
+ return simstates[state];
+}
+
+static char const *subtypes[] = { "subtype0", "subtype1", "subtype2", "subtype3",
+ "subtype4", "subtype5", "subtype6", "subtype7",
+ "subtype8", "subtype9",
+ "start",
+ "challenge",
+ "notification",
+ "reauth",
+ "client-error",
+ NULL };
+
+char const *sim_subtype2name(enum eapsim_subtype subtype, char *subtypenamebuf, int subtypenamebuflen)
+{
+ if (subtype >= EAPSIM_MAX_SUBTYPE) {
+ snprintf(subtypenamebuf, subtypenamebuflen, "illegal-subtype:%d", subtype);
+
+ return subtypenamebuf;
+ }
+
+ return subtypes[subtype];
+}
diff --git a/src/modules/rlm_eap/libeap/fips186prf.c b/src/modules/rlm_eap/libeap/fips186prf.c
new file mode 100644
index 0000000..2002c62
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/fips186prf.c
@@ -0,0 +1,270 @@
+/*
+ * fips186prf.c An implementation of the FIPS-186-2 SHA1-based PRF.
+ *
+ * The development of the EAP/SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * This code was written from scratch by Michael Richardson, and it is
+ * dual licensed under both GPL and BSD.
+ *
+ * Version: $Id$
+ *
+ * GPL notice:
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * BSD notice:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * Copyright 2006 The FreeRADIUS server project
+ *
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <freeradius-devel/sha1.h>
+
+/*
+ * we do it in 8-bit chunks, because we have to keep the numbers
+ * in network byte order (i.e. MSB)
+ *
+ * make it a structure so that we can do structure assignments.
+ */
+typedef struct onesixty {
+ uint8_t p[20];
+} onesixty;
+
+static void onesixty_add_mod(onesixty *sum, onesixty *a, onesixty *b)
+{
+ uint32_t s;
+ int i, carry;
+
+ carry = 0;
+ for(i=19; i>=0; i--) {
+/* for(i=0; i<20; i++) { */
+ s = a->p[i] + b->p[i] + carry;
+ sum->p[i] = s & 0xff;
+ carry = s >> 8;
+ }
+}
+
+/*
+ * run the FIPS-186-2 PRF on the given Master Key (160 bits)
+ * in order to derive 1280 bits (160 bytes) of keying data from
+ * it.
+ *
+ * Given that in EAP-SIM, this is coming from a 64-bit Kc it seems
+ * like an awful lot of "randomness" to pull out.. (MCR)
+ *
+ */
+void fips186_2prf(uint8_t mk[20], uint8_t finalkey[160])
+{
+ fr_sha1_ctx context;
+ int j;
+ onesixty xval, xkey, w_0, w_1, sum, one;
+ uint8_t *f;
+ uint8_t zeros[64];
+
+ /*
+ * let XKEY := MK,
+ *
+ * Step 3: For j = 0 to 3 do
+ * a. XVAL = XKEY
+ * b. w_0 = SHA1(XVAL)
+ * c. XKEY = (1 + XKEY + w_0) mod 2^160
+ * d. XVAL = XKEY
+ * e. w_1 = SHA1(XVAL)
+ * f. XKEY = (1 + XKEY + w_1) mod 2^160
+ * 3.3 x_j = w_0|w_1
+ *
+ */
+ memcpy(&xkey, mk, sizeof(xkey));
+
+ /* make the value 1 */
+ memset(&one, 0, sizeof(one));
+ one.p[19]=1;
+
+ f=finalkey;
+
+ for(j=0; j<4; j++) {
+ /* a. XVAL = XKEY */
+ xval = xkey;
+
+ /* b. w_0 = SHA1(XVAL) */
+ fr_sha1_init(&context);
+
+ memset(zeros + 20, 0, sizeof(zeros) - 20);
+ memcpy(zeros, xval.p, 20);
+#ifndef WITH_OPENSSL_SHA1
+ fr_sha1_transform(context.state, zeros);
+#else
+ fr_sha1_transform(&context, zeros);
+#endif
+ fr_sha1_final_no_len(w_0.p, &context);
+
+ /* c. XKEY = (1 + XKEY + w_0) mod 2^160 */
+ onesixty_add_mod(&sum, &xkey, &w_0);
+ onesixty_add_mod(&xkey, &sum, &one);
+
+ /* d. XVAL = XKEY */
+ xval = xkey;
+
+ /* e. w_1 = SHA1(XVAL) */
+ fr_sha1_init(&context);
+
+ memset(zeros + 20, 0, sizeof(zeros) - 20);
+ memcpy(zeros, xval.p, 20);
+#ifndef WITH_OPENSSL_SHA1
+ fr_sha1_transform(context.state, zeros);
+#else
+ fr_sha1_transform(&context, zeros);
+#endif
+ fr_sha1_final_no_len(w_1.p, &context);
+
+ /* f. XKEY = (1 + XKEY + w_1) mod 2^160 */
+ onesixty_add_mod(&sum, &xkey, &w_1);
+ onesixty_add_mod(&xkey, &sum, &one);
+
+ /* now store it away */
+ memcpy(f, &w_0, 20);
+ f += 20;
+
+ memcpy(f, &w_1, 20);
+ f += 20;
+ }
+}
+
+/*
+ * test vectors
+ * from http://csrc.nist.gov/CryptoToolkit/dss/Examples-1024bit.pdf
+ *
+ * page 5
+ *
+ * XKEY= bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6
+ * XSEED= 00000000 00000000 00000000 00000000 00000000
+ *
+ *
+ * The first loop through step 3.2 provides:
+ *
+ * XVAL= bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6
+ *
+ * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1,
+ * in step 3.2.b of the Change Notice algorithm for computing values of x
+ * provides:
+ *
+ * w[0]= 2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614
+ *
+ *
+ * The following value is the updated XKEY value from step 3.2.c:
+ *
+ * XKEY= dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb
+ *
+ * The second loop through step 3.2 provides:
+ *
+ * XVAL= dd734ee0 bd0bcd3b adbaeb27 dd1eaa59 76803ecb
+ *
+ * Using the routine in Appendix 3.3, Constructing The Function G From SHA-1,
+ * in step 3.2.b of the Change Notice algorithm for computing values of x
+ * provides:
+ *
+ * w[1]= 3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116
+ *
+ * The following value is the updated XKEY value from step 3.2.c:
+ *
+ *
+ * XKEY= 19df679b 881b3991 6875fea0 6b3f8191 19a78fe2
+ *
+ * Step 3.3 provides the following values:
+ *
+ * w[0] || w[1]= 2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614
+ * 3c6c18ba cb0f6c55 babb1378 8e20d737 a3275116
+ *
+ */
+
+#ifdef TEST_CASE
+
+#include <assert.h>
+
+uint8_t mk[20]={ 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
+ 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
+ 0xeb, 0x5a, 0x38, 0xb6 };
+
+main(int argc, char *argv[])
+{
+ uint8_t finalkey[160];
+ int i, j, k;
+
+ fips186_2prf(mk, finalkey);
+
+ printf("Input was: |");
+ j=0;
+ for (i = 0; i < 20; i++) {
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ printf("%02x", mk[i]);
+ }
+
+ printf("|\nOutput was: ");
+ j=0; k=0;
+ for (i = 0; i < 160; i++) {
+ if(k==20) {
+ printf("\n ");
+ k=0;
+ j=0;
+ }
+ if(j==4) {
+ printf("_");
+ j=0;
+ }
+ k++;
+ j++;
+
+ printf("%02x", finalkey[i]);
+ }
+ printf("\n");
+}
+#endif
diff --git a/src/modules/rlm_eap/libeap/mppe_keys.c b/src/modules/rlm_eap/libeap/mppe_keys.c
new file mode 100644
index 0000000..385441c
--- /dev/null
+++ b/src/modules/rlm_eap/libeap/mppe_keys.c
@@ -0,0 +1,384 @@
+/*
+ * mppe_keys.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2002 Axis Communications AB
+ * Copyright 2006 The FreeRADIUS server project
+ * Authors: Henrik Eriksson <henriken@axis.com> & Lars Viklund <larsv@axis.com>
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include "eap_tls.h"
+#include <openssl/ssl.h>
+#include <openssl/hmac.h>
+#include <freeradius-devel/openssl3.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+#endif
+
+/*
+ * TLS P_hash from RFC 2246/5246 section 5
+ */
+static void P_hash(EVP_MD const *evp_md,
+ unsigned char const *secret, unsigned int secret_len,
+ unsigned char const *seed, unsigned int seed_len,
+ unsigned char *out, unsigned int out_len)
+{
+ HMAC_CTX *ctx_a, *ctx_out;
+ unsigned char a[EVP_MAX_MD_SIZE];
+ unsigned int size = EVP_MAX_MD_SIZE;
+ unsigned int digest_len;
+
+ ctx_a = HMAC_CTX_new();
+ ctx_out = HMAC_CTX_new();
+ HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL);
+ HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL);
+
+ /* Calculate A(1) */
+ HMAC_Update(ctx_a, seed, seed_len);
+ HMAC_Final(ctx_a, a, &size);
+
+ while (1) {
+ /* Calculate next part of output */
+ HMAC_Update(ctx_out, a, size);
+ HMAC_Update(ctx_out, seed, seed_len);
+
+ /* Check if last part */
+ if (out_len < size) {
+ digest_len = EVP_MAX_MD_SIZE;
+ HMAC_Final(ctx_out, a, &digest_len);
+ memcpy(out, a, out_len);
+ break;
+ }
+
+ /* Place digest in output buffer */
+ digest_len = EVP_MAX_MD_SIZE;
+ HMAC_Final(ctx_out, out, &digest_len);
+ HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL);
+ out += size;
+ out_len -= size;
+
+ /* Calculate next A(i) */
+ HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL);
+ HMAC_Update(ctx_a, a, size);
+ digest_len = EVP_MAX_MD_SIZE;
+ HMAC_Final(ctx_a, a, &digest_len);
+ }
+
+ HMAC_CTX_free(ctx_a);
+ HMAC_CTX_free(ctx_out);
+ memset(a, 0, sizeof(a));
+}
+
+/*
+ * TLS PRF from RFC 2246 section 5
+ */
+static void PRF(unsigned char const *secret, unsigned int secret_len,
+ unsigned char const *seed, unsigned int seed_len,
+ unsigned char *out, unsigned int out_len)
+{
+ uint8_t buf[out_len + (out_len % SHA_DIGEST_LENGTH)];
+ unsigned int i;
+
+ unsigned int len = (secret_len + 1) / 2;
+ uint8_t const *s1 = secret;
+ uint8_t const *s2 = secret + (secret_len - len);
+
+ EVP_MD const *md5 = NULL;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MD *md5_to_free = NULL;
+
+ /*
+ * If we are using OpenSSL >= 3.0 and FIPS mode is
+ * enabled, we need to load the default provider in a
+ * standalone context in order to access MD5.
+ */
+ OSSL_LIB_CTX *libctx = NULL;
+ OSSL_PROVIDER *default_provider = NULL;
+
+ if (EVP_default_properties_is_fips_enabled(NULL)) {
+ libctx = OSSL_LIB_CTX_new();
+ default_provider = OSSL_PROVIDER_load(libctx, "default");
+
+ if (!default_provider) {
+ ERROR("Failed loading OpenSSL default provider.");
+ return;
+ }
+
+ md5_to_free = EVP_MD_fetch(libctx, "MD5", NULL);
+ if (!md5_to_free) {
+ ERROR("Failed loading OpenSSL MD5 function.");
+ return;
+ }
+
+ md5 = md5_to_free;
+ } else {
+ md5 = EVP_md5();
+ }
+#else
+ md5 = EVP_md5();
+#endif
+
+ P_hash(md5, s1, len, seed, seed_len, out, out_len);
+ P_hash(EVP_sha1(), s2, len, seed, seed_len, buf, out_len);
+
+ for (i = 0; i < out_len; i++) {
+ out[i] ^= buf[i];
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (libctx) {
+ OSSL_PROVIDER_unload(default_provider);
+ OSSL_LIB_CTX_free(libctx);
+ EVP_MD_free(md5_to_free);
+ }
+#endif
+}
+
+/*
+ * TLS 1.2 PRF from RFC 5246 section 5
+ */
+static void PRFv12(unsigned char const *secret, unsigned int secret_len,
+ unsigned char const *seed, unsigned int seed_len,
+ unsigned char *out, unsigned int out_len)
+{
+ P_hash(EVP_sha256(), secret, secret_len, seed, seed_len, out, out_len);
+}
+
+/* EAP-FAST Pseudo-Random Function (T-PRF): RFC 4851, Section 5.5 */
+void T_PRF(unsigned char const *secret, unsigned int secret_len,
+ char const *prf_label,
+ unsigned char const *seed, unsigned int seed_len,
+ unsigned char *out, unsigned int out_len)
+{
+ size_t prf_size = strlen(prf_label);
+ size_t pos;
+ uint8_t *buf;
+
+ if (prf_size > 128) prf_size = 128;
+ prf_size++; /* include trailing zero */
+
+ buf = talloc_size(NULL, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+
+ memcpy(buf + SHA1_DIGEST_LENGTH, prf_label, prf_size);
+ if (seed) memcpy(buf + SHA1_DIGEST_LENGTH + prf_size, seed, seed_len);
+ *(uint16_t *)&buf[SHA1_DIGEST_LENGTH + prf_size + seed_len] = htons(out_len);
+ buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2] = 1;
+
+ // T1 is just the seed
+ fr_hmac_sha1(buf, buf + SHA1_DIGEST_LENGTH, prf_size + seed_len + 2 + 1, secret, secret_len);
+
+#define MIN(a,b) (((a)>(b)) ? (b) : (a))
+ memcpy(out, buf, MIN(out_len, SHA1_DIGEST_LENGTH));
+
+ pos = SHA1_DIGEST_LENGTH;
+ while (pos < out_len) {
+ buf[SHA1_DIGEST_LENGTH + prf_size + seed_len + 2]++;
+
+ fr_hmac_sha1(buf, buf, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1, secret, secret_len);
+ memcpy(&out[pos], buf, MIN(out_len - pos, SHA1_DIGEST_LENGTH));
+
+ if (out_len - pos <= SHA1_DIGEST_LENGTH)
+ break;
+
+ pos += SHA1_DIGEST_LENGTH;
+ }
+
+ memset(buf, 0, SHA1_DIGEST_LENGTH + prf_size + seed_len + 2 + 1);
+ talloc_free(buf);
+}
+
+#define EAPTLS_MPPE_KEY_LEN 32
+
+/*
+ * Generate keys according to RFC 2716 and add to reply
+ */
+void eaptls_gen_mppe_keys(REQUEST *request, SSL *s, char const *label, uint8_t const *context, UNUSED size_t context_size)
+{
+ uint8_t out[4 * EAPTLS_MPPE_KEY_LEN];
+ uint8_t *p;
+ size_t len;
+
+ len = strlen(label);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ if (SSL_export_keying_material(s, out, sizeof(out), label, len, context, context_size, context != NULL) != 1) {
+ ERROR("Failed generating keying material");
+ return;
+ }
+#else
+ {
+ uint8_t seed[64 + (2 * SSL3_RANDOM_SIZE) + (context ? 2 + context_size : 0)];
+ uint8_t buf[4 * EAPTLS_MPPE_KEY_LEN];
+
+ p = seed;
+
+ memcpy(p, label, len);
+ p += len;
+
+ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ len += SSL3_RANDOM_SIZE;
+
+ memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ len += SSL3_RANDOM_SIZE;
+
+ if (context) {
+ /* cloned and reversed FR_PUT_LE16 */
+ p[0] = ((uint16_t) (context_size)) >> 8;
+ p[1] = ((uint16_t) (context_size)) & 0xff;
+ p += 2;
+ len += 2;
+ memcpy(p, context, context_size);
+ p += context_size;
+ len += context_size;
+ }
+
+ PRF(s->session->master_key, s->session->master_key_length,
+ seed, len, out, buf, sizeof(out));
+ }
+#endif
+
+ p = out;
+ eap_add_reply(request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
+ p += EAPTLS_MPPE_KEY_LEN;
+ eap_add_reply(request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
+
+ eap_add_reply(request, "EAP-MSK", out, 64);
+ eap_add_reply(request, "EAP-EMSK", out + 64, 64);
+}
+
+
+#define FR_TLS_PRF_CHALLENGE "ttls challenge"
+
+/*
+ * Generate the TTLS challenge
+ *
+ * It's in the TLS module simply because it's only a few lines
+ * of code, and it needs access to the TLS PRF functions.
+ */
+void eapttls_gen_challenge(SSL *s, uint8_t *buffer, size_t size)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ if (SSL_export_keying_material(s, buffer, size, FR_TLS_PRF_CHALLENGE,
+ sizeof(FR_TLS_PRF_CHALLENGE)-1, NULL, 0, 0) != 1) {
+ ERROR("Failed generating keying material");
+ }
+#else
+ uint8_t out[32], buf[32];
+ uint8_t seed[sizeof(FR_TLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
+ uint8_t *p = seed;
+
+ memcpy(p, FR_TLS_PRF_CHALLENGE, sizeof(FR_TLS_PRF_CHALLENGE)-1);
+ p += sizeof(FR_TLS_PRF_CHALLENGE)-1;
+ memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
+
+ PRF(s->session->master_key, s->session->master_key_length,
+ seed, sizeof(seed), out, buf, sizeof(out));
+ memcpy(buffer, out, size);
+#endif
+}
+
+#define FR_TLS_EXPORTER_METHOD_ID "EXPORTER_EAP_TLS_Method-Id"
+
+/*
+ * Actually generates EAP-Session-Id, which is an internal server
+ * attribute. Not all systems want to send EAP-Key-Name.
+ */
+void eaptls_gen_eap_key(eap_handler_t *handler)
+{
+ RADIUS_PACKET *packet = handler->request->reply;
+ tls_session_t *tls_session = handler->opaque;
+ SSL *s = tls_session->ssl;
+ VALUE_PAIR *vp;
+ uint8_t *buff, *p;
+ uint8_t type = handler->type & 0xff;
+
+ vp = fr_pair_afrom_num(packet, PW_EAP_SESSION_ID, 0);
+ if (!vp) return;
+
+ vp->vp_length = 1 + 2 * SSL3_RANDOM_SIZE;
+ buff = p = talloc_array(vp, uint8_t, vp->vp_length);
+
+ *p++ = type;
+
+ switch (SSL_version(tls_session->ssl)) {
+ case TLS1_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_2_VERSION:
+ SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
+ break;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+#endif
+ default:
+ {
+ uint8_t const context[] = { type };
+
+ if (SSL_export_keying_material(s, p, 2 * SSL3_RANDOM_SIZE,
+ FR_TLS_EXPORTER_METHOD_ID, sizeof(FR_TLS_EXPORTER_METHOD_ID)-1,
+ context, sizeof(context), 1) != 1) {
+ ERROR("Failed generating keying material");
+ return;
+ }
+ }
+#endif
+ }
+
+ vp->vp_octets = buff;
+ fr_pair_add(&packet->vps, vp);
+}
+
+/*
+ * Same as before, but for EAP-FAST the order of {server,client}_random is flipped
+ */
+void eap_fast_tls_gen_challenge(SSL *s, int version, uint8_t *buffer, size_t size, char const *prf_label)
+{
+ uint8_t *p;
+ size_t len, master_key_len;
+ uint8_t seed[128 + 2*SSL3_RANDOM_SIZE];
+ uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH];
+
+ len = strlen(prf_label);
+ if (len > 128) len = 128;
+
+ p = seed;
+ memcpy(p, prf_label, len);
+ p += len;
+ SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+ SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
+ p += SSL3_RANDOM_SIZE;
+
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s), master_key, sizeof(master_key));
+
+ if (version == TLS1_2_VERSION)
+ PRFv12(master_key, master_key_len, seed, p - seed, buffer, size);
+ else
+ PRF(master_key, master_key_len, seed, p - seed, buffer, size);
+}
diff --git a/src/modules/rlm_eap/mem.c b/src/modules/rlm_eap/mem.c
new file mode 100644
index 0000000..6be8ca4
--- /dev/null
+++ b/src/modules/rlm_eap/mem.c
@@ -0,0 +1,503 @@
+/*
+ * mem.c Memory allocation, deallocation stuff.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2001,2006 The FreeRADIUS server project
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include "rlm_eap.h"
+
+#ifdef WITH_TLS
+#include <freeradius-devel/tls.h>
+#endif
+
+#ifdef HAVE_PTHREAD_H
+#define PTHREAD_MUTEX_LOCK pthread_mutex_lock
+#define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
+#else
+#define PTHREAD_MUTEX_LOCK(_x)
+#define PTHREAD_MUTEX_UNLOCK(_x)
+#endif
+
+/*
+ * Allocate a new eap_packet_t
+ */
+EAP_DS *eap_ds_alloc(eap_handler_t *handler)
+{
+ EAP_DS *eap_ds;
+
+ eap_ds = talloc_zero(handler, EAP_DS);
+ eap_ds->response = talloc_zero(eap_ds, eap_packet_t);
+ if (!eap_ds->response) {
+ eap_ds_free(&eap_ds);
+ return NULL;
+ }
+ eap_ds->request = talloc_zero(eap_ds, eap_packet_t);
+ if (!eap_ds->response) {
+ eap_ds_free(&eap_ds);
+ return NULL;
+ }
+
+ return eap_ds;
+}
+
+void eap_ds_free(EAP_DS **eap_ds_p)
+{
+ EAP_DS *eap_ds;
+
+ if (!eap_ds_p) return;
+
+ eap_ds = *eap_ds_p;
+ if (!eap_ds) return;
+
+ if (eap_ds->response) talloc_free(eap_ds->response);
+ if (eap_ds->request) talloc_free(eap_ds->request);
+
+ talloc_free(eap_ds);
+ *eap_ds_p = NULL;
+}
+
+static int _eap_handler_free(eap_handler_t *handler)
+{
+ if (handler->identity) {
+ talloc_free(handler->identity);
+ handler->identity = NULL;
+ }
+
+ if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds));
+ if (handler->eap_ds) eap_ds_free(&(handler->eap_ds));
+
+ if ((handler->opaque) && (handler->free_opaque)) {
+ handler->free_opaque(handler->opaque);
+ handler->opaque = NULL;
+ }
+
+ handler->opaque = NULL;
+ handler->free_opaque = NULL;
+
+ /*
+ * Give helpful debug messages if:
+ *
+ * we're debugging TLS sessions, which don't finish,
+ * and which aren't deleted early due to a likely RADIUS
+ * retransmit which nukes our ID, and therefore our stare.
+ */
+ if (fr_debug_lvl && handler->tls && !handler->finished &&
+ (time(NULL) > (handler->timestamp + 3))) {
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! EAP session with state 0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x did not finish! !!",
+ handler->state[0], handler->state[1],
+ handler->state[2], handler->state[3],
+ handler->state[4], handler->state[5],
+ handler->state[6], handler->state[7],
+ handler->state[8], handler->state[9],
+ handler->state[10], handler->state[11],
+ handler->state[12], handler->state[13],
+ handler->state[14], handler->state[15]);
+
+ WARN("!! Please read http://wiki.freeradius.org/guide/Certificate_Compatibility !!");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate a new eap_handler_t
+ */
+eap_handler_t *eap_handler_alloc(rlm_eap_t *inst)
+{
+ eap_handler_t *handler;
+
+ handler = talloc_zero(NULL, eap_handler_t);
+ if (!handler) {
+ ERROR("Failed allocating handler");
+ return NULL;
+ }
+ handler->inst_holder = inst;
+
+ /* Doesn't need to be inside the critical region */
+ talloc_set_destructor(handler, _eap_handler_free);
+
+ return handler;
+}
+
+
+void eaplist_free(rlm_eap_t *inst)
+{
+ eap_handler_t *node, *next;
+
+ for (node = inst->session_head; node != NULL; node = next) {
+ next = node->next;
+ talloc_free(node);
+ }
+
+ inst->session_head = inst->session_tail = NULL;
+}
+
+/*
+ * Return a 32-bit random number.
+ */
+static uint32_t eap_rand(fr_randctx *ctx)
+{
+ uint32_t num;
+
+ num = ctx->randrsl[ctx->randcnt++];
+ if (ctx->randcnt >= 256) {
+ ctx->randcnt = 0;
+ fr_isaac(ctx);
+ }
+
+ return num;
+}
+
+
+static eap_handler_t *eaplist_delete(rlm_eap_t *inst, REQUEST *request,
+ eap_handler_t *handler)
+{
+ rbnode_t *node;
+
+ node = rbtree_find(inst->session_tree, handler);
+ if (!node) return NULL;
+
+ handler = rbtree_node2data(inst->session_tree, node);
+
+ RDEBUG("Finished EAP session with state "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ handler->state[0], handler->state[1],
+ handler->state[2], handler->state[3],
+ handler->state[4], handler->state[5],
+ handler->state[6], handler->state[7]);
+ /*
+ * Delete old handler from the tree.
+ */
+ rbtree_delete(inst->session_tree, node);
+
+ /*
+ * And unsplice it from the linked list.
+ */
+ if (handler->prev) {
+ handler->prev->next = handler->next;
+ } else {
+ inst->session_head = handler->next;
+ }
+ if (handler->next) {
+ handler->next->prev = handler->prev;
+ } else {
+ inst->session_tail = handler->prev;
+ }
+ handler->prev = handler->next = NULL;
+
+ return handler;
+}
+
+
+static void eaplist_expire(rlm_eap_t *inst, REQUEST *request, time_t timestamp)
+{
+ int i;
+ eap_handler_t *handler;
+
+ /*
+ * Check the first few handlers in the list, and delete
+ * them if they're too old. We don't need to check them
+ * all, as incoming requests will quickly cause older
+ * handlers to be deleted.
+ *
+ */
+ for (i = 0; i < 3; i++) {
+ handler = inst->session_head;
+ if (!handler) break;
+
+ RDEBUG("Expiring EAP session with state "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ handler->state[0], handler->state[1],
+ handler->state[2], handler->state[3],
+ handler->state[4], handler->state[5],
+ handler->state[6], handler->state[7]);
+
+ /*
+ * Expire entries from the start of the list.
+ * They should be the oldest ones.
+ */
+ if ((timestamp - handler->timestamp) > (int)inst->timer_limit) {
+ rbnode_t *node;
+ node = rbtree_find(inst->session_tree, handler);
+ rad_assert(node != NULL);
+ rbtree_delete(inst->session_tree, node);
+
+ /*
+ * handler == inst->session_head
+ */
+ inst->session_head = handler->next;
+ if (handler->next) {
+ handler->next->prev = NULL;
+ } else {
+ inst->session_head = NULL;
+ inst->session_tail = NULL;
+ }
+
+#ifdef WITH_TLS
+ /*
+ * Remove expired TLS sessions.
+ */
+ switch (handler->type) {
+ case PW_EAP_TLS:
+ case PW_EAP_TTLS:
+ case PW_EAP_PEAP:
+ case PW_EAP_FAST:
+ tls_fail(handler->opaque); /* MUST be a tls_session! */
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ talloc_free(handler);
+ } else {
+ break;
+ }
+ }
+}
+
+/*
+ * Add a handler to the set of active sessions.
+ *
+ * Since we're adding it to the list, we guess that this means
+ * the packet needs a State attribute. So add one.
+ */
+int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler)
+{
+ int status = 0;
+ VALUE_PAIR *state;
+ REQUEST *request = handler->request;
+
+ /*
+ * Generate State, since we've been asked to add it to
+ * the list.
+ */
+ state = pair_make_reply("State", NULL, T_OP_EQ);
+ if (!state) return 0;
+
+ /*
+ * The time at which this request was made was the time
+ * at which it was received by the RADIUS server.
+ */
+ handler->timestamp = request->timestamp;
+ handler->status = 1;
+
+ handler->src_ipaddr = request->packet->src_ipaddr;
+ handler->eap_id = handler->eap_ds->request->id;
+
+ /*
+ * Playing with a data structure shared among threads
+ * means that we need a lock, to avoid conflict.
+ */
+ PTHREAD_MUTEX_LOCK(&(inst->session_mutex));
+
+ /*
+ * If we have a DoS attack, discard new sessions.
+ */
+ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) {
+ status = -1;
+ eaplist_expire(inst, request, handler->timestamp);
+ goto done;
+ }
+
+ /*
+ * Create a unique content for the State variable.
+ * It will be modified slightly per round trip, but less so
+ * than in 1.x.
+ */
+ if (handler->trips == 0) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ uint32_t lvalue;
+
+ lvalue = eap_rand(&inst->rand_pool);
+
+ memcpy(handler->state + i * 4, &lvalue,
+ sizeof(lvalue));
+ }
+ }
+
+ /*
+ * Add some more data to distinguish the sessions.
+ */
+ handler->state[4] = handler->trips ^ handler->state[0];
+ handler->state[5] = handler->eap_id ^ handler->state[1];
+ handler->state[6] = handler->type ^ handler->state[2];
+ handler->state[12] = handler->state[2] ^ (RADIUSD_VERSION & 0xff);
+
+ fr_pair_value_memcpy(state, handler->state, sizeof(handler->state));
+
+ /*
+ * Big-time failure.
+ */
+ status = rbtree_insert(inst->session_tree, handler);
+
+ if (status) {
+ eap_handler_t *prev;
+
+ prev = inst->session_tail;
+ if (prev) {
+ prev->next = handler;
+ handler->prev = prev;
+ handler->next = NULL;
+ inst->session_tail = handler;
+ } else {
+ inst->session_head = inst->session_tail = handler;
+ handler->next = handler->prev = NULL;
+ }
+ }
+
+ /*
+ * Now that we've finished mucking with the list,
+ * unlock it.
+ */
+ done:
+
+ /*
+ * We don't need this any more.
+ */
+ if (status > 0) handler->request = NULL;
+
+ PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex));
+
+ if (status <= 0) {
+ fr_pair_delete_by_num(&request->reply->vps, PW_STATE, 0, TAG_ANY);
+
+ if (status < 0) {
+ static time_t last_logged = 0;
+
+ if (last_logged < handler->timestamp) {
+ last_logged = handler->timestamp;
+ ERROR("rlm_eap (%s): Too many open sessions. Try increasing \"max_sessions\" "
+ "in the EAP module configuration", inst->xlat_name);
+ }
+ } else {
+ ERROR("rlm_eap (%s): Failed to store handler", inst->xlat_name);
+ }
+ return 0;
+ }
+
+ RDEBUG("EAP session adding &reply:State = 0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ state->vp_octets[0], state->vp_octets[1], state->vp_octets[2], state->vp_octets[3],
+ state->vp_octets[4], state->vp_octets[5], state->vp_octets[6], state->vp_octets[7]);
+
+ return 1;
+}
+
+/*
+ * Find a a previous EAP-Request sent by us, which matches
+ * the current EAP-Response.
+ *
+ * Then, release the handle from the list, and return it to
+ * the caller.
+ *
+ * Also since we fill the eap_ds with the present EAP-Response we
+ * got to free the prev_eapds & move the eap_ds to prev_eapds
+ */
+eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request,
+ eap_packet_raw_t *eap_packet)
+{
+ VALUE_PAIR *state;
+ eap_handler_t *handler, myHandler;
+
+ /*
+ * We key the sessions off of the 'state' attribute, so it
+ * must exist.
+ */
+ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (!state) {
+ REDEBUG("EAP requires the State attribute to work, but no State exists in the Access-Request packet.");
+ REDEBUG("The RADIUS client is broken. No amount of changing FreeRADIUS will fix the RADIUS client.");
+ return NULL;
+ }
+
+ if (state->vp_length != EAP_STATE_LEN) {
+ REDEBUG("The RADIUS client has mangled the State attribute, OR you are forcing EAP in the wrong situation");
+ return NULL;
+ }
+
+ myHandler.src_ipaddr = request->packet->src_ipaddr;
+ myHandler.eap_id = eap_packet->id;
+ memcpy(myHandler.state, state->vp_strvalue, sizeof(myHandler.state));
+
+ /*
+ * Playing with a data structure shared among threads
+ * means that we need a lock, to avoid conflict.
+ */
+ PTHREAD_MUTEX_LOCK(&(inst->session_mutex));
+
+ eaplist_expire(inst, request, request->timestamp);
+
+ handler = eaplist_delete(inst, request, &myHandler);
+ PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex));
+
+ /*
+ * Might not have been there.
+ */
+ if (!handler) {
+ RERROR("rlm_eap (%s): No EAP session matching state "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ inst->xlat_name,
+ state->vp_octets[0], state->vp_octets[1],
+ state->vp_octets[2], state->vp_octets[3],
+ state->vp_octets[4], state->vp_octets[5],
+ state->vp_octets[6], state->vp_octets[7]);
+ return NULL;
+ }
+
+ if (handler->trips >= 50) {
+ RERROR("rlm_eap (%s): Aborting! More than 50 roundtrips "
+ "made in session with state "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+ inst->xlat_name,
+ state->vp_octets[0], state->vp_octets[1],
+ state->vp_octets[2], state->vp_octets[3],
+ state->vp_octets[4], state->vp_octets[5],
+ state->vp_octets[6], state->vp_octets[7]);
+
+
+ talloc_free(handler);
+ return NULL;
+ }
+ handler->trips++;
+
+ RDEBUG("Previous EAP request found for state "
+ "0x%02x%02x%02x%02x%02x%02x%02x%02x, released from the list",
+ state->vp_octets[0], state->vp_octets[1],
+ state->vp_octets[2], state->vp_octets[3],
+ state->vp_octets[4], state->vp_octets[5],
+ state->vp_octets[6], state->vp_octets[7]);
+
+ /*
+ * Remember what the previous request was.
+ */
+ eap_ds_free(&(handler->prev_eapds));
+ handler->prev_eapds = handler->eap_ds;
+ handler->eap_ds = NULL;
+
+ return handler;
+}
diff --git a/src/modules/rlm_eap/radeapclient.c b/src/modules/rlm_eap/radeapclient.c
new file mode 100644
index 0000000..ae24f06
--- /dev/null
+++ b/src/modules/rlm_eap/radeapclient.c
@@ -0,0 +1,2315 @@
+/*
+ * radeapclient.c EAP specific radius packet debug tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <ctype.h>
+#include <assert.h>
+
+#if HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/radpaths.h>
+#include <freeradius-devel/md5.h>
+
+#include "eap_types.h"
+#include "eap_sim.h"
+#include "comp128.h"
+
+extern int sha1_data_problems;
+
+#undef DEBUG
+#undef DEBUG2
+#undef ERROR
+
+#define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
+#define DEBUG2 if ((fr_debug_lvl >= 2) && fr_log_fp) fr_printf_log
+#define ERROR if (fr_debug_lvl && fr_log_fp) fr_printf_log
+
+#define USEC 1000000
+
+static uint32_t parallel = 1;
+static unsigned int retries = 3;
+static float timeout = 5;
+static struct timeval tv_timeout;
+static char const *secret = NULL;
+static int do_output = 1;
+static int do_summary = 0;
+static int totalapp = 0;
+static int totaldeny = 0;
+static char filesecret[256];
+static char const *radius_dir = NULL;
+static char const *progname = "radeapclient";
+/* fr_randctx randctx; */
+
+main_config_t main_config;
+char const *radiusd_version = "";
+
+#ifdef WITH_TLS
+#include <freeradius-devel/tls.h>
+#endif
+
+log_lvl_t rad_debug_lvl = 0;
+
+//TODO: move structures to a header file.
+
+typedef struct rc_input_vps_list rc_input_vps_list_t;
+typedef struct rc_input_vps rc_input_vps_t;
+typedef struct rc_transaction rc_transaction_t;
+
+/** Structure which contains EAP context, necessary to perform the full EAP transaction.
+ */
+typedef struct rc_eap_sim_context {
+ struct eapsim_keys keys;
+} rc_eap_sim_context_t;
+
+typedef struct rc_eap_md5_context {
+ int tried;
+} rc_eap_md5_context_t;
+
+typedef struct rc_eap_context {
+ int eap_type; //!< contains the EAP-Type
+ char password[256]; //!< copy of User-Password (or CHAP-Password).
+ VALUE_PAIR *ki;
+ union {
+ rc_eap_sim_context_t sim;
+ rc_eap_md5_context_t md5;
+ } eap;
+} rc_eap_context_t;
+
+
+/** Structure which holds a list of available input vps.
+ */
+struct rc_input_vps_list {
+ rc_input_vps_t *head;
+ rc_input_vps_t *tail;
+ uint32_t size;
+};
+
+/** Structure which holds an input vps entry (read from file or stdin),
+ * and linkage to previous / next entries.
+ */
+struct rc_input_vps {
+ uint32_t num; //!< The number (within the file) of the input we're reading.
+
+ VALUE_PAIR *vps_in; //!< the list of attribute/value pairs.
+
+ rc_input_vps_list_t *list; //!< the list to which this entry belongs (NULL for an unchained entry).
+
+ rc_input_vps_t *prev;
+ rc_input_vps_t *next;
+};
+
+
+/** Structure which holds a transaction: sent packet, reply received...
+ */
+struct rc_transaction {
+ uint32_t id; //!< id of transaction (0 for the first one).
+
+ uint32_t num_packet; //!< number of packets sent for this transaction.
+
+ RADIUS_PACKET *packet;
+ RADIUS_PACKET *reply;
+
+ rc_input_vps_t *input_vps;
+
+ rc_eap_context_t *eap_context;
+
+ uint32_t tries;
+
+ fr_event_t *event; //!< armed event (if any).
+
+ char password[256];
+ char const *name; //!< Test name (as specified in the request).
+};
+
+typedef struct eap_sim_server_state {
+ enum eapsim_serverstates state;
+ struct eapsim_keys keys;
+ int sim_id;
+} eap_sim_state_t;
+
+
+static TALLOC_CTX *autofree;
+static uint32_t num_trans = 0; //!< number of transactions initialized.
+static uint32_t num_started = 0; //!< number of transactions started.
+static uint32_t num_ongoing = 0; //!< number of ongoing transactions.
+static uint32_t num_finished = 0; //!< number of finished transactions.
+
+static rc_input_vps_list_t rc_vps_list_in; //!< list of available input vps entries.
+static fr_packet_list_t *pl = NULL; //!< list of outgoing packets.
+static unsigned int num_sockets = 0; //!< number of allocated sockets.
+static fr_event_list_t *ev_list = NULL; //!< list of armed events.
+
+static int force_af = AF_UNSPEC;
+static int ipproto = IPPROTO_UDP;
+static fr_ipaddr_t server_ipaddr;
+static bool server_addr_init = false;
+static uint16_t server_port = 0;
+static int packet_code = PW_CODE_UNDEFINED;
+
+static int rc_map_eap_methods(RADIUS_PACKET *req);
+static void rc_unmap_eap_methods(RADIUS_PACKET *rep);
+static int rc_map_eapsim_types(RADIUS_PACKET *r);
+static int rc_unmap_eapsim_types(RADIUS_PACKET *r);
+
+static void rc_get_port(PW_CODE type, uint16_t *port);
+static void rc_evprep_packet_timeout(rc_transaction_t *trans);
+static void rc_deallocate_id(rc_transaction_t *trans);
+
+/*
+ * For cbtls_cache_*()
+ */
+rlm_rcode_t process_post_auth(UNUSED int postauth_type, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_FAIL;
+}
+
+
+fr_event_list_t *radius_event_list_corral(UNUSED event_corral_t hint)
+{
+ return NULL;
+}
+
+static void NEVER_RETURNS usage(void)
+{
+ fprintf(stdout, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
+
+ fprintf(stdout, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
+ fprintf(stdout, " -4 Use IPv4 address of server\n");
+ fprintf(stdout, " -6 Use IPv6 address of server.\n");
+ fprintf(stdout, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
+ fprintf(stdout, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stdout, " -f <file> Read packets from file, not stdin.\n");
+ fprintf(stdout, " -h Print usage help information.\n");
+ fprintf(stdout, " -p <num> Send 'num' packets in parallel.\n");
+ fprintf(stdout, " -q Do not print anything out.\n");
+ fprintf(stdout, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
+ fprintf(stdout, " -s Print out summary information of auth results.\n");
+ fprintf(stdout, " -S <file> read secret from file, not command line.\n");
+ fprintf(stdout, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
+ fprintf(stdout, " -v Show program version information.\n");
+ fprintf(stdout, " -x Debugging mode.\n");
+
+ exit(1);
+}
+
+static const FR_NAME_NUMBER rc_request_types[] = {
+ { "auth", PW_CODE_ACCESS_REQUEST },
+ { "challenge", PW_CODE_ACCESS_CHALLENGE },
+ { "acct", PW_CODE_ACCOUNTING_REQUEST },
+ { "status", PW_CODE_STATUS_SERVER },
+ { "disconnect", PW_CODE_DISCONNECT_REQUEST },
+ { "coa", PW_CODE_COA_REQUEST },
+ { "auto", PW_CODE_UNDEFINED },
+
+ { NULL, 0}
+};
+
+int rad_virtual_server(REQUEST UNUSED *request)
+{
+ /*We're not the server so we cannot do this*/
+ abort();
+}
+
+/** Convert a float to struct timeval.
+ */
+static void rc_float_to_timeval(struct timeval *tv, float f_val)
+{
+ tv->tv_sec = (time_t)f_val;
+ uint64_t usec = (uint64_t)(f_val * USEC) - (tv->tv_sec * USEC);
+ tv->tv_usec = usec;
+}
+
+/** Add an allocated rc_input_vps_t entry to the tail of the list.
+ */
+ static void rc_add_vps_entry(rc_input_vps_list_t *list, rc_input_vps_t *entry)
+{
+ if (!list || !entry) return;
+
+ if (!list->head) {
+ assert(list->tail == NULL);
+ list->head = entry;
+ entry->prev = NULL;
+ } else {
+ assert(list->tail != NULL);
+ assert(list->tail->next == NULL);
+ list->tail->next = entry;
+ entry->prev = list->tail;
+ }
+ list->tail = entry;
+ entry->next = NULL;
+ entry->list = list;
+ list->size ++;
+}
+
+/** Remove a selected rc_input_vps_t entry from its current list.
+ */
+static rc_input_vps_t *rc_yank_vps_entry(rc_input_vps_t *entry)
+{
+ if (!entry) return NULL;
+
+ if (!entry->list) return entry; /* not in a list, nothing to do. Just return the entry. */
+
+ rc_input_vps_t *prev, *next;
+
+ prev = entry->prev;
+ next = entry->next;
+
+ rc_input_vps_list_t *list = entry->list;
+
+ assert(list->head != NULL); /* entry belongs to a list, so the list can't be empty. */
+ assert(list->tail != NULL); /* same. */
+
+ if (prev) {
+ assert(list->head != entry); /* if entry has a prev, then entry can't be head. */
+ prev->next = next;
+ }
+ else {
+ assert(list->head == entry); /* if entry has no prev, then entry must be head. */
+ list->head = next;
+ }
+
+ if (next) {
+ assert(list->tail != entry); /* if entry has a next, then entry can't be tail. */
+ next->prev = prev;
+ }
+ else {
+ assert(list->tail == entry); /* if entry has no next, then entry must be tail. */
+ list->tail = prev;
+ }
+
+ entry->list = NULL;
+ entry->prev = NULL;
+ entry->next = NULL;
+ list->size --;
+ return entry;
+}
+
+/** Load input entries (list of vps) from a file or stdin, and add them to the list.
+ * They will be used to initiate transactions.
+ */
+static int rc_load_input(TALLOC_CTX *ctx, char const *filename, rc_input_vps_list_t *list, uint32_t max_entries)
+{
+ FILE *file_in = NULL;
+ bool file_done = false;
+ rc_input_vps_t *request;
+ char const *input;
+ uint32_t input_num = 0;
+
+ /* Determine where to read the VP's from. */
+ if (filename && strcmp(filename, "-") != 0) {
+ DEBUG2("Opening input file: %s\n", filename);
+ file_in = fopen(filename, "r");
+ if (!file_in) {
+ ERROR("Error opening %s: %s\n", filename, strerror(errno));
+ return 0;
+ }
+ input = filename;
+ } else {
+ DEBUG2("Reading input vps from stdin\n");
+ file_in = stdin;
+ input = "stdin";
+ }
+
+ /* Loop over the file (or stdin). */
+ do {
+ input_num ++;
+ MEM(request = talloc_zero(ctx, rc_input_vps_t));
+
+ if (fr_pair_list_afrom_file(request, &request->vps_in, file_in, &file_done) < 0) {
+ ERROR("Error parsing entry %u from input: %s\n", input_num, input);
+ talloc_free(request);
+ break;
+ }
+ if (NULL == request->vps_in) {
+ /* Last line might be empty, in this case fr_pair_list_afrom_file will return a NULL vps pointer. Silently ignore this. */
+ talloc_free(request);
+ break;
+ }
+
+ /* Add that to the list */
+ rc_add_vps_entry(list, request);
+
+ request->num = list->size;
+
+ if (max_entries && list->size >= max_entries) {
+ /* Only load what we need. */
+ break;
+ }
+ } while (!file_done);
+
+ if (file_in != stdin) fclose(file_in);
+
+ /* And we're done. */
+ DEBUG("Read %d element(s) from input: %s\n", list->size, input);
+ return 1;
+}
+
+/** Perform packet initialization for a transaction.
+ */
+static int rc_init_packet(rc_transaction_t *trans)
+{
+ if (!trans || !trans->packet) return 0;
+
+ RADIUS_PACKET *packet = trans->packet;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ /*
+ * Process special attributes
+ */
+ for (vp = fr_cursor_init(&cursor, &packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * Double quoted strings get marked up as xlat expansions,
+ * but we don't support that in request.
+ */
+ if (vp->type == VT_XLAT) {
+ vp->type = VT_DATA;
+ vp->vp_strvalue = vp->value.xlat;
+ vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
+ }
+
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ default:
+ break;
+
+ /*
+ * Allow it to set the packet type in
+ * the attributes read from the file.
+ */
+ case PW_PACKET_TYPE:
+ packet->code = vp->vp_integer;
+ break;
+
+ case PW_PACKET_DST_PORT:
+ packet->dst_port = (vp->vp_integer & 0xffff);
+ break;
+
+ case PW_PACKET_DST_IP_ADDRESS:
+ packet->dst_ipaddr.af = AF_INET;
+ packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ packet->dst_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_DST_IPV6_ADDRESS:
+ packet->dst_ipaddr.af = AF_INET6;
+ packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ packet->dst_ipaddr.prefix = 128;
+ break;
+
+ case PW_PACKET_SRC_PORT:
+ if ((vp->vp_integer < 1024) ||
+ (vp->vp_integer > 65535)) {
+ DEBUG("Invalid value '%u' for Packet-Src-Port\n", vp->vp_integer);
+ } else {
+ packet->src_port = (vp->vp_integer & 0xffff);
+ }
+ break;
+
+ case PW_PACKET_SRC_IP_ADDRESS:
+ packet->src_ipaddr.af = AF_INET;
+ packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+ packet->src_ipaddr.prefix = 32;
+ break;
+
+ case PW_PACKET_SRC_IPV6_ADDRESS:
+ packet->src_ipaddr.af = AF_INET6;
+ packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
+ packet->src_ipaddr.prefix = 128;
+ break;
+
+ case PW_DIGEST_REALM:
+ case PW_DIGEST_NONCE:
+ case PW_DIGEST_METHOD:
+ case PW_DIGEST_URI:
+ case PW_DIGEST_QOP:
+ case PW_DIGEST_ALGORITHM:
+ case PW_DIGEST_BODY_DIGEST:
+ case PW_DIGEST_CNONCE:
+ case PW_DIGEST_NONCE_COUNT:
+ case PW_DIGEST_USER_NAME:
+ /* overlapping! */
+ {
+ DICT_ATTR const *da;
+ uint8_t *p, *q;
+
+ p = talloc_array(vp, uint8_t, vp->vp_length + 2);
+
+ memcpy(p + 2, vp->vp_octets, vp->vp_length);
+ p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
+ vp->vp_length += 2;
+ p[1] = vp->vp_length;
+
+ da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
+ if (!da) {
+ ERROR("Attribute 'Digest-Attributes' not found by value\n");
+ exit(1);
+ }
+ vp->da = da;
+
+ /*
+ * Re-do fr_pair_value_memsteal ourselves,
+ * because we play games with
+ * vp->da, and fr_pair_value_memsteal goes
+ * to GREAT lengths to sanitize
+ * and fix and change and
+ * double-check the various
+ * fields.
+ */
+ memcpy(&q, &vp->vp_octets, sizeof(q));
+ talloc_free(q);
+
+ vp->vp_octets = talloc_steal(vp, p);
+ vp->type = VT_DATA;
+
+ VERIFY_VP(vp);
+ }
+ break;
+
+ /*
+ * Keep a copy of the the password attribute.
+ */
+ case PW_CLEARTEXT_PASSWORD:
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_MS_CHAP_PASSWORD:
+ strlcpy(trans->password, vp->vp_strvalue, sizeof(trans->password));
+ break;
+
+ case PW_RADCLIENT_TEST_NAME:
+ trans->name = vp->vp_strvalue;
+ break;
+ }
+ } /* loop over the VP's we read in */
+
+ if (packet->dst_port == 0) packet->dst_port = server_port;
+
+ if (packet->dst_ipaddr.af == AF_UNSPEC) {
+ if (!server_addr_init) {
+ DEBUG("No server was given, and input entry %u did not contain Packet-Dst-IP-Address, ignored.\n", trans->input_vps->num);
+ return 0;
+ }
+ packet->dst_ipaddr = server_ipaddr;
+ }
+
+ /* Use the default set on the command line. */
+ if (packet->code == PW_CODE_UNDEFINED) {
+ if (packet_code == PW_CODE_UNDEFINED) {
+ DEBUG("No packet type was given, and input entry %u did not contain Packet-Type, ignored.\n", trans->input_vps->num);
+ return 0;
+ }
+ packet->code = packet_code;
+ }
+
+ /* Automatically set the dst port (if one wasn't already set). */
+ if (packet->dst_port == 0) {
+ rc_get_port(packet->code, &packet->dst_port);
+ if (packet->dst_port == 0) {
+ DEBUG("Can't determine destination port for input entry %u, ignored.\n", trans->input_vps->num);
+ return 0;
+ }
+ }
+
+ packet->sockfd = -1;
+
+ /* Done. */
+ return 1;
+}
+
+/** Map EAP methods and build EAP-Message (if EAP is involved).
+ * Also allocate the EAP context.
+ */
+static void rc_build_eap_context(rc_transaction_t *trans)
+{
+ if (!trans || !trans->packet) return;
+
+ RADIUS_PACKET *packet = trans->packet;
+
+ /* Build EAP-Message (if EAP is involved. Otherwise, do nothing). */
+ int eap_type = rc_map_eap_methods(packet);
+
+ if (eap_type) {
+ if (!trans->eap_context) {
+ MEM(trans->eap_context = talloc_zero(trans, rc_eap_context_t));
+ }
+ trans->eap_context->eap_type = eap_type;
+
+ /*
+ * Keep a copy of the the User-Password or CHAP-Password.
+ * Note: this is not useful for EAP-SIM, but we cannot know what kind
+ * of challenge the server will issue.
+ */
+ VALUE_PAIR *vp;
+ vp = fr_pair_find_by_num(packet->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ if (!vp) vp = fr_pair_find_by_num(packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ if (vp) {
+ strlcpy(trans->eap_context->password, vp->vp_strvalue, sizeof(trans->eap_context->password));
+ }
+
+ vp = fr_pair_find_by_num(packet->vps, PW_EAP_SIM_KI, 0, TAG_ANY);
+ if (vp) trans->eap_context->ki = fr_pair_copy(autofree, vp);
+ }
+}
+
+
+/** Grab an element from the input list. Initialize a new transaction context, using this element.
+ */
+static rc_transaction_t *rc_init_transaction(TALLOC_CTX *ctx)
+{
+ if (!rc_vps_list_in.head || rc_vps_list_in.size == 0) {
+ /* Empty list, can't create a new transaction. */
+ return NULL;
+ }
+
+ rc_input_vps_t *vps_entry = rc_vps_list_in.head;
+
+ rc_yank_vps_entry(vps_entry); /* This cannot fail (we checked the list beforehand.) */
+
+ /* We grabbed an vps entry, now we can initialize a new transaction. */
+ rc_transaction_t *trans;
+ MEM(trans = talloc_zero(ctx, rc_transaction_t));
+
+ trans->input_vps = vps_entry;
+ trans->id = num_trans ++;
+
+ talloc_steal(trans, vps_entry); /* It's ours now. */
+
+ RADIUS_PACKET *packet;
+ MEM(packet = rad_alloc(trans, 1));
+ trans->packet = packet;
+
+ /* Fill in the packet value pairs. */
+ packet->vps = fr_pair_list_copy(packet, vps_entry->vps_in);
+
+ /* Initialize the transaction packet. */
+ if (!rc_init_packet(trans)) {
+ /* Failed... */
+ talloc_free(trans);
+ return NULL;
+ }
+
+ /* Update transactions counters. */
+ num_started ++;
+ num_ongoing ++;
+
+ return trans;
+}
+
+/** Terminate a transaction.
+ */
+static void rc_finish_transaction(rc_transaction_t *trans)
+{
+ if (!trans) return;
+
+ if (trans->event) fr_event_delete(ev_list, &trans->event);
+ rc_deallocate_id(trans);
+ talloc_free(trans);
+
+ /* Update transactions counters. */
+ num_ongoing --;
+ num_finished ++;
+
+ DEBUG4("pl: %d, ev: %d, in: %d\n", fr_packet_list_num_outgoing(pl), fr_event_list_num_elements(ev_list), rc_vps_list_in.size);
+}
+
+
+static uint16_t getport(char const *name)
+{
+ struct servent *svp;
+
+ svp = getservbyname(name, "udp");
+ if (!svp) return 0;
+
+ return ntohs(svp->s_port);
+}
+
+
+static void rc_cleanresp(RADIUS_PACKET *resp)
+{
+ VALUE_PAIR *vpnext, *vp, **last;
+
+ /*
+ * maybe should just copy things we care about, or keep
+ * a copy of the original input and start from there again?
+ */
+ fr_pair_delete_by_num(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&resp->vps, PW_EAP_TYPE_BASE+PW_EAP_IDENTITY, 0, TAG_ANY);
+
+ last = &resp->vps;
+ for (vp = *last; vp != NULL; vp = vpnext)
+ {
+ vpnext = vp->next;
+
+ if ((vp->da->attr > PW_EAP_TYPE_BASE &&
+ vp->da->attr <= PW_EAP_TYPE_BASE+256) ||
+ (vp->da->attr > PW_EAP_SIM_BASE &&
+ vp->da->attr <= PW_EAP_SIM_BASE+256))
+ {
+ *last = vpnext;
+ talloc_free(vp);
+ } else {
+ last = &vp->next;
+ }
+ }
+}
+
+
+static void generate_triplets(RADIUS_PACKET *packet, VALUE_PAIR *ki, uint8_t const *ch)
+{
+ int i, idx;
+ eap_sim_state_t ess;
+
+ for (idx = 0; idx < 3; idx++) {
+ VALUE_PAIR *vp;
+ char *p;
+ char buffer[33]; /* 32 hexits (16 bytes) + 1 */
+
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ ess.keys.rand[idx][i] = ch[(idx * EAPSIM_RAND_SIZE) + i];
+ }
+
+ /*
+ * <sigh>, we always do version 1.
+ */
+ switch (EAP_SIM_VERSION) {
+ case 1:
+ comp128v1(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx]);
+ break;
+
+ case 2:
+ comp128v23(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx],
+ true);
+ break;
+
+ case 3:
+ comp128v23(ess.keys.sres[idx], ess.keys.Kc[idx], ki->vp_octets, ess.keys.rand[idx],
+ false);
+ break;
+
+ case 4:
+ DEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
+ "If you have details of this algorithm please contact the FreeRADIUS "
+ "maintainers\n");
+ break;
+
+ default:
+ DEBUG("Unknown/unsupported algorithm Comp128-4\n");
+ }
+
+
+ DEBUG2("Generated following triplets for round %i:\n", idx);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ p += sprintf(p, "%02x", ess.keys.rand[idx][i]);
+ }
+ DEBUG2("RAND%d : 0x%s\n", idx, buffer);
+ vp = fr_pair_afrom_num(packet, PW_EAP_SIM_RAND1 + idx, 0);
+ fr_pair_value_memcpy(vp, ess.keys.rand[idx], EAPSIM_RAND_SIZE);
+ fr_pair_add(&packet->vps, vp);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
+ p += sprintf(p, "%02x", ess.keys.sres[idx][i]);
+ }
+ DEBUG2("SRES%d : 0x%s\n", idx, buffer);
+ vp = fr_pair_afrom_num(packet, PW_EAP_SIM_SRES1 + idx, 0);
+ fr_pair_value_memcpy(vp, ess.keys.sres[idx], EAPSIM_SRES_SIZE);
+ fr_pair_add(&packet->vps, vp);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_KC_SIZE; i++) {
+ p += sprintf(p, "%02x", ess.keys.Kc[idx][i]);
+ }
+ DEBUG2("Kc%d : 0x%s\n", idx, buffer);
+ vp = fr_pair_afrom_num(packet, PW_EAP_SIM_KC1 + idx, 0);
+ fr_pair_value_memcpy(vp, ess.keys.Kc[idx], EAPSIM_KC_SIZE);
+ fr_pair_add(&packet->vps, vp);
+ }
+}
+
+
+/*
+ * we got an EAP-Request/Sim/Start message in a legal state.
+ *
+ * pick a supported version, put it into the reply, and insert a nonce.
+ */
+static int rc_process_eap_start(rc_eap_context_t *eap_context,
+ RADIUS_PACKET *req, RADIUS_PACKET *rep)
+{
+ VALUE_PAIR *vp, *newvp;
+ VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
+ uint16_t const *versions;
+ uint16_t selectedversion;
+ unsigned int i,versioncount;
+ VALUE_PAIR *ki;
+
+ /* form new response clear of any EAP stuff */
+ rc_cleanresp(rep);
+
+ if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) {
+ ERROR("illegal start message has no VERSION_LIST\n");
+ return 0;
+ }
+
+ versions = (uint16_t const *) vp->vp_strvalue;
+
+ /* verify that the attribute length is big enough for a length field */
+ if (vp->vp_length < 4)
+ {
+ ERROR("start message has illegal VERSION_LIST. Too short: %u\n", (unsigned int) vp->vp_length);
+ return 0;
+ }
+
+ versioncount = ntohs(versions[0])/2;
+ /* verify that the attribute length is big enough for the given number
+ * of versions present.
+ */
+ if ((unsigned)vp->vp_length <= (versioncount*2 + 2))
+ {
+ ERROR("start message is too short. Claimed %d versions does not fit in %u bytes\n", versioncount, (unsigned int) vp->vp_length);
+ return 0;
+ }
+
+ /*
+ * record the versionlist for the MK calculation.
+ */
+ eap_context->eap.sim.keys.versionlistlen = versioncount*2;
+ memcpy(eap_context->eap.sim.keys.versionlist, (unsigned char const *)(versions+1),
+ eap_context->eap.sim.keys.versionlistlen);
+
+ /* walk the version list, and pick the one we support, which
+ * at present, is 1, EAP_SIM_VERSION.
+ */
+ selectedversion=0;
+ for (i=0; i < versioncount; i++)
+ {
+ if (ntohs(versions[i+1]) == EAP_SIM_VERSION)
+ {
+ selectedversion=EAP_SIM_VERSION;
+ break;
+ }
+ }
+ if (selectedversion == 0)
+ {
+ ERROR("eap-sim start message. No compatible version found. We need %d\n", EAP_SIM_VERSION);
+ for (i=0; i < versioncount; i++)
+ {
+ ERROR("\tfound version %d\n",
+ ntohs(versions[i+1]));
+ }
+ }
+
+ /*
+ * now make sure that we have only FULLAUTH_ID_REQ.
+ * I think that it actually might not matter - we can answer in
+ * anyway we like, but it is illegal to have more than one
+ * present.
+ */
+ anyidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY);
+ fullauthidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY);
+ permanentidreq_vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY);
+
+ if (!fullauthidreq_vp ||
+ anyidreq_vp != NULL ||
+ permanentidreq_vp != NULL) {
+ ERROR("start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.\n",
+ (anyidreq_vp != NULL ? "a ": "no "),
+ (fullauthidreq_vp != NULL ? "a ": "no "),
+ (permanentidreq_vp != NULL ? "a ": "no "));
+ return 0;
+ }
+
+ /* okay, we have just any_id_req there, so fill in response */
+
+ /* mark the subtype as being EAP-SIM/Response/Start */
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
+ newvp->vp_integer = EAPSIM_START;
+ fr_pair_replace(&(rep->vps), newvp);
+
+ /* insert selected version into response. */
+ {
+ uint16_t no_versions;
+
+ no_versions = htons(selectedversion);
+
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SELECTED_VERSION, 0);
+ fr_pair_value_memcpy(newvp, (uint8_t *) &no_versions, 2);
+ fr_pair_replace(&(rep->vps), newvp);
+
+ /* record the selected version */
+ memcpy(eap_context->eap.sim.keys.versionselect, &no_versions, 2);
+ }
+
+ vp = newvp = NULL;
+
+ {
+ uint32_t nonce[4];
+ uint8_t *p;
+ /*
+ * insert a nonce_mt that we make up.
+ */
+ nonce[0]=fr_rand();
+ nonce[1]=fr_rand();
+ nonce[2]=fr_rand();
+ nonce[3]=fr_rand();
+
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_NONCE_MT, 0);
+
+ p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
+ memcpy(&p[2], nonce, 16);
+ fr_pair_value_memsteal(newvp, p);
+
+ fr_pair_replace(&(rep->vps), newvp);
+
+ /* also keep a copy of the nonce! */
+ memcpy(eap_context->eap.sim.keys.nonce_mt, nonce, 16);
+ }
+
+ {
+ uint16_t idlen;
+ uint8_t *p;
+ uint16_t no_idlen;
+
+ /*
+ * insert the identity here.
+ */
+ vp = fr_pair_find_by_num(rep->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp)
+ {
+ ERROR("eap-sim: We need to have a User-Name attribute!\n");
+ return 0;
+ }
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_IDENTITY, 0);
+
+ idlen = strlen(vp->vp_strvalue);
+ p = talloc_zero_array(newvp, uint8_t, idlen + 2);
+ no_idlen = htons(idlen);
+ memcpy(p, &no_idlen, 2);
+ memcpy(p + 2, vp->vp_strvalue, idlen);
+ fr_pair_value_memsteal(newvp, p);
+
+ fr_pair_replace(&(rep->vps), newvp);
+
+ /* record it */
+ memcpy(eap_context->eap.sim.keys.identity, vp->vp_strvalue, idlen);
+ eap_context->eap.sim.keys.identitylen = idlen;
+ }
+
+ ki = fr_pair_find_by_num(req->vps, PW_EAP_SIM_KI, 0, TAG_ANY);
+ if (ki && !fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY)) {
+ generate_triplets(req, ki, NULL);
+ }
+
+ return 1;
+}
+
+
+/*
+ * we got an EAP-Request/Sim/Challenge message in a legal state.
+ *
+ * use the RAND challenge to produce the SRES result, and then
+ * use that to generate a new MAC.
+ *
+ * for the moment, we ignore the RANDs, then just plug in the SRES
+ * values.
+ *
+ */
+static int rc_process_eap_challenge(rc_eap_context_t *eap_context,
+ RADIUS_PACKET *req, RADIUS_PACKET *rep)
+{
+ VALUE_PAIR *newvp;
+ VALUE_PAIR *mac, *randvp;
+ VALUE_PAIR *sres1,*sres2,*sres3;
+ VALUE_PAIR *Kc1, *Kc2, *Kc3;
+ uint8_t calcmac[20];
+
+ /* look for the AT_MAC and the challenge data */
+ mac = fr_pair_find_by_num(req->vps, PW_EAP_SIM_MAC, 0, TAG_ANY);
+ randvp= fr_pair_find_by_num(req->vps, PW_EAP_SIM_RAND, 0, TAG_ANY);
+ if (!mac || !randvp) {
+ ERROR("challenge message needs to contain RAND and MAC\n");
+ return 0;
+ }
+
+ /*
+ * compare RAND with randX, to verify this is the right response
+ * to this challenge.
+ */
+ {
+ VALUE_PAIR *randcfgvp[3];
+ uint8_t const *randcfg[3];
+
+ randcfg[0] = &randvp->vp_octets[2];
+ randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
+ randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2];
+
+ randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY);
+ randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY);
+ randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY);
+
+ if (!randcfgvp[0] ||
+ !randcfgvp[1] ||
+ !randcfgvp[2]) {
+ int i;
+ VALUE_PAIR *ki;
+
+ /*
+ * Generate a new RAND value, and derive Kc and SRES from
+ * Ki, but only if we don't already have the random
+ * numbers.
+ */
+ ki = eap_context->ki;
+ if (!ki) {
+ ERROR("Need EAP-SIM-Rand1, EAP-SIM-Rand2, and EAP-SIM-Rand3\n");
+ return 0;
+ }
+
+ for (i = 0; i < 3; i++) {
+ fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_RAND1 + i, 0, TAG_ANY);
+ fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_SRES1 + i, 0, TAG_ANY);
+ fr_pair_delete_by_num(&req->vps, PW_EAP_SIM_KC1 + i, 0, TAG_ANY);
+ }
+
+ generate_triplets(rep, ki, randvp->vp_octets + 2);
+
+ randcfgvp[0] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND1, 0, TAG_ANY);
+ randcfgvp[1] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND2, 0, TAG_ANY);
+ randcfgvp[2] = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_RAND3, 0, TAG_ANY);
+
+ if (!randcfgvp[0] ||
+ !randcfgvp[1] ||
+ !randcfgvp[2]) {
+ ERROR("Failed to create triplets\n");
+ return 0;
+ }
+ }
+
+ if (memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
+ memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 ||
+ memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) {
+ int rnum, i;
+
+ ERROR("one of rand 1,2,3 didn't match\n");
+ for (rnum = 0; rnum < 3; rnum++) {
+ ERROR("rand %d\trecv\tconfig\n", rnum);
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ fprintf(fr_log_fp, "\t%02x\t%02x\n",
+ randcfg[rnum][i], randcfgvp[rnum]->vp_octets[i]);
+ }
+ }
+ return 0;
+ }
+ }
+
+ /*
+ * now dig up the sres values from the response packet,
+ * which were put there when we read things in.
+ *
+ * Really, they should be calculated from the RAND!
+ *
+ */
+ sres1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES1, 0, TAG_ANY);
+ sres2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES2, 0, TAG_ANY);
+ sres3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_SRES3, 0, TAG_ANY);
+
+ if (!sres1 ||
+ !sres2 ||
+ !sres3) {
+ ERROR("needs to have sres1, 2 and 3 set.\n");
+ return 0;
+ }
+ memcpy(eap_context->eap.sim.keys.sres[0], sres1->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[0]));
+ memcpy(eap_context->eap.sim.keys.sres[1], sres2->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[1]));
+ memcpy(eap_context->eap.sim.keys.sres[2], sres3->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[2]));
+
+ Kc1 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC1, 0, TAG_ANY);
+ Kc2 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC2, 0, TAG_ANY);
+ Kc3 = fr_pair_find_by_num(rep->vps, PW_EAP_SIM_KC3, 0, TAG_ANY);
+
+ if (!Kc1 ||
+ !Kc2 ||
+ !Kc3) {
+ ERROR("needs to have Kc1, 2 and 3 set.\n");
+ return 0;
+ }
+ memcpy(eap_context->eap.sim.keys.Kc[0], Kc1->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[0]));
+ memcpy(eap_context->eap.sim.keys.Kc[1], Kc2->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[1]));
+ memcpy(eap_context->eap.sim.keys.Kc[2], Kc3->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[2]));
+
+ /* all set, calculate keys */
+ eapsim_calculate_keys(&eap_context->eap.sim.keys);
+
+ if (rad_debug_lvl > 2) {
+ eapsim_dump_mk(&eap_context->eap.sim.keys);
+ }
+
+ /* verify the MAC, now that we have all the keys. */
+ if (eapsim_checkmac(NULL, req->vps, eap_context->eap.sim.keys.K_aut,
+ eap_context->eap.sim.keys.nonce_mt, sizeof(eap_context->eap.sim.keys.nonce_mt),
+ calcmac)) {
+ DEBUG2("MAC check succeed\n");
+ } else {
+ int i, j;
+ j=0;
+ DEBUG("calculated MAC (\n");
+ for (i = 0; i < 20; i++) {
+ if (j==4) {
+ printf("_");
+ j=0;
+ }
+ j++;
+
+ DEBUG("%02x\n", calcmac[i]);
+ }
+ DEBUG("did not match\n");
+ return 0;
+ }
+
+ /* form new response clear of any EAP stuff */
+ rc_cleanresp(rep);
+
+ /* mark the subtype as being EAP-SIM/Response/Start */
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_SUBTYPE, 0);
+ newvp->vp_integer = EAPSIM_CHALLENGE;
+ fr_pair_replace(&(rep->vps), newvp);
+
+ {
+ uint8_t *p;
+ /*
+ * fill the SIM_MAC with a field that will in fact get appended
+ * to the packet before the MAC is calculated
+ */
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_MAC, 0);
+
+ p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3);
+ memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
+ memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
+ memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
+ fr_pair_value_memsteal(newvp, p);
+
+ fr_pair_replace(&(rep->vps), newvp);
+ }
+
+ newvp = fr_pair_afrom_num(rep, PW_EAP_SIM_KEY, 0);
+ fr_pair_value_memcpy(newvp, eap_context->eap.sim.keys.K_aut, EAPSIM_AUTH_SIZE);
+
+ fr_pair_replace(&(rep->vps), newvp);
+
+ return 1;
+}
+
+/*
+ * this code runs the EAP-SIM client state machine.
+ * the *request* is from the server.
+ * the *reponse* is to the server.
+ *
+ */
+static int rc_respond_eap_sim(rc_eap_context_t *eap_context,
+ RADIUS_PACKET *req, RADIUS_PACKET *resp)
+{
+ enum eapsim_clientstates state, newstate;
+ enum eapsim_subtype subtype, newsubtype;
+ VALUE_PAIR *vp, *statevp, *radstate, *eapid;
+ char statenamebuf[32], subtypenamebuf[32];
+
+ if ((radstate = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
+ {
+ return 0;
+ }
+
+ if ((eapid = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
+ {
+ return 0;
+ }
+
+ /* first, dig up the state from the request packet, setting
+ * ourselves to be in EAP-SIM-Start state if there is none.
+ */
+
+ if ((statevp = fr_pair_find_by_num(resp->vps, PW_EAP_SIM_STATE, 0, TAG_ANY)) == NULL)
+ {
+ /* must be initial request */
+ statevp = fr_pair_afrom_num(resp, PW_EAP_SIM_STATE, 0);
+ statevp->vp_integer = EAPSIM_CLIENT_INIT;
+ fr_pair_replace(&(resp->vps), statevp);
+ }
+ state = statevp->vp_integer;
+
+ /*
+ * map the attributes, and authenticate them.
+ */
+ rc_unmap_eapsim_types(req);
+
+ if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL)
+ {
+ return 0;
+ }
+ subtype = vp->vp_integer;
+
+ DEBUG2("IN state %s subtype %s\n",
+ sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
+ sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
+
+ /*
+ * look for the appropriate state, and process incoming message
+ */
+ switch (state) {
+ case EAPSIM_CLIENT_INIT:
+ switch (subtype) {
+ case EAPSIM_START:
+ newstate = rc_process_eap_start(eap_context, req, resp);
+ break;
+
+ case EAPSIM_CHALLENGE:
+ case EAPSIM_NOTIFICATION:
+ case EAPSIM_REAUTH:
+ default:
+ ERROR("sim in state %s message %s is illegal. Reply dropped.\n",
+ sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
+ sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
+ /* invalid state, drop message */
+ return 0;
+ }
+ break;
+
+ case EAPSIM_CLIENT_START:
+ switch (subtype) {
+ case EAPSIM_START:
+ /* NOT SURE ABOUT THIS ONE, retransmit, I guess */
+ newstate = rc_process_eap_start(eap_context, req, resp);
+ break;
+
+ case EAPSIM_CHALLENGE:
+ newstate = rc_process_eap_challenge(eap_context, req, resp);
+ break;
+
+ default:
+ ERROR("sim in state %s message %s is illegal. Reply dropped.\n",
+ sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
+ sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
+ /* invalid state, drop message */
+ return 0;
+ }
+ break;
+
+
+ default:
+ ERROR("sim in illegal state %s\n",
+ sim_state2name(state, statenamebuf, sizeof(statenamebuf)));
+ return 0;
+ }
+
+ /* copy the eap state object in */
+ fr_pair_replace(&(resp->vps), eapid);
+
+ /* update stete info, and send new packet */
+ rc_map_eapsim_types(resp);
+
+ /* copy the radius state object in */
+ fr_pair_replace(&(resp->vps), radstate);
+
+ vp = fr_pair_find_by_num(req->vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY);
+ newsubtype = vp->vp_integer;
+
+
+ DEBUG2("MOVE from state %s subtype %s\n",
+ sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
+ sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
+
+ DEBUG2(" to state %s subtype %s\n",
+ sim_state2name(newstate, statenamebuf, sizeof(statenamebuf)),
+ sim_subtype2name(newsubtype, subtypenamebuf, sizeof(subtypenamebuf)));
+
+ statevp->vp_integer = newstate;
+ return 1;
+}
+
+static int rc_respond_eap_md5(rc_eap_context_t *eap_context,
+ RADIUS_PACKET *req, RADIUS_PACKET *rep)
+{
+ VALUE_PAIR *vp, *id, *state;
+ size_t valuesize;
+ uint8_t identifier;
+ uint8_t const *value;
+ FR_MD5_CTX context;
+ uint8_t response[16];
+
+ rc_cleanresp(rep);
+
+ if ((state = fr_pair_list_copy_by_num(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
+ {
+ ERROR("no state attribute found\n");
+ return 0;
+ }
+
+ if ((id = fr_pair_list_copy_by_num(NULL, req->vps, PW_EAP_ID, 0, TAG_ANY)) == NULL)
+ {
+ ERROR("no EAP-ID attribute found\n");
+ return 0;
+ }
+ identifier = id->vp_integer;
+
+ if ((vp = fr_pair_find_by_num(req->vps, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL)
+ {
+ ERROR("no EAP-MD5 attribute found\n");
+ return 0;
+ }
+
+ /* got the details of the MD5 challenge */
+ valuesize = vp->vp_octets[0];
+ value = &vp->vp_octets[1];
+
+ /* sanitize items */
+ if (valuesize > vp->vp_length)
+ {
+ ERROR("md5 valuesize if too big (%u > %u)\n",
+ (unsigned int) valuesize, (unsigned int) vp->vp_length);
+ return 0;
+ }
+
+ /* now do the CHAP operation ourself, rather than build the
+ * buffer. We could also call rad_chap_encode, but it wants
+ * a CHAP-Challenge, which we don't want to bother with.
+ */
+ fr_md5_init(&context);
+ fr_md5_update(&context, &identifier, 1);
+ fr_md5_update(&context, (uint8_t *) eap_context->password, strlen(eap_context->password));
+ fr_md5_update(&context, value, valuesize);
+ fr_md5_final(response, &context);
+
+ {
+ uint8_t *p;
+ uint8_t lg_response;
+
+ vp = fr_pair_afrom_num(rep, PW_EAP_TYPE_BASE+PW_EAP_MD5, 0);
+ vp->vp_length = 17;
+
+ p = talloc_zero_array(vp, uint8_t, 17);
+ lg_response = 16;
+ memcpy(p, &lg_response, 1);
+ memcpy(p + 1, response, 16);
+ fr_pair_value_memsteal(vp, p);
+ }
+ fr_pair_replace(&(rep->vps), vp);
+
+ fr_pair_replace(&(rep->vps), id);
+
+ /* copy the state object in */
+ fr_pair_replace(&(rep->vps), state);
+
+ return 1;
+}
+
+
+/** Allocate a new socket, and add it to the packet list.
+ */
+static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
+{
+ int mysockfd;
+
+ /* Trace what we're doing. */
+ char src_addr[15+1] = "";
+ char dst_addr[15+1] = "";
+ inet_ntop(AF_INET, &(src_ipaddr->ipaddr.ip4addr.s_addr), src_addr, sizeof(src_addr));
+ inet_ntop(AF_INET, &(dst_ipaddr->ipaddr.ip4addr.s_addr), dst_addr, sizeof(dst_addr));
+
+ INFO("Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port);
+
+ mysockfd = fr_socket(src_ipaddr, src_port);
+ if (mysockfd < 0) {
+ ERROR("Failed to create new socket: %s\n", fr_strerror());
+ exit(1);
+ }
+
+ if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
+#ifdef WITH_RADIUSV11
+ false,
+#endif
+ dst_ipaddr, dst_port, NULL)) {
+ ERROR("Failed to add new socket: %s\n", fr_strerror());
+ exit(1);
+ }
+
+ num_sockets ++;
+ DEBUG("Added new socket: %d (num sockets: %d)\n", mysockfd, num_sockets);
+}
+
+/** Send one packet for a transaction.
+ */
+static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
+{
+ if (!trans || !packet_p || !*packet_p) return -1;
+
+ assert(pl != NULL);
+
+ RADIUS_PACKET *packet = *packet_p;
+
+ if (packet->id == -1) {
+ /* Haven't sent the packet yet. Initialize it. */
+ bool rcode;
+ int i;
+
+ rc_build_eap_context(trans); /* In case of EAP, build EAP-Message and initialize EAP context. */
+
+ assert(trans->reply == NULL);
+
+ trans->tries = 0;
+ packet->src_ipaddr.af = server_ipaddr.af;
+ int nb_sock_add = 0;
+ while (1) {
+ /* Allocate a RADIUS packet ID from a suitable socket of the packet list. */
+ rcode = fr_packet_list_id_alloc(pl, ipproto, packet_p, NULL);
+
+ if (rcode) { /* Got an ID. */
+ break;
+ }
+ if (nb_sock_add >= 1) {
+ ERROR("Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).\n",
+ nb_sock_add, fr_packet_list_num_outgoing(pl));
+ exit(1);
+ }
+
+ /* Could not find a free packet ID. Allocate a new socket, then try again. */
+ rc_add_socket(&packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port);
+
+ nb_sock_add ++;
+ }
+
+ assert(packet->id != -1);
+ assert(packet->data == NULL);
+
+ for (i = 0; i < 4; i++) {
+ ((uint32_t *) packet->vector)[i] = fr_rand();
+ }
+ }
+
+ /*
+ * Send the packet.
+ */
+ DEBUG2("Transaction: %u, sending packet: %u (id: %u)...\n", trans->id, trans->num_packet, packet->id);
+
+ gettimeofday(&packet->timestamp, NULL); /* set outgoing packet timestamp. */
+
+ if (rad_send(packet, NULL, secret) < 0) {
+ ERROR("Failed to send packet (sockfd: %d, id: %d): %s\n",
+ packet->sockfd, packet->id, fr_strerror());
+ }
+
+ trans->num_packet ++;
+ trans->tries ++;
+
+ if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, packet, false);
+ if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, packet->vps);
+
+ return 1;
+}
+
+/** Send current packet of a transaction. Arm timeout event.
+ */
+static int rc_send_transaction_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
+// note: we need a 'RADIUS_PACKET **' for fr_packet_list_id_alloc.
+{
+ if (!trans || !packet_p || !*packet_p) return -1;
+
+ int ret = rc_send_one_packet(trans, packet_p);
+ if (ret == 1) {
+ /* Send successful: arm the timeout callback. */
+ rc_evprep_packet_timeout(trans);
+ }
+ return ret;
+}
+
+/** Deallocate RADIUS packet ID.
+ */
+static void rc_deallocate_id(rc_transaction_t *trans)
+{
+ if (!trans || !trans->packet ||
+ (trans->packet->id < 0)) {
+ return;
+ }
+
+ RADIUS_PACKET *packet = trans->packet;
+
+ DEBUG2("Deallocating (sockfd: %d, id: %d)\n", packet->sockfd, packet->id);
+
+ /*
+ * One more unused RADIUS ID.
+ */
+ fr_packet_list_id_free(pl, packet, true);
+ /* note: "true" means automatically yank, so we must *not* yank ourselves before calling (otherwise, it does nothing)
+ * so, *don't*: fr_packet_list_yank(pl, request->packet); */
+
+ /* free more stuff to ensure next allocate won't be stuck on a "full" socket. */
+ packet->id = -1;
+ packet->sockfd = -1;
+ packet->src_ipaddr.af = AF_UNSPEC;
+ packet->src_port = 0;
+
+ /*
+ * If we've already sent a packet, free up the old one,
+ * and ensure that the next packet has a unique
+ * authentication vector.
+ */
+ if (packet->data) {
+ talloc_free(packet->data);
+ packet->data = NULL;
+ }
+
+ if (trans->reply) rad_free(&trans->reply);
+}
+
+/** Receive one packet, maybe.
+ */
+static int rc_recv_one_packet(struct timeval *tv_wait_time)
+{
+ fd_set set;
+ struct timeval tv;
+ rc_transaction_t *trans;
+ RADIUS_PACKET *reply, **packet_p;
+ volatile int max_fd;
+ bool ongoing_trans = false;
+ char buffer[128];
+
+ /* Wait for reply, timing out as necessary */
+ FD_ZERO(&set);
+
+ max_fd = fr_packet_list_fd_set(pl, &set);
+ if (max_fd < 0) {
+ /* no sockets to listen on! */
+ return 0;
+ }
+
+ if (NULL == tv_wait_time) {
+ timerclear(&tv);
+ } else {
+ tv.tv_sec = tv_wait_time->tv_sec;
+ tv.tv_usec = tv_wait_time->tv_usec;
+ }
+
+ if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
+ /* No packet was received. */
+ return 0;
+ }
+
+ /*
+ * Receive the reply.
+ */
+ reply = fr_packet_list_recv(pl, &set);
+ if (!reply) {
+ ERROR("Received bad packet: %s\n", fr_strerror());
+ return -1; /* bad packet */
+ }
+
+ /*
+ * Look for the packet which matches the reply.
+ */
+ reply->src_ipaddr = server_ipaddr;
+ reply->src_port = server_port;
+
+ /*
+ * Note: this only works if all packets have the same destination (IP, port).
+ * We should handle a list of destinations. But we don't. radclient doesn't do it either).
+ */
+
+ packet_p = fr_packet_list_find_byreply(pl, reply);
+
+ if (!packet_p) {
+ /* got reply to packet we didn't send.
+ * (or maybe we sent it, got no response, freed the ID. Then server responds to first request.)
+ */
+ DEBUG("No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)\n",
+ inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
+ reply->src_port, reply->sockfd, reply->id);
+ rad_free(&reply);
+ return -1;
+ }
+
+ trans = fr_packet2myptr(rc_transaction_t, packet, packet_p);
+
+ if (trans->event) fr_event_delete(ev_list, &trans->event);
+
+ /*
+ * Fails the signature validation: not a valid reply.
+ */
+ if (rad_verify(reply, trans->packet, secret) < 0) {
+ /* shared secret is incorrect.
+ * (or maybe this is a response to another packet we sent, for which we got no response,
+ * freed the ID, then reused it. Then server responds to first packet.)
+ */
+ DEBUG("Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)\n",
+ inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
+ reply->sockfd, reply->id);
+
+ goto packet_done;
+ }
+
+ /* Set reply destination = packet source. */
+ reply->dst_ipaddr = trans->packet->src_ipaddr;
+ reply->dst_port = trans->packet->src_port;
+
+ trans->reply = reply;
+ reply = NULL;
+
+ if (rad_decode(trans->reply, trans->packet, secret) != 0) {
+ /* This can fail if packet contains too many attributes. */
+ DEBUG("Failed decoding reply\n");
+ goto packet_done;
+ }
+
+ gettimeofday(&trans->reply->timestamp, NULL); /* set received packet timestamp. */
+
+ if (trans->eap_context) {
+ /* Call unmap before packet print (so we can see the decoded EAP stuff). */
+ rc_unmap_eap_methods(trans->reply);
+ }
+
+ DEBUG2("Transaction: %u, received packet (id: %u).\n", trans->id, trans->reply->id);
+
+ if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, trans->reply, true);
+ if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, trans->reply->vps);
+
+ if (!trans->eap_context) {
+ goto packet_done;
+ }
+
+ /* now look for the code type. */
+ VALUE_PAIR *vp, *vpnext;
+ for (vp = trans->reply->vps; vp != NULL; vp = vpnext) {
+ vpnext = vp->next;
+
+ switch (vp->da->attr) {
+ default:
+ break;
+
+ case PW_EAP_TYPE_BASE + PW_EAP_MD5:
+ if (rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3)
+ {
+ /* answer the challenge from server. */
+ trans->eap_context->eap.md5.tried ++;
+ rc_deallocate_id(trans);
+ rc_send_transaction_packet(trans, &trans->packet);
+ ongoing_trans = true; // don't free the transaction yet.
+ }
+ goto packet_done;
+
+ case PW_EAP_TYPE_BASE + PW_EAP_SIM:
+ if (rc_respond_eap_sim(trans->eap_context, trans->reply, trans->packet)) {
+ /* answer the challenge from server. */
+ rc_deallocate_id(trans);
+ rc_send_transaction_packet(trans, &trans->packet);
+ ongoing_trans = true; // don't free the transaction yet.
+ }
+ goto packet_done;
+ }
+ }
+
+ /* EAP transaction ends here (no more requests from EAP server). */
+
+ /*
+ * success: if we have EAP-Code = Success, and reply is an Access-Accept.
+ */
+ if (trans->reply->code != PW_CODE_ACCESS_ACCEPT) {
+ DEBUG("EAP transaction finished, but reply is not an Access-Accept");
+ goto packet_done;
+ }
+ vp = fr_pair_find_by_num(trans->reply->vps, PW_EAP_CODE, 0, TAG_ANY);
+ if ( (!vp) || (vp->vp_integer != 3) ) {
+ DEBUG("EAP transaction finished, but reply does not contain EAP-Code = Success");
+ goto packet_done;
+ }
+
+ goto packet_done;
+
+packet_done:
+
+ /* Basic statistics (salvaged from old code). TODO: something better. */
+ if (trans->reply) {
+ if (trans->reply->code == PW_CODE_ACCESS_ACCEPT) {
+ totalapp ++;
+ } else if (trans->reply->code == PW_CODE_ACCESS_REJECT) {
+ totaldeny ++;
+ }
+ }
+
+ rad_free(&trans->reply);
+ rad_free(&reply); /* may be NULL */
+
+ if (!ongoing_trans) {
+ rc_deallocate_id(trans);
+ rc_finish_transaction(trans);
+ }
+
+ return 1;
+}
+
+/** Event callback: packet timeout.
+ */
+static void rc_evcb_packet_timeout(void *ctx)
+{
+ rc_transaction_t *trans = ctx;
+ if (!trans || !trans->packet) return;
+
+ DEBUG("Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->id, trans->tries, retries);
+
+ if (trans->event) fr_event_delete(ev_list, &trans->event);
+
+ if (trans->tries < retries) {
+ /* Try again. */
+ rc_send_transaction_packet(trans, &trans->packet);
+ } else {
+ DEBUG("No response for transaction: %d, giving up", trans->id);
+ rc_finish_transaction(trans);
+ }
+}
+
+/** Prepare event: packet timeout.
+ */
+static void rc_evprep_packet_timeout(rc_transaction_t *trans)
+{
+ struct timeval tv_event;
+ gettimeofday(&tv_event, NULL);
+ timeradd(&tv_event, &tv_timeout, &tv_event);
+
+ if (!fr_event_insert(ev_list, rc_evcb_packet_timeout, (void *)trans, &tv_event, &trans->event)) {
+ ERROR("Failed to insert event\n");
+ exit(1);
+ }
+}
+
+/** Trigger all armed events for which time is reached.
+ */
+static int rc_loop_events(void)
+{
+ struct timeval when;
+ uint32_t nb_processed = 0;
+
+ if (!fr_event_list_num_elements(ev_list)) return 0;
+
+ while (1) {
+ gettimeofday(&when, NULL);
+ if (!fr_event_run(ev_list, &when)) {
+ /* no more. */
+ break;
+ }
+ nb_processed ++;
+ }
+ return nb_processed;
+}
+
+/** Receive loop.
+ * Handle incoming packets, until nothing more is received.
+ */
+static int dhb_loop_recv(void)
+{
+ uint32_t nb_received = 0;
+ while (rc_recv_one_packet(NULL) > 0) {
+ nb_received ++;
+ }
+ return nb_received;
+}
+
+/** Loop starting new transactions, until a limit is reached
+ * (max parallelism, or no more input available.)
+ */
+static int rc_loop_start_transactions(void)
+{
+ int nb_started = 0;
+
+ while (1) {
+ if (num_ongoing >= parallel) break;
+
+ /* Try to initialize a new transaction. */
+ rc_transaction_t *trans = rc_init_transaction(autofree);
+ if (!trans) break;
+
+ nb_started ++;
+ rc_send_transaction_packet(trans, &trans->packet);
+ }
+ return nb_started;
+}
+
+/** Main loop: Handle events. Receive and process responses. Start new transactions.
+ * Until we're done.
+ */
+static void rc_main_loop(void)
+{
+ while (1) {
+ /* Handle events. */
+ rc_loop_events();
+
+ /* Receive and process response until no more are received (don't wait). */
+ dhb_loop_recv();
+
+ /* Start new transactions and send the associated packet. */
+ rc_loop_start_transactions();
+
+ /* Check if we're done. */
+ if ( (rc_vps_list_in.size == 0)
+ && (fr_packet_list_num_outgoing(pl) == 0) ) {
+ break;
+ }
+ }
+ INFO("Main loop: done.");
+}
+
+
+void set_radius_dir(TALLOC_CTX *ctx, char const *path)
+{
+ if (radius_dir) {
+ char *p;
+
+ memcpy(&p, &radius_dir, sizeof(p));
+ talloc_free(p);
+ radius_dir = NULL;
+ }
+ if (path) radius_dir = talloc_strdup(ctx, path);
+}
+
+
+/** Set a port from the request type if we don't already have one.
+ */
+static void rc_get_port(PW_CODE type, uint16_t *port)
+{
+ switch (type) {
+ default:
+ case PW_CODE_ACCESS_REQUEST:
+ case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_STATUS_SERVER:
+ if (*port == 0) *port = getport("radius");
+ if (*port == 0) *port = PW_AUTH_UDP_PORT;
+ return;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (*port == 0) *port = getport("radacct");
+ if (*port == 0) *port = PW_ACCT_UDP_PORT;
+ return;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ if (*port == 0) *port = PW_POD_UDP_PORT;
+ return;
+
+ case PW_CODE_COA_REQUEST:
+ if (*port == 0) *port = PW_COA_UDP_PORT;
+ return;
+
+ case PW_CODE_UNDEFINED:
+ if (*port == 0) *port = 0;
+ return;
+ }
+}
+
+/** Resolve a port to a request type.
+ */
+static PW_CODE rc_get_code(uint16_t port)
+{
+ /*
+ * getport returns 0 if the service doesn't exist
+ * so we need to return early, to avoid incorrect
+ * codes.
+ */
+ if (port == 0) return PW_CODE_UNDEFINED;
+
+ if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
+ return PW_CODE_ACCESS_REQUEST;
+ }
+ if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
+ return PW_CODE_ACCOUNTING_REQUEST;
+ }
+ if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
+ if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
+
+ return PW_CODE_UNDEFINED;
+}
+
+/** Resolve server hostname.
+ */
+static void rc_resolve_hostname(char *server_arg)
+{
+ if (force_af == AF_UNSPEC) force_af = AF_INET;
+ server_ipaddr.af = force_af;
+ if (strcmp(server_arg, "-") != 0) {
+ char *p;
+ char const *hostname = server_arg;
+ char const *portname = server_arg;
+ char buffer[256];
+
+ if (*server_arg == '[') { /* IPv6 URL encoded */
+ p = strchr(server_arg, ']');
+ if ((size_t) (p - server_arg) >= sizeof(buffer)) {
+ usage();
+ }
+
+ memcpy(buffer, server_arg + 1, p - server_arg - 1);
+ buffer[p - server_arg - 1] = '\0';
+
+ hostname = buffer;
+ portname = p + 1;
+
+ }
+ p = strchr(portname, ':');
+ if (p && (strchr(p + 1, ':') == NULL)) {
+ *p = '\0';
+ portname = p + 1;
+ } else {
+ portname = NULL;
+ }
+
+ if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) {
+ ERROR("%s: Failed to find IP address for host %s: %s\n", progname, hostname, strerror(errno));
+ exit(1);
+ }
+ server_addr_init = true;
+
+ /* Strip port from hostname if needed. */
+ if (portname) server_port = atoi(portname);
+
+ /*
+ * Work backwards from the port to determine the packet type
+ */
+ if (packet_code == PW_CODE_UNDEFINED) packet_code = rc_get_code(server_port);
+ }
+ rc_get_port(packet_code, &server_port);
+}
+
+int main(int argc, char **argv)
+{
+ char *p;
+ int c;
+ char *filename = NULL;
+ FILE *fp;
+
+ static fr_log_t radclient_log = {
+ .colourise = true,
+ .fd = STDOUT_FILENO,
+ .dst = L_DST_STDOUT,
+ .file = NULL,
+ .debug_file = NULL,
+ };
+
+ radlog_init(&radclient_log, false);
+
+ /*
+ * We probably don't want to free the talloc autofree context
+ * directly, so we'll allocate a new context beneath it, and
+ * free that before any leak reports.
+ */
+ autofree = talloc_init("main");
+
+ fr_debug_lvl = 0;
+ fr_log_fp = stdout;
+
+ set_radius_dir(autofree, RADIUS_DIR);
+
+ while ((c = getopt(argc, argv, "46c:d:D:f:hp:qst:r:S:xXv")) != EOF)
+ {
+ switch (c) {
+ case '4':
+ force_af = AF_INET;
+ break;
+ case '6':
+ force_af = AF_INET6;
+ break;
+ case 'd':
+ set_radius_dir(autofree, optarg);
+ break;
+ case 'D':
+ main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
+ break;
+ case 'f':
+ filename = optarg;
+ break;
+ case 'p':
+ parallel = atoi(optarg);
+ if (parallel == 0) parallel = 1;
+ if (parallel > 65536) parallel = 65536;
+ break;
+ case 'q':
+ do_output = 0;
+ break;
+ case 'x':
+ rad_debug_lvl++;
+ fr_debug_lvl++;
+ break;
+
+ case 'X':
+#if 0
+ sha1_data_problems = 1; /* for debugging only */
+#endif
+ break;
+
+ case 'r':
+ if (!isdigit((uint8_t) *optarg))
+ usage();
+ retries = atoi(optarg);
+ break;
+ case 's':
+ do_summary = 1;
+ break;
+ case 't':
+ if (!isdigit((uint8_t) *optarg))
+ usage();
+ timeout = atof(optarg);
+ break;
+ case 'v':
+ printf("$Id$"
+#ifndef ENABLE_REPRODUCIBLE_BUILDS
+ ", built on " __DATE__ " at " __TIME__
+#endif
+ "\n"
+ );
+ exit(0);
+
+ case 'S':
+ fp = fopen(optarg, "r");
+ if (!fp) {
+ ERROR("Error opening %s: %s\n",
+ optarg, fr_syserror(errno));
+ exit(1);
+ }
+ if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
+ ERROR("Error reading %s: %s\n",
+ optarg, fr_syserror(errno));
+ exit(1);
+ }
+ fclose(fp);
+
+ /* truncate newline */
+ p = filesecret + strlen(filesecret) - 1;
+ while ((p >= filesecret) &&
+ (*p < ' ')) {
+ *p = '\0';
+ --p;
+ }
+
+ if (strlen(filesecret) < 2) {
+ ERROR("Secret in %s is too short\n", optarg);
+ exit(1);
+ }
+ secret = filesecret;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ if ((argc < 3) ||
+ ((!secret) && (argc < 4))) {
+ usage();
+ }
+
+ /* Prepare the timeout. */
+ rc_float_to_timeval(&tv_timeout, timeout);
+
+ if (!main_config.dictionary_dir) {
+ main_config.dictionary_dir = DICTDIR;
+ }
+
+ /*
+ * Read the distribution dictionaries first, then
+ * the ones in raddb.
+ */
+ DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
+ if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
+ ERROR("Errors reading dictionary: %s\n", fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * It's OK if this one doesn't exist.
+ */
+ int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
+ if (rcode == -1) {
+ ERROR("Errors reading %s/%s: %s\n", radius_dir, RADIUS_DICTIONARY, fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * We print this after reading it. That way if
+ * it doesn't exist, it's OK, and we don't print
+ * anything.
+ */
+ if (rcode == 0) {
+ DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
+ }
+
+ /*
+ * Get the request type
+ */
+ if (!isdigit((uint8_t) argv[2][0])) {
+ packet_code = fr_str2int(rc_request_types, argv[2], -2);
+ if (packet_code == -2) {
+ ERROR("Unrecognised request type \"%s\"\n", argv[2]);
+ usage();
+ }
+ } else {
+ packet_code = atoi(argv[2]);
+ }
+
+ /*
+ * Resolve hostname.
+ */
+ rc_resolve_hostname(argv[1]);
+
+ /*
+ * Add the secret.
+ */
+ if (argv[3]) secret = argv[3];
+
+ /*
+ * Read input data vp(s) from the file (or stdin).
+ */
+ INFO("Loading input data...");
+ if (!rc_load_input(autofree, filename, &rc_vps_list_in, 0)
+ || rc_vps_list_in.size == 0) {
+ ERROR("No valid input. Nothing to send.\n");
+ exit(EXIT_FAILURE);
+ }
+ INFO("Loaded: %d input element(s).", rc_vps_list_in.size);
+
+ /* Initialize the packets list. */
+ MEM(pl = fr_packet_list_create(1));
+
+ /* Initialize the events list. */
+ ev_list = fr_event_list_create(autofree, NULL);
+ if (!ev_list) {
+ ERROR("Failed to create event list\n");
+ exit(1);
+ }
+
+ /*
+ * Start main loop.
+ */
+ rc_main_loop();
+
+ if (do_summary) {
+ INFO("\n\t Total approved auths: %d", totalapp);
+ INFO("\t Total denied auths: %d", totaldeny);
+ }
+
+ talloc_free(autofree);
+
+ return 0;
+}
+
+/** Given a radius request with some attributes in the EAP range, build
+ * them all into a single EAP-Message body.
+ *
+ * If there are multiple eligibles EAP-Type, the first one is picked.
+ * Function returns 0 if no EAP is involved, or the EAP-Type otherwise.
+ */
+static int rc_map_eap_methods(RADIUS_PACKET *req)
+{
+ VALUE_PAIR *vp, *vpnext;
+ int id, eapcode;
+ int eap_method = 0;
+
+ eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);
+
+ vp = fr_pair_find_by_num(req->vps, PW_EAP_ID, 0, TAG_ANY);
+ if (!vp) {
+ id = ((int)getpid() & 0xff);
+ } else {
+ id = vp->vp_integer;
+ }
+
+ vp = fr_pair_find_by_num(req->vps, PW_EAP_CODE, 0, TAG_ANY);
+ if (!vp) {
+ eapcode = PW_EAP_REQUEST;
+ } else {
+ eapcode = vp->vp_integer;
+ }
+
+ for (vp = req->vps; vp != NULL; vp = vpnext) {
+ /* save it in case it changes! */
+ vpnext = vp->next;
+
+ if (vp->da->attr >= PW_EAP_TYPE_BASE &&
+ vp->da->attr < PW_EAP_TYPE_BASE+256) {
+ break;
+ }
+ }
+
+ if (!vp) {
+ return 0;
+ }
+
+ eap_method = vp->da->attr - PW_EAP_TYPE_BASE;
+
+ switch (eap_method) {
+ case PW_EAP_IDENTITY:
+ case PW_EAP_NOTIFICATION:
+ case PW_EAP_NAK:
+ case PW_EAP_MD5:
+ case PW_EAP_OTP:
+ case PW_EAP_GTC:
+ case PW_EAP_TLS:
+ case PW_EAP_LEAP:
+ case PW_EAP_TTLS:
+ case PW_EAP_PEAP:
+ default:
+ /*
+ * no known special handling, it is just encoded as an
+ * EAP-message with the given type.
+ */
+
+ /* nuke any existing EAP-Messages */
+ fr_pair_delete_by_num(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+
+ pt_ep->code = eapcode;
+ pt_ep->id = id;
+ pt_ep->type.num = eap_method;
+ pt_ep->type.length = vp->vp_length;
+
+ pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length);
+ talloc_set_type(pt_ep->type.data, uint8_t);
+
+ eap_basic_compose(req, pt_ep);
+ }
+
+ return eap_method;
+}
+
+/*
+ * given a radius request with an EAP-Message body, decode it specific
+ * attributes.
+ */
+static void rc_unmap_eap_methods(RADIUS_PACKET *rep)
+{
+ VALUE_PAIR *eap1;
+ eap_packet_raw_t *e;
+ int len;
+ int type;
+
+ if (!rep) return;
+
+ /* find eap message */
+ e = eap_vp2packet(NULL, rep->vps);
+ if (!e) {
+ ERROR("failed decoding EAP: %s\n", fr_strerror());
+ return;
+ }
+ /* create EAP-ID and EAP-CODE attributes to start */
+ eap1 = fr_pair_afrom_num(rep, PW_EAP_ID, 0);
+ eap1->vp_integer = e->id;
+ fr_pair_add(&(rep->vps), eap1);
+
+ eap1 = fr_pair_afrom_num(rep, PW_EAP_CODE, 0);
+ eap1->vp_integer = e->code;
+ fr_pair_add(&(rep->vps), eap1);
+
+ switch (e->code) {
+ default:
+ case PW_EAP_SUCCESS:
+ case PW_EAP_FAILURE:
+ /* no data */
+ break;
+
+ case PW_EAP_REQUEST:
+ case PW_EAP_RESPONSE:
+ /* there is a type field, which we use to create
+ * a new attribute */
+
+ /* the length was decode already into the attribute
+ * length, and was checked already. Network byte
+ * order, just pull it out using math.
+ */
+ len = e->length[0]*256 + e->length[1];
+
+ /* verify the length is big enough to hold type */
+ if (len < 5)
+ {
+ talloc_free(e);
+ return;
+ }
+
+ type = e->data[0];
+
+ type += PW_EAP_TYPE_BASE;
+ len -= 5;
+
+ if (len > MAX_STRING_LEN) {
+ len = MAX_STRING_LEN;
+ }
+
+ eap1 = fr_pair_afrom_num(rep, type, 0);
+ fr_pair_value_memcpy(eap1, e->data + 1, len);
+
+ fr_pair_add(&(rep->vps), eap1);
+ break;
+ }
+
+ talloc_free(e);
+ return;
+}
+
+static int rc_map_eapsim_types(RADIUS_PACKET *r)
+{
+ int ret;
+
+ eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t);
+
+ ret = map_eapsim_basictypes(r, pt_ep);
+
+ if (ret != 1) {
+ return ret;
+ }
+
+ eap_basic_compose(r, pt_ep);
+
+ return 1;
+}
+
+static int rc_unmap_eapsim_types(RADIUS_PACKET *r)
+{
+ VALUE_PAIR *esvp;
+ uint8_t *eap_data;
+ int rcode_unmap;
+
+ esvp = fr_pair_find_by_num(r->vps, PW_EAP_TYPE_BASE+PW_EAP_SIM, 0, TAG_ANY);
+ if (!esvp) {
+ ERROR("eap: EAP-Sim attribute not found\n");
+ return 0;
+ }
+
+ eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length);
+ talloc_set_type(eap_data, uint8_t);
+
+ rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->vp_length);
+
+ talloc_free(eap_data);
+ return rcode_unmap;
+}
+
diff --git a/src/modules/rlm_eap/radeapclient.mk b/src/modules/rlm_eap/radeapclient.mk
new file mode 100644
index 0000000..6068f54
--- /dev/null
+++ b/src/modules/rlm_eap/radeapclient.mk
@@ -0,0 +1,29 @@
+TARGET := radeapclient
+SOURCES := radeapclient.c
+
+SOURCES += ${top_srcdir}/src/main/files.c \
+ ${top_srcdir}/src/main/threads.c \
+ ${top_srcdir}/src/main/version.c
+
+TGT_PREREQS := libfreeradius-radius.a libfreeradius-server.a
+TGT_LDLIBS := $(LIBS)
+
+#
+# For future work, if we want radeapclient to become radclient
+#
+ifneq "$(filter libfreeradius-eap%,${ALL_TGTS})" ""
+TGT_PREREQS += libfreeradius-eap.a
+
+ifneq ($(OPENSSL_LIBS),)
+SOURCES += ${top_srcdir}/src/main/cb.c ${top_srcdir}/src/main/tls.c
+TGT_LDLIBS += $(OPENSSL_LIBS)
+endif
+
+SRC_CFLAGS += -DWITH_EAPCLIENT
+SRC_INCDIRS := ${top_srcdir}/src/modules/rlm_eap/libeap
+
+ifneq ($(MAKECMDGOALS),scan)
+SRC_CFLAGS += -DBUILT_WITH_CPPFLAGS=\"$(CPPFLAGS)\" -DBUILT_WITH_CFLAGS=\"$(CFLAGS)\" -DBUILT_WITH_LDFLAGS=\"$(LDFLAGS)\" -DBUILT_WITH_LIBS=\"$(LIBS)\"
+endif
+
+endif
diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c
new file mode 100644
index 0000000..efb9660
--- /dev/null
+++ b/src/modules/rlm_eap/rlm_eap.c
@@ -0,0 +1,859 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_eap.c
+ * @brief Implements the EAP framework.
+ *
+ * @copyright 2000-2003,2006 The FreeRADIUS server project
+ * @copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * @copyright 2003 Alan DeKok <aland@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "rlm_eap.h"
+
+#include <sys/stat.h>
+
+static const CONF_PARSER module_config[] = {
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_t, default_method_name), "md5" },
+ { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, timer_limit), "60" },
+ { "max_eap_type", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, max_eap_type), "52" },
+ { "ignore_unknown_eap_types", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, ignore_unknown_types), "no" },
+ { "cisco_accounting_username_bug", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_t, mod_accounting_username_bug), "no" },
+ { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_t, max_sessions), "2048" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * delete all the allocated space by eap module
+ */
+static int mod_detach(void *instance)
+{
+ rlm_eap_t *inst;
+
+ inst = (rlm_eap_t *)instance;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_destroy(&(inst->session_mutex));
+#endif
+
+ rbtree_free(inst->session_tree);
+ inst->session_tree = NULL;
+ eaplist_free(inst);
+
+ return 0;
+}
+
+
+/*
+ * Compare two handlers.
+ */
+static int eap_handler_cmp(void const *a, void const *b)
+{
+ int rcode;
+ eap_handler_t const *one = a;
+ eap_handler_t const *two = b;
+
+ if (one->eap_id < two->eap_id) return -1;
+ if (one->eap_id > two->eap_id) return +1;
+
+ rcode = memcmp(one->state, two->state, sizeof(one->state));
+ if (rcode != 0) return rcode;
+
+ /*
+ * As of 2.1.8, we don't key off of source IP. This
+ * a NAS to send packets load-balanced (or fail-over)
+ * across multiple intermediate proxies, and still have
+ * EAP work.
+ */
+ if (fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr) != 0) {
+ char src1[64], src2[64];
+
+ fr_ntop(src1, sizeof(src1), &one->src_ipaddr);
+ fr_ntop(src2, sizeof(src2), &two->src_ipaddr);
+
+ RATE_LIMIT(WARN("EAP packets for one session are arriving from two different upstream"
+ "servers (%s and %s). Has there been a proxy fail-over?",
+ src1, src2));
+ }
+
+ return 0;
+}
+
+
+/*
+ * read the config section and load all the eap authentication types present.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void *instance)
+{
+ int i, ret;
+ eap_type_t method;
+ int num_methods;
+ CONF_SECTION *scs;
+ rlm_eap_t *inst = instance;
+
+ /*
+ * Create our own random pool.
+ */
+ for (i = 0; i < 256; i++) {
+ inst->rand_pool.randrsl[i] = fr_rand();
+ }
+ fr_randinit(&inst->rand_pool, 1);
+ inst->rand_pool.randcnt = 0;
+
+ inst->xlat_name = cf_section_name2(cs);
+ if (!inst->xlat_name) inst->xlat_name = "EAP";
+
+ if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) {
+ cf_log_err_cs(cs, "Failed to find 'Auth-Type %s' section. Cannot authenticate users.",
+ inst->xlat_name);
+ return -1;
+ }
+
+ /* Load all the configured EAP-Types */
+ num_methods = 0;
+ for(scs = cf_subsection_find_next(cs, NULL, NULL);
+ scs != NULL;
+ scs = cf_subsection_find_next(cs, scs, NULL)) {
+ char const *name;
+
+ name = cf_section_name1(scs);
+ if (!name) continue;
+
+ if (!strcmp(name, TLS_CONFIG_SECTION)) continue;
+
+ /*
+ * Don't break configurations for lazy people who still have LEAP enabled.
+ */
+ if (!strcmp(name, "leap")) {
+ WARN("rlm_eap (%s): Ignoring EAP method 'leap', because it is no longer supported",
+ inst->xlat_name);
+ continue;
+ }
+
+ /*
+ * Easier sometimes than commenting out blocks,
+ * or deleting blocks.
+ */
+ if (!strcmp(name, "disable")) continue;
+
+ method = eap_name2type(name);
+ if (method == PW_EAP_INVALID) {
+ cf_log_err_cs(cs, "No dictionary definition for EAP method %s", name);
+ return -1;
+ }
+
+ if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) {
+ cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name);
+ return -1;
+ }
+
+#if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL)
+ /*
+ * This allows the default configuration to be
+ * shipped with EAP-TLS, etc. enabled. If the
+ * system doesn't have OpenSSL, they will be
+ * ignored.
+ *
+ * If the system does have OpenSSL, then this
+ * code will not be used. The administrator will
+ * then have to delete the tls,
+ * etc. configurations from eap.conf in order to
+ * have EAP without the TLS types.
+ */
+ switch (method) {
+ case PW_EAP_FAST:
+ case PW_EAP_TLS:
+ case PW_EAP_TTLS:
+ case PW_EAP_PEAP:
+ case PW_EAP_PWD:
+ WARN("rlm_eap (%s): Ignoring EAP method %s because we don't have OpenSSL support",
+ inst->xlat_name, name);
+ continue;
+
+ default:
+ break;
+ }
+#endif
+
+ /*
+ * Load the type.
+ */
+ ret = eap_module_instantiate(inst, &inst->methods[method], method, scs);
+
+ (void) talloc_get_type_abort(inst->methods[method], eap_module_t);
+
+ if (ret < 0) {
+ (void) talloc_steal(inst, inst->methods[method]);
+ return -1;
+ }
+
+ (void) talloc_steal(inst, inst->methods[method]);
+ num_methods++; /* successfully loaded one more methods */
+ }
+
+ if (num_methods == 0) {
+ cf_log_err_cs(cs, "No EAP method configured, module cannot do anything");
+ return -1;
+ }
+
+ /*
+ * Ensure that the default EAP type is loaded.
+ */
+ method = eap_name2type(inst->default_method_name);
+ if (method == PW_EAP_INVALID) {
+ cf_log_err_cs(cs, "No dictionary definition for default EAP method '%s'",
+ inst->default_method_name);
+ return -1;
+ }
+
+ if (!inst->methods[method]) {
+ cf_log_err_cs(cs, "No such sub-type for default EAP method %s",
+ inst->default_method_name);
+ return -1;
+ }
+ inst->default_method = method; /* save the numerical method */
+
+ /*
+ * List of sessions are set to NULL by the memset
+ * of 'inst', above.
+ */
+
+ /*
+ * Lookup sessions in the tree. We don't free them in
+ * the tree, as that's taken care of elsewhere...
+ */
+ inst->session_tree = rbtree_create(NULL, eap_handler_cmp, NULL, 0);
+ if (!inst->session_tree) {
+ ERROR("rlm_eap (%s): Cannot initialize tree", inst->xlat_name);
+ return -1;
+ }
+ fr_link_talloc_ctx_free(inst, inst->session_tree);
+
+#ifdef HAVE_PTHREAD_H
+ if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) {
+ ERROR("rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, fr_syserror(errno));
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+/*
+ * For backwards compatibility.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_eap_t *inst;
+ eap_handler_t *handler;
+ eap_packet_raw_t *eap_packet;
+ eap_rcode_t status;
+ rlm_rcode_t rcode;
+
+ inst = (rlm_eap_t *) instance;
+
+ if (!fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
+ REDEBUG("You set 'Auth-Type = %s' for a request that does "
+ "not contain an EAP-Message attribute!", inst->xlat_name);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Get the eap packet to start with
+ */
+ eap_packet = eap_vp2packet(request, request->packet->vps);
+ if (!eap_packet) {
+ RERROR("Malformed EAP Message: %s", fr_strerror());
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Create the eap handler. The eap_packet will end up being
+ * "swallowed" into the handler, so we can't access it after
+ * this call.
+ */
+ handler = eap_handler(inst, &eap_packet, request);
+ if (!handler) {
+ RDEBUG2("Failed in handler");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Select the appropriate method or default to the
+ * configured one
+ */
+ status = eap_method_select(inst, handler);
+
+ /*
+ * If it failed, die.
+ */
+ if (status == EAP_INVALID) {
+ eap_fail(handler);
+ talloc_free(handler);
+ RDEBUG2("Failed in EAP select");
+ return RLM_MODULE_INVALID;
+ }
+
+#ifdef WITH_PROXY
+ /*
+ * If we're doing horrible tunneling work, remember it.
+ */
+ if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+ RDEBUG2("No EAP proxy set. Not composing EAP");
+ /*
+ * Add the handle to the proxied list, so that we
+ * can retrieve it in the post-proxy stage, and
+ * send a response.
+ */
+ handler->inst_holder = inst;
+ status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true);
+
+ rad_assert(status == 0);
+ return RLM_MODULE_HANDLED;
+ }
+#endif
+
+#ifdef WITH_PROXY
+ /*
+ * Maybe the request was marked to be proxied. If so,
+ * proxy it.
+ */
+ if (request->proxy != NULL) {
+ VALUE_PAIR *vp = NULL;
+
+ rad_assert(!request->proxy_reply);
+
+ /*
+ * Add the handle to the proxied list, so that we
+ * can retrieve it in the post-proxy stage, and
+ * send a response.
+ */
+ handler->inst_holder = inst;
+
+ status = request_data_add(request, inst, REQUEST_DATA_EAP_HANDLER, handler, true);
+
+ rad_assert(status == 0);
+
+ /*
+ * Some simple sanity checks. These should really
+ * be handled by the radius library...
+ */
+ vp = fr_pair_find_by_num(request->proxy->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (vp) {
+ vp = fr_pair_find_by_num(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ if (!vp) {
+ fr_pair_make(request->proxy,
+ &request->proxy->vps,
+ "Message-Authenticator",
+ NULL, T_OP_EQ);
+ }
+ }
+
+ /*
+ * Delete the "proxied to" attribute, as it's
+ * set to 127.0.0.1 for tunneled requests, and
+ * we don't want to tell the world that...
+ */
+ fr_pair_delete_by_num(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY);
+
+ RWDEBUG2("Tunneled session will be proxied. Not doing EAP");
+ return RLM_MODULE_HANDLED;
+ }
+#endif
+
+ /*
+ * We are done, wrap the EAP-request in RADIUS to send
+ * with all other required radius attributes
+ */
+ rcode = eap_compose(handler);
+
+ /*
+ * Add to the list only if it is EAP-Request.
+ */
+ if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
+ (handler->eap_ds->request->type.num >= PW_EAP_MD5)) {
+ /*
+ * Return FAIL if we can't remember the handler.
+ * This is actually disallowed by the
+ * specification, as unexpected FAILs could have
+ * been forged. However, we want to signal to
+ * everyone else involved that we are
+ * intentionally failing the session, as opposed
+ * to accidentally failing it.
+ */
+ if (!eaplist_add(inst, handler)) {
+ RDEBUG("Failed adding handler to the list");
+ eap_fail(handler);
+ talloc_free(handler);
+ return RLM_MODULE_FAIL;
+ }
+
+ } else {
+ /*
+ * Enable the cached entry on success.
+ */
+ if (handler->eap_ds->request->code == PW_EAP_SUCCESS) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_find_by_num(request->state, PW_TLS_CACHE_FILENAME, 0, TAG_ANY);
+ if (vp) (void) chmod(vp->vp_strvalue, S_IRUSR | S_IWUSR);
+ }
+
+ /*
+ * Disable the cached entry on failure.
+ */
+ if (handler->eap_ds->request->code == PW_EAP_FAILURE) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_find_by_num(request->state, PW_TLS_CACHE_FILENAME, 0, TAG_ANY);
+ if (vp) (void) unlink(vp->vp_strvalue);
+ }
+
+ RDEBUG2("Freeing handler");
+ /* handler is not required any more, free it now */
+ talloc_free(handler);
+ }
+
+ /*
+ * If it's an Access-Accept, RFC 2869, Section 2.3.1
+ * says that we MUST include a User-Name attribute in the
+ * Access-Accept.
+ */
+ if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) &&
+ request->username) {
+ VALUE_PAIR *vp;
+
+ /*
+ * Doesn't exist, add it in.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ vp = request->username;
+ if (vp->da->attr != PW_USER_NAME) {
+ vp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+ if (vp) {
+ vp = fr_pair_copy(request->reply, vp);
+ fr_pair_add(&request->reply->vps, vp);
+ }
+ }
+
+ /*
+ * Cisco AP1230 has a bug and needs a zero
+ * terminated string in Access-Accept. This
+ * means it requires 2 trailing zeros. One to
+ * send in the RADIUS packet, and the other to
+ * convince the rest of the server that
+ * vp->vp_strvalue is still a NUL-terminated C
+ * string.
+ */
+ if (vp && inst->mod_accounting_username_bug) {
+ char const *old = vp->vp_strvalue;
+ char *new;
+
+ vp->vp_length++; /* account for an additional zero */
+
+ new = talloc_array(vp, char, vp->vp_length + 1);
+
+ memcpy(new, old, vp->vp_length);
+ new[vp->length] = '\0';
+ vp->vp_strvalue = new;
+
+ rad_const_free(old);
+ VERIFY_VP(vp);
+ }
+ }
+
+ return rcode;
+}
+
+/*
+ * EAP authorization DEPENDS on other rlm authorizations,
+ * to check for user existence & get their configured values.
+ * It Handles EAP-START Messages, User-Name initilization.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_eap_t *inst;
+ int status;
+ VALUE_PAIR *vp;
+
+ inst = (rlm_eap_t *)instance;
+
+#ifdef WITH_PROXY
+ /*
+ * We don't do authorization again, once we've seen the
+ * proxy reply (or the proxied packet)
+ */
+ if (request->proxy != NULL)
+ return RLM_MODULE_NOOP;
+#endif
+
+ /*
+ * For EAP_START, send Access-Challenge with EAP Identity
+ * request. even when we have to proxy this request
+ *
+ * RFC 2869, Section 2.3.1 notes that the "domain" of the
+ * user, (i.e. where to proxy him) comes from the EAP-Identity,
+ * so we CANNOT proxy the user, until we know his identity.
+ *
+ * We therefore send an EAP Identity request.
+ */
+ status = eap_start(inst, request);
+ switch (status) {
+ case EAP_NOOP:
+ return RLM_MODULE_NOOP;
+ case EAP_FAIL:
+ return RLM_MODULE_FAIL;
+ case EAP_FOUND:
+ return RLM_MODULE_HANDLED;
+ case EAP_OK:
+ case EAP_NOTFOUND:
+ default:
+ break;
+ }
+
+ /*
+ * RFC 2869, Section 2.3.1. If a NAS sends an EAP-Identity,
+ * it MUST copy the identity into the User-Name attribute.
+ *
+ * But we don't worry about that too much. We depend on
+ * each EAP sub-module to look for handler->request->username,
+ * and to get excited if it doesn't appear.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY);
+ if ((!vp) || (vp->vp_integer != PW_AUTH_TYPE_REJECT)) {
+ vp = pair_make_config("Auth-Type", inst->xlat_name, T_OP_EQ);
+ if (!vp) {
+ RDEBUG2("Failed to create Auth-Type %s: %s\n",
+ inst->xlat_name, fr_strerror());
+ return RLM_MODULE_FAIL;
+ }
+ } else {
+ RWDEBUG2("Auth-Type already set. Not setting to EAP");
+ }
+
+ if (status == EAP_OK) return RLM_MODULE_OK;
+
+ return RLM_MODULE_UPDATED;
+}
+
+
+#ifdef WITH_PROXY
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ VALUE_PAIR *vp;
+ size_t length;
+ rlm_eap_t *inst = instance;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (!vp) return RLM_MODULE_NOOP;
+
+ if (vp->vp_length < 4) return RLM_MODULE_NOOP;
+
+ if ((vp->vp_octets[0] == 0) ||( vp->vp_octets[0] > 6)) {
+ RDEBUG("EAP header byte zero has invalid value");
+
+ add_error_cause:
+ /*
+ * Invalid EAP packet (ignored)
+ */
+ pair_make_reply("Error-Cause", "202", T_OP_EQ);
+ return RLM_MODULE_REJECT;
+ }
+
+ length = (vp->vp_octets[2] << 8) | vp->vp_octets[3];
+ if (length != vp->vp_length) {
+ RDEBUG("EAP length does not match attribute length");
+ return RLM_MODULE_REJECT;
+ }
+
+ if (vp->vp_octets[0] != PW_EAP_REQUEST) return RLM_MODULE_NOOP;
+ if (!inst->max_eap_type) return RLM_MODULE_NOOP;
+
+ if (vp->vp_length < 5) return RLM_MODULE_NOOP;
+
+ if (vp->vp_octets[4] == 254) return RLM_MODULE_NOOP; /* allow extended types */
+
+ if (vp->vp_octets[4] > inst->max_eap_type) {
+ RDEBUG("EAP method %u is too large", vp->vp_octets[4]);
+ goto add_error_cause;
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+/*
+ * If we're proxying EAP, then there may be magic we need
+ * to do.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *inst, REQUEST *request)
+{
+ size_t i;
+ size_t len;
+ ssize_t ret;
+ char *p;
+ VALUE_PAIR *vp;
+ eap_handler_t *handler;
+ vp_cursor_t cursor;
+
+ /*
+ * If there was a handler associated with this request,
+ * then it's a tunneled request which was proxied...
+ */
+ handler = request_data_get(request, inst, REQUEST_DATA_EAP_HANDLER);
+ if (handler != NULL) {
+ rlm_rcode_t rcode;
+ eap_tunnel_data_t *data;
+
+ /*
+ * Grab the tunnel callbacks from the request.
+ */
+ data = (eap_tunnel_data_t *) request_data_get(request,
+ request->proxy,
+ REQUEST_DATA_EAP_TUNNEL_CALLBACK);
+ if (!data) {
+ RERROR("Failed to retrieve callback for tunneled session!");
+ talloc_free(handler);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Do the callback...
+ */
+ RDEBUG2("Doing post-proxy callback");
+ rcode = data->callback(handler, data->tls_session);
+ talloc_free(data);
+ if (rcode == 0) {
+ RDEBUG2("Failed in post-proxy callback");
+ eap_fail(handler);
+ talloc_free(handler);
+ return RLM_MODULE_REJECT;
+ }
+
+ /*
+ * We are done, wrap the EAP-request in RADIUS to send
+ * with all other required radius attributes
+ */
+ eap_compose(handler);
+
+ /*
+ * Add to the list only if it is EAP-Request.
+ */
+ if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
+ (handler->eap_ds->request->type.num >= PW_EAP_MD5)) {
+ if (!eaplist_add(inst, handler)) {
+ eap_fail(handler);
+ talloc_free(handler);
+ return RLM_MODULE_FAIL;
+ }
+
+ } else {
+ RDEBUG2("Freeing handler");
+ /* handler is not required any more, free it now */
+ talloc_free(handler);
+ }
+
+ /*
+ * If it's an Access-Accept, RFC 2869, Section 2.3.1
+ * says that we MUST include a User-Name attribute in the
+ * Access-Accept.
+ */
+ if ((request->reply->code == PW_CODE_ACCESS_ACCEPT) &&
+ request->username) {
+ /*
+ * Doesn't exist, add it in.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ pair_make_reply("User-Name",
+ request->username->vp_strvalue,
+ T_OP_EQ);
+ }
+ }
+
+ return RLM_MODULE_OK;
+ } else {
+ RDEBUG2("No pre-existing handler found");
+ }
+
+ /*
+ * This is allowed.
+ */
+ if (!request->proxy_reply) return RLM_MODULE_NOOP;
+
+ /*
+ * There may be more than one Cisco-AVPair.
+ * Ensure we find the one with the LEAP attribute.
+ */
+ fr_cursor_init(&cursor, &request->proxy_reply->vps);
+ for (;;) {
+ /*
+ * Hmm... there's got to be a better way to
+ * discover codes for vendor attributes.
+ *
+ * This is vendor Cisco (9), Cisco-AVPair
+ * attribute (1)
+ */
+ vp = fr_cursor_next_by_num(&cursor, 1, 9, TAG_ANY);
+ if (!vp) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * If it's "leap:session-key", then stop.
+ *
+ * The format is VERY specific!
+ */
+ if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) {
+ break;
+ }
+ }
+
+ /*
+ * The format is very specific.
+ */
+ if (vp->vp_length != (17 + 34)) {
+ RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %zu: Expected %d",
+ vp->vp_length, 17 + 34);
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Decrypt the session key, using the proxy data.
+ *
+ * Note that the session key is *binary*, and therefore
+ * may contain embedded zeros. So we have to use memdup.
+ * However, Cisco-AVPair is a "string", so the rest of the
+ * code assumes that it's terminated by a trailing '\0'.
+ *
+ * So... be sure to (a) use memdup, and (b) include the last
+ * zero byte.
+ */
+ i = 34;
+ p = talloc_memdup(vp, vp->vp_strvalue, vp->vp_length + 1);
+ talloc_set_type(p, uint8_t);
+ ret = rad_tunnel_pwdecode((uint8_t *)p + 17, &i, request->home_server->secret, request->proxy->vector);
+ if (ret < 0) {
+ REDEBUG("Decoding leap:session-key failed");
+ talloc_free(p);
+ return RLM_MODULE_FAIL;
+ }
+ len = i;
+
+ if (i != 16) {
+ REDEBUG("Decoded key length is incorrect, must be 16 bytes");
+ talloc_free(p);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Encrypt the session key again, using the request data.
+ */
+ ret = rad_tunnel_pwencode(p + 17, &len, request->client->secret, request->packet->vector);
+ if (ret < 0) {
+ REDEBUG("Decoding leap:session-key failed");
+ talloc_free(p);
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_pair_value_strsteal(vp, p);
+
+ return RLM_MODULE_UPDATED;
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_eap_t *inst = instance;
+ VALUE_PAIR *vp;
+ eap_handler_t *handler;
+ eap_packet_raw_t *eap_packet;
+
+ /*
+ * Only build a failure message if something previously rejected the request
+ */
+ vp = fr_pair_find_by_num(request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY);
+
+ if (!vp || (vp->vp_integer != PW_POST_AUTH_TYPE_REJECT)) return RLM_MODULE_NOOP;
+
+ if (!fr_pair_find_by_num(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
+ RDEBUG3("Request didn't contain an EAP-Message, not inserting EAP-Failure");
+ return RLM_MODULE_NOOP;
+ }
+
+ if (fr_pair_find_by_num(request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) {
+ RDEBUG3("Reply already contained an EAP-Message, not inserting EAP-Failure");
+ return RLM_MODULE_NOOP;
+ }
+
+ eap_packet = eap_vp2packet(request, request->packet->vps);
+ if (!eap_packet) {
+ RERROR("Malformed EAP Message: %s", fr_strerror());
+ return RLM_MODULE_FAIL;
+ }
+
+ handler = eap_handler(inst, &eap_packet, request);
+ if (!handler) {
+ RDEBUG2("Failed to get handler, probably already removed, not inserting EAP-Failure");
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("Request was previously rejected, inserting EAP-Failure");
+ eap_fail(handler);
+ talloc_free(handler);
+
+ /*
+ * Make sure there's a message authenticator attribute in the response
+ * RADIUS protocol code will calculate the correct value later...
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+ if (!vp) {
+ pair_make_reply("Message-Authenticator", "0x00", T_OP_EQ);
+ }
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern module_t rlm_eap;
+module_t rlm_eap = {
+ .magic = RLM_MODULE_INIT,
+ .name = "eap",
+ .inst_size = sizeof(rlm_eap_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_eap/rlm_eap.h b/src/modules/rlm_eap/rlm_eap.h
new file mode 100644
index 0000000..0b9311c
--- /dev/null
+++ b/src/modules/rlm_eap/rlm_eap.h
@@ -0,0 +1,116 @@
+/*
+ * rlm_eap.h Local Header file.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _RLM_EAP_H
+#define _RLM_EAP_H
+
+RCSIDH(rlm_eap_h, "$Id$")
+
+#include <freeradius-devel/modpriv.h>
+#include "eap.h"
+#include "eap_types.h"
+
+/*
+ * Keep track of which sub modules we've loaded.
+ */
+typedef struct eap_module {
+ char const *name;
+ rlm_eap_module_t *type;
+ fr_dlhandle handle;
+ CONF_SECTION *cs;
+ void *instance;
+} eap_module_t;
+
+/*
+ * This structure contains eap's persistent data.
+ * sessions = remembered sessions, in a tree for speed.
+ * types = All supported EAP-Types
+ * mutex = ensure only one thread is updating the sessions[] struct
+ */
+typedef struct rlm_eap {
+ rbtree_t *session_tree;
+ eap_handler_t *session_head, *session_tail;
+ eap_module_t *methods[PW_EAP_MAX_TYPES];
+
+ /*
+ * Configuration items.
+ */
+ uint32_t timer_limit;
+ uint32_t max_eap_type;
+
+ char const *default_method_name;
+ eap_type_t default_method;
+
+ bool ignore_unknown_types;
+ bool mod_accounting_username_bug;
+
+ uint32_t max_sessions;
+
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t session_mutex;
+ pthread_mutex_t handler_mutex;
+#endif
+
+ char const *xlat_name; /* no xlat's yet */
+ fr_randctx rand_pool;
+} rlm_eap_t;
+
+/*
+ * For simplicity in the rest of the code.
+ */
+#ifndef HAVE_PTHREAD_H
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+#define pthread_mutex_init(_x, _y)
+#define pthread_mutex_destroy(_x)
+#define pthread_mutex_lock(_x)
+#define pthread_mutex_unlock(_x)
+#endif
+
+/* function definitions */
+/* EAP-Type */
+int eap_module_instantiate(rlm_eap_t *inst, eap_module_t **method, eap_type_t num, CONF_SECTION *cs);
+eap_rcode_t eap_method_select(rlm_eap_t *inst, eap_handler_t *handler);
+
+/* EAP */
+int eap_start(rlm_eap_t *inst, REQUEST *request) CC_HINT(nonnull);
+void eap_fail(eap_handler_t *handler) CC_HINT(nonnull);
+void eap_success(eap_handler_t *handler) CC_HINT(nonnull);
+rlm_rcode_t eap_compose(eap_handler_t *handler) CC_HINT(nonnull);
+eap_handler_t *eap_handler(rlm_eap_t *inst, eap_packet_raw_t **eap_msg, REQUEST *request) CC_HINT(nonnull);
+
+/* Memory Management */
+EAP_DS *eap_ds_alloc(eap_handler_t *handler);
+eap_handler_t *eap_handler_alloc(rlm_eap_t *inst);
+void eap_ds_free(EAP_DS **eap_ds);
+int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) CC_HINT(nonnull);
+eap_handler_t *eaplist_find(rlm_eap_t *inst, REQUEST *request, eap_packet_raw_t *eap_packet);
+void eaplist_free(rlm_eap_t *inst);
+
+/* State */
+void generate_key(void);
+VALUE_PAIR *generate_state(time_t timestamp);
+int verify_state(VALUE_PAIR *state, time_t timestamp);
+
+#endif /*_RLM_EAP_H*/
diff --git a/src/modules/rlm_eap/rlm_eap.mk b/src/modules/rlm_eap/rlm_eap.mk
new file mode 100644
index 0000000..4459563
--- /dev/null
+++ b/src/modules/rlm_eap/rlm_eap.mk
@@ -0,0 +1,6 @@
+TARGET := rlm_eap.a
+SOURCES := rlm_eap.c eap.c mem.c
+
+SRC_INCDIRS := . libeap
+
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/all.mk b/src/modules/rlm_eap/types/all.mk
new file mode 100644
index 0000000..b85d501
--- /dev/null
+++ b/src/modules/rlm_eap/types/all.mk
@@ -0,0 +1 @@
+SUBMAKEFILES := $(wildcard ${top_srcdir}/src/modules/rlm_eap/types/rlm_eap_*/all.mk)
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore b/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/README.md b/src/modules/rlm_eap/types/rlm_eap_fast/README.md
new file mode 100644
index 0000000..0112975
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/README.md
@@ -0,0 +1,10 @@
+# rlm_eap_fast
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 4851](https://tools.ietf.org/html/rfc4851),
+Cisco's EAP-FAST (Flexible Authentication via Secure Tunnelling)
+protocol.
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in
new file mode 100644
index 0000000..41920f5
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/all.mk.in
@@ -0,0 +1,12 @@
+TARGETNAME := @targetname@
+
+ifneq "$(OPENSSL_LIBS)" ""
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+endif
+
+SOURCES := $(TARGETNAME).c eap_fast.c eap_fast_crypto.c
+
+SRC_INCDIRS := ${top_srcdir}/src/modules/rlm_eap/ ${top_srcdir}/src/modules/rlm_eap/libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/configure b/src/modules/rlm_eap/types/rlm_eap_fast/configure
new file mode 100755
index 0000000..5aeb696
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/configure
@@ -0,0 +1,4512 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap_fast.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap_fast
+with_openssl_lib_dir
+with_openssl_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap_fast build without rlm_eap_fast
+ --with-openssl-lib-dir=DIR
+ directory for LDAP library files
+ -with-openssl-include-dir=DIR
+ directory for LDAP include files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap_fast
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap_fast was given.
+if test "${with_rlm_eap_fast+set}" = set; then :
+ withval=$with_rlm_eap_fast;
+fi
+
+
+
+mod_ldflags=
+mod_cflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap_fast" != xno; then
+
+
+openssl_lib_dir=
+
+# Check whether --with-openssl-lib-dir was given.
+if test "${with_openssl_lib_dir+set}" = set; then :
+ withval=$with_openssl_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need openssl-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+openssl_include_dir=
+
+# Check whether --with-openssl-include-dir was given.
+if test "${with_openssl_include_dir+set}" = set; then :
+ withval=$with_openssl_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need openssl-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir=$openssl_include_dir
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "openssl/ec.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+ for _dir in $smart_try_dir; do
+ _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+ done
+
+ for _dir in $smart_include_dir; do
+ _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+ done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5
+$as_echo_n "checking for openssl/ec.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/openssl/ec.h" >&5
+$as_echo_n "checking for ${_prefix}/openssl/ec.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem ${_prefix}/"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h" >&5
+$as_echo_n "checking for openssl/ec.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5
+$as_echo_n "checking for openssl/ec.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_openssl_ec_h" != "yes"; then
+
+fail="$fail openssl/ec.h"
+
+fi
+
+smart_try_dir=$openssl_lib_dir
+
+
+sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "EVP_CIPHER_CTX_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then
+
+fail="$fail libssl"
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x01000100fL)
+ yes
+ #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 1.0.1a" >&5
+$as_echo_n "checking for OpenSSL version >= 1.0.1a... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL version >= 1.0.1a" >&5
+$as_echo_n "checking for OpenSSL version >= 1.0.1a... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fail="$fail OpenSSL>1.0.1"
+
+
+
+fi
+rm -f conftest*
+
+
+
+ targetname=rlm_eap_fast
+else
+ targetname=
+ echo \*\*\* module rlm_eap_fast is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap_fast to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_fast." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap_fast." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_fast requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap_fast requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac b/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac
new file mode 100644
index 0000000..b778c42
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/configure.ac
@@ -0,0 +1,86 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap_fast.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap_fast])
+
+mod_ldflags=
+mod_cflags=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+dnl extra argument: --with-openssl-lib-dir
+openssl_lib_dir=
+AC_ARG_WITH(openssl-lib-dir,
+ [AS_HELP_STRING([--with-openssl-lib-dir=DIR],
+ [directory for LDAP library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need openssl-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-openssl-include-dir
+openssl_include_dir=
+AC_ARG_WITH(openssl-include-dir,
+ [AS_HELP_STRING([-with-openssl-include-dir=DIR],
+ [directory for LDAP include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need openssl-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_include_dir="$withval"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir=$openssl_include_dir
+FR_SMART_CHECK_INCLUDE(openssl/ec.h)
+if test "$ac_cv_header_openssl_ec_h" != "yes"; then
+ FR_MODULE_FAIL([openssl/ec.h])
+fi
+
+smart_try_dir=$openssl_lib_dir
+FR_SMART_CHECK_LIB(crypto, EVP_CIPHER_CTX_new)
+if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then
+ FR_MODULE_FAIL([libssl])
+fi
+
+AC_EGREP_CPP(yes,
+ [#include <openssl/crypto.h>
+ #if (OPENSSL_VERSION_NUMBER >= 0x01000100fL)
+ yes
+ #endif
+ ],
+ [
+ AC_MSG_CHECKING([for OpenSSL version >= 1.0.1a])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_CHECKING([for OpenSSL version >= 1.0.1a])
+ AC_MSG_RESULT(no)
+ FR_MODULE_FAIL([OpenSSL>1.0.1])
+ ]
+)
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c
new file mode 100644
index 0000000..bbb5a03
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.c
@@ -0,0 +1,1315 @@
+/*
+ * eap_fast.c contains the interfaces that are called from the main handler
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2016 Alan DeKok <aland@freeradius.org>
+ * Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include "eap_fast.h"
+#include "eap_fast_crypto.h"
+#include <freeradius-devel/sha1.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+
+#define RANDFILL(x) do { rad_assert(sizeof(x) % sizeof(uint32_t) == 0); for (size_t i = 0; i < sizeof(x); i += sizeof(uint32_t)) *((uint32_t *)&x[i]) = fr_rand(); } while(0)
+
+/*
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
+ * All Rights Reserved.
+ *
+ * These programs are licensed under the BSD license (the one with
+ * advertisement clause removed).
+ *
+ * this function shamelessly stolen from from hostap:src/crypto/tls_openssl.c
+ */
+static int openssl_get_keyblock_size(REQUEST *request, SSL *ssl)
+{
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ int md_size;
+
+ if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
+ ssl->read_hash == NULL)
+ return -1;
+
+ c = ssl->enc_read_ctx->cipher;
+ h = EVP_MD_CTX_md(ssl->read_hash);
+ if (h)
+ md_size = EVP_MD_size(h);
+ else if (ssl->s3)
+ md_size = ssl->s3->tmp.new_mac_secret_size;
+ else
+ return -1;
+
+ RDEBUG2("OpenSSL: keyblock size: key_len=%d MD_size=%d "
+ "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+ EVP_CIPHER_iv_length(c));
+ return 2 * (EVP_CIPHER_key_length(c) +
+ md_size +
+ EVP_CIPHER_iv_length(c));
+#else
+ const SSL_CIPHER *ssl_cipher;
+ int cipher, digest;
+ int mac_key_len, enc_key_len, fixed_iv_len;
+
+ ssl_cipher = SSL_get_current_cipher(ssl);
+ if (!ssl_cipher)
+ return -1;
+ cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
+ digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
+ RDEBUG3("OpenSSL: cipher nid %d digest nid %d",
+ cipher, digest);
+ if (cipher < 0 || digest < 0)
+ return -1;
+ if (cipher == NID_undef) {
+ RDEBUG3("OpenSSL: no cipher in use?!");
+ return -1;
+ }
+ c = EVP_get_cipherbynid(cipher);
+ if (!c)
+ return -1;
+ enc_key_len = EVP_CIPHER_key_length(c);
+ if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE ||
+ EVP_CIPHER_mode(c) == EVP_CIPH_CCM_MODE)
+ fixed_iv_len = 4; /* only part of IV from PRF */
+ else
+ fixed_iv_len = EVP_CIPHER_iv_length(c);
+ if (digest == NID_undef) {
+ RDEBUG3("OpenSSL: no digest in use (e.g., AEAD)");
+ mac_key_len = 0;
+ } else {
+ h = EVP_get_digestbynid(digest);
+ if (!h)
+ return -1;
+ mac_key_len = EVP_MD_size(h);
+ }
+
+ RDEBUG2("OpenSSL: keyblock size: mac_key_len=%d enc_key_len=%d fixed_iv_len=%d",
+ mac_key_len, enc_key_len, fixed_iv_len);
+ return 2 * (mac_key_len + enc_key_len + fixed_iv_len);
+#endif
+}
+
+/**
+ * RFC 4851 section 5.1 - EAP-FAST Authentication Phase 1: Key Derivations
+ */
+static void eap_fast_init_keys(REQUEST *request, tls_session_t *tls_session)
+{
+ eap_fast_tunnel_t *t = tls_session->opaque;
+ uint8_t *buf;
+ size_t ksize;
+
+ RDEBUG2("Deriving EAP-FAST keys");
+
+ rad_assert(t->simck == NULL);
+
+ ksize = openssl_get_keyblock_size(request, tls_session->ssl);
+ rad_assert(ksize > 0);
+ buf = talloc_size(request, ksize + sizeof(*t->keyblock));
+
+ t->keyblock = talloc(t, eap_fast_keyblock_t);
+
+ eap_fast_tls_gen_challenge(tls_session->ssl, SSL_version(tls_session->ssl), buf, ksize + sizeof(*t->keyblock), "key expansion");
+ memcpy(t->keyblock, &buf[ksize], sizeof(*t->keyblock));
+ memset(buf, 0, ksize + sizeof(*t->keyblock));
+
+ t->simck = talloc_size(t, EAP_FAST_SIMCK_LEN);
+ memcpy(t->simck, t->keyblock, EAP_FAST_SKS_LEN); /* S-IMCK[0] = session_key_seed */
+
+ t->cmk = talloc_size(t, EAP_FAST_CMK_LEN); /* note that CMK[0] is not defined */
+ t->imckc = 0;
+
+ talloc_free(buf);
+}
+
+/**
+ * RFC 4851 section 5.2 - Intermediate Compound Key Derivations
+ */
+static void eap_fast_update_icmk(REQUEST *request, tls_session_t *tls_session, uint8_t *msk)
+{
+ eap_fast_tunnel_t *t = tls_session->opaque;
+ uint8_t imck[EAP_FAST_SIMCK_LEN + EAP_FAST_CMK_LEN];
+
+ RDEBUG2("Updating ICMK");
+
+ T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Inner Methods Compound Keys", msk, 32, imck, sizeof(imck));
+
+ memcpy(t->simck, imck, EAP_FAST_SIMCK_LEN);
+ memcpy(t->cmk, &imck[EAP_FAST_SIMCK_LEN], EAP_FAST_CMK_LEN);
+ t->imckc++;
+
+ /*
+ * Calculate MSK/EMSK at the same time as they are coupled to ICMK
+ *
+ * RFC 4851 section 5.4 - EAP Master Session Key Generation
+ */
+ t->msk = talloc_size(t, EAP_FAST_KEY_LEN);
+ T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Session Key Generating Function", NULL, 0, t->msk, EAP_FAST_KEY_LEN);
+
+ t->emsk = talloc_size(t, EAP_EMSK_LEN);
+ T_PRF(t->simck, EAP_FAST_SIMCK_LEN, "Extended Session Key Generating Function", NULL, 0, t->emsk, EAP_EMSK_LEN);
+}
+
+void eap_fast_tlv_append(tls_session_t *tls_session, int tlv, bool mandatory, int length, const void *data)
+{
+ uint16_t hdr[2];
+
+ hdr[0] = (mandatory) ? htons(tlv | EAP_FAST_TLV_MANDATORY) : htons(tlv);
+ hdr[1] = htons(length);
+
+ tls_session->record_plus(&tls_session->clean_in, &hdr, 4);
+ tls_session->record_plus(&tls_session->clean_in, data, length);
+}
+
+static void eap_fast_send_error(tls_session_t *tls_session, int error)
+{
+ uint32_t value;
+ value = htonl(error);
+
+ eap_fast_tlv_append(tls_session, EAP_FAST_TLV_ERROR, true, sizeof(value), &value);
+}
+
+static void eap_fast_append_result(tls_session_t *tls_session, PW_CODE code)
+{
+ eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+ int type = (t->result_final)
+ ? EAP_FAST_TLV_RESULT
+ : EAP_FAST_TLV_INTERMED_RESULT;
+
+ uint16_t state = (code == PW_CODE_ACCESS_REJECT)
+ ? EAP_FAST_TLV_RESULT_FAILURE
+ : EAP_FAST_TLV_RESULT_SUCCESS;
+ state = htons(state);
+
+ eap_fast_tlv_append(tls_session, type, true, sizeof(state), &state);
+}
+
+static void eap_fast_send_identity_request(REQUEST *request, tls_session_t *tls_session, eap_handler_t *eap_session)
+{
+ eap_packet_raw_t eap_packet;
+
+ RDEBUG("Sending EAP-Identity");
+
+ eap_packet.code = PW_EAP_REQUEST;
+ eap_packet.id = eap_session->eap_ds->response->id + 1;
+ eap_packet.length[0] = 0;
+ eap_packet.length[1] = EAP_HEADER_LEN + 1;
+ eap_packet.data[0] = PW_EAP_IDENTITY;
+
+ eap_fast_tlv_append(tls_session, EAP_FAST_TLV_EAP_PAYLOAD, true, sizeof(eap_packet), &eap_packet);
+}
+
+static void eap_fast_send_pac_tunnel(REQUEST *request, tls_session_t *tls_session)
+{
+ eap_fast_tunnel_t *t = tls_session->opaque;
+ eap_fast_pac_t pac;
+ eap_fast_attr_pac_opaque_plaintext_t opaque_plaintext;
+ int alen, dlen;
+
+ memset(&pac, 0, sizeof(pac));
+ memset(&opaque_plaintext, 0, sizeof(opaque_plaintext));
+
+ RDEBUG("Sending Tunnel PAC");
+
+ pac.key.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_KEY);
+ pac.key.hdr.length = htons(sizeof(pac.key.data));
+ rad_assert(sizeof(pac.key.data) % sizeof(uint32_t) == 0);
+ RANDFILL(pac.key.data);
+
+ pac.info.lifetime.hdr.type = htons(PAC_INFO_PAC_LIFETIME);
+ pac.info.lifetime.hdr.length = htons(sizeof(pac.info.lifetime.data));
+ pac.info.lifetime.data = htonl(time(NULL) + t->pac_lifetime);
+
+ pac.info.a_id.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_A_ID);
+ pac.info.a_id.hdr.length = htons(sizeof(pac.info.a_id.data));
+ memcpy(pac.info.a_id.data, t->a_id, sizeof(pac.info.a_id.data));
+
+ pac.info.a_id_info.hdr.type = htons(PAC_INFO_A_ID_INFO);
+ pac.info.a_id_info.hdr.length = htons(sizeof(pac.info.a_id_info.data));
+ #define MIN(a,b) (((a)>(b)) ? (b) : (a))
+ alen = MIN(talloc_array_length(t->authority_identity) - 1, sizeof(pac.info.a_id_info.data));
+ memcpy(pac.info.a_id_info.data, t->authority_identity, alen);
+
+ pac.info.type.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_TYPE);
+ pac.info.type.hdr.length = htons(sizeof(pac.info.type.data));
+ pac.info.type.data = htons(PAC_TYPE_TUNNEL);
+
+ pac.info.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_INFO);
+ pac.info.hdr.length = htons(sizeof(pac.info.lifetime)
+ + sizeof(pac.info.a_id)
+ + sizeof(pac.info.a_id_info)
+ + sizeof(pac.info.type));
+
+ memcpy(&opaque_plaintext.type, &pac.info.type, sizeof(opaque_plaintext.type));
+ memcpy(&opaque_plaintext.lifetime, &pac.info.lifetime, sizeof(opaque_plaintext.lifetime));
+ memcpy(&opaque_plaintext.key, &pac.key, sizeof(opaque_plaintext.key));
+
+
+ rad_assert(PAC_A_ID_LENGTH <= EVP_GCM_TLS_TAG_LEN);
+ memcpy(pac.opaque.aad, t->a_id, PAC_A_ID_LENGTH);
+ rad_assert(RAND_bytes(pac.opaque.iv, sizeof(pac.opaque.iv)) != 0);
+ dlen = eap_fast_encrypt((unsigned const char *)&opaque_plaintext, sizeof(opaque_plaintext),
+ t->a_id, PAC_A_ID_LENGTH, t->pac_opaque_key, pac.opaque.iv,
+ pac.opaque.data, pac.opaque.tag);
+ if (dlen < 0) return;
+
+ pac.opaque.hdr.type = htons(EAP_FAST_TLV_MANDATORY | PAC_INFO_PAC_OPAQUE);
+ pac.opaque.hdr.length = htons(sizeof(pac.opaque) - sizeof(pac.opaque.hdr) - sizeof(pac.opaque.data) + dlen);
+
+ eap_fast_tlv_append(tls_session, EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_PAC, true,
+ sizeof(pac) - sizeof(pac.opaque.data) + dlen, &pac);
+}
+
+static void eap_fast_append_crypto_binding(REQUEST *request, tls_session_t *tls_session)
+{
+ eap_fast_tunnel_t *t = tls_session->opaque;
+ eap_tlv_crypto_binding_tlv_t binding;
+ const int len = sizeof(binding) - (&binding.reserved - (uint8_t *)&binding);
+
+ RDEBUG("Sending Cryptobinding");
+
+ memset(&binding, 0, sizeof(eap_tlv_crypto_binding_tlv_t));
+ binding.tlv_type = htons(EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_CRYPTO_BINDING);
+ binding.length = htons(len);
+ binding.version = EAP_FAST_VERSION;
+ binding.received_version = EAP_FAST_VERSION; /* FIXME use the clients value */
+ binding.subtype = EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
+
+ rad_assert(sizeof(binding.nonce) % sizeof(uint32_t) == 0);
+ RANDFILL(binding.nonce);
+ binding.nonce[sizeof(binding.nonce) - 1] &= ~0x01; /* RFC 4851 section 4.2.8 */
+
+ fr_hmac_sha1(binding.compound_mac, (uint8_t *)&binding, sizeof(binding), t->cmk, EAP_FAST_CMK_LEN);
+
+ eap_fast_tlv_append(tls_session, EAP_FAST_TLV_CRYPTO_BINDING, true, len, &binding.reserved);
+}
+
+static int eap_fast_verify(REQUEST *request, tls_session_t *tls_session, uint8_t const *data, unsigned int data_len)
+{
+ uint16_t attr;
+ uint16_t length;
+ unsigned int remaining = data_len;
+ int total = 0;
+ int num[EAP_FAST_TLV_MAX] = {0};
+ eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+ uint32_t present = 0;
+
+ rad_assert(sizeof(present) * 8 > EAP_FAST_TLV_MAX);
+
+ while (remaining > 0) {
+ if (remaining < 4) {
+ RDEBUG2("EAP-FAST TLV is too small (%u) to contain a EAP-FAST TLV header", remaining);
+ return 0;
+ }
+
+ memcpy(&attr, data, sizeof(attr));
+ attr = ntohs(attr) & EAP_FAST_TLV_TYPE;
+
+ switch (attr) {
+ case EAP_FAST_TLV_RESULT:
+ case EAP_FAST_TLV_NAK:
+ case EAP_FAST_TLV_ERROR:
+ case EAP_FAST_TLV_VENDOR_SPECIFIC:
+ case EAP_FAST_TLV_EAP_PAYLOAD:
+ case EAP_FAST_TLV_INTERMED_RESULT:
+ case EAP_FAST_TLV_PAC:
+ case EAP_FAST_TLV_CRYPTO_BINDING:
+ num[attr]++;
+ present |= 1 << attr;
+
+ if (num[EAP_FAST_TLV_EAP_PAYLOAD] > 1) {
+ RDEBUG("Too many EAP-Payload TLVs");
+unexpected:
+ for (int i = 0; i < EAP_FAST_TLV_MAX; i++)
+ if (present & (1 << i))
+ RDEBUG(" - attribute %d is present", i);
+ eap_fast_send_error(tls_session, EAP_FAST_ERR_UNEXPECTED_TLV);
+ return 0;
+ }
+
+ if (num[EAP_FAST_TLV_INTERMED_RESULT] > 1) {
+ RDEBUG("Too many Intermediate-Result TLVs");
+ goto unexpected;
+ }
+ break;
+ default:
+ if ((data[0] & 0x80) != 0) {
+ RDEBUG("Unknown mandatory TLV %02x", attr);
+ goto unexpected;
+ }
+
+ num[0]++;
+ }
+
+ total++;
+
+ memcpy(&length, data + 2, sizeof(length));
+ length = ntohs(length);
+
+ data += 4;
+ remaining -= 4;
+
+ if (length > remaining) {
+ RDEBUG2("EAP-FAST TLV %u is longer than room remaining in the packet (%u > %u).", attr,
+ length, remaining);
+ return 0;
+ }
+
+ /*
+ * If the rest of the TLVs are larger than
+ * this attribute, continue.
+ *
+ * Otherwise, if the attribute over-flows the end
+ * of the TLCs, die.
+ */
+ if (remaining < length) {
+ RDEBUG2("EAP-FAST TLV overflows packet!");
+ return 0;
+ }
+
+ /*
+ * If there's an error, we bail out of the
+ * authentication process before allocating
+ * memory.
+ */
+ if ((attr == EAP_FAST_TLV_INTERMED_RESULT) || (attr == EAP_FAST_TLV_RESULT)) {
+ uint16_t status;
+
+ if (length < 2) {
+ RDEBUG("EAP-FAST TLV %u is too short. Expected 2, got %d.", attr, length);
+ return 0;
+ }
+
+ memcpy(&status, data, 2);
+ status = ntohs(status);
+
+ if (status == EAP_FAST_TLV_RESULT_FAILURE) {
+ RDEBUG("EAP-FAST TLV %u indicates failure. Rejecting request.", attr);
+ return 0;
+ }
+
+ if (status != EAP_FAST_TLV_RESULT_SUCCESS) {
+ RDEBUG("EAP-FAST TLV %u contains unknown value. Rejecting request.", attr);
+ goto unexpected;
+ }
+ }
+
+ /*
+ * remaining > length, continue.
+ */
+ remaining -= length;
+ data += length;
+ }
+
+ /*
+ * Check if the peer mixed & matched TLVs.
+ */
+ if ((num[EAP_FAST_TLV_NAK] > 0) && (num[EAP_FAST_TLV_NAK] != total)) {
+ RDEBUG("NAK TLV sent with non-NAK TLVs. Rejecting request.");
+ goto unexpected;
+ }
+
+ if (num[EAP_FAST_TLV_INTERMED_RESULT] > 0 && num[EAP_FAST_TLV_RESULT]) {
+ RDEBUG("NAK TLV sent with non-NAK TLVs. Rejecting request.");
+ goto unexpected;
+ }
+
+ /*
+ * Check mandatory or not mandatory TLVs.
+ */
+ switch (t->stage) {
+ case TLS_SESSION_HANDSHAKE:
+ if (present) {
+ RDEBUG("Unexpected TLVs in TLS Session Handshake stage");
+ goto unexpected;
+ }
+ break;
+ case AUTHENTICATION:
+ if (present != 1 << EAP_FAST_TLV_EAP_PAYLOAD) {
+ RDEBUG("Unexpected TLVs in authentication stage");
+ goto unexpected;
+ }
+ break;
+ case CRYPTOBIND_CHECK:
+ {
+ uint32_t bits = (t->result_final)
+ ? 1 << EAP_FAST_TLV_RESULT
+ : 1 << EAP_FAST_TLV_INTERMED_RESULT;
+ if (present & ~(bits | (1 << EAP_FAST_TLV_CRYPTO_BINDING) | (1 << EAP_FAST_TLV_PAC))) {
+ RDEBUG("Unexpected TLVs in cryptobind checking stage");
+ goto unexpected;
+ }
+ break;
+ }
+ case PROVISIONING:
+ if (present & ~((1 << EAP_FAST_TLV_PAC) | (1 << EAP_FAST_TLV_RESULT))) {
+ RDEBUG("Unexpected TLVs in provisioning stage");
+ goto unexpected;
+ }
+ break;
+ case COMPLETE:
+ if (present) {
+ RDEBUG("Unexpected TLVs in complete stage");
+ goto unexpected;
+ }
+ break;
+ default:
+ RDEBUG("Unexpected stage %d", t->stage);
+ return 0;
+ }
+
+ /*
+ * We got this far. It looks OK.
+ */
+ return 1;
+}
+
+static ssize_t eap_fast_decode_vp(TALLOC_CTX *request, DICT_ATTR const *parent,
+ uint8_t const *data, size_t const attr_len, VALUE_PAIR **out)
+{
+ int8_t tag = TAG_NONE;
+ VALUE_PAIR *vp;
+ uint8_t const *p = data;
+
+ /*
+ * FIXME: Attrlen can be larger than 253 for extended attrs!
+ */
+ if (!parent || !out ) {
+ RERROR("eap_fast_decode_vp: Invalid arguments");
+ return -1;
+ }
+
+ /*
+ * Silently ignore zero-length attributes.
+ */
+ if (attr_len == 0) return 0;
+
+ /*
+ * And now that we've verified the basic type
+ * information, decode the actual p.
+ */
+ vp = fr_pair_afrom_da(request, parent);
+ if (!vp) return -1;
+
+ vp->vp_length = attr_len;
+ vp->tag = tag;
+
+ switch (parent->type) {
+ case PW_TYPE_STRING:
+ fr_pair_value_bstrncpy(vp, p, attr_len);
+ break;
+
+ case PW_TYPE_OCTETS:
+ fr_pair_value_memcpy(vp, p, attr_len);
+ break;
+
+ case PW_TYPE_ABINARY:
+ if (vp->vp_length > sizeof(vp->vp_filter)) {
+ vp->vp_length = sizeof(vp->vp_filter);
+ }
+ memcpy(vp->vp_filter, p, vp->vp_length);
+ break;
+
+ case PW_TYPE_BYTE:
+ vp->vp_byte = p[0];
+ break;
+
+ case PW_TYPE_SHORT:
+ vp->vp_short = (p[0] << 8) | p[1];
+ break;
+
+ case PW_TYPE_INTEGER:
+ memcpy(&vp->vp_integer, p, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ memcpy(&vp->vp_integer64, p, 8);
+ vp->vp_integer64 = ntohll(vp->vp_integer64);
+ break;
+
+ case PW_TYPE_DATE:
+ memcpy(&vp->vp_date, p, 4);
+ vp->vp_date = ntohl(vp->vp_date);
+ break;
+
+ case PW_TYPE_ETHERNET:
+ memcpy(vp->vp_ether, p, 6);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(&vp->vp_ipaddr, p, 4);
+ break;
+
+ case PW_TYPE_IFID:
+ memcpy(vp->vp_ifid, p, 8);
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ memcpy(&vp->vp_ipv6addr, p, 16);
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ /*
+ * FIXME: double-check that
+ * (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
+ */
+ memcpy(vp->vp_ipv6prefix, p, vp->vp_length);
+ if (vp->vp_length < 18) {
+ memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
+ 18 - vp->vp_length);
+ }
+ break;
+
+ case PW_TYPE_IPV4_PREFIX:
+ /* FIXME: do the same double-check as for IPv6Prefix */
+ memcpy(vp->vp_ipv4prefix, p, vp->vp_length);
+
+ /*
+ * /32 means "keep all bits". Otherwise, mask
+ * them out.
+ */
+ if ((p[1] & 0x3f) > 32) {
+ uint32_t addr, mask;
+
+ memcpy(&addr, vp->vp_octets + 2, sizeof(addr));
+ mask = 1;
+ mask <<= (32 - (p[1] & 0x3f));
+ mask--;
+ mask = ~mask;
+ mask = htonl(mask);
+ addr &= mask;
+ memcpy(vp->vp_ipv4prefix + 2, &addr, sizeof(addr));
+ }
+ break;
+
+ case PW_TYPE_SIGNED: /* overloaded with vp_integer */
+ memcpy(&vp->vp_integer, p, 4);
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ default:
+ RERROR("eap_fast_decode_vp: type %d Internal sanity check %d ", parent->type, __LINE__);
+ fr_pair_list_free(&vp);
+ return -1;
+ }
+ vp->type = VT_DATA;
+ *out = vp;
+ return attr_len;
+}
+
+
+VALUE_PAIR *eap_fast_fast2vp(REQUEST *request, SSL *ssl, uint8_t const *data, size_t data_len,
+ DICT_ATTR const *fast_da, vp_cursor_t *out)
+{
+ uint16_t attr;
+ uint16_t length;
+ size_t data_left = data_len;
+ VALUE_PAIR *first = NULL;
+ VALUE_PAIR *vp = NULL;
+ DICT_ATTR const *da;
+
+ if (!fast_da)
+ fast_da = dict_attrbyvalue(PW_FREERADIUS_EAP_FAST_TLV, VENDORPEC_FREERADIUS);
+ rad_assert(fast_da != NULL);
+
+ if (!out) {
+ out = talloc(request, vp_cursor_t);
+ rad_assert(out != NULL);
+ fr_cursor_init(out, &first);
+ }
+
+ /*
+ * Decode the TLVs
+ */
+ while (data_left > 0) {
+ ssize_t decoded;
+
+ /* FIXME do something with mandatory */
+
+ memcpy(&attr, data, sizeof(attr));
+ attr = ntohs(attr) & EAP_FAST_TLV_TYPE;
+
+ memcpy(&length, data + 2, sizeof(length));
+ length = ntohs(length);
+
+ data += 4;
+ data_left -= 4;
+
+ /*
+ * Look up the TLV.
+ *
+ * For now, if it doesn't exist, ignore it.
+ */
+ da = dict_attrbyparent(fast_da, attr, fast_da->vendor);
+ if (!da) {
+ RDEBUG("eap_fast_fast2vp: no sub attribute found %s attr: %u vendor: %u",
+ fast_da->name, attr, fast_da->vendor);
+ goto next_attr;
+ }
+ if (da->type == PW_TYPE_TLV) {
+ eap_fast_fast2vp(request, ssl, data, length, da, out);
+ goto next_attr;
+ }
+ decoded = eap_fast_decode_vp(request, da, data, length, &vp);
+ if (decoded < 0) {
+ RERROR("Failed decoding %s: %s", da->name, fr_strerror());
+ goto next_attr;
+ }
+
+ fr_cursor_merge(out, vp);
+
+ next_attr:
+ while (fr_cursor_next(out)) {
+ /* nothing */
+ }
+
+ data += length;
+ data_left -= length;
+ }
+
+ /*
+ * We got this far. It looks OK.
+ */
+ return first;
+}
+
+
+static void eapfast_copy_request_to_tunnel(REQUEST *request, REQUEST *fake) {
+ VALUE_PAIR *copy, *vp;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * The attribute is a server-side thingy,
+ * don't copy it.
+ */
+ if ((vp->da->attr > 255) && (((vp->da->attr >> 16) & 0xffff) == 0)) {
+ continue;
+ }
+
+ /*
+ * The outside attribute is already in the
+ * tunnel, don't copy it.
+ *
+ * This works for BOTH attributes which
+ * are originally in the tunneled request,
+ * AND attributes which are copied there
+ * from below.
+ */
+ if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) continue;
+
+ /*
+ * Some attributes are handled specially.
+ */
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ /*
+ * NEVER copy Message-Authenticator,
+ * EAP-Message, or State. They're
+ * only for outside of the tunnel.
+ */
+ case PW_USER_NAME:
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_CHAP_CHALLENGE:
+ case PW_PROXY_STATE:
+ case PW_MESSAGE_AUTHENTICATOR:
+ case PW_EAP_MESSAGE:
+ case PW_STATE:
+ continue;
+
+ /*
+ * By default, copy it over.
+ */
+ default:
+ break;
+ }
+
+ /*
+ * Don't copy from the head, we've already
+ * checked it.
+ */
+ copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->attr, vp->da->vendor, TAG_ANY);
+ fr_pair_add(&fake->packet->vps, copy);
+ }
+}
+
+/*
+ * Use a reply packet to determine what to do.
+ */
+static rlm_rcode_t CC_HINT(nonnull) process_reply( eap_handler_t *eap_session,
+ tls_session_t *tls_session,
+ REQUEST *request, RADIUS_PACKET *reply)
+{
+ rlm_rcode_t rcode = RLM_MODULE_REJECT;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ eap_fast_tunnel_t *t = tls_session->opaque;
+
+ rad_assert(eap_session->request == request);
+
+ /*
+ * If the response packet was Access-Accept, then
+ * we're OK. If not, die horribly.
+ *
+ * FIXME: EAP-Messages can only start with 'identity',
+ * NOT 'eap start', so we should check for that....
+ */
+ switch (reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ RDEBUG("Got tunneled Access-Accept");
+ tls_session->authentication_success = true;
+ rcode = RLM_MODULE_OK;
+
+ for (vp = fr_cursor_init(&cursor, &reply->vps); vp; vp = fr_cursor_next(&cursor)) {
+ if (vp->da->vendor != VENDORPEC_MICROSOFT) continue;
+
+ /* FIXME must be a better way to capture/re-derive this later for ISK */
+ switch (vp->da->attr) {
+ case PW_MSCHAP_MPPE_SEND_KEY:
+ if (vp->vp_length != CHAP_VALUE_LENGTH) {
+ wrong_length:
+ REDEBUG("Found %s with incorrect length. Expected %u, got %zu",
+ vp->da->name, 16, vp->vp_length);
+ rcode = RLM_MODULE_INVALID;
+ break;
+ }
+
+
+ memcpy(t->isk.mppe_send, vp->vp_octets, CHAP_VALUE_LENGTH);
+ break;
+
+ case PW_MSCHAP_MPPE_RECV_KEY:
+ if (vp->length != CHAP_VALUE_LENGTH) goto wrong_length;
+
+ memcpy(t->isk.mppe_recv, vp->vp_octets, CHAP_VALUE_LENGTH);
+ break;
+
+ case PW_MSCHAP2_SUCCESS:
+ RDEBUG("Got %s, tunneling it to the client in a challenge", vp->da->name);
+ rcode = RLM_MODULE_HANDLED;
+ if (t->use_tunneled_reply) {
+ t->authenticated = true;
+ /*
+ * Clean up the tunneled reply.
+ */
+ fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+
+ /*
+ * Delete MPPE keys & encryption policy. We don't
+ * want these here.
+ */
+ fr_pair_delete_by_num(&reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ fr_pair_list_free(&t->accept_vps); /* for proxying MS-CHAP2 */
+ fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
+ rad_assert(!reply->vps);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case PW_CODE_ACCESS_REJECT:
+ RDEBUG("Got tunneled Access-Reject");
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ /*
+ * Handle Access-Challenge, but only if we
+ * send tunneled reply data. This is because
+ * an Access-Challenge means that we MUST tunnel
+ * a Reply-Message to the client.
+ */
+ case PW_CODE_ACCESS_CHALLENGE:
+ RDEBUG("Got tunneled Access-Challenge");
+
+ /*
+ * Keep the State attribute, if necessary.
+ *
+ * Get rid of the old State, too.
+ */
+ fr_pair_list_free(&t->state);
+ fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, PW_STATE, 0, TAG_ANY);
+
+ /*
+ * Copy the EAP-Message back to the tunnel.
+ */
+ (void) fr_cursor_init(&cursor, &reply->vps);
+
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY)) != NULL) {
+ eap_fast_tlv_append(tls_session, EAP_FAST_TLV_EAP_PAYLOAD, true, vp->vp_length, vp->vp_octets);
+ }
+
+ rcode = RLM_MODULE_HANDLED;
+ break;
+
+ default:
+ RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
+ rcode = RLM_MODULE_INVALID;
+ break;
+ }
+
+
+ return rcode;
+}
+
+static PW_CODE eap_fast_eap_payload(REQUEST *request, eap_handler_t *eap_session,
+ tls_session_t *tls_session, VALUE_PAIR *tlv_eap_payload)
+{
+ PW_CODE code = PW_CODE_ACCESS_REJECT;
+ rlm_rcode_t rcode;
+ VALUE_PAIR *vp;
+ eap_fast_tunnel_t *t;
+ REQUEST *fake;
+
+ RDEBUG("Processing received EAP Payload");
+
+ /*
+ * Allocate a fake REQUEST structure.
+ */
+ fake = request_alloc_fake(request);
+ rad_assert(!fake->packet->vps);
+
+ t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+ /*
+ * Add the tunneled attributes to the fake request.
+ */
+
+ fake->packet->vps = fr_pair_afrom_num(fake->packet, PW_EAP_MESSAGE, 0);
+ fr_pair_value_memcpy(fake->packet->vps, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length);
+
+ RDEBUG("Got tunneled request");
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
+
+ /*
+ * Tell the request that it's a fake one.
+ */
+ fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+ /*
+ * Update other items in the REQUEST data structure.
+ */
+ fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ fake->password = fr_pair_find_by_num(fake->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+ /*
+ * No User-Name, try to create one from stored data.
+ */
+ if (!fake->username) {
+ /*
+ * No User-Name in the stored data, look for
+ * an EAP-Identity, and pull it out of there.
+ */
+ if (!t->username) {
+ vp = fr_pair_find_by_num(fake->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (vp &&
+ (vp->vp_length >= EAP_HEADER_LEN + 2) &&
+ (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
+ (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
+ (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
+ /*
+ * Create & remember a User-Name
+ */
+ t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
+ rad_assert(t->username != NULL);
+
+ fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);
+
+ RDEBUG("Got tunneled identity of %s", t->username->vp_strvalue);
+ } else {
+ /*
+ * Don't reject the request outright,
+ * as it's permitted to do EAP without
+ * user-name.
+ */
+ RWDEBUG2("No EAP-Identity found to start EAP conversation");
+ }
+ } /* else there WAS a t->username */
+
+ if (t->username) {
+ vp = fr_pair_list_copy(fake->packet, t->username);
+ fr_pair_add(&fake->packet->vps, vp);
+ fake->username = vp;
+ }
+ } /* else the request ALREADY had a User-Name */
+
+ /*
+ * Add the State attribute, too, if it exists.
+ */
+ if (t->state) {
+ vp = fr_pair_list_copy(fake->packet, t->state);
+ if (vp) fr_pair_add(&fake->packet->vps, vp);
+ }
+
+
+ if (t->stage == AUTHENTICATION) { /* FIXME do this only for MSCHAPv2 */
+ VALUE_PAIR *tvp;
+
+ RDEBUG2("AUTHENTICATION");
+ vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ);
+ vp->vp_integer = t->default_method;
+
+ /*
+ * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
+ */
+ if (t->mode == EAP_FAST_PROVISIONING_ANON) {
+ tvp = fr_pair_afrom_num(fake, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
+ fr_pair_value_memcpy(tvp, t->keyblock->server_challenge, CHAP_VALUE_LENGTH);
+ fr_pair_add(&fake->config, tvp);
+
+ tvp = fr_pair_afrom_num(fake, PW_MS_CHAP_PEER_CHALLENGE, 0);
+ fr_pair_value_memcpy(tvp, t->keyblock->client_challenge, CHAP_VALUE_LENGTH);
+ fr_pair_add(&fake->config, tvp);
+ }
+ }
+
+ if (t->copy_request_to_tunnel) {
+ eapfast_copy_request_to_tunnel(request, fake);
+ }
+
+ if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+ fake->server = vp->vp_strvalue;
+
+ } else if (t->virtual_server) {
+ fake->server = t->virtual_server;
+
+ } /* else fake->server == request->server */
+
+ /*
+ * Call authentication recursively, which will
+ * do PAP, CHAP, MS-CHAP, etc.
+ */
+ rad_virtual_server(fake);
+
+ /*
+ * Decide what to do with the reply.
+ */
+ switch (fake->reply->code) {
+ case 0:
+ RDEBUG("No tunneled reply was found, rejecting the user.");
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+
+ default:
+ /*
+ * Returns RLM_MODULE_FOO, and we want to return PW_FOO
+ */
+ rcode = process_reply(eap_session, tls_session, request, fake->reply);
+ switch (rcode) {
+ case RLM_MODULE_REJECT:
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ code = PW_CODE_ACCESS_CHALLENGE;
+ break;
+
+ case RLM_MODULE_OK:
+ code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ default:
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+ break;
+ }
+
+ talloc_free(fake);
+
+ return code;
+}
+
+static PW_CODE eap_fast_crypto_binding(REQUEST *request, UNUSED eap_handler_t *eap_session,
+ tls_session_t *tls_session, eap_tlv_crypto_binding_tlv_t *binding)
+{
+ uint8_t cmac[sizeof(binding->compound_mac)];
+ eap_fast_tunnel_t *t = tls_session->opaque;
+
+ memcpy(cmac, binding->compound_mac, sizeof(cmac));
+ memset(binding->compound_mac, 0, sizeof(binding->compound_mac));
+
+
+ fr_hmac_sha1(binding->compound_mac, (uint8_t *)binding, sizeof(*binding), t->cmk, EAP_FAST_CMK_LEN);
+ if (memcmp(binding->compound_mac, cmac, sizeof(cmac))) {
+ RDEBUG2("Crypto-Binding TLV mis-match");
+ return PW_CODE_ACCESS_REJECT;
+ }
+
+ return PW_CODE_ACCESS_ACCEPT;
+}
+
+
+#define PW_EAP_FAST_TLV_PAC (PW_FREERADIUS_EAP_FAST_TLV | (EAP_FAST_TLV_PAC << 8))
+
+
+
+static PW_CODE eap_fast_process_tlvs(REQUEST *request, eap_handler_t *eap_session,
+ tls_session_t *tls_session, VALUE_PAIR *fast_vps)
+{
+ eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ eap_tlv_crypto_binding_tlv_t *binding = NULL;
+ eap_tlv_crypto_binding_tlv_t my_binding;
+
+ for (vp = fr_cursor_init(&cursor, &fast_vps); vp; vp = fr_cursor_next(&cursor)) {
+ PW_CODE code = PW_CODE_ACCESS_REJECT;
+ char *value;
+ DICT_ATTR const *parent_da = NULL;
+ parent_da = dict_parent(vp->da->attr, vp->da->vendor);
+ if (parent_da == NULL || vp->da->vendor != VENDORPEC_FREERADIUS ||
+ ((vp->da->attr & 0xff) != PW_FREERADIUS_EAP_FAST_TLV)) {
+ value = vp_aprints(request->packet, vp, '"');
+ RDEBUG2("ignoring non-EAP-FAST TLV %s", value);
+ talloc_free(value);
+ continue;
+ }
+
+ switch (parent_da->attr) {
+ case PW_FREERADIUS_EAP_FAST_TLV:
+ switch (vp->da->attr >> 8) {
+ case EAP_FAST_TLV_EAP_PAYLOAD:
+ code = eap_fast_eap_payload(request, eap_session, tls_session, vp);
+ if (code == PW_CODE_ACCESS_ACCEPT)
+ t->stage = CRYPTOBIND_CHECK;
+ break;
+ case EAP_FAST_TLV_RESULT:
+ case EAP_FAST_TLV_INTERMED_RESULT:
+ code = PW_CODE_ACCESS_ACCEPT;
+ t->stage = PROVISIONING;
+ break;
+ case EAP_FAST_TLV_CRYPTO_BINDING:
+ if (!binding && (vp->vp_length >= sizeof(eap_tlv_crypto_binding_tlv_t))) {
+ binding = &my_binding;
+ binding->tlv_type = htons(EAP_FAST_TLV_MANDATORY | EAP_FAST_TLV_CRYPTO_BINDING);
+ binding->length = htons(sizeof(*binding) - 2 * sizeof(uint16_t));
+ memcpy(&my_binding.reserved, vp->vp_octets, sizeof(my_binding) - 4);
+ }
+ continue;
+ default:
+ value = vp_aprints_value(request->packet, vp, '"');
+ RDEBUG2("ignoring unknown %s", value);
+ talloc_free(value);
+ continue;
+ }
+ break;
+ case PW_EAP_FAST_TLV_PAC:
+ switch ( ( vp->da->attr >> 16 )) {
+ case PAC_INFO_PAC_ACK:
+ if (vp->vp_integer == EAP_FAST_TLV_RESULT_SUCCESS) {
+ code = PW_CODE_ACCESS_ACCEPT;
+ t->pac.expires = UINT32_MAX;
+ t->pac.expired = false;
+ t->stage = COMPLETE;
+ }
+ break;
+ case PAC_INFO_PAC_TYPE:
+ if (vp->vp_integer != PAC_TYPE_TUNNEL) {
+ RDEBUG("only able to serve Tunnel PAC's, ignoring request");
+ continue;
+ }
+ t->pac.send = true;
+ continue;
+ default:
+ value = vp_aprints(request->packet, vp, '"');
+ RDEBUG2("ignoring unknown EAP-FAST-PAC-TLV %s", value);
+ talloc_free(value);
+ continue;
+ }
+ break;
+ default:
+ value = vp_aprints(request->packet, vp, '"');
+ RDEBUG2("ignoring EAP-FAST TLV %s", value);
+ talloc_free(value);
+ continue;
+ }
+
+ if (code == PW_CODE_ACCESS_REJECT)
+ return PW_CODE_ACCESS_REJECT;
+ }
+
+ if (binding) {
+ PW_CODE code = eap_fast_crypto_binding(request, eap_session, tls_session, binding);
+ if (code == PW_CODE_ACCESS_ACCEPT) {
+ t->stage = PROVISIONING;
+ }
+ return code;
+ }
+
+ return PW_CODE_ACCESS_ACCEPT;
+}
+
+
+/*
+ * Process the inner tunnel data
+ */
+PW_CODE eap_fast_process(eap_handler_t *eap_session, tls_session_t *tls_session)
+{
+ PW_CODE code;
+ VALUE_PAIR *fast_vps;
+ uint8_t const *data;
+ size_t data_len;
+ eap_fast_tunnel_t *t;
+ REQUEST *request = eap_session->request;
+
+ /*
+ * Just look at the buffer directly, without doing
+ * record_to_buff.
+ */
+ data_len = tls_session->clean_out.used;
+ tls_session->clean_out.used = 0;
+ data = tls_session->clean_out.data;
+
+ t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+ /*
+ * See if the tunneled data is well formed.
+ */
+ if (!eap_fast_verify(request, tls_session, data, data_len)) return PW_CODE_ACCESS_REJECT;
+
+ if (t->stage == TLS_SESSION_HANDSHAKE) {
+ rad_assert(t->mode == EAP_FAST_UNKNOWN);
+
+ char buf[256];
+ if (strstr(SSL_CIPHER_description(SSL_get_current_cipher(tls_session->ssl),
+ buf, sizeof(buf)), "Au=None")) {
+ /* FIXME enforce MSCHAPv2 - RFC 5422 section 3.2.2 */
+ RDEBUG2("Using anonymous provisioning");
+ t->mode = EAP_FAST_PROVISIONING_ANON;
+ t->pac.send = true;
+ } else {
+ if (SSL_session_reused(tls_session->ssl)) {
+ RDEBUG("Session Resumed from PAC");
+ t->mode = EAP_FAST_NORMAL_AUTH;
+ } else {
+ RDEBUG2("Using authenticated provisioning");
+ t->mode = EAP_FAST_PROVISIONING_AUTH;
+ }
+
+ /*
+ * Send a new pac at ~0.6 times the lifetime.
+ */
+ if (!t->pac.expires || t->pac.expired || t->pac.expires < (time(NULL) + (t->pac_lifetime >> 1) + (t->pac_lifetime >> 3))) {
+ t->pac.send = true;
+ }
+ }
+
+ eap_fast_init_keys(request, tls_session);
+
+ eap_fast_send_identity_request(request, tls_session, eap_session);
+
+ t->stage = AUTHENTICATION;
+ return PW_CODE_ACCESS_CHALLENGE;
+ }
+
+ fast_vps = eap_fast_fast2vp(request, tls_session->ssl, data, data_len, NULL, NULL);
+
+ RDEBUG("Got Tunneled FAST TLVs");
+ rdebug_pair_list(L_DBG_LVL_1, request, fast_vps, NULL);
+
+ code = eap_fast_process_tlvs(request, eap_session, tls_session, fast_vps);
+
+ fr_pair_list_free(&fast_vps);
+
+ if (code == PW_CODE_ACCESS_REJECT) return PW_CODE_ACCESS_REJECT;
+
+ switch (t->stage) {
+ case AUTHENTICATION:
+ code = PW_CODE_ACCESS_CHALLENGE;
+ break;
+ case CRYPTOBIND_CHECK:
+ {
+ if (t->mode != EAP_FAST_PROVISIONING_ANON && !t->pac.send)
+ t->result_final = true;
+
+ eap_fast_append_result(tls_session, code);
+
+ eap_fast_update_icmk(request, tls_session, (uint8_t *)&t->isk);
+ eap_fast_append_crypto_binding(request, tls_session);
+
+ code = PW_CODE_ACCESS_CHALLENGE;
+ break;
+ }
+ case PROVISIONING:
+ t->result_final = true;
+
+ eap_fast_append_result(tls_session, code);
+
+ if (t->pac.send) {
+ RDEBUG("Peer requires new PAC");
+ eap_fast_send_pac_tunnel(request, tls_session);
+ code = PW_CODE_ACCESS_CHALLENGE;
+ break;
+ }
+
+ t->stage = COMPLETE;
+ /* fallthrough */
+ case COMPLETE:
+ /*
+ * RFC 5422 section 3.5 - Network Access after EAP-FAST Provisioning
+ */
+ if (t->pac.type && t->pac.expired) {
+ REDEBUG("Rejecting expired PAC.");
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+
+ if (t->mode == EAP_FAST_PROVISIONING_ANON) {
+ REDEBUG("Rejecting unauthenticated provisioning");
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+
+ /*
+ * eap_tls_gen_mppe_keys() is unsuitable for EAP-FAST as Cisco decided
+ * it would be a great idea to flip the recv/send keys around
+ */
+ #define EAPTLS_MPPE_KEY_LEN 32
+ eap_add_reply(request, "MS-MPPE-Recv-Key", t->msk, EAPTLS_MPPE_KEY_LEN);
+ eap_add_reply(request, "MS-MPPE-Send-Key", &t->msk[EAPTLS_MPPE_KEY_LEN], EAPTLS_MPPE_KEY_LEN);
+ eap_add_reply(request, "EAP-MSK", t->msk, EAP_FAST_KEY_LEN);
+ eap_add_reply(request, "EAP-EMSK", t->emsk, EAP_EMSK_LEN);
+
+ break;
+
+ default:
+ RERROR("Internal sanity check failed in EAP-FAST at %d", t->stage);
+ code = PW_CODE_ACCESS_REJECT;
+ }
+
+ return code;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h
new file mode 100644
index 0000000..8a88bd6
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast.h
@@ -0,0 +1,260 @@
+/*
+ * eap_fast.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_FAST_H
+#define _EAP_FAST_H
+
+RCSIDH(eap_fast_h, "$Id$")
+
+#include "eap_tls.h"
+
+#define EAP_FAST_VERSION 1
+
+#define EAP_FAST_KEY_LEN 64
+#define EAP_EMSK_LEN 64
+#define EAP_FAST_SKS_LEN 40
+#define EAP_FAST_SIMCK_LEN 40
+#define EAP_FAST_CMK_LEN 20
+
+#define EAP_FAST_TLV_MANDATORY 0x8000
+#define EAP_FAST_TLV_TYPE 0x3fff
+
+#define EAP_FAST_FATAL_ERROR 2000
+#define EAP_FAST_ERR_TUNNEL_COMPROMISED 2001
+#define EAP_FAST_ERR_UNEXPECTED_TLV 2002
+
+#define EAP_FAST_TLV_RESULT_SUCCESS 1
+#define EAP_FAST_TLV_RESULT_FAILURE 2
+
+typedef enum eap_fast_stage_t {
+ TLS_SESSION_HANDSHAKE = 0,
+ AUTHENTICATION,
+ CRYPTOBIND_CHECK,
+ PROVISIONING,
+ COMPLETE
+} eap_fast_stage_t;
+
+typedef enum eap_fast_auth_type {
+ EAP_FAST_UNKNOWN = 0,
+ EAP_FAST_PROVISIONING_ANON,
+ EAP_FAST_PROVISIONING_AUTH,
+ EAP_FAST_NORMAL_AUTH
+} eap_fast_auth_type_t;
+
+typedef enum eap_fast_pac_info_attr_type_t {
+ PAC_INFO_PAC_KEY = 1, // 1
+ PAC_INFO_PAC_OPAQUE, // 2
+ PAC_INFO_PAC_LIFETIME, // 3
+ PAC_INFO_A_ID, // 4
+ PAC_INFO_I_ID, // 5
+ PAC_INFO_PAC_RESERVED6, // 6
+ PAC_INFO_A_ID_INFO, // 7
+ PAC_INFO_PAC_ACK, // 8
+ PAC_INFO_PAC_INFO, // 9
+ PAC_INFO_PAC_TYPE, // 10
+ PAC_INFO_MAX
+} eap_fast_pac_info_attr_type_t;
+
+typedef enum eap_fast_pac_type_t {
+ PAC_TYPE_TUNNEL = 1, // 1
+ PAC_TYPE_MACHINE_AUTH, // 2
+ PAC_TYPE_USER_AUTHZ, // 3
+ PAC_TYPE_MAX
+} eap_fast_pac_type_t;
+
+#define PAC_KEY_LENGTH 32
+#define PAC_A_ID_LENGTH 16
+#define PAC_I_ID_LENGTH 16
+#define PAC_A_ID_INFO_LENGTH 32
+
+typedef struct eap_fast_pac_attr_hdr_t {
+ uint16_t type;
+ uint16_t length;
+} CC_HINT(__packed__) eap_fast_pac_attr_hdr_t;
+
+typedef struct eap_fast_pac_attr_lifetime_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint32_t data; // secs since epoch
+} CC_HINT(__packed__) eap_fast_pac_attr_lifetime_t;
+
+typedef struct eap_fast_pac_attr_a_id_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint8_t data[PAC_A_ID_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_a_id_t;
+
+typedef struct eap_fast_pac_attr_i_id_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint8_t data[PAC_I_ID_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_i_id_t;
+
+typedef struct eap_fast_pac_attr_a_id_info_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint8_t data[PAC_A_ID_INFO_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_a_id_info_t;
+
+typedef struct eap_fast_pac_attr_pac_type_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint16_t data;
+} CC_HINT(__packed__) eap_fast_pac_attr_pac_type_t;
+
+typedef struct eap_fast_pac_attr_pac_key_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ uint8_t data[PAC_KEY_LENGTH];
+} CC_HINT(__packed__) eap_fast_pac_attr_pac_key_t;
+
+typedef struct eap_fast_attr_pac_opaque_plaintext_t {
+ eap_fast_pac_attr_pac_type_t type;
+ eap_fast_pac_attr_lifetime_t lifetime;
+ eap_fast_pac_attr_pac_key_t key;
+} CC_HINT(__packed__) eap_fast_attr_pac_opaque_plaintext_t;
+
+typedef struct eap_fast_attr_pac_opaque_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ unsigned char aad[PAC_A_ID_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char tag[EVP_GCM_TLS_TAG_LEN];
+ uint8_t data[sizeof(eap_fast_attr_pac_opaque_plaintext_t) * 2]; // space for EVP
+} CC_HINT(__packed__) eap_fast_attr_pac_opaque_t;
+
+typedef struct eap_fast_attr_pac_info_t {
+ eap_fast_pac_attr_hdr_t hdr;
+ eap_fast_pac_attr_lifetime_t lifetime;
+ eap_fast_pac_attr_a_id_t a_id;
+ eap_fast_pac_attr_a_id_info_t a_id_info;
+ eap_fast_pac_attr_pac_type_t type;
+} CC_HINT(__packed__) eap_fast_attr_pac_info_t;
+
+typedef struct eap_fast_pac_t {
+ eap_fast_pac_attr_pac_key_t key;
+ eap_fast_attr_pac_info_t info;
+ eap_fast_attr_pac_opaque_t opaque; // has to be last!
+} CC_HINT(__packed__) eap_fast_pac_t;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+typedef struct eap_tlv_crypto_binding_tlv_t {
+ uint16_t tlv_type;
+ uint16_t length;
+ uint8_t reserved;
+ uint8_t version;
+ uint8_t received_version;
+ uint8_t subtype;
+ uint8_t nonce[32];
+ uint8_t compound_mac[20];
+} CC_HINT(__packed__) eap_tlv_crypto_binding_tlv_t;
+
+typedef enum eap_fast_tlv_type_t {
+ EAP_FAST_TLV_RESERVED_0 = 0, // 0
+ EAP_FAST_TLV_RESERVED_1, // 1
+ EAP_FAST_TLV_RESERVED_2, // 2
+ EAP_FAST_TLV_RESULT, // 3
+ EAP_FAST_TLV_NAK, // 4
+ EAP_FAST_TLV_ERROR, // 5
+ EAP_FAST_TLV_RESERVED6, // 6
+ EAP_FAST_TLV_VENDOR_SPECIFIC, // 7
+ EAP_FAST_TLV_RESERVED8, // 8
+ EAP_FAST_TLV_EAP_PAYLOAD, // 9
+ EAP_FAST_TLV_INTERMED_RESULT, // 10
+ EAP_FAST_TLV_PAC, // 11
+ EAP_FAST_TLV_CRYPTO_BINDING, // 12
+ EAP_FAST_TLV_RESERVED_13, // 13
+ EAP_FAST_TLV_RESERVED_14, // 14
+ EAP_FAST_TLV_RESERVED_15, // 15
+ EAP_FAST_TLV_RESERVED_16, // 16
+ EAP_FAST_TLV_RESERVED_17, // 17
+ EAP_FAST_TLV_TRUSTED_ROOT, // 18
+ EAP_FAST_TLV_REQ_ACTION, // 19
+ EAP_FAST_TLV_PKCS, // 20
+ EAP_FAST_TLV_MAX
+} eap_fast_tlv_type_t;
+
+typedef enum eap_fast_tlv_crypto_binding_tlv_subtype_t {
+ EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST = 0, // 0
+ EAP_FAST_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE // 1
+} eap_fast_tlv_crypto_binding_tlv_subtype_t;
+
+/* RFC 5422: Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange */
+typedef struct eap_fast_keyblock_t {
+ uint8_t session_key_seed[EAP_FAST_SKS_LEN];
+ uint8_t server_challenge[CHAP_VALUE_LENGTH];
+ uint8_t client_challenge[CHAP_VALUE_LENGTH];
+} CC_HINT(__packed__) eap_fast_keyblock_t;
+
+typedef struct eap_fast_tunnel_t {
+ VALUE_PAIR *username;
+ VALUE_PAIR *state;
+ VALUE_PAIR *accept_vps;
+ bool copy_request_to_tunnel;
+ bool use_tunneled_reply;
+
+ bool authenticated;
+
+ int mode;
+ eap_fast_stage_t stage;
+ eap_fast_keyblock_t *keyblock;
+ uint8_t *simck;
+ uint8_t *cmk;
+ int imckc;
+ struct {
+ uint8_t mppe_send[CHAP_VALUE_LENGTH];
+ uint8_t mppe_recv[CHAP_VALUE_LENGTH];
+ } CC_HINT(__packed__) isk;
+ uint8_t *msk;
+ uint8_t *emsk;
+
+ int default_method;
+
+ uint32_t pac_lifetime;
+ char const *authority_identity;
+ uint8_t const *a_id;
+ uint8_t const *pac_opaque_key;
+
+ struct {
+ uint8_t *key;
+ eap_fast_pac_type_t type;
+ uint32_t expires;
+ bool expired;
+ bool send;
+ } pac;
+
+ bool result_final;
+
+#ifdef WITH_PROXY
+ bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated
+ //!< protocol.
+#endif
+ char const *virtual_server;
+} eap_fast_tunnel_t;
+
+/*
+ * Process the FAST portion of an EAP-FAST request.
+ */
+void eap_fast_tlv_append(tls_session_t *tls_session, int tlv, bool mandatory,
+ int length, const void *data) CC_HINT(nonnull);
+PW_CODE eap_fast_process(eap_handler_t *eap_session, tls_session_t *tls_session) CC_HINT(nonnull);
+
+/*
+ * A bunch of EAP-FAST helper functions.
+ */
+VALUE_PAIR *eap_fast_fast2vp(REQUEST *request, UNUSED SSL *ssl, uint8_t const *data,
+ size_t data_len, DICT_ATTR const *fast_da, vp_cursor_t *out);
+
+#endif /* _EAP_FAST_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c
new file mode 100644
index 0000000..e386e70
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.c
@@ -0,0 +1,198 @@
+/*
+ * fast-crypto.c Cryptographic functions for EAP-FAST.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2016 Alan DeKok <aland@freeradius.org>
+ * Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <stdio.h>
+#include <freeradius-devel/libradius.h>
+
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/err.h>
+
+#include "eap_fast_crypto.h"
+
+# define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
+
+static void debug_errors(void)
+{
+ unsigned long errCode;
+
+ while((errCode = ERR_get_error())) {
+ char *err = ERR_error_string(errCode, NULL);
+ DEBUG("EAP-FAST error in OpenSSL - %s", err);
+ }
+}
+
+// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode
+int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
+ uint8_t const *aad, size_t aad_len,
+ uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
+ uint8_t *tag)
+{
+ EVP_CIPHER_CTX *ctx;
+
+ int len;
+
+ int ciphertext_len;
+
+
+ /* Create and initialise the context */
+ if (!(ctx = EVP_CIPHER_CTX_new())) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Initialise the encryption operation. */
+ if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Set IV length if default 12 bytes (96 bits) is not appropriate */
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Initialise key and IV */
+ if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Provide any AAD data. This can be called zero or more times as
+ * required
+ */
+ if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Provide the message to be encrypted, and obtain the encrypted output.
+ * EVP_EncryptUpdate can be called multiple times if necessary
+ */
+ if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
+ debug_errors();
+ return -1;
+ };
+ ciphertext_len = len;
+
+ /* Finalise the encryption. Normally ciphertext bytes may be written at
+ * this stage, but this does not occur in GCM mode
+ */
+ if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
+ debug_errors();
+ return -1;
+ };
+ ciphertext_len += len;
+
+ /* Get the tag */
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Clean up */
+ EVP_CIPHER_CTX_free(ctx);
+
+ return ciphertext_len;
+}
+
+int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
+ uint8_t const *aad, size_t aad_len,
+ uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext)
+{
+ EVP_CIPHER_CTX *ctx;
+ int len;
+ int plaintext_len;
+ int ret;
+
+ /* Create and initialise the context */
+ if (!(ctx = EVP_CIPHER_CTX_new())) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Initialise the decryption operation. */
+ if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Initialise key and IV */
+ if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Provide any AAD data. This can be called zero or more times as
+ * required
+ */
+ if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) {
+ debug_errors();
+ return -1;
+ };
+
+ /* Provide the message to be decrypted, and obtain the plaintext output.
+ * EVP_DecryptUpdate can be called multiple times if necessary
+ */
+ if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) {
+ debug_errors();
+ return -1;
+ };
+ plaintext_len = len;
+
+ {
+ unsigned char *tmp;
+
+ memcpy(&tmp, &tag, sizeof(tmp));
+
+ /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tmp)) {
+ debug_errors();
+ return -1;
+ };
+ }
+
+ /* Finalise the decryption. A positive return value indicates success,
+ * anything else is a failure - the plaintext is not trustworthy.
+ */
+ ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+
+ /* Clean up */
+ EVP_CIPHER_CTX_free(ctx);
+
+ if (ret < 0) return -1;
+
+ /* Success */
+ plaintext_len += len;
+ return plaintext_len;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h
new file mode 100644
index 0000000..d00e9a2
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/eap_fast_crypto.h
@@ -0,0 +1,39 @@
+/*
+ * eap_fast_crypto.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+#ifndef _EAP_FAST_CRYPTO_H
+#define _EAP_FAST_CRYPTO_H
+
+RCSIDH(eap_fast_crypto_h, "$Id$")
+
+
+int eap_fast_encrypt(uint8_t const *plaintext, size_t plaintext_len,
+ uint8_t const *aad, size_t aad_len,
+ uint8_t const *key, uint8_t *iv, unsigned char *ciphertext,
+ uint8_t *tag);
+
+int eap_fast_decrypt(uint8_t const *ciphertext, size_t ciphertext_len,
+ uint8_t const *aad, size_t aad_len,
+ uint8_t const *tag, uint8_t const *key, uint8_t const *iv, uint8_t *plaintext);
+
+#endif /* _EAP_FAST_CRYPTO_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c b/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
new file mode 100644
index 0000000..093dc86
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_fast/rlm_eap_fast.c
@@ -0,0 +1,659 @@
+/*
+ * rlm_eap_fast.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2016 Alan DeKok <aland@freeradius.org>
+ * Copyright 2016 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+
+#include "eap_fast.h"
+#include "eap_fast_crypto.h"
+
+
+#include <freeradius-devel/md5.h>
+
+/*
+ * An instance of EAP-FAST
+ */
+typedef struct rlm_eap_fast_t {
+ char const *tls_conf_name; //!< Name of shared TLS config.
+ fr_tls_server_conf_t *tls_conf;
+
+ char const *default_method_name;
+ int default_method;
+
+ char const *virtual_server; //!< Virtual server to use for processing
+ //!< inner EAP method.
+ char const *cipher_list; //!< cipher list specific to EAP-FAST
+ bool req_client_cert; //!< Whether we require a client cert
+ //!< in the outer tunnel.
+
+ int stage; //!< Processing stage.
+
+ uint32_t pac_lifetime; //!< seconds to add to current time to describe PAC lifetime
+ char const *authority_identity; //!< The identity we present in the EAP-TLS
+ uint8_t a_id[PAC_A_ID_LENGTH]; //!< The identity we present in the EAP-TLS
+ char const *pac_opaque_key; //!< The key used to encrypt PAC-Opaque
+ bool use_tunneled_reply; //!< Use the reply attributes from the tunneled session in
+ //!< the non-tunneled reply to the client.
+
+ bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the
+} rlm_eap_fast_t;
+
+
+static CONF_PARSER module_config[] = {
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, tls_conf_name), NULL },
+
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, default_method_name), "mschapv2" },
+
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_NOT_EMPTY, rlm_eap_fast_t, virtual_server) , NULL},
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_fast_t, cipher_list) , NULL},
+
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, req_client_cert), "no" },
+
+ { "pac_lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_fast_t, pac_lifetime), "604800" },
+ { "authority_identity", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, authority_identity), NULL },
+ { "pac_opaque_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_eap_fast_t, pac_opaque_key), NULL },
+ { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, copy_request_to_tunnel), "no" },
+
+ { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_fast_t, use_tunneled_reply), "no" },
+
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_fast_t *inst;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_fast_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ if (!cf_section_sub_find_name2(main_config.config, "server", inst->virtual_server)) {
+ ERROR("rlm_eap_fast.virtual_server: Unknown virtual server '%s'", inst->virtual_server);
+ return -1;
+ }
+
+ inst->default_method = eap_name2type(inst->default_method_name);
+ if (!inst->default_method) {
+ ERROR("rlm_eap_fast.default_provisioning_eap_type: "
+ "Unknown EAP type %s",
+ inst->default_method_name);
+ return -1;
+ }
+
+ /*
+ * Read tls configuration, either from group given by 'tls'
+ * option, or from the eap-tls configuration.
+ */
+ inst->tls_conf = eaptls_conf_parse(cs, "tls");
+
+ if (!inst->tls_conf) {
+ ERROR("rlm_eap_fast.tls: Failed initializing SSL context");
+ return -1;
+ }
+
+ if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) {
+ ERROR("rlm_eap_fast.pac_opaque_key: Must be 32 bytes long");
+ return -1;
+ }
+
+ if (!inst->pac_lifetime) {
+ ERROR("rlm_eap_fast.pac_lifetime: must be non-zero");
+ return -1;
+ }
+
+#ifdef TLS1_3_VERSION
+ if (inst->tls_conf->min_version == TLS1_3_VERSION) {
+ ERROR("There are no standards for using TLS 1.3 with EAP-FAST.");
+ ERROR("You MUST enable TLS 1.2 for EAP-FAST to work.");
+ return -1;
+ }
+
+ if ((inst->tls_conf->max_version == TLS1_3_VERSION) ||
+ (inst->tls_conf->min_version == TLS1_3_VERSION)) {
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! There is no standard for using EAP-FAST with TLS 1.3");
+ WARN("!! Please set tls_max_version = \"1.2\"");
+ WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows");
+ WARN("!! This limitation is likely to change in late 2021.");
+ WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+#endif
+
+ rad_assert(PAC_A_ID_LENGTH == MD5_DIGEST_LENGTH);
+ FR_MD5_CTX ctx;
+ fr_md5_init(&ctx);
+ fr_md5_update(&ctx, inst->authority_identity, talloc_array_length(inst->authority_identity) - 1);
+ fr_md5_final(inst->a_id, &ctx);
+
+ return 0;
+}
+
+/** Allocate the FAST per-session data
+ *
+ */
+static eap_fast_tunnel_t *eap_fast_alloc(TALLOC_CTX *ctx, rlm_eap_fast_t *inst)
+{
+ eap_fast_tunnel_t *t = talloc_zero(ctx, eap_fast_tunnel_t);
+
+ t->mode = EAP_FAST_UNKNOWN;
+ t->stage = TLS_SESSION_HANDSHAKE;
+
+ t->default_method = inst->default_method;
+ t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
+ t->use_tunneled_reply = inst->use_tunneled_reply;
+
+ t->pac_lifetime = inst->pac_lifetime;
+ t->authority_identity = inst->authority_identity;
+ t->a_id = inst->a_id;
+ t->pac_opaque_key = (const uint8_t *)inst->pac_opaque_key;
+
+ t->virtual_server = inst->virtual_server;
+
+ return t;
+}
+
+static void eap_fast_session_ticket(tls_session_t *tls_session, uint8_t *client_random,
+ uint8_t *server_random, uint8_t *secret, int *secret_len)
+{
+ eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+ uint8_t seed[2 * SSL3_RANDOM_SIZE];
+
+ rad_assert(t->pac.key);
+
+ memcpy(seed, server_random, SSL3_RANDOM_SIZE);
+ memcpy(&seed[SSL3_RANDOM_SIZE], client_random, SSL3_RANDOM_SIZE);
+
+ T_PRF(t->pac.key, PAC_KEY_LENGTH, "PAC to master secret label hash",
+ seed, sizeof(seed), secret, SSL_MAX_MASTER_KEY_LENGTH);
+ *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+}
+
+// hostap:src/crypto/tls_openssl.c:tls_sess_sec_cb()
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+static int _session_secret(SSL *s, void *secret, int *secret_len,
+ UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
+ UNUSED SSL_CIPHER **cipher, void *arg)
+#else
+static int _session_secret(SSL *s, void *secret, int *secret_len,
+ UNUSED STACK_OF(SSL_CIPHER) *peer_ciphers,
+ UNUSED const SSL_CIPHER **cipher, void *arg)
+#endif
+{
+ // FIXME enforce non-anon cipher
+
+ REQUEST *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
+ tls_session_t *tls_session = arg;
+ eap_fast_tunnel_t *t;
+
+ if (!tls_session) return 0;
+
+ t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+ if (!t->pac.key) return 0;
+
+ RDEBUG("processing PAC-Opaque");
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+ eap_fast_session_ticket(tls_session, s->s3->client_random, s->s3->server_random, secret, secret_len);
+#else
+ uint8_t client_random[SSL3_RANDOM_SIZE];
+ uint8_t server_random[SSL3_RANDOM_SIZE];
+
+ SSL_get_client_random(s, client_random, sizeof(client_random));
+ SSL_get_server_random(s, server_random, sizeof(server_random));
+
+ eap_fast_session_ticket(tls_session, client_random, server_random, secret, secret_len);
+#endif
+
+ memset(t->pac.key, 0, PAC_KEY_LENGTH);
+ talloc_free(t->pac.key);
+ t->pac.key = NULL;
+
+ return 1;
+}
+
+/*
+ * hints from hostap:src/crypto/tls_openssl.c:tls_session_ticket_ext_cb()
+ *
+ * N.B. we actually always tell OpenSSL we have digested the ticket so that
+ * it does not cause a fail loop and enables us to update the PAC easily
+ *
+ */
+static int _session_ticket(SSL *s, uint8_t const *data, int len, void *arg)
+{
+ tls_session_t *tls_session = arg;
+ REQUEST *request = (REQUEST *)SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST);
+ eap_fast_tunnel_t *t;
+ VALUE_PAIR *fast_vps = NULL;
+ vp_cursor_t cursor;
+ DICT_ATTR const *fast_da;
+ char const *errmsg;
+ int dlen, plen;
+ int length;
+ eap_fast_attr_pac_opaque_t const *opaque = (eap_fast_attr_pac_opaque_t const *) data;
+ eap_fast_attr_pac_opaque_t opaque_plaintext;
+
+ if (!tls_session) return 0;
+
+ t = (eap_fast_tunnel_t *) tls_session->opaque;
+
+ RDEBUG("PAC provided via ClientHello SessionTicket extension");
+
+ if ((ntohs(opaque->hdr.type) & EAP_FAST_TLV_TYPE) != PAC_INFO_PAC_OPAQUE) {
+ errmsg = "PAC is not of type Opaque";
+error:
+ RERROR("%s, sending alert to client", errmsg);
+ /*
+ if (tls_session_handshake_alert(request, tls_session, SSL3_AL_FATAL, SSL_AD_BAD_CERTIFICATE)) {
+ RERROR("too many alerts");
+ return 0;
+ }
+ */
+ if (t->pac.key) talloc_free(t->pac.key);
+
+ memset(&t->pac, 0, sizeof(t->pac));
+ if (fast_vps) fr_pair_list_free(&fast_vps);
+ return 1;
+ }
+
+ /*
+ * we would like to use the length of the SessionTicket
+ * but Cisco hates everyone and sends a zero padding payload
+ * so we have to use the length in the PAC-Opaque header
+ */
+ length = ntohs(opaque->hdr.length);
+ if (len < (int) (length + sizeof(opaque->hdr))) {
+ errmsg = "PAC has bad length in header";
+ goto error;
+ }
+
+ if (length < PAC_A_ID_LENGTH + EVP_MAX_IV_LENGTH + EVP_GCM_TLS_TAG_LEN + 1) {
+ errmsg = "PAC file too short";
+ goto error;
+ }
+
+ if (memcmp(opaque->aad, t->a_id, PAC_A_ID_LENGTH)) {
+ errmsg = "PAC has incorrect A_ID";
+ goto error;
+ }
+
+ dlen = length - sizeof(opaque->aad) - sizeof(opaque->iv) - sizeof(opaque->tag);
+ plen = eap_fast_decrypt(opaque->data, dlen, opaque->aad, PAC_A_ID_LENGTH,
+ (uint8_t const *) opaque->tag, t->pac_opaque_key, opaque->iv,
+ (uint8_t *)&opaque_plaintext);
+ if (plen < 0) {
+ errmsg = "PAC failed to decrypt";
+ goto error;
+ }
+
+ fast_da = dict_attrbyname("FreeRADIUS-EAP-FAST-PAC-Opaque-TLV");
+ rad_assert(fast_da != NULL);
+
+ fast_vps = eap_fast_fast2vp((REQUEST *)tls_session, s, (uint8_t *)&opaque_plaintext, plen, fast_da, NULL);
+ if (!fast_vps) return 0;
+
+ for (VALUE_PAIR *vp = fr_cursor_init(&cursor, &fast_vps); vp; vp = fr_cursor_next(&cursor)) {
+ char *value;
+
+ switch ((vp->da->attr >> fr_attr_shift[3]) & fr_attr_mask[3]) {
+ case PAC_INFO_PAC_TYPE:
+ rad_assert(t->pac.type == 0);
+ t->pac.type = vp->vp_integer;
+ break;
+ case PAC_INFO_PAC_LIFETIME:
+ rad_assert(t->pac.expires == 0);
+ t->pac.expires = vp->vp_integer + time(NULL);
+ t->pac.expired = false;
+ break;
+ case PAC_INFO_PAC_KEY:
+ rad_assert(t->pac.key == NULL);
+ rad_assert(vp->vp_length == PAC_KEY_LENGTH);
+ t->pac.key = talloc_size(t, PAC_KEY_LENGTH);
+ rad_assert(t->pac.key != NULL);
+ memcpy(t->pac.key, vp->vp_octets, PAC_KEY_LENGTH);
+ break;
+ default:
+ value = vp_aprints(tls_session, vp, '"');
+ RERROR("unknown TLV: %s", value);
+ talloc_free(value);
+ errmsg = "unknown TLV";
+ goto error;
+ }
+ }
+
+ fr_pair_list_free(&fast_vps);
+
+ if (!t->pac.type) {
+ errmsg = "PAC missing type TLV";
+ goto error;
+ }
+
+ if (t->pac.type != PAC_TYPE_TUNNEL) {
+ errmsg = "PAC is of not of tunnel type";
+ goto error;
+ }
+
+ if (!t->pac.expires) {
+ errmsg = "PAC missing lifetime TLV";
+ goto error;
+ }
+
+ if (!t->pac.key) {
+ errmsg = "PAC missing key TLV";
+ goto error;
+ }
+
+ if (!SSL_set_session_secret_cb(tls_session->ssl, _session_secret, tls_session)) {
+ RERROR("Failed setting SSL session secret callback");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Do authentication, by letting EAP-TLS do most of the work.
+ */
+static int mod_process(void *arg, eap_handler_t *handler)
+{
+ int rcode;
+ int ret = 0;
+ fr_tls_status_t status;
+ rlm_eap_fast_t *inst = (rlm_eap_fast_t *) arg;
+ tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+ eap_fast_tunnel_t *t = (eap_fast_tunnel_t *) tls_session->opaque;
+ REQUEST *request = handler->request;
+
+ RDEBUG2("Authenticate");
+
+ /*
+ * We need FAST data associated with the session, so
+ * allocate it here, if it wasn't already alloacted.
+ */
+ if (!t) t = tls_session->opaque = eap_fast_alloc(tls_session, inst);
+
+ /*
+ * Process TLS layer until done.
+ */
+ status = eaptls_process(handler);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+
+ /*
+ * Make request available to any SSL callbacks
+ */
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
+ switch (status) {
+ /*
+ * EAP-TLS handshake was successful, tell the
+ * client to keep talking.
+ *
+ * If this was EAP-TLS, we would just return
+ * an EAP-TLS-Success packet here.
+ */
+ case FR_TLS_SUCCESS:
+ tls_handshake_send(request, tls_session);
+ rad_assert(t != NULL);
+ break;
+
+ /*
+ * The TLS code is still working on the TLS
+ * exchange, and it's a valid TLS request.
+ * do nothing.
+ */
+ case FR_TLS_HANDLED:
+ ret = 1;
+ goto done;
+
+ /*
+ * Handshake is done, proceed with decoding tunneled
+ * data.
+ */
+ case FR_TLS_OK:
+ break;
+
+ /*
+ * Anything else: fail.
+ */
+ default:
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Session is established, proceed with decoding
+ * tunneled data.
+ */
+ RDEBUG2("Session established. Proceeding to decode tunneled attributes");
+
+ /*
+ * Process the FAST portion of the request.
+ */
+ rcode = eap_fast_process(handler, tls_session);
+
+ switch (rcode) {
+ case PW_CODE_ACCESS_REJECT:
+ RDEBUG("Reject");
+ eaptls_fail(handler, EAP_FAST_VERSION);
+ ret = 0;
+ goto done;
+
+ /*
+ * Access-Challenge, continue tunneled conversation.
+ */
+ case PW_CODE_ACCESS_CHALLENGE:
+ RDEBUG("Challenge");
+ tls_handshake_send(request, tls_session);
+ eaptls_request(handler->eap_ds, tls_session);
+ ret = 1;
+ goto done;
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ case PW_CODE_ACCESS_ACCEPT:
+ if (t->accept_vps) {
+ RDEBUG2("Using saved attributes from the original Access-Accept");
+ rdebug_pair_list(L_DBG_LVL_2, request, t->accept_vps, NULL);
+ fr_pair_list_mcopy_by_num(handler->request->reply,
+ &handler->request->reply->vps,
+ &t->accept_vps, 0, 0, TAG_ANY);
+ } else if (t->use_tunneled_reply) {
+ RDEBUG2("No saved attributes in the original Access-Accept");
+ }
+ ret = eaptls_success(handler, EAP_FAST_VERSION);
+ goto done;
+
+ /*
+ * No response packet, MUST be proxying it.
+ * The main EAP module will take care of discovering
+ * that the request now has a "proxy" packet, and
+ * will proxy it, rather than returning an EAP packet.
+ */
+ case PW_CODE_STATUS_CLIENT:
+#ifdef WITH_PROXY
+ rad_assert(handler->request->proxy != NULL);
+#endif
+ ret = 1;
+ goto done;
+
+ default:
+ break;
+ }
+
+ /*
+ * Something we don't understand: Reject it.
+ */
+ eaptls_fail(handler, EAP_FAST_VERSION);
+
+done:
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
+
+ return ret;
+}
+
+static int eap_fast_tls_start(EAP_DS * eap_ds,tls_session_t *tls_session)
+{
+ EAPTLS_PACKET reply;
+
+ reply.code = FR_TLS_START;
+ reply.length = TLS_HEADER_LEN + 1 + tls_session->clean_in.used;/*flags*/
+
+ reply.flags = tls_session->peap_flag;
+ reply.flags = SET_START(reply.flags);
+
+ reply.data = tls_session->clean_in.data;
+ reply.dlen = tls_session->clean_in.used;
+
+ eaptls_compose(eap_ds, &reply);
+
+ return 1;
+}
+
+
+/*
+ * Send an initial eap-tls request to the peer, using the libeap functions.
+ */
+static int mod_session_init(void *type_arg, eap_handler_t *handler)
+{
+ int rcode;
+ tls_session_t *tls_session;
+ rlm_eap_fast_t *inst;
+ VALUE_PAIR *vp;
+ bool client_cert;
+ REQUEST *request = handler->request;
+
+ inst = type_arg;
+
+ handler->tls = true;
+
+ /*
+ * EAP-TLS-Require-Client-Cert attribute will override
+ * the require_client_cert configuration option.
+ */
+ vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
+ if (vp) {
+ client_cert = vp->vp_integer ? true : false;
+ } else {
+ client_cert = inst->req_client_cert;
+ }
+
+ /*
+ * Don't allow TLS 1.3 for us, even if it's allowed
+ * elsewhere. We haven't implemented the necessary
+ * changes, so we don't allow it.
+ */
+ handler->opaque = tls_session = eaptls_session(handler, inst->tls_conf, client_cert, false);
+
+ if (!tls_session) return 0;
+
+ if (inst->cipher_list) {
+ RDEBUG("Over-riding main cipher list with '%s'", inst->cipher_list);
+
+ if (!SSL_set_cipher_list(tls_session->ssl, inst->cipher_list)) {
+ REDEBUG("Failed over-riding cipher list to '%s'. EAP-FAST will likely not work",
+ inst->cipher_list);
+ }
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ {
+ int i;
+ for (i = 0; ; i++) {
+ const char *cipher = SSL_get_cipher_list(tls_session->ssl, i);
+ if (!cipher) break;
+ if (!strstr(cipher, "ADH-")) continue;
+ RDEBUG("Setting security level to 0 to allow anonymous cipher suites");
+ SSL_set_security_level(tls_session->ssl, 0);
+ break;
+ }
+ }
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_3
+ /*
+ * Forcibly disable TLSv1.3
+ *
+ * TLSv1.3 does not support opaque session tickets, which
+ * are needed for EAP-FAST.
+ */
+ SSL_set_options(tls_session->ssl, SSL_OP_NO_TLSv1_3);
+#endif
+
+ /*
+ * Push TLV of authority_identity into tls_record
+ * call eap_tls_compose() with args
+ *
+ * RFC 4851 section 4.1.1
+ * N.B. mandatory/reserved flags are not applicable here
+ */
+ eap_fast_tlv_append(tls_session, PAC_INFO_A_ID, false, PAC_A_ID_LENGTH, inst->a_id);
+ tls_session->peap_flag = EAP_FAST_VERSION;
+ tls_session->length_flag = false;
+ rcode = eap_fast_tls_start(handler->eap_ds, tls_session);
+
+ if (rcode < 0) {
+ error:
+ talloc_free(tls_session);
+ return 0;
+ }
+
+ tls_session->record_init(&tls_session->clean_in);
+
+ if (!SSL_set_session_ticket_ext_cb(tls_session->ssl, _session_ticket, tls_session)) {
+ RERROR("Failed setting SSL session ticket callback");
+ goto error;
+ }
+
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_fast;
+rlm_eap_module_t rlm_eap_fast = {
+ .name = "eap_fast",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_gtc/README.md b/src/modules/rlm_eap/types/rlm_eap_gtc/README.md
new file mode 100644
index 0000000..d608462
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_gtc/README.md
@@ -0,0 +1,12 @@
+# rlm_eap_gtc
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 3748](https://tools.ietf.org/html/rfc3748) EAP-GTC authentication. EAP-GTC allows EAP authentication
+using a plaintext password.
+
+Does not provide keying material for 802.11i, so cannot be used for WPA/2-Enterprise authentication unless wrapped
+in another method such as EAP-TTLS.
diff --git a/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk b/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk
new file mode 100644
index 0000000..26f2eb0
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_gtc/all.mk
@@ -0,0 +1,12 @@
+TARGETNAME := rlm_eap_gtc
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS :=
+TGT_LDLIBS :=
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c b/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c
new file mode 100644
index 0000000..031eba2
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_gtc/rlm_eap_gtc.c
@@ -0,0 +1,250 @@
+/*
+ * rlm_eap_gtc.c Handles that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "eap.h"
+
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * EAP-GTC is just ASCII data carried inside of the EAP session.
+ * The length of the data is indicated by the encapsulating EAP
+ * protocol.
+ */
+typedef struct rlm_eap_gtc_t {
+ char const *challenge;
+ char const *auth_type_name;
+ int auth_type;
+} rlm_eap_gtc_t;
+
+static CONF_PARSER module_config[] = {
+ { "challenge", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, challenge), "Password: " },
+ { "auth_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, auth_type_name), "PAP" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+
+/*
+ * Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_gtc_t *inst;
+ DICT_VALUE *dval;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_gtc_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ if (inst->auth_type_name && *inst->auth_type_name) {
+ dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name);
+ if (!dval) {
+ ERROR("rlm_eap_gtc: Unknown Auth-Type %s",
+ inst->auth_type_name);
+ return -1;
+ }
+
+ inst->auth_type = dval->value;
+ } else {
+ inst->auth_type = PW_AUTH_TYPE_LOCAL;
+ }
+ return 0;
+}
+
+/*
+ * Initiate the EAP-GTC session by sending a challenge to the peer.
+ */
+static int mod_session_init(void *instance, eap_handler_t *handler)
+{
+ char challenge_str[1024];
+ int length;
+ EAP_DS *eap_ds = handler->eap_ds;
+ rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
+
+ if (radius_xlat(challenge_str, sizeof(challenge_str), handler->request, inst->challenge, NULL, NULL) < 0) {
+ return 0;
+ }
+
+ length = strlen(challenge_str);
+
+ /*
+ * We're sending a request...
+ */
+ eap_ds->request->code = PW_EAP_REQUEST;
+
+ eap_ds->request->type.data = talloc_array(eap_ds->request,
+ uint8_t, length);
+ if (!eap_ds->request->type.data) {
+ return 0;
+ }
+
+ memcpy(eap_ds->request->type.data, challenge_str, length);
+ eap_ds->request->type.length = length;
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+
+/*
+ * Authenticate a previously sent challenge.
+ */
+static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler)
+{
+ VALUE_PAIR *vp;
+ EAP_DS *eap_ds = handler->eap_ds;
+ rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
+ REQUEST *request = handler->request;
+
+ /*
+ * Get the Cleartext-Password for this user.
+ */
+ rad_assert(handler->stage == PROCESS);
+
+ /*
+ * Sanity check the response. We need at least one byte
+ * of data.
+ */
+ if (eap_ds->response->length <= 4) {
+ ERROR("rlm_eap_gtc: corrupted data");
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+ }
+
+#if 0
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ int i;
+
+ for (i = 0; i < eap_ds->response->length - 4; i++) {
+ if ((i & 0x0f) == 0) fprintf(fr_log_fp, "%d: ", i);
+
+ fprintf(fr_log_fp, "%02x ", eap_ds->response->type.data[i]);
+
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ }
+#endif
+
+ /*
+ * Handle passwords here.
+ */
+ if (inst->auth_type == PW_AUTH_TYPE_LOCAL) {
+ /*
+ * For now, do cleartext password authentication.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG2("Cleartext-Password is required for authentication");
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+ }
+
+ if (eap_ds->response->type.length != vp->vp_length) {
+ REDEBUG2("Passwords are of different length. %u %u", (unsigned) eap_ds->response->type.length, (unsigned) vp->vp_length);
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+ }
+
+ if (memcmp(eap_ds->response->type.data,
+ vp->vp_strvalue, vp->vp_length) != 0) {
+ REDEBUG2("Passwords are different");
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+ }
+
+ /*
+ * EAP packets can be ~64k long maximum, and
+ * we don't like that.
+ */
+ } else if (eap_ds->response->type.length <= 128) {
+ int rcode;
+
+ /*
+ * If there was a User-Password in the request,
+ * why the heck are they using EAP-GTC?
+ */
+ fr_pair_delete_by_num(&request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+ vp = pair_make_request("User-Password", NULL, T_OP_EQ);
+ if (!vp) {
+ return 0;
+ }
+
+ fr_pair_value_bstrncpy(vp, eap_ds->response->type.data, eap_ds->response->type.length);
+
+ /*
+ * Add the password to the request, and allow
+ * another module to do the work of authenticating it.
+ */
+ request->password = vp;
+
+ /*
+ * This is a wild & crazy hack.
+ */
+ rcode = process_authenticate(inst->auth_type, request);
+ if (rcode != RLM_MODULE_OK) {
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+ }
+
+ } else {
+ ERROR("rlm_eap_gtc: Response is too large to understand");
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 0;
+
+ }
+
+ eap_ds->request->code = PW_EAP_SUCCESS;
+
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_gtc;
+rlm_eap_module_t rlm_eap_gtc = {
+ .name = "eap_gtc",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore b/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/README.md b/src/modules/rlm_eap/types/rlm_eap_ikev2/README.md
new file mode 100644
index 0000000..9f80791
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/README.md
@@ -0,0 +1,11 @@
+# rlm_eap_ikev2
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements the EAP-IKEv2 authentication method based on the Internet
+Key Exchange Protocol version 2 (IKEv2), as specified in
+[draft-tschofenig-eap-ikev2-12](https://datatracker.ietf.org/doc/html/draft-tschofenig-eap-ikev2-12).
+Not compatible with RFC 5106 and should not be used.
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in
new file mode 100644
index 0000000..40ba9e7
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/all.mk.in
@@ -0,0 +1,13 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c logging_impl.c ike_conf.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_cflags@
+TGT_LDLIBS += $(LIBS)
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/configure b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure
new file mode 100755
index 0000000..e125aa6
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure
@@ -0,0 +1,4206 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap_ikev2.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap_ikev2
+with_eap_ikev2_include_dir
+with_eap_ikev2_lib_dir
+with_eap_ikev2_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap_ikev2 build without rlm_eap_ikev2
+ --with-eap-ikev2-include-dir=DIR
+ Directory where the eap-ikev2 includes may be found
+ --with-eap-ikev2-lib-dir=DIR
+ Directory where the eap-ikev2 libraries may be found
+ --with-eap-ikev2-dir=DIR
+ Base directory where eap-ikev2 is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap_ikev2
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap_ikev2 was given.
+if test "${with_rlm_eap_ikev2+set}" = set; then :
+ withval=$with_rlm_eap_ikev2;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap_ikev2" != xno; then
+
+
+eap_ikev2_include_dir=
+
+# Check whether --with-eap-ikev2-include-dir was given.
+if test "${with_eap_ikev2_include_dir+set}" = set; then :
+ withval=$with_eap_ikev2_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-ikev2-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+eap_ikev2_lib_dir=
+
+# Check whether --with-eap-ikev2-lib-dir was given.
+if test "${with_eap_ikev2_lib_dir+set}" = set; then :
+ withval=$with_eap_ikev2_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-ikev2-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-eap-ikev2-dir was given.
+if test "${with_eap_ikev2_dir+set}" = set; then :
+ withval=$with_eap_ikev2_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-ikev2-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_lib_dir="$withval/lib"
+ eap_ikev2_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL support" >&5
+$as_echo_n "checking for OpenSSL support... " >&6; }
+if test "x$OPENSSL_LIBS" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fail="$fail OpenSSL"
+
+fi
+
+
+smart_try_dir="$eap_ikev2_include_dir"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "EAPIKEv2/connector.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+ for _dir in $smart_try_dir; do
+ _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+ done
+
+ for _dir in $smart_include_dir; do
+ _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+ done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EAPIKEv2/connector.h in $try" >&5
+$as_echo_n "checking for EAPIKEv2/connector.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EAPIKEv2/connector.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/EAPIKEv2/connector.h" >&5
+$as_echo_n "checking for ${_prefix}/EAPIKEv2/connector.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EAPIKEv2/connector.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem ${_prefix}/"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EAPIKEv2/connector.h" >&5
+$as_echo_n "checking for EAPIKEv2/connector.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EAPIKEv2/connector.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EAPIKEv2/connector.h in $try" >&5
+$as_echo_n "checking for EAPIKEv2/connector.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EAPIKEv2/connector.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "x$ac_cv_header_EAPIKEv2_connector_h" != "xyes"; then
+
+fail="$fail EAPIKEv2/connector.h"
+
+fi
+
+
+LIBS="${OPENSSL_LIBS}"
+smart_try_dir="$eap_ikev2_lib_dir"
+
+
+sm_lib_safe=`echo "eap-ikev2" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ikev2_set_log_callback" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2 in $try" >&5
+$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2 in $try... " >&6; }
+ LIBS="-leap-ikev2 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ikev2_set_log_callback();
+int
+main ()
+{
+ikev2_set_log_callback()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-leap-ikev2"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2" >&5
+$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2... " >&6; }
+ LIBS="-leap-ikev2 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ikev2_set_log_callback();
+int
+main ()
+{
+ikev2_set_log_callback()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-leap-ikev2"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ikev2_set_log_callback in -leap-ikev2 in $try" >&5
+$as_echo_n "checking for ikev2_set_log_callback in -leap-ikev2 in $try... " >&6; }
+ LIBS="-leap-ikev2 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ikev2_set_log_callback();
+int
+main ()
+{
+ikev2_set_log_callback()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-leap-ikev2"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_eap_ikev2_ikev2_set_log_callback" != "xyes"; then
+
+fail="$fail libeap-ikev2"
+
+fi
+
+
+ targetname=rlm_eap_ikev2
+else
+ targetname=
+ echo \*\*\* module rlm_eap_ikev2 is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap_ikev2 to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_ikev2." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap_ikev2." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_ikev2 requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap_ikev2 requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldfags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac
new file mode 100644
index 0000000..6c01056
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/configure.ac
@@ -0,0 +1,99 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap_ikev2.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap_ikev2])
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-eap-ikev2-include-dir=DIR
+eap_ikev2_include_dir=
+AC_ARG_WITH(eap-ikev2-include-dir,
+ [AS_HELP_STRING([--with-eap-ikev2-include-dir=DIR],
+ [Directory where the eap-ikev2 includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-ikev2-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-eap-ikev2-lib-dir=DIR
+eap_ikev2_lib_dir=
+AC_ARG_WITH(eap-ikev2-lib-dir,
+ [AS_HELP_STRING([--with-eap-ikev2-lib-dir=DIR],
+ [Directory where the eap-ikev2 libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-ikev2-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-eap-ikev2-dir=DIR
+AC_ARG_WITH(eap-ikev2-dir,
+ [AS_HELP_STRING([--with-eap-ikev2-dir=DIR],
+ [Base directory where eap-ikev2 is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-ikev2-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_ikev2_lib_dir="$withval/lib"
+ eap_ikev2_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for OpenSSL support
+dnl ############################################################
+
+AC_MSG_CHECKING(for OpenSSL support)
+if test "x$OPENSSL_LIBS" != "x"; then
+ AC_MSG_RESULT(yes)
+else
+ AC_MSG_RESULT(no)
+ FR_MODULE_FAIL([OpenSSL])
+fi
+
+dnl ############################################################
+dnl # Check for eap-ikev2 includes
+dnl ############################################################
+
+smart_try_dir="$eap_ikev2_include_dir"
+FR_SMART_CHECK_INCLUDE([EAPIKEv2/connector.h])
+if test "x$ac_cv_header_EAPIKEv2_connector_h" != "xyes"; then
+ FR_MODULE_FAIL([EAPIKEv2/connector.h])
+fi
+
+dnl ############################################################
+dnl # Check for eap-ikev2 library
+dnl ############################################################
+
+LIBS="${OPENSSL_LIBS}"
+smart_try_dir="$eap_ikev2_lib_dir"
+FR_SMART_CHECK_LIB([eap-ikev2],[ikev2_set_log_callback])
+if test "x$ac_cv_lib_eap_ikev2_ikev2_set_log_callback" != "xyes"; then
+ FR_MODULE_FAIL([libeap-ikev2])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldfags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c
new file mode 100644
index 0000000..dda4f67
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.c
@@ -0,0 +1,420 @@
+/*
+ * ike_conf.c - module config loading functions
+ *
+ * This file is part of rlm_eap_ikev2 freeRADIUS module which implements
+ * EAP-IKEv2 protocol functionality.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
+ * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
+ * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
+ * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
+ * Copyright 1999-2007 The FreeRADIUS server project
+ *
+ */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "ike_conf.h"
+#include "eap.h"
+#include "logging_impl.h"
+
+static int rad_load_transforms(struct Protocol *prot,CONF_SECTION *cf);
+
+struct config_transform
+{
+ char const *name;
+ u_int8_t type;
+ int exist_flag;
+};
+
+enum {
+ OPT_INTEGRITY = 0x01,
+ OPT_PRF = 0x02,
+ OPT_ENCRYPTION = 0x04,
+ OPT_DHGROUP = 0x08,
+ OPT_NEEDED = OPT_INTEGRITY | OPT_PRF | OPT_ENCRYPTION | OPT_DHGROUP
+
+};
+
+static struct config_transform config_transforms[] =
+{
+ {"integrity", IKEv2_TRT_INTEGRITY_ALGORITHM, OPT_INTEGRITY},
+ {"prf", IKEv2_TRT_PSEUDO_RANDOM_FUNCTION, OPT_PRF},
+ {"encryption", IKEv2_TRT_ENCRYPTION_ALGORITHM, OPT_ENCRYPTION},
+ {"dhgroup", IKEv2_TRT_DIFFIE_HELLMAN_GROUP, OPT_DHGROUP },
+ {NULL, 0, 0} /* end of list */
+
+};
+
+/*
+ * Copied from rlm_files, and NOT under the same copyright
+ * as the rest of the module!
+ *
+ * Also, it is UNNECESSARY to read the "users" file here!
+ * Doing this shows a misunderstanding of how the server works.
+ */
+int getusersfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list, char const *compat_mode_str)
+{
+ int rcode;
+ PAIR_LIST *users = NULL;
+
+ rcode = pairlist_read(ctx, filename, &users, 1);
+ if (rcode < 0) {
+ return -1;
+ }
+
+ /*
+ * Walk through the 'users' file list, if we're debugging,
+ * or if we're in compat_mode.
+ */
+ if ((rad_debug_lvl) ||
+ (strcmp(compat_mode_str, "cistron") == 0)) {
+ PAIR_LIST *entry;
+ VALUE_PAIR *vp;
+ bool compat_mode = false;
+
+ if (strcmp(compat_mode_str, "cistron") == 0) {
+ compat_mode = true;
+ }
+
+ entry = users;
+ while (entry) {
+ if (compat_mode) {
+ DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...",
+ filename, entry->lineno,
+ entry->name);
+ }
+
+ /*
+ * Look for improper use of '=' in the
+ * check items. They should be using
+ * '==' for on-the-wire RADIUS attributes,
+ * and probably ':=' for server
+ * configuration items.
+ */
+ for (vp = entry->check; vp != NULL; vp = vp->next) {
+ /*
+ * Ignore attributes which are set
+ * properly.
+ */
+ if (vp->op != T_OP_EQ) {
+ continue;
+ }
+
+ /*
+ * If it's a vendor attribute,
+ * or it's a wire protocol,
+ * ensure it has '=='.
+ */
+ if ((vp->da->vendor!= 0) ||
+ (vp->da->attr < 0x100)) {
+ if (!compat_mode) {
+ WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
+ filename, entry->lineno,
+ vp->da->name, vp->da->name,
+ entry->name);
+ } else {
+ DEBUG("\tChanging '%s =' to '%s =='",
+ vp->da->name, vp->da->name);
+ }
+ vp->op = T_OP_CMP_EQ;
+ continue;
+ }
+
+ /*
+ * Cistron Compatibility mode.
+ *
+ * Re-write selected attributes
+ * to be '+=', instead of '='.
+ *
+ * All others get set to '=='
+ */
+ if (compat_mode) {
+ /*
+ * Non-wire attributes become +=
+ *
+ * On the write attributes
+ * become ==
+ */
+ if ((vp->da->attr >= 0x100) &&
+ (vp->da->attr <= 0xffff) &&
+ (vp->da->attr != PW_HINT) &&
+ (vp->da->attr != PW_HUNTGROUP_NAME)) {
+ DEBUG("\tChanging '%s =' to '%s +='",
+ vp->da->name, vp->da->name);
+ vp->op = T_OP_ADD;
+ } else {
+ DEBUG("\tChanging '%s =' to '%s =='",
+ vp->da->name, vp->da->name);
+ vp->op = T_OP_CMP_EQ;
+ }
+ }
+
+ } /* end of loop over check items */
+
+
+ /*
+ * Look for server configuration items
+ * in the reply list.
+ *
+ * It's a common enough mistake, that it's
+ * worth doing.
+ */
+ for (vp = entry->reply; vp != NULL; vp = vp->next) {
+ /*
+ * If it's NOT a vendor attribute,
+ * and it's NOT a wire protocol
+ * and we ignore Fall-Through,
+ * then bitch about it, giving a
+ * good warning message.
+ */
+ if ((vp->da->vendor == 0) &&
+ (vp->da->attr > 1000)) {
+ WARN("[%s]:%d Check item \"%s\"\n"
+ "\tfound in reply item list for user \"%s\".\n"
+ "\tThis attribute MUST go on the first line"
+ " with the other check items",
+ filename, entry->lineno, vp->da->name, entry->name);
+ }
+ }
+
+ entry = entry->next;
+ }
+ }
+
+ *pair_list = users;
+ return 0;
+}
+
+/**
+ * Load all proposals from 'propsals' subsection
+ */
+
+int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf)
+{
+ rad_assert(i2!=NULL && cf!=NULL);
+
+ CONF_SECTION *cf_prop=NULL;
+ cf=cf_subsection_find_next(cf,NULL,"proposals");
+ if(!cf) {
+ ERROR(IKEv2_LOG_PREFIX "Can't find proposals section");
+ return -1;
+ }
+ int nprop=0;
+ for(
+ cf_prop=cf_subsection_find_next(cf,NULL,"proposal");
+ cf_prop;
+ cf_prop=cf_subsection_find_next(cf,cf_prop,"proposal")
+ ) {
+ nprop++;
+ struct Proposal *prop;
+ struct Protocol *prot;
+ prop=AddProposal(&i2->suppProp);
+ prot=AddProtocol(prop,IKEv2_PID_IKE_SA,0,0);
+ if(rad_load_transforms(prot,cf_prop)) {
+ ERROR(IKEv2_LOG_PREFIX "Failed to load proposal (%d)",
+ nprop);
+ return -1;
+ }
+ }
+ if(!nprop) {
+ ERROR(IKEv2_LOG_PREFIX "Can't find any proposal");
+ return -1;
+ }
+ return 0;
+
+}
+
+
+
+/**
+ * Load transforms from protocol subsection
+ */
+
+static int rad_load_transforms(struct Protocol *prot, CONF_SECTION *cf)
+{
+ CONF_PAIR *cp;
+ int option_exists = 0;
+ int i = 0;
+
+ rad_assert(prot);
+ rad_assert(cf);
+
+ DEBUG(IKEv2_LOG_PREFIX "Begin load transforms");
+
+ while(config_transforms[i].name)
+ {
+ uint8_t id;
+ uint16_t keylen;
+
+ for(cp = cf_pair_find(cf,config_transforms[i].name);
+ cp;
+ cp = cf_pair_find_next(cf,cp,config_transforms[i].name)) {
+ if (TransformFromName(cf_pair_value(cp),config_transforms[i].type,&id,&keylen)) {
+ ERROR(IKEv2_LOG_PREFIX "Unsupported %s transform: %s ",
+ config_transforms[i].name,cf_pair_value(cp));
+ return -1;
+ }
+
+ if (!AddTransform(prot,config_transforms[i].type,id,keylen)) {
+ ERROR(IKEv2_LOG_PREFIX "Problem with transform %s:%s",
+ config_transforms[i].name,cf_pair_value(cp));
+ return -1;
+ }
+ option_exists |= config_transforms[i].exist_flag;
+ }
+ i++;
+ }
+
+ if ((option_exists & OPT_NEEDED) != OPT_NEEDED) {
+ ERROR(IKEv2_LOG_PREFIX "Not all mandatory transforms are set properly");
+ DEBUG(IKEv2_LOG_PREFIX "Option flags: 0x%02X",option_exists);
+
+ return -1;
+ }
+ return 0;
+}
+
+
+void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
+ int default_client_authtype)
+{
+ rad_assert(list && id);
+
+ char *ike_id;
+ char *secret = NULL;
+ int id_type = 0;
+ int authtype = default_client_authtype;
+ VALUE_PAIR *vp;
+
+ memcpy(&ike_id, &id, sizeof(id));
+
+ if (!items) {
+ AddSharedSec(list, 0, ike_id, NULL, default_client_authtype);
+
+ return;
+ }
+
+ //idtype
+ vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_IDTYPE, 0, TAG_ANY);
+ if (!vp) {
+ DEBUG(IKEv2_LOG_PREFIX "[%s] -- Id type not set", id);
+ } else {
+ id_type = vp->vp_integer;
+ if (!id_type) {
+ DEBUG(IKEv2_LOG_PREFIX "[%s] -- Not valid id type", id);
+ }
+ }
+
+ //secret
+ vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_SECRET, 0, TAG_ANY);
+ if (!vp || !vp->vp_length) {
+ DEBUG(IKEv2_LOG_PREFIX "[%s] -- Secret not set", id);
+ } else {
+ memcpy(&secret, &vp->vp_strvalue, sizeof(secret));
+ }
+
+ //authtype
+ vp = fr_pair_find_by_num(items, RAD_EAP_IKEV2_AUTHTYPE, 0, TAG_ANY);
+ if (vp && vp->vp_length) {
+ authtype = AuthtypeFromName(vp->vp_strvalue);
+
+ if (authtype == -1) {
+ ERROR(IKEv2_LOG_PREFIX "Unsupported 'EAP-IKEv2-AuthType' value (%s),using 'both'",
+ vp->vp_strvalue);
+ authtype = IKEv2_AUTH_BOTH;
+ }
+
+ }
+
+ AddSharedSec(list, id_type, ike_id, secret, authtype);
+}
+
+/**
+ * load user credentials from raddb/users (read directly from users file)
+ */
+
+int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name)
+{
+ rad_assert(i2 && filename && authtype_name);
+ int authtype;
+
+ authtype=AuthtypeFromName(authtype_name);
+ if(authtype==-1) {
+ ERROR(IKEv2_LOG_PREFIX "Unsupported 'default_auth_type' value (%s), using both",authtype_name);
+ authtype=IKEv2_AUTH_BOTH;
+ }
+
+ PAIR_LIST *users=NULL;
+ if(getusersfile(ctx, filename,&users,"no")!=0) {
+ ERROR(IKEv2_LOG_PREFIX "Error while loading %s userfile",filename);
+ return -1;
+ }
+ PAIR_LIST *tusers=users;
+ while(tusers) {
+ if(strcmp(tusers->name,"DEFAULT")) {
+ rad_update_shared_seclist(&i2->sslist,tusers->name,tusers->check,authtype);
+ }
+ tusers=tusers->next;
+ }
+ pairlist_free(&users);
+ //print sslist
+// struct sharedSecList *sslist=i2->sslist;
+// while(sslist) {
+// ERROR("sslist:id=%s",sslist->id);
+// ERROR("sslist:idlen=%d",sslist->idlen);
+// ERROR("sslist:pwd=%s",sslist->pwd);
+// ERROR("sslist:pwdlen=%d",sslist->pwdlen);
+// ERROR("sslist:idtype= %d",sslist->idtype);
+// ERROR("sslist:authtype=%d",sslist->authtype);
+// sslist=sslist->next;
+// }
+ return 0;
+
+
+}
+
+int rad_get_authtype(char* authtype_name)
+{
+ rad_assert(authtype_name);
+ if(!strcmp(authtype_name,"cert")) {
+ DEBUG(IKEv2_LOG_PREFIX "Using server auth type: cert");
+ return IKEv2_AUTH_CERT;
+ }
+ if(!strcmp(authtype_name,"secret")) {
+ DEBUG(IKEv2_LOG_PREFIX "Using server auth type: secret");
+ return IKEv2_AUTH_SK;
+ }
+ AUTH(IKEv2_LOG_PREFIX "Unsupported server auth type: %s",authtype_name);
+ AUTH(IKEv2_LOG_PREFIX "Using server auth type: secret (default)");
+ return IKEv2_AUTH_SK;
+}
+
+int file_exists(char *filename)
+{
+ int result=0;
+ FILE *fp=fopen(filename,"r");
+ if(fp) {
+ result=1;
+ fclose(fp);
+ }
+ return result;
+}
+
+
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h
new file mode 100644
index 0000000..ee2561c
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/ike_conf.h
@@ -0,0 +1,48 @@
+/*
+ * ike_conf.h - module config loading functions
+ *
+ * This file is part of rlm_eap_ikev2 freeRADIUS module which implements
+ * EAP-IKEv2 protocol functionality.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
+ * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
+ * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
+ * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
+ *
+ */
+
+#ifndef IKE_CONF_H
+#define IKE_CONF_H
+
+#include <EAPIKEv2/connector.h>
+#include "eap.h"
+
+#define RAD_EAP_IKEV2_IDTYPE 1103
+#define RAD_EAP_IKEV2_ID 1104
+#define RAD_EAP_IKEV2_SECRET 1105
+#define RAD_EAP_IKEV2_AUTHTYPE 1106
+
+
+int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf);
+int rad_load_credentials(TALLOC_CTX *ctx, ikev2_ctx *i2,char *filename,char *authtype_name);
+int getusersfile(TALLOC_CTX *ctx, char const *filename, PAIR_LIST **pair_list,char const *compat_mode_str);
+void rad_update_shared_seclist(struct sharedSecList **list, char const *id, VALUE_PAIR *items,
+ int default_client_authtype);
+int rad_get_authtype(char *authtype_name);
+int rad_get_client_authtype(char const *authtype);
+int file_exists(char *filename);
+#endif //IKE_CONF_H
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c
new file mode 100644
index 0000000..d618b6f
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.c
@@ -0,0 +1,52 @@
+/*
+ * logging_impl.c - logging callback for lib-eapikev2
+ *
+ * This file is part of rlm_eap_ikev2 freeRADIUS module which implements
+ * EAP-IKEv2 protocol functionality.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
+ * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
+ * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
+ * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
+ *
+ */
+
+#include <freeradius-devel/radiusd.h>
+#include "logging_impl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <EAPIKEv2/logging.h>
+
+void vxlogf(int iklevel, char const * fmt,va_list ap)
+{
+ int level;
+ switch (iklevel) {
+ case I2L_DBG:
+ level=L_DBG;
+ break;
+ case I2L_INFO:
+ level=L_INFO;
+ break;
+ case I2L_ERR:
+ level=L_ERR;
+ break;
+ default:
+ level=L_DBG;
+
+ }
+ vradlog(level, fmt, ap);
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h
new file mode 100644
index 0000000..923cd04
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/logging_impl.h
@@ -0,0 +1,35 @@
+/*
+ * logging_impl.c - logging callback for lib-eapikev2
+ *
+ * This file is part of rlm_eap_ikev2 freeRADIUS module which implements
+ * EAP-IKEv2 protocol functionality.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
+ * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
+ * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
+ * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
+ *
+ */
+
+#ifndef LOGGING_IMPL_H
+#define LOGGING_IMPL_H
+#include <stdarg.h>
+
+#define IKEv2_LOG_PREFIX " rlm_eap_ikev2: "
+
+void CC_HINT(format (printf, 2, 0)) vxlogf(int iklevel, char const * fmt, va_list ap);
+#endif //LOGGING_IMPL_H
diff --git a/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c b/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c
new file mode 100644
index 0000000..9733632
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ikev2/rlm_eap_ikev2.c
@@ -0,0 +1,526 @@
+/*
+ * rlm_eap_ikev2.c - Handles that are called from eap
+ *
+ * This file is part of rlm_eap_ikev2 freeRADIUS module which implements
+ * EAP-IKEv2 protocol functionality.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2005-2006 Krzysztof Rzecki <krzysztof.rzecki@ccns.pl>
+ * Copyright (C) 2005-2006 Rafal Mijal <rafal.mijal@ccns.pl>
+ * Copyright (C) 2005-2006 Piotr Marnik <piotr.marnik@ccns.pl>
+ * Copyright (C) 2005-2006 Pawel Matejski <pawel.matejski@ccns.pl>
+ * Copyright 1999-2007 The FreeRADIUS server project
+ *
+ */
+
+#include <freeradius-devel/radiusd.h>
+#include "eap.h"
+
+#include <assert.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "logging_impl.h"
+#include <EAPIKEv2/connector.h>
+#include "ike_conf.h"
+
+typedef enum {
+ PW_IKEV2_CHALLENGE = 1,
+ PW_IKEV2_RESPONSE,
+ PW_IKEV2_SUCCESS,
+ PW_IKEV2_FAILURE,
+ PW_IKEV2_MAX_CODES
+} pw_ikev2_code;
+
+#define IKEV2_HEADER_LEN 4
+#define IKEV2_MPPE_KEY_LEN 32
+
+typedef struct rlm_eap_ikev2 {
+ char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate
+ //!< the certificate the server presents).
+
+ char const *tls_private_key_file; //!< Sets the path to the private key for our public
+ //!< certificate.
+ char const *tls_private_key_password; //!< Sets the path to the private key for our public
+ //!< certificate.
+
+ char const *tls_certificate_file; //!< Sets the path to the public certificate file we present
+ //!< to the servers.
+ char const *tls_crl;
+
+ char const *id;
+ uint32_t max_fragment_size;
+ uint32_t dh_counter_max;
+
+ char const *default_auth_type;
+ char const *users_file_name;
+ char const *server_auth_type;
+ char const *server_id_type;
+ bool send_cert_request;
+
+ uint32_t fast_expire;
+
+ bool enable_fast_dhex;
+ bool enable_fast_reconnect;
+} rlm_eap_ikev2_t;
+
+CONF_PARSER module_config[] = {
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_ca_file), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_file), NULL },
+ { "private_key_password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_private_key_password), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_certificate_file), NULL },
+ { "crl_file", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, tls_crl), NULL },
+
+ { "id", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, id), NULL },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, max_fragment_size), IKEv2_DEFAULT_MAX_FRAGMENT_SIZE_STR },
+ { "dh_counter_max", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, dh_counter_max), IKEv2_DEFAULT_DH_COUNTER_MAX_STR },
+ { "default_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, default_auth_type), "both" },
+ { "usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_eap_ikev2_t, users_file_name),"${confdir}/users" },
+ { "server_authtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_auth_type), "secret" },
+ { "idtype", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ikev2_t, server_id_type), IKEv2_DEFAULT_IDTYPE_STR },
+ { "certreq", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, send_cert_request), "no" },
+ { "fast_timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_eap_ikev2_t, fast_expire), "900" },
+
+ { "fast_dh_exchange", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_dhex), "no" },
+ { "enable_fast_reauth", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ikev2_t, enable_fast_reconnect), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int set_mppe_keys(eap_handler_t *handler)
+{
+ uint8_t const *p;
+ struct IKEv2Session *session;
+
+ session = ((struct IKEv2Data*)handler->opaque)->session;
+
+ if (session->eapKeyData==NULL){
+ INFO(IKEv2_LOG_PREFIX "Key session not available!!!");
+ return 1;
+ }
+
+ p = session->eapKeyData;
+ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, IKEV2_MPPE_KEY_LEN);
+ p += IKEV2_MPPE_KEY_LEN;
+ eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, IKEV2_MPPE_KEY_LEN);
+ return 0;
+}
+
+/** Compose Radius like message from table of output bytes
+ *
+ */
+static int compose_rad_message(uint8_t *out,u_int32_t olen, EAP_DS *eap_ds) {
+ int len;
+
+ eap_ds->request->type.num = PW_EAP_IKEV2;
+ eap_ds->request->code = ((struct EAPHeader *)out)->Code;
+
+ if (eap_ds->request->code > PW_EAP_REQUEST || (olen <= 4)) {
+ eap_ds->request->type.data = NULL;
+ eap_ds->request->type.length = 0;
+
+ return 0;
+ }
+
+ len = ntohs(((struct EAPHeader *)out)->Length);
+
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, len);
+ if (!eap_ds->request->type.data) return 1;
+
+ memcpy(eap_ds->request->type.data, out + 5, len - 5);
+ eap_ds->request->type.length = len - 5;
+
+ return 0;
+}
+
+/** Free memory after EAP-IKEv2 module usage
+ *
+ */
+static int mod_detach(void *instance)
+{
+ struct ikev2_ctx *data = (struct ikev2_ctx *) instance;
+
+ if (data) {
+ Free_ikev2_ctx(data);
+ data = NULL;
+ }
+ return 0;
+}
+
+/** Free memory after finished IKEv2 session
+ *
+ */
+static void ikev2_free_opaque(void *opaque)
+{
+
+ int fast_deleted;
+ struct IKEv2Data *ikev2_data=(struct IKEv2Data*)opaque;
+
+ DEBUG(IKEv2_LOG_PREFIX "Free session data");
+
+ if (ikev2_data->session) {
+ if (ikev2_data->session->Status != IKEv2_SST_ESTABLISHED) {
+ DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - cleanup!!!");
+ IKEv2EndSession(ikev2_data->i2, ikev2_data->session);
+ ikev2_data->session = NULL;
+ } else {
+ DEBUG(IKEv2_LOG_PREFIX "Unfinished IKEv2 session - keep it!!!");
+ ikev2_data->session = NULL;
+ }
+ }
+
+ fast_deleted = FreeSessionIfExpired(ikev2_data->i2, time(NULL));
+ if (fast_deleted) {
+ DEBUG(IKEv2_LOG_PREFIX "Deleted %d expired IKEv2 sessions", fast_deleted);
+ }
+
+ free(ikev2_data);
+}
+
+/** Configure EAP-ikev2 handler
+ *
+ */
+static int mod_instantiate(CONF_SECTION *conf, void **instance)
+{
+ int ret;
+
+ struct ikev2_ctx *i2;
+ rlm_eap_ikev2_t *inst;
+
+ char *server_auth_type, *default_auth_type, *users_file_name;
+
+ ikev2_set_log_callback(vxlogf);
+
+ inst = talloc_zero(conf, rlm_eap_ikev2_t);
+ if (cf_section_parse(conf, &inst, module_config) < 0) return -1;
+
+ i2 = Create_ikev2_ctx();
+ if (!i2) return -1;
+ *instance = i2;
+
+ /*
+ * Map our config structure onto the IKEv2 context
+ */
+ memcpy(&i2->trusted, &inst->tls_ca_file, sizeof(i2->trusted));
+ memcpy(&i2->pkfile, &inst->tls_private_key_file, sizeof(i2->pkfile));
+ memcpy(&i2->pkfile_pwd, &inst->tls_private_key_password, sizeof(i2->pkfile_pwd));
+ memcpy(&i2->certfile, &inst->tls_certificate_file, sizeof(i2->certfile));
+ memcpy(&i2->id, &inst->id, sizeof(i2->id));
+ i2->max_fragment_size = inst->max_fragment_size;
+ i2->DHCounterMax = inst->dh_counter_max;
+ i2->sendCertReq = (uint8_t) inst->send_cert_request;
+ i2->fastExpire = inst->fast_expire;
+ i2->enableFastDHEx = inst->enable_fast_dhex;
+ i2->enableFastReconnect = inst->enable_fast_reconnect;
+
+ memcpy(&server_auth_type, &inst->server_auth_type, sizeof(server_auth_type));
+ memcpy(&default_auth_type, &inst->default_auth_type, sizeof(default_auth_type));
+ memcpy(&users_file_name, &inst->users_file_name, sizeof(users_file_name));
+ hexalize(&i2->id, &i2->idlen);
+
+ i2->authtype = rad_get_authtype(server_auth_type);
+ if (!i2->id) {
+ ERROR(IKEv2_LOG_PREFIX "'id' configuration option is required!!!");
+ return -1;
+ }
+
+ switch (i2->authtype) {
+ default:
+ case IKEv2_AUTH_SK:
+ break;
+
+ case IKEv2_AUTH_CERT:
+ if (!i2->certfile || !i2->pkfile) {
+ ERROR(IKEv2_LOG_PREFIX "'certificate_file' and 'private_key_file' items are required "
+ "for 'cert' auth type");
+ return -1;
+ }
+
+ if (!file_exists(i2->certfile)) {
+ ERROR(IKEv2_LOG_PREFIX "Can not open 'certificate_file' %s", i2->certfile);
+ return -1;
+ }
+
+ if (!file_exists(i2->pkfile)) {
+ ERROR(IKEv2_LOG_PREFIX "Can not open 'private_key_file' %s",i2->pkfile);
+ return -1;
+ }
+ break;
+ }
+
+ if (!i2->trusted) {
+ AUTH(IKEv2_LOG_PREFIX "'ca_file' item not set, client cert based authentication will fail");
+ } else {
+ if (!file_exists(i2->trusted)) {
+ ERROR(IKEv2_LOG_PREFIX "Can not open 'ca_file' %s", i2->trusted);
+ return -1;
+ }
+ }
+
+ if (i2->crl_file) {
+ if (!file_exists(i2->crl_file)) {
+ ERROR(IKEv2_LOG_PREFIX "Can not open 'crl_file' %s", i2->crl_file);
+ return -1;
+ }
+ }
+
+ i2->idtype = IdTypeFromName(inst->server_id_type);
+ if (i2->idtype <= 0) {
+ ERROR(IKEv2_LOG_PREFIX "Unsupported 'idtype': %s", inst->server_id_type);
+ return -1;
+ }
+
+ if (rad_load_proposals(i2, conf)) {
+ ERROR(IKEv2_LOG_PREFIX "Failed to load proposals");
+ return -1;
+ }
+
+ ret = rad_load_credentials(instance, i2, users_file_name, default_auth_type);
+ if (ret == -1) {
+ ERROR(IKEv2_LOG_PREFIX "Error while loading users credentials");
+ return -1;
+ }
+
+ i2->x509_store = NULL;
+ if(CertInit(i2)){
+ ERROR(IKEv2_LOG_PREFIX "Error while loading certs/crl");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Initiate the EAP-ikev2 session by sending a challenge to the peer.
+ *
+ */
+static int mod_session_init(void *instance, eap_handler_t *handler)
+{
+ INFO(IKEv2_LOG_PREFIX "Initiate connection!");
+
+ struct IKEv2Data *ikev2_data;
+ struct ikev2_ctx *i2=(struct ikev2_ctx*)instance;
+
+ uint8_t *sikemsg = NULL;
+ u_int32_t slen = 0;
+
+ uint8_t *out = NULL;
+ u_int32_t olen = 0;
+
+ struct IKEv2Session *session;
+ handler->free_opaque = ikev2_free_opaque;
+
+ /* try get respondent FASTID */
+ uint8_t const *eap_username;
+
+ eap_username = handler->request->username->vp_octets;
+ session = FindSessionByFastid(i2, (char const *)eap_username);
+ if (!session) {
+ if (IKEv2BeginSession( i2, &session, IKEv2_STY_INITIATOR ) != IKEv2_RET_OK) {
+ ERROR(IKEv2_LOG_PREFIX "Can't initialize IKEv2 session");
+ return 1;
+ }
+ } else {
+ DEBUG(IKEv2_LOG_PREFIX "Fast reconnect procedure start");
+ }
+ session->timestamp=time(NULL);
+
+ ikev2_data = IKEv2Data_new(i2,session);
+ handler->opaque = ikev2_data;
+
+ if (IKEv2ProcessMsg(i2, NULL , &sikemsg, &slen, session) != IKEv2_RET_OK) {
+ ERROR(IKEv2_LOG_PREFIX "Error while processing IKEv2 message");
+ return 1;
+ }
+
+ if (slen != 0) {
+ session->eapMsgID++;
+ olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out );
+ if (session->fragdata) {
+ session->sendfrag = true;
+ }
+ }
+
+ if ((olen > 0) && (out!=NULL)) {
+ if (compose_rad_message(out, olen, handler->eap_ds)) {
+ free(out);
+ return 0;
+ }
+ free(out);
+ }
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+ return 1;
+}
+
+/** Authenticate a previously sent challenge
+ *
+ */
+static int mod_process(void *instance, eap_handler_t *handler)
+{
+ uint8_t *in;
+ uint8_t *out = NULL;
+
+ uint8_t *ikemsg;
+ u_int32_t len;
+
+ uint8_t *sikemsg = NULL; //out message
+ u_int32_t slen = 0;
+
+ u_int32_t olen = 0;
+ struct ikev2_ctx *i2 = (struct ikev2_ctx*)instance;
+ struct EAPHeader *hdr;
+
+ struct IKEv2Data *ikev2_data;
+ struct IKEv2Session *session;
+
+ INFO(IKEv2_LOG_PREFIX "authenticate" );
+
+ rad_assert(handler->request != NULL);
+ rad_assert(handler->stage == PROCESS);
+
+ EAP_DS *eap_ds=handler->eap_ds;
+ if (!eap_ds ||
+ !eap_ds->response ||
+ (eap_ds->response->code != PW_IKEV2_RESPONSE) ||
+ eap_ds->response->type.num != PW_EAP_IKEV2 ||
+ !eap_ds->response->type.data) {
+ ERROR(IKEv2_LOG_PREFIX "corrupted data");
+ return -1;
+ }
+
+ in = talloc_array(eap_ds, uint8_t, eap_ds->response->length);
+ if (in){
+ ERROR(IKEv2_LOG_PREFIX "alloc error");
+ return -1;
+ }
+
+ rad_assert(in != NULL);
+ hdr = (struct EAPHeader *)in;
+
+ hdr->Code = eap_ds->response->code;
+ hdr->Id = eap_ds->response->id;
+ hdr->Length = htons(eap_ds->response->length);
+ hdr->Type = eap_ds->response->type.num;
+ memcpy(in + 5, eap_ds->response->type.data, eap_ds->response->length - 5);
+
+ ikev2_data = (struct IKEv2Data*)handler->opaque;
+ session = ikev2_data->session;
+ session->timestamp = time(NULL);
+
+ if (!session->fragdata) session->sendfrag = false;
+
+ if (session->sendfrag && !ParseFragmentAck(in, session)){
+ session->eapMsgID = eap_ds->response->id + 1;
+
+ olen = CreateIKEv2Message(i2, NULL, 0, false, hdr->Id, session, (uint8_t **)&out);
+ talloc_free(in);
+
+ if (compose_rad_message(out,olen,handler->eap_ds)) {
+ free(out);
+ return 0;
+ }
+
+ free(out);
+ return 1;
+ }
+
+ session->eapMsgID = eap_ds->response->id + 1;
+
+ if (ParseIKEv2Message(in, &ikemsg, &len, session)){
+ if (ikemsg != NULL) free(ikemsg);
+
+ handler->eap_ds->request->code=PW_EAP_FAILURE;
+ INFO(IKEv2_LOG_PREFIX "Discarded packet");
+
+ return 1;
+ }
+
+ /* Send fragment ack */
+ if (!ikemsg || !len) {
+ if (session->SK_ready) session->include_integ = 1;
+
+ olen = CreateFragmentAck(in, &out, session); // confirm fragment
+ TALLOC_FREE(in);
+
+ if (compose_rad_message(out,olen,handler->eap_ds)) {
+ free(out);
+ return 0;
+ }
+
+ free(out);
+ return 1;
+ }
+ TALLOC_FREE(in);
+
+ if (IKEv2ProcessMsg(i2, ikemsg, &sikemsg, &slen, session) != IKEv2_RET_OK) {
+ INFO(IKEv2_LOG_PREFIX "EAP_STATE_DISCARD");
+ //session->State = EAP_STATE_DISCARD;
+ free(out);
+ return 1;
+ }
+
+ free(ikemsg);
+
+ /* If there is there is something to send */
+ if (slen != 0){
+ olen = CreateIKEv2Message(i2, sikemsg, slen, false, 0, session, &out);
+ if (session->fragdata) session->sendfrag = true;
+ } else {
+ if (session->Status == IKEv2_SST_FAILED ) {
+ INFO(IKEv2_LOG_PREFIX "FAILED");
+ olen = CreateResultMessage( false, session, &out );
+ }
+
+ if(session->Status == IKEv2_SST_ESTABLISHED) {
+ INFO(IKEv2_LOG_PREFIX "SUCCESS");
+ olen = CreateResultMessage(true, session, &out);
+ session->fFastReconnect = i2->enableFastReconnect;
+
+ GenEapKeys(session ,EAP_IKEv2_KEY_LEN);
+ set_mppe_keys(handler);
+ }
+
+ // keep sessions in memory, only reference cleared
+ ikev2_data->session = NULL;
+ }
+ if ((olen > 0) && (out != NULL)){
+ if (compose_rad_message(out, olen, handler->eap_ds)){
+ free(out);
+ return 0;
+ }
+ }
+
+ free(out);
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_ikev2;
+rlm_eap_module_t rlm_eap_ikev2 = {
+ .name = "eap_ikev2",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process, /* Process next round of EAP method */
+ .detach = mod_detach /* detach */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/README.md b/src/modules/rlm_eap/types/rlm_eap_md5/README.md
new file mode 100644
index 0000000..dba25cc
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_md5/README.md
@@ -0,0 +1,12 @@
+# rlm_eap_md5
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 3748](https://tools.ietf.org/html/rfc3748) EAP-MD5 authentication. EAP-MD5 allows EAP authentication
+using a plaintext password.
+
+Does not provide keying material for 802.11i, so cannot be used for WPA/2-Enterprise authentication unless wrapped
+in another method such as EAP-TTLS.
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/all.mk b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk
new file mode 100644
index 0000000..528ee82
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_md5/all.mk
@@ -0,0 +1,12 @@
+TARGETNAME := rlm_eap_md5
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c eap_md5.c
+
+SRC_CFLAGS :=
+TGT_LDLIBS :=
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c
new file mode 100644
index 0000000..e8acb5c
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c
@@ -0,0 +1,229 @@
+/*
+ * eap_md5.c EAP MD5 functionality.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2001,2006 The FreeRADIUS server project
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ */
+
+/*
+ *
+ * MD5 Packet Format in EAP Type-Data
+ * --- ------ ------ -- --- ---------
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Value-Size | Value ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Name ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "eap.h"
+
+#include "eap_md5.h"
+#include <freeradius-devel/md5.h>
+
+/*
+ * We expect only RESPONSE for which SUCCESS or FAILURE is sent back
+ */
+MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
+{
+ md5_packet_t *data;
+ MD5_PACKET *packet;
+ unsigned short name_len;
+
+ /*
+ * We need a response, of type EAP-MD5, with at least
+ * one byte of type data (EAP-MD5) following the 4-byte
+ * EAP-Packet header.
+ */
+ if (!eap_ds ||
+ !eap_ds->response ||
+ (eap_ds->response->code != PW_MD5_RESPONSE) ||
+ eap_ds->response->type.num != PW_EAP_MD5 ||
+ !eap_ds->response->type.data ||
+ (eap_ds->response->length <= MD5_HEADER_LEN) ||
+ (eap_ds->response->type.data[0] <= 0)) {
+ ERROR("rlm_eap_md5: corrupted data");
+ return NULL;
+ }
+
+ packet = talloc_zero(eap_ds, MD5_PACKET);
+ if (!packet) return NULL;
+
+ /*
+ * Code & id for MD5 & EAP are same
+ *
+ * but md5_length = length of the EAP-MD5 data, which
+ * doesn't include the EAP header, or the octet saying
+ * EAP-MD5.
+ */
+ packet->code = eap_ds->response->code;
+ packet->id = eap_ds->response->id;
+ packet->length = eap_ds->response->length - (MD5_HEADER_LEN + 1);
+
+ /*
+ * Sanity check the EAP-MD5 packet sent to us
+ * by the client.
+ */
+ data = (md5_packet_t *)eap_ds->response->type.data;
+
+ /*
+ * Already checked the size above.
+ */
+ packet->value_size = data->value_size;
+
+ /*
+ * Allocate room for the data, and copy over the data.
+ */
+ packet->value = talloc_array(packet, uint8_t, packet->value_size);
+ if (!packet->value) {
+ talloc_free(packet);
+ return NULL;
+ }
+ memcpy(packet->value, data->value_name, packet->value_size);
+
+ /*
+ * Name is optional and is present after Value, but we
+ * need to check for it, as eapmd5_compose()
+ */
+ name_len = packet->length - (packet->value_size + 1);
+ if (name_len) {
+ packet->name = talloc_array(packet, char, name_len + 1);
+ if (!packet->name) {
+ talloc_free(packet);
+ return NULL;
+ }
+ memcpy(packet->name, data->value_name + packet->value_size,
+ name_len);
+ packet->name[name_len] = 0;
+ }
+
+ return packet;
+}
+
+
+/*
+ * verify = MD5(id+password+challenge_sent)
+ */
+int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password,
+ uint8_t *challenge)
+{
+ char *ptr;
+ char string[1 + MAX_STRING_LEN*2];
+ uint8_t digest[16];
+ unsigned short len;
+
+ /*
+ * Sanity check it.
+ */
+ if (packet->value_size != 16) {
+ ERROR("rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size);
+ return 0;
+ }
+
+ len = 0;
+ ptr = string;
+
+ /*
+ * This is really rad_chap_pwencode()...
+ */
+ *ptr++ = packet->id;
+ len++;
+ memcpy(ptr, password->vp_strvalue, password->vp_length);
+ ptr += password->vp_length;
+ len += password->vp_length;
+
+ /*
+ * The challenge size is hard-coded.
+ */
+ memcpy(ptr, challenge, MD5_CHALLENGE_LEN);
+ len += MD5_CHALLENGE_LEN;
+
+ fr_md5_calc(digest, (u_char *)string, len);
+
+ /*
+ * The length of the response is always 16 for MD5.
+ */
+ if (rad_digest_cmp(digest, packet->value, 16) != 0) {
+ DEBUG("EAP-MD5 digests do not match.");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compose the portions of the reply packet specific to the
+ * EAP-MD5 protocol, in the EAP reply typedata
+ */
+int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
+{
+ uint8_t *ptr;
+ unsigned short name_len;
+
+ /*
+ * We really only send Challenge (EAP-Identity),
+ * and EAP-Success, and EAP-Failure.
+ */
+ if (reply->code < 3) {
+ eap_ds->request->type.num = PW_EAP_MD5;
+
+ rad_assert(reply->length > 0);
+
+ eap_ds->request->type.data = talloc_array(eap_ds->request,
+ uint8_t,
+ reply->length);
+ if (!eap_ds->request->type.data) {
+ talloc_free(reply);
+ return 0;
+ }
+ ptr = eap_ds->request->type.data;
+ *ptr++ = (uint8_t)(reply->value_size & 0xFF);
+ memcpy(ptr, reply->value, reply->value_size);
+
+ /* Just the Challenge length */
+ eap_ds->request->type.length = reply->value_size + 1;
+
+ /*
+ * Return the name, if necessary.
+ *
+ * Don't see why this is *ever* necessary...
+ */
+ name_len = reply->length - (reply->value_size + 1);
+ if (name_len && reply->name) {
+ ptr += reply->value_size;
+ memcpy(ptr, reply->name, name_len);
+ /* Challenge length + Name length */
+ eap_ds->request->type.length += name_len;
+ }
+ } else {
+ eap_ds->request->type.length = 0;
+ /* TODO: In future we might add message here wrt rfc1994 */
+ }
+ eap_ds->request->code = reply->code;
+ talloc_free(reply);
+
+ return 1;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h
new file mode 100644
index 0000000..aafa407
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h
@@ -0,0 +1,52 @@
+#ifndef _EAP_MD5_H
+#define _EAP_MD5_H
+
+RCSIDH(eap_md5_h, "$Id$")
+
+#include "eap.h"
+
+#define PW_MD5_CHALLENGE 1
+#define PW_MD5_RESPONSE 2
+#define PW_MD5_SUCCESS 3
+#define PW_MD5_FAILURE 4
+#define PW_MD5_MAX_CODES 4
+
+#define MD5_HEADER_LEN 4
+#define MD5_CHALLENGE_LEN 16
+
+/*
+ ****
+ * EAP - MD5 does not specify code, id & length but chap specifies them,
+ * for generalization purpose, complete header should be sent
+ * and not just value_size, value and name.
+ * future implementation.
+ *
+ * Huh? What does that mean?
+ */
+
+/* eap packet structure */
+typedef struct md5_packet_t {
+/*
+ uint8_t code;
+ uint8_t id;
+ uint16_t length;
+*/
+ uint8_t value_size;
+ uint8_t value_name[1];
+} md5_packet_t;
+
+typedef struct md5_packet {
+ unsigned char code;
+ unsigned char id;
+ unsigned short length;
+ unsigned char value_size;
+ unsigned char *value;
+ char *name;
+} MD5_PACKET;
+
+/* function declarations here */
+
+int eapmd5_compose(EAP_DS *auth, MD5_PACKET *reply);
+MD5_PACKET *eapmd5_extract(EAP_DS *auth);
+int eapmd5_verify(MD5_PACKET *pkt, VALUE_PAIR* pwd, uint8_t *ch);
+#endif /*_EAP_MD5_H*/
diff --git a/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c
new file mode 100644
index 0000000..2fa0077
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c
@@ -0,0 +1,168 @@
+/*
+ * rlm_eap_md5.c Handles that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2001,2006 The FreeRADIUS server project
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "eap_md5.h"
+
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/md5.h>
+
+/*
+ * Initiate the EAP-MD5 session by sending a challenge to the peer.
+ */
+static int mod_session_init(UNUSED void *instance, eap_handler_t *handler)
+{
+ int i;
+ MD5_PACKET *reply;
+ REQUEST *request = handler->request;
+
+ /*
+ * Allocate an EAP-MD5 packet.
+ */
+ reply = talloc(handler, MD5_PACKET);
+ if (!reply) {
+ return 0;
+ }
+
+ /*
+ * Fill it with data.
+ */
+ reply->code = PW_MD5_CHALLENGE;
+ reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */
+ reply->value_size = MD5_CHALLENGE_LEN;
+
+ /*
+ * Allocate user data.
+ */
+ reply->value = talloc_array(reply, uint8_t, reply->value_size);
+ if (!reply->value) {
+ talloc_free(reply);
+ return 0;
+ }
+
+ /*
+ * Get a random challenge.
+ */
+ for (i = 0; i < reply->value_size; i++) {
+ reply->value[i] = fr_rand();
+ }
+ RDEBUG2("Issuing MD5 Challenge");
+
+ /*
+ * Keep track of the challenge.
+ */
+ handler->opaque = talloc_array(handler, uint8_t, reply->value_size);
+ rad_assert(handler->opaque != NULL);
+ memcpy(handler->opaque, reply->value, reply->value_size);
+ handler->free_opaque = NULL;
+
+ /*
+ * Compose the EAP-MD5 packet out of the data structure,
+ * and free it.
+ */
+ eapmd5_compose(handler->eap_ds, reply);
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+/*
+ * Authenticate a previously sent challenge.
+ */
+static int mod_process(UNUSED void *arg, eap_handler_t *handler)
+{
+ MD5_PACKET *packet;
+ MD5_PACKET *reply;
+ VALUE_PAIR *password;
+ REQUEST *request = handler->request;
+
+ /*
+ * Get the Cleartext-Password for this user.
+ */
+ rad_assert(handler->request != NULL);
+ rad_assert(handler->stage == PROCESS);
+
+ password = fr_pair_find_by_num(handler->request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (!password) {
+ REDEBUG2("Cleartext-Password is required for EAP-MD5 authentication");
+ return 0;
+ }
+
+ /*
+ * Extract the EAP-MD5 packet.
+ */
+ if (!(packet = eapmd5_extract(handler->eap_ds)))
+ return 0;
+
+ /*
+ * Create a reply, and initialize it.
+ */
+ reply = talloc(packet, MD5_PACKET);
+ if (!reply) {
+ talloc_free(packet);
+ return 0;
+ }
+ reply->id = handler->eap_ds->request->id;
+ reply->length = 0;
+
+ /*
+ * Verify the received packet against the previous packet
+ * (i.e. challenge) which we sent out.
+ */
+ if (eapmd5_verify(packet, password, handler->opaque)) {
+ reply->code = PW_MD5_SUCCESS;
+ } else {
+ reply->code = PW_MD5_FAILURE;
+ }
+
+ /*
+ * Compose the EAP-MD5 packet out of the data structure,
+ * and free it.
+ */
+ eapmd5_compose(handler->eap_ds, reply);
+ talloc_free(packet);
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_md5;
+rlm_eap_module_t rlm_eap_md5 = {
+ .name = "eap_md5",
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/README.md b/src/modules/rlm_eap/types/rlm_eap_mschapv2/README.md
new file mode 100644
index 0000000..4d87c49
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/README.md
@@ -0,0 +1,13 @@
+# rlm_eap_mschapv2
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements EAP-MSCHAPv2. Usually used as an inner method for PEAP.
+
+Allows NTLMv2 style authentication against Active-Directory, or where the NT-Password is known.
+
+Technically does provide its own keying material via MPPE key attributes which could be used for 802.11i
+(WPA/2-Enterprise) but in most instances, the keying material from an outer method is used instead.
diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk b/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk
new file mode 100644
index 0000000..d57c636
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/all.mk
@@ -0,0 +1,12 @@
+TARGETNAME := rlm_eap_mschapv2
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS :=
+TGT_LDLIBS :=
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h b/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h
new file mode 100644
index 0000000..1ce2470
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/eap_mschapv2.h
@@ -0,0 +1,51 @@
+#ifndef _EAP_MSCHAPV2_H
+#define _EAP_MSCHAPV2_H
+
+RCSIDH(eap_mschapv2_h, "$Id$")
+
+#include "eap.h"
+
+/*
+ * draft-kamath-pppext-eap-mschapv2-00.txt says:
+ *
+ * Supplicant FreeRADIUS
+ * <-- challenge
+ * response -->
+ * <-- success
+ * success -->
+ *
+ * But what we often see is:
+ *
+ * Supplicant FreeRADIUS
+ * <-- challenge
+ * response -->
+ * <-- success
+ * ack -->
+ */
+#define PW_EAP_MSCHAPV2_ACK 0
+#define PW_EAP_MSCHAPV2_CHALLENGE 1
+#define PW_EAP_MSCHAPV2_RESPONSE 2
+#define PW_EAP_MSCHAPV2_SUCCESS 3
+#define PW_EAP_MSCHAPV2_FAILURE 4
+#define PW_EAP_MSCHAPV2_CHGPASSWD 7
+#define PW_EAP_MSCHAPV2_MAX_CODES 7
+
+#define MSCHAPV2_HEADER_LEN 5
+#define MSCHAPV2_CHALLENGE_LEN 16
+#define MSCHAPV2_RESPONSE_LEN 50
+
+typedef struct mschapv2_header_t {
+ uint8_t opcode;
+ uint8_t mschapv2_id;
+ uint8_t ms_length[2];
+ uint8_t value_size;
+} mschapv2_header_t;
+
+typedef struct mschapv2_opaque_t {
+ int code;
+ uint8_t challenge[MSCHAPV2_CHALLENGE_LEN];
+ VALUE_PAIR *mppe_keys;
+ VALUE_PAIR *reply;
+} mschapv2_opaque_t;
+
+#endif /*_EAP_MSCHAPV2_H*/
diff --git a/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c b/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c
new file mode 100644
index 0000000..c1a0045
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_mschapv2/rlm_eap_mschapv2.c
@@ -0,0 +1,757 @@
+/*
+ * rlm_eap_mschapv2.c Handles that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003,2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "eap_mschapv2.h"
+
+#include <freeradius-devel/rad_assert.h>
+
+typedef struct rlm_eap_mschapv2_t {
+ bool with_ntdomain_hack;
+ bool send_error;
+ char const *identity;
+ int auth_type_mschap;
+} rlm_eap_mschapv2_t;
+
+static CONF_PARSER module_config[] = {
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, with_ntdomain_hack), "no" },
+
+ { "send_error", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_mschapv2_t, send_error), "no" },
+ { "identity", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_mschapv2_t, identity), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static void fix_mppe_keys(eap_handler_t *handler, mschapv2_opaque_t *data)
+{
+ fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_list_mcopy_by_num(data, &data->mppe_keys, &handler->request->reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+}
+
+/*
+ * Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_mschapv2_t *inst;
+ DICT_VALUE const *dv;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_mschapv2_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ if (inst->identity && (strlen(inst->identity) > 255)) {
+ cf_log_err_cs(cs, "identity is too long");
+ return -1;
+ }
+
+ if (!inst->identity) {
+ inst->identity = talloc_asprintf(inst, "freeradius-%s", RADIUSD_VERSION_STRING);
+ }
+
+ dv = dict_valbyname(PW_AUTH_TYPE, 0, "MSCHAP");
+ if (!dv) dv = dict_valbyname(PW_AUTH_TYPE, 0, "MS-CHAP");
+ if (!dv) {
+ cf_log_err_cs(cs, "Failed to find 'Auth-Type MS-CHAP' section. Cannot authenticate users.");
+ return -1;
+ }
+ inst->auth_type_mschap = dv->value;
+
+ return 0;
+}
+
+
+/*
+ * Compose the response.
+ */
+static int eapmschapv2_compose(rlm_eap_mschapv2_t *inst, eap_handler_t *handler, VALUE_PAIR *reply)
+{
+ uint8_t *ptr;
+ int16_t length;
+ mschapv2_header_t *hdr;
+ EAP_DS *eap_ds = handler->eap_ds;
+ REQUEST *request = handler->request;
+
+ eap_ds->request->code = PW_EAP_REQUEST;
+ eap_ds->request->type.num = PW_EAP_MSCHAPV2;
+
+ /*
+ * Always called with vendor Microsoft
+ */
+ switch (reply->da->attr) {
+ case PW_MSCHAP_CHALLENGE:
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | OpCode | MS-CHAPv2-ID | MS-Length...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MS-Length | Value-Size | Challenge...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Challenge...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Server Name...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ length = MSCHAPV2_HEADER_LEN + MSCHAPV2_CHALLENGE_LEN + strlen(inst->identity);
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length);
+
+ /*
+ * Allocate room for the EAP-MS-CHAPv2 data.
+ */
+ if (!eap_ds->request->type.data) {
+ return 0;
+ }
+ eap_ds->request->type.length = length;
+
+ ptr = eap_ds->request->type.data;
+ hdr = (mschapv2_header_t *) ptr;
+
+ hdr->opcode = PW_EAP_MSCHAPV2_CHALLENGE;
+ hdr->mschapv2_id = eap_ds->response->id + 1;
+ length = htons(length);
+ memcpy(hdr->ms_length, &length, sizeof(uint16_t));
+ hdr->value_size = MSCHAPV2_CHALLENGE_LEN;
+
+ ptr += MSCHAPV2_HEADER_LEN;
+
+ /*
+ * Copy the Challenge, success, or error over.
+ */
+ memcpy(ptr, reply->vp_octets, reply->vp_length);
+
+ memcpy((ptr + reply->vp_length), inst->identity, strlen(inst->identity));
+ break;
+
+ case PW_MSCHAP2_SUCCESS:
+ /*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | OpCode | MS-CHAPv2-ID | MS-Length...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MS-Length | Message...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ RDEBUG2("MSCHAP Success");
+ length = 46;
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length);
+ /*
+ * Allocate room for the EAP-MS-CHAPv2 data.
+ */
+ if (!eap_ds->request->type.data) {
+ return 0;
+ }
+ memset(eap_ds->request->type.data, 0, length);
+ eap_ds->request->type.length = length;
+
+ eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_SUCCESS;
+ eap_ds->request->type.data[1] = eap_ds->response->id;
+ length = htons(length);
+ memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t));
+ memcpy((eap_ds->request->type.data + 4), reply->vp_strvalue + 1, 42);
+ break;
+
+ case PW_MSCHAP_ERROR:
+ REDEBUG("MSCHAP Failure");
+ length = 4 + reply->vp_length - 1;
+ eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, length);
+
+ /*
+ * Allocate room for the EAP-MS-CHAPv2 data.
+ */
+ if (!eap_ds->request->type.data) return 0;
+ memset(eap_ds->request->type.data, 0, length);
+ eap_ds->request->type.length = length;
+
+ eap_ds->request->type.data[0] = PW_EAP_MSCHAPV2_FAILURE;
+ eap_ds->request->type.data[1] = eap_ds->response->id;
+ length = htons(length);
+ memcpy((eap_ds->request->type.data + 2), &length, sizeof(uint16_t));
+ /*
+ * Copy the entire failure message.
+ */
+ memcpy((eap_ds->request->type.data + 4),
+ reply->vp_strvalue + 1, reply->vp_length - 1);
+ break;
+
+ default:
+ RERROR("Internal sanity check failed");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Initiate the EAP-MSCHAPV2 session by sending a challenge to the peer.
+ */
+static int mod_session_init(void *instance, eap_handler_t *handler)
+{
+ int i;
+ VALUE_PAIR *challenge;
+ mschapv2_opaque_t *data;
+ REQUEST *request = handler->request;
+ uint8_t *p;
+ bool created_challenge = false;
+ rlm_eap_mschapv2_t *inst = instance;
+
+ challenge = fr_pair_find_by_num(request->config, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (challenge && (challenge->vp_length != MSCHAPV2_CHALLENGE_LEN)) {
+ RWDEBUG("control:MS-CHAP-Challenge is incorrect length. Ignoring it.");
+ challenge = NULL;
+ }
+
+ if (!challenge) {
+ created_challenge = true;
+ challenge = fr_pair_make(handler, NULL, "MS-CHAP-Challenge", NULL, T_OP_EQ);
+
+ /*
+ * Get a random challenge.
+ */
+ challenge->vp_length = MSCHAPV2_CHALLENGE_LEN;
+ challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->vp_length);
+ for (i = 0; i < MSCHAPV2_CHALLENGE_LEN; i++) {
+ p[i] = fr_rand();
+ }
+ }
+ RDEBUG2("Issuing Challenge");
+
+ /*
+ * Keep track of the challenge.
+ */
+ data = talloc_zero(handler, mschapv2_opaque_t);
+ rad_assert(data != NULL);
+
+ /*
+ * We're at the stage where we're challenging the user.
+ */
+ data->code = PW_EAP_MSCHAPV2_CHALLENGE;
+ memcpy(data->challenge, challenge->vp_octets, MSCHAPV2_CHALLENGE_LEN);
+ data->mppe_keys = NULL;
+ data->reply = NULL;
+
+ handler->opaque = data;
+
+ /*
+ * Compose the EAP-MSCHAPV2 packet out of the data structure,
+ * and free it.
+ */
+ eapmschapv2_compose(inst, handler, challenge);
+ if (created_challenge) fr_pair_list_free(&challenge);
+
+#ifdef WITH_PROXY
+ /*
+ * The EAP session doesn't have enough information to
+ * proxy the "inside EAP" protocol. Disable EAP proxying.
+ */
+ handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+#endif
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+#ifdef WITH_PROXY
+/*
+ * Do post-proxy processing,
+ * 0 = fail
+ * 1 = OK.
+ *
+ * Called from rlm_eap.c, eap_postproxy().
+ */
+static int CC_HINT(nonnull) mschap_postproxy(eap_handler_t *handler, UNUSED void *tunnel_data)
+{
+ VALUE_PAIR *response = NULL;
+ mschapv2_opaque_t *data;
+ REQUEST *request = handler->request;
+
+ data = (mschapv2_opaque_t *) handler->opaque;
+ rad_assert(request != NULL);
+
+ RDEBUG2("Passing reply from proxy back into the tunnel %d", request->reply->code);
+
+ /*
+ * There is only a limited number of possibilities.
+ */
+ switch (request->reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ RDEBUG2("Proxied authentication succeeded");
+
+ /*
+ * Move the attribute, so it doesn't go into
+ * the reply.
+ */
+ fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
+ break;
+
+ default:
+ case PW_CODE_ACCESS_REJECT:
+ REDEBUG("Proxied authentication was rejected");
+ return 0;
+ }
+
+ /*
+ * No response, die.
+ */
+ if (!response) {
+ REDEBUG("Proxied reply contained no MS-CHAP2-Success or MS-CHAP-Error");
+ return 0;
+ }
+
+ /*
+ * Done doing EAP proxy stuff.
+ */
+ request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ eapmschapv2_compose(NULL, handler, response);
+ data->code = PW_EAP_MSCHAPV2_SUCCESS;
+
+ /*
+ * Delete MPPE keys & encryption policy
+ *
+ * FIXME: Use intelligent names...
+ */
+ fix_mppe_keys(handler, data);
+
+ /*
+ * Save any other attributes for re-use in the final
+ * access-accept e.g. vlan, etc. This lets the PEAP
+ * use_tunneled_reply code work
+ */
+ data->reply = fr_pair_list_copy(data, request->reply->vps);
+
+ /*
+ * And we need to challenge the user, not ack/reject them,
+ * so we re-write the ACK to a challenge. Yuck.
+ */
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ fr_pair_list_free(&response);
+
+ return 1;
+}
+#endif
+
+/*
+ * Authenticate a previously sent challenge.
+ */
+static int CC_HINT(nonnull) mod_process(void *arg, eap_handler_t *handler)
+{
+ int rcode, ccode;
+ uint8_t *p;
+ size_t length;
+ char *q;
+ mschapv2_opaque_t *data;
+ EAP_DS *eap_ds = handler->eap_ds;
+ VALUE_PAIR *challenge, *response, *name;
+ rlm_eap_mschapv2_t *inst = (rlm_eap_mschapv2_t *) arg;
+ REQUEST *request = handler->request;
+
+ rad_assert(handler->stage == PROCESS);
+
+ data = (mschapv2_opaque_t *) handler->opaque;
+
+ /*
+ * Sanity check the response.
+ */
+ if (eap_ds->response->length <= 5) {
+ REDEBUG("corrupted data");
+ return 0;
+ }
+
+ ccode = eap_ds->response->type.data[0];
+
+ switch (data->code) {
+ case PW_EAP_MSCHAPV2_FAILURE:
+ if (ccode == PW_EAP_MSCHAPV2_RESPONSE) {
+ RDEBUG2("Authentication re-try from client after we sent a failure");
+ break;
+ }
+
+ /*
+ * if we sent error 648 (password expired) to the client
+ * we might get an MSCHAP-CPW packet here; turn it into a
+ * regular MS-CHAP2-CPW packet and pass it to rlm_mschap
+ * (or proxy it, I guess)
+ */
+ if (ccode == PW_EAP_MSCHAPV2_CHGPASSWD) {
+ VALUE_PAIR *cpw;
+ int mschap_id = eap_ds->response->type.data[1];
+ int copied = 0 ,seq = 1;
+
+ RDEBUG2("Password change packet received");
+
+ challenge = pair_make_request("MS-CHAP-Challenge", NULL, T_OP_EQ);
+ if (!challenge) return 0;
+ fr_pair_value_memcpy(challenge, data->challenge, MSCHAPV2_CHALLENGE_LEN);
+
+ cpw = pair_make_request("MS-CHAP2-CPW", NULL, T_OP_EQ);
+ cpw->vp_length = 68;
+
+ cpw->vp_octets = p = talloc_array(cpw, uint8_t, cpw->vp_length);
+ p[0] = 7;
+ p[1] = mschap_id;
+ memcpy(p + 2, eap_ds->response->type.data + 520, 66);
+
+ /*
+ * break the encoded password into VPs (3 of them)
+ */
+ while (copied < 516) {
+ VALUE_PAIR *nt_enc;
+
+ int to_copy = 516 - copied;
+ if (to_copy > 243) to_copy = 243;
+
+ nt_enc = pair_make_request("MS-CHAP-NT-Enc-PW", NULL, T_OP_ADD);
+ nt_enc->vp_length = 4 + to_copy;
+
+ nt_enc->vp_octets = p = talloc_array(nt_enc, uint8_t, nt_enc->vp_length);
+
+ p[0] = 6;
+ p[1] = mschap_id;
+ p[2] = 0;
+ p[3] = seq++;
+
+ memcpy(p + 4, eap_ds->response->type.data + 4 + copied, to_copy);
+ copied += to_copy;
+ }
+
+ RDEBUG2("Built change password packet");
+ rdebug_pair_list(L_DBG_LVL_2, request, request->packet->vps, NULL);
+
+ /*
+ * jump to "authentication"
+ */
+ goto packet_ready;
+ }
+
+ /*
+ * we sent a failure and are expecting a failure back
+ */
+ if (ccode != PW_EAP_MSCHAPV2_FAILURE) {
+ REDEBUG("Sent FAILURE expecting FAILURE but got %d", ccode);
+ return 0;
+ }
+
+failure:
+ request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 1;
+
+ case PW_EAP_MSCHAPV2_SUCCESS:
+ /*
+ * we sent a success to the client; some clients send a
+ * success back as-per the RFC, some send an ACK. Permit
+ * both, I guess...
+ */
+
+ switch (ccode) {
+ case PW_EAP_MSCHAPV2_SUCCESS:
+ eap_ds->request->code = PW_EAP_SUCCESS;
+
+ fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &data->mppe_keys, 0, 0, TAG_ANY);
+ /* FALL-THROUGH */
+
+ case PW_EAP_MSCHAPV2_ACK:
+#ifdef WITH_PROXY
+ /*
+ * It's a success. Don't proxy it.
+ */
+ request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+#endif
+ fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &data->reply, 0, 0, TAG_ANY);
+ return 1;
+ }
+ REDEBUG("Sent SUCCESS expecting SUCCESS (or ACK) but got %d", ccode);
+ return 0;
+
+ case PW_EAP_MSCHAPV2_CHALLENGE:
+ if (ccode == PW_EAP_MSCHAPV2_FAILURE) goto failure;
+
+ /*
+ * we sent a challenge, expecting a response
+ */
+ if (ccode != PW_EAP_MSCHAPV2_RESPONSE) {
+ REDEBUG("Sent CHALLENGE expecting RESPONSE but got %d", ccode);
+ return 0;
+ }
+ /* authentication happens below */
+ break;
+
+ default:
+ /* should never happen */
+ REDEBUG("Unknown state %d", data->code);
+ return 0;
+ }
+
+
+ /*
+ * Ensure that we have at least enough data
+ * to do the following checks.
+ *
+ * EAP header (4), EAP type, MS-CHAP opcode,
+ * MS-CHAP ident, MS-CHAP data length (2),
+ * MS-CHAP value length.
+ */
+ if (eap_ds->response->length < (4 + 1 + 1 + 1 + 2 + 1)) {
+ REDEBUG("Response is too short");
+ return 0;
+ }
+
+ /*
+ * The 'value_size' is the size of the response,
+ * which is supposed to be the response (48
+ * bytes) plus 1 byte of flags at the end.
+ *
+ * NOTE: When using Cisco NEAT with EAP-MSCHAPv2, the
+ * switch supplicant will send MSCHAPv2 data (EAP type = 26)
+ * but will always set a value_size of 16 and NULL out the
+ * peer challenge.
+ *
+ */
+ if ((eap_ds->response->type.data[4] != 49) &&
+ (eap_ds->response->type.data[4] != 16)) {
+ REDEBUG("Response is of incorrect length %d", eap_ds->response->type.data[4]);
+ return 0;
+ }
+
+ /*
+ * The MS-Length field is 5 + value_size + length
+ * of name, which is put after the response.
+ */
+ length = (eap_ds->response->type.data[2] << 8) | eap_ds->response->type.data[3];
+ if ((length < (5 + 49)) || (length > (256 + 5 + 49))) {
+ REDEBUG("Response contains contradictory length %zu %d", length, 5 + 49);
+ return 0;
+ }
+
+ /*
+ * We now know that the user has sent us a response
+ * to the challenge. Let's try to authenticate it.
+ *
+ * We do this by taking the challenge from 'data',
+ * the response from the EAP packet, and creating VALUE_PAIR's
+ * to pass to the 'mschap' module. This is a little wonky,
+ * but it works.
+ */
+ challenge = pair_make_request("MS-CHAP-Challenge", NULL, T_OP_EQ);
+ if (!challenge) return 0;
+ fr_pair_value_memcpy(challenge, data->challenge, MSCHAPV2_CHALLENGE_LEN);
+
+ response = pair_make_request("MS-CHAP2-Response", NULL, T_OP_EQ);
+ if (!response) return 0;
+ response->vp_length = MSCHAPV2_RESPONSE_LEN;
+ response->vp_octets = p = talloc_array(response, uint8_t, response->vp_length);
+
+ p[0] = eap_ds->response->type.data[1];
+ p[1] = eap_ds->response->type.data[5 + MSCHAPV2_RESPONSE_LEN];
+ memcpy(p + 2, &eap_ds->response->type.data[5], MSCHAPV2_RESPONSE_LEN - 2);
+
+ name = pair_make_request("MS-CHAP-User-Name", NULL, T_OP_EQ);
+ if (!name) return 0;
+
+ /*
+ * MS-Length - MS-Value - 5.
+ */
+ name->vp_length = length - 49 - 5;
+ name->vp_strvalue = q = talloc_array(name, char, name->vp_length + 1);
+ memcpy(q, &eap_ds->response->type.data[4 + MSCHAPV2_RESPONSE_LEN], name->vp_length);
+ q[name->vp_length] = '\0';
+
+packet_ready:
+
+#ifdef WITH_PROXY
+ /*
+ * If this options is set, then we do NOT authenticate the
+ * user here. Instead, now that we've added the MS-CHAP
+ * attributes to the request, we STOP, and let the outer
+ * tunnel code handle it.
+ *
+ * This means that the outer tunnel code will DELETE the
+ * EAP attributes, and proxy the MS-CHAP attributes to a
+ * home server.
+ */
+ if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) {
+ char *username = NULL;
+ eap_tunnel_data_t *tunnel;
+
+ RDEBUG2("Cancelling authentication and letting it be proxied");
+
+ /*
+ * Set up the callbacks for the tunnel
+ */
+ tunnel = talloc_zero(request, eap_tunnel_data_t);
+
+ tunnel->tls_session = arg;
+ tunnel->callback = mschap_postproxy;
+
+ /*
+ * Associate the callback with the request.
+ */
+ rcode = request_data_add(request,
+ request->proxy,
+ REQUEST_DATA_EAP_TUNNEL_CALLBACK,
+ tunnel, false);
+ rad_assert(rcode == 0);
+
+ /*
+ * The State attribute is NOT supposed to
+ * go into the proxied packet, it will confuse
+ * other RADIUS servers, and they will discard
+ * the request.
+ *
+ * The PEAP module will take care of adding
+ * the State attribute back, before passing
+ * the handler & request back into the tunnel.
+ */
+ fr_pair_delete_by_num(&request->packet->vps, PW_STATE, 0, TAG_ANY);
+
+ /*
+ * Fix the User-Name when proxying, to strip off
+ * the NT Domain, if we're told to, and a User-Name
+ * exists, and there's a \\, meaning an NT-Domain
+ * in the user name, THEN discard the user name.
+ */
+ if (inst->with_ntdomain_hack &&
+ ((challenge = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY)) != NULL) &&
+ ((username = memchr(challenge->vp_octets, '\\', challenge->vp_length)) != NULL)) {
+ /*
+ * Wipe out the NT domain.
+ *
+ * FIXME: Put it into MS-CHAP-Domain?
+ */
+ username++; /* skip the \\ */
+ fr_pair_value_strcpy(challenge, username);
+ }
+
+ /*
+ * Remember that in the post-proxy stage, we've got
+ * to do the work below, AFTER the call to MS-CHAP
+ * authentication...
+ */
+ return 1;
+ }
+#endif
+
+ /*
+ * This is a wild & crazy hack.
+ */
+ rcode = process_authenticate(inst->auth_type_mschap, request);
+
+ /*
+ * Delete MPPE keys & encryption policy. We don't
+ * want these here.
+ */
+ fix_mppe_keys(handler, data);
+
+ /*
+ * Take the response from the mschap module, and
+ * return success or failure, depending on the result.
+ */
+ response = NULL;
+ if (rcode == RLM_MODULE_OK) {
+ fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
+ data->code = PW_EAP_MSCHAPV2_SUCCESS;
+ } else if (inst->send_error) {
+ fr_pair_list_mcopy_by_num(data, &response, &request->reply->vps, PW_MSCHAP_ERROR, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (response) {
+ int n,err,retry;
+ char buf[34];
+
+ VERIFY_VP(response);
+
+ RDEBUG2("MSCHAP-Error: %s", response->vp_strvalue);
+
+ /*
+ * Parse the new challenge out of the
+ * MS-CHAP-Error, so that if the client
+ * issues a re-try, we will know which
+ * challenge value that they used.
+ */
+ n = sscanf(response->vp_strvalue, "%*cE=%d R=%d C=%32s", &err, &retry, &buf[0]);
+ if (n == 3) {
+ RDEBUG2("Found new challenge from MS-CHAP-Error: err=%d retry=%d challenge=%s",
+ err, retry, buf);
+ fr_hex2bin(data->challenge, 16, buf, strlen(buf));
+ } else {
+ RDEBUG2("Could not parse new challenge from MS-CHAP-Error: %d", n);
+ }
+ }
+ data->code = PW_EAP_MSCHAPV2_FAILURE;
+ } else {
+ eap_ds->request->code = PW_EAP_FAILURE;
+ return 1;
+ }
+
+ /*
+ * No response, die.
+ */
+ if (!response) {
+ REDEBUG("No MS-CHAP2-Success or MS-CHAP-Error was found");
+ return 0;
+ }
+
+ /*
+ * Compose the response (whatever it is),
+ * and return it to the over-lying EAP module.
+ */
+ eapmschapv2_compose(inst, handler, response);
+ fr_pair_list_free(&response);
+
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_mschapv2;
+rlm_eap_module_t rlm_eap_mschapv2 = {
+ .name = "eap_mschapv2",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/README.md b/src/modules/rlm_eap/types/rlm_eap_peap/README.md
new file mode 100644
index 0000000..26e7d73
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/README.md
@@ -0,0 +1,13 @@
+# rlm_eap_peap
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements PEAPv0, Microsoft's proprietary EAP method.
+
+Allows NTLMv2 style authentication against Active-Directory, or where the NT-Password is known.
+
+PEAP can also act as a transport for SoH (Statement of Health) messages, and as such, can be used as part of a NAC
+solution, providing firewall, patch level, and antivirus state of the client.
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/all.mk b/src/modules/rlm_eap/types/rlm_eap_peap/all.mk
new file mode 100644
index 0000000..19f51d8
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/all.mk
@@ -0,0 +1,10 @@
+TARGETNAME := rlm_eap_peap
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c peap.c
+
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
new file mode 100644
index 0000000..7b803f8
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
@@ -0,0 +1,76 @@
+/*
+ * eap_peap.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_PEAP_H
+#define _EAP_PEAP_H
+
+RCSIDH(eap_peap_h, "$Id$")
+
+#include "eap_tls.h"
+#include <freeradius-devel/soh.h>
+
+typedef enum {
+ PEAP_STATUS_INVALID,
+ PEAP_STATUS_SENT_TLV_SUCCESS,
+ PEAP_STATUS_SENT_TLV_FAILURE,
+ PEAP_STATUS_TUNNEL_ESTABLISHED,
+ PEAP_STATUS_INNER_IDENTITY_REQ_SENT,
+ PEAP_STATUS_PHASE2_INIT,
+ PEAP_STATUS_PHASE2,
+ PEAP_STATUS_WAIT_FOR_SOH_RESPONSE
+} peap_status;
+
+typedef enum {
+ PEAP_RESUMPTION_NO,
+ PEAP_RESUMPTION_YES,
+ PEAP_RESUMPTION_MAYBE
+} peap_resumption;
+
+typedef struct peap_tunnel_t {
+ VALUE_PAIR *username;
+ VALUE_PAIR *state;
+ VALUE_PAIR *accept_vps;
+ peap_status status;
+ bool home_access_accept;
+ int default_method;
+ bool copy_request_to_tunnel;
+ bool use_tunneled_reply;
+ bool proxy_tunneled_request_as_eap;
+ char const *virtual_server;
+ bool soh;
+ char const *soh_virtual_server;
+ VALUE_PAIR *soh_reply_vps;
+ peap_resumption session_resumption_state;
+} peap_tunnel_t;
+
+
+#define EAP_TLV_SUCCESS (1)
+#define EAP_TLV_FAILURE (2)
+#define EAP_TLV_ACK_RESULT (3)
+
+#define PW_EAP_TLV 33
+
+/*
+ * Process the PEAP portion of an EAP-PEAP request.
+ */
+rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session, int auth_type_eap) CC_HINT(nonnull);
+#endif /* _EAP_PEAP_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c
new file mode 100644
index 0000000..a8589ae
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c
@@ -0,0 +1,1316 @@
+/*
+ * peap.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include "eap_peap.h"
+
+static int setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t);
+
+/*
+ * Send protected EAP-Failure
+ *
+ * Result-TLV = Failure
+ */
+static int eappeap_failure(eap_handler_t *handler, tls_session_t *tls_session)
+{
+ uint8_t tlv_packet[11];
+ REQUEST *request = handler->request;
+
+ RDEBUG2("FAILURE");
+
+ tlv_packet[0] = PW_EAP_REQUEST;
+ tlv_packet[1] = handler->eap_ds->response->id +1;
+ tlv_packet[2] = 0;
+ tlv_packet[3] = 11; /* length of this packet */
+ tlv_packet[4] = PW_EAP_TLV;
+ tlv_packet[5] = 0x80;
+ tlv_packet[6] = EAP_TLV_ACK_RESULT;
+ tlv_packet[7] = 0;
+ tlv_packet[8] = 2; /* length of the data portion */
+ tlv_packet[9] = 0;
+ tlv_packet[10] = EAP_TLV_FAILURE;
+
+ (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11);
+
+ /*
+ * FIXME: Check the return code.
+ */
+ tls_handshake_send(request, tls_session);
+
+ return 1;
+}
+
+
+/*
+ * Send protected EAP-Success
+ *
+ * Result-TLV = Success
+ */
+static int eappeap_success(eap_handler_t *handler, tls_session_t *tls_session)
+{
+ uint8_t tlv_packet[11];
+ REQUEST *request = handler->request;
+
+ RDEBUG2("SUCCESS");
+
+ tlv_packet[0] = PW_EAP_REQUEST;
+ tlv_packet[1] = handler->eap_ds->response->id +1;
+ tlv_packet[2] = 0;
+ tlv_packet[3] = 11; /* length of this packet */
+ tlv_packet[4] = PW_EAP_TLV;
+ tlv_packet[5] = 0x80; /* mandatory AVP */
+ tlv_packet[6] = EAP_TLV_ACK_RESULT;
+ tlv_packet[7] = 0;
+ tlv_packet[8] = 2; /* length of the data portion */
+ tlv_packet[9] = 0;
+ tlv_packet[10] = EAP_TLV_SUCCESS;
+
+ (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11);
+
+ /*
+ * FIXME: Check the return code.
+ */
+ tls_handshake_send(request, tls_session);
+
+ return 1;
+}
+
+
+static int eappeap_identity(eap_handler_t *handler, tls_session_t *tls_session)
+{
+ eap_packet_raw_t eap_packet;
+
+ eap_packet.code = PW_EAP_REQUEST;
+ eap_packet.id = handler->eap_ds->response->id + 1;
+ eap_packet.length[0] = 0;
+ eap_packet.length[1] = EAP_HEADER_LEN + 1;
+ eap_packet.data[0] = PW_EAP_IDENTITY;
+
+ (tls_session->record_plus)(&tls_session->clean_in,
+ &eap_packet, sizeof(eap_packet));
+
+ tls_handshake_send(handler->request, tls_session);
+ (tls_session->record_init)(&tls_session->clean_in);
+
+ return 1;
+}
+
+/*
+ * Send an MS SoH request
+ */
+static int eappeap_soh(eap_handler_t *handler, tls_session_t *tls_session)
+{
+ uint8_t tlv_packet[20];
+
+ tlv_packet[0] = 254; /* extended type */
+
+ tlv_packet[1] = 0;
+ tlv_packet[2] = 0x01; /* ms vendor */
+ tlv_packet[3] = 0x37;
+
+ tlv_packet[4] = 0; /* ms soh eap */
+ tlv_packet[5] = 0;
+ tlv_packet[6] = 0;
+ tlv_packet[7] = 0x21;
+
+ tlv_packet[8] = 0; /* vendor-spec tlv */
+ tlv_packet[9] = 7;
+
+ tlv_packet[10] = 0;
+ tlv_packet[11] = 8; /* payload len */
+
+ tlv_packet[12] = 0; /* ms vendor */
+ tlv_packet[13] = 0;
+ tlv_packet[14] = 0x01;
+ tlv_packet[15] = 0x37;
+
+ tlv_packet[16] = 0;
+ tlv_packet[17] = 2;
+ tlv_packet[18] = 0;
+ tlv_packet[19] = 0;
+
+ (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 20);
+ tls_handshake_send(handler->request, tls_session);
+ return 1;
+}
+
+static void eapsoh_verify(REQUEST *request, RADIUS_PACKET *packet,
+ uint8_t const *data, unsigned int data_len) {
+
+ VALUE_PAIR *vp;
+ uint8_t eap_method_base;
+ uint32_t eap_vendor;
+ uint32_t eap_method;
+ int rv;
+
+ vp = fr_pair_make(packet, &packet->vps, "SoH-Supported", "no", T_OP_EQ);
+ if (data && data[0] == PW_EAP_NAK) {
+ RDEBUG("SoH - client NAKed");
+ return;
+ }
+
+ if (!data || data_len < 8) {
+ RDEBUG("SoH - eap payload too short");
+ return;
+ }
+
+ eap_method_base = *data++;
+ if (eap_method_base != 254) {
+ RDEBUG("SoH - response is not extended EAP: %i", eap_method_base);
+ return;
+ }
+
+ eap_vendor = soh_pull_be_24(data); data += 3;
+ if (eap_vendor != 0x137) {
+ RDEBUG("SoH - extended eap vendor %08x is not Microsoft", eap_vendor);
+ return;
+ }
+
+ eap_method = soh_pull_be_32(data); data += 4;
+ if (eap_method != 0x21) {
+ RDEBUG("SoH - response eap type %08x is not EAP-SoH", eap_method);
+ return;
+ }
+
+
+ rv = soh_verify(request, data, data_len - 8);
+ if (rv<0) {
+ RDEBUG("SoH - error decoding payload: %s", fr_strerror());
+ } else {
+ vp->vp_integer = 1;
+ }
+}
+
+/*
+ * Verify the tunneled EAP message.
+ */
+static int eapmessage_verify(REQUEST *request,
+ uint8_t const *data, unsigned int data_len, int peap_version)
+{
+ eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data;
+ eap_type_t eap_method;
+
+ /*
+ * Hack for now.
+ */
+ if (peap_version == 1) return 1;
+
+ /*
+ * No data, OR only 1 byte of EAP type.
+ */
+ if (!data || (data_len == 0) ||
+ ((data_len <= 1) && (data[0] != PW_EAP_IDENTITY))) {
+ return 0;
+ }
+
+ eap_method = *data;
+ switch (eap_method) {
+ case PW_EAP_IDENTITY:
+ if (data_len == 1) {
+ RDEBUG2("Identity - ");
+ return 1;
+ }
+ RDEBUG2("Identity - %*s",
+ data_len - 1, data + 1);
+ return 1;
+
+ /*
+ * If the first byte of the packet is
+ * EAP-Response, and the EAP data is a TLV,
+ * then it looks OK...
+ */
+ case PW_EAP_RESPONSE:
+ if (eap_packet->data[0] == PW_EAP_TLV) {
+ RDEBUG2("Received EAP-TLV response");
+ return 1;
+ }
+ RDEBUG2("Received unexpected EAP-Response, rejecting the session.");
+ break;
+
+
+ /*
+ * We normally do Microsoft MS-CHAPv2 (26), versus
+ * Cisco MS-CHAPv2 (29).
+ */
+ case PW_EAP_MSCHAPV2:
+ default:
+ RDEBUG2("EAP method %s (%d)", eap_type2name(eap_method),
+ eap_method);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert a pseudo-EAP packet to a list of VALUE_PAIR's.
+ */
+static VALUE_PAIR *eap2vp(UNUSED REQUEST *request, RADIUS_PACKET *packet,
+ EAP_DS *eap_ds,
+ uint8_t const *data, size_t data_len, int peap_version)
+{
+ size_t total;
+ uint8_t *p;
+ VALUE_PAIR *vp = NULL, *head = NULL;
+ vp_cursor_t cursor;
+
+ if (data_len > 65535) return NULL; /* paranoia */
+
+ vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0);
+ if (!vp) {
+ return NULL;
+ }
+
+ total = data_len;
+ if (total > 249) total = 249;
+
+ if (peap_version == 0) {
+ /*
+ * Hand-build an EAP packet from the crap in PEAP version 0.
+ */
+ vp->vp_length = EAP_HEADER_LEN + total;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+
+ p[0] = PW_EAP_RESPONSE;
+ p[1] = eap_ds->response->id;
+ p[2] = (data_len + EAP_HEADER_LEN) >> 8;
+ p[3] = (data_len + EAP_HEADER_LEN) & 0xff;
+
+ memcpy(p + EAP_HEADER_LEN, data, total);
+
+ } else { /* peapv1 */
+ vp->vp_length = total;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+ memcpy(p, data, total);
+ }
+
+ fr_cursor_init(&cursor, &head);
+ fr_cursor_insert(&cursor, vp);
+ while (total < data_len) {
+ vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0);
+ if (!vp) {
+ fr_pair_list_free(&head);
+ return NULL;
+ }
+
+ fr_pair_value_memcpy(vp, data + total, (data_len - total));
+
+ total += vp->vp_length;
+
+ fr_cursor_insert(&cursor, vp);
+ }
+
+ return head;
+}
+
+
+/*
+ * Convert a list of VALUE_PAIR's to an EAP packet, through the
+ * simple expedient of dumping the EAP message
+ */
+static int vp2eap(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *vp)
+{
+ rad_assert(vp != NULL);
+ VALUE_PAIR *this;
+ vp_cursor_t cursor;
+ size_t header = EAP_HEADER_LEN;
+
+ if (tls_session->peap_flag > 0) header = 0;
+
+ /*
+ * Skip the id, code, and length. Just write the EAP
+ * type & data to the client.
+ */
+#ifndef NDEBUG
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ size_t i, total, start = header;
+ total = 0;
+
+ for (this = fr_cursor_init(&cursor, &vp); this; this = fr_cursor_next(&cursor)) {
+ for (i = start; i < vp->vp_length; i++) {
+ if ((total & 0x0f) == 0) {
+ fprintf(fr_log_fp, " PEAP tunnel data out %04x: ", (int) total);
+ }
+ fprintf(fr_log_fp, "%02x ", vp->vp_octets[i]);
+
+ if ((total & 0x0f) == 0x0f) {
+ fprintf(fr_log_fp, "\n");
+ }
+
+ total++;
+ }
+
+ start = 0;
+ }
+
+ if ((total & 0x0f) != 0) {
+ fprintf(fr_log_fp, "\n");
+ }
+ }
+#endif
+
+ /*
+ * Send the EAP data in the first attribute, WITHOUT the
+ * header.
+ */
+ (tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets + header, vp->vp_length - header);
+
+ /*
+ * Send the rest of the EAP data, but skipping the first VP.
+ */
+ fr_cursor_init(&cursor, &vp);
+ for (this = fr_cursor_next(&cursor);
+ this;
+ this = fr_cursor_next(&cursor)) {
+ (tls_session->record_plus)(&tls_session->clean_in, this->vp_octets, this->vp_length);
+ }
+
+ tls_handshake_send(request, tls_session);
+
+ return 1;
+}
+
+
+/*
+ * See if there's a TLV in the response.
+ */
+static int eappeap_check_tlv(REQUEST *request, uint8_t const *data,
+ size_t data_len)
+{
+ eap_packet_raw_t const *eap_packet = (eap_packet_raw_t const *) data;
+
+ if (data_len < 11) return 0;
+
+ /*
+ * Look for success or failure.
+ */
+ if ((eap_packet->code == PW_EAP_RESPONSE) &&
+ (eap_packet->data[0] == PW_EAP_TLV)) {
+ if (data[10] == EAP_TLV_SUCCESS) {
+ return 1;
+ }
+
+ if (data[10] == EAP_TLV_FAILURE) {
+ RDEBUG2("Client rejected our response. The password is probably incorrect");
+ return 0;
+ }
+ }
+
+ RDEBUG("Unknown TLV %02x", data[10]);
+
+ return 0;
+}
+
+
+/*
+ * Use a reply packet to determine what to do.
+ */
+static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session,
+ REQUEST *request, RADIUS_PACKET *reply)
+{
+ rlm_rcode_t rcode = RLM_MODULE_REJECT;
+ VALUE_PAIR *vp;
+ peap_tunnel_t *t = tls_session->opaque;
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ RDEBUG("Got tunneled reply RADIUS code %d", reply->code);
+ rdebug_pair_list(L_DBG_LVL_1, request, reply->vps, NULL);
+ }
+
+ switch (reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ RDEBUG2("Tunneled authentication was successful");
+ tls_session->authentication_success = true;
+ t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
+ eappeap_success(handler, tls_session);
+ rcode = RLM_MODULE_HANDLED;
+
+ /*
+ * If we've been told to use the attributes from
+ * the reply, then do so.
+ *
+ * WARNING: This may leak information about the
+ * tunneled user!
+ */
+ if (t->use_tunneled_reply) {
+ RDEBUG2("Saving tunneled attributes for later");
+
+ /*
+ * Clean up the tunneled reply.
+ */
+ fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+
+ /*
+ * Delete MPPE keys & encryption policy. We don't
+ * want these here.
+ */
+ fr_pair_delete_by_num(&reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ fr_pair_list_free(&t->accept_vps); /* for proxying MS-CHAP2 */
+ fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
+ rad_assert(!reply->vps);
+ }
+ break;
+
+ case PW_CODE_ACCESS_REJECT:
+ RDEBUG2("Tunneled authentication was rejected");
+ t->status = PEAP_STATUS_SENT_TLV_FAILURE;
+ eappeap_failure(handler, tls_session);
+ rcode = RLM_MODULE_HANDLED;
+ break;
+
+ case PW_CODE_ACCESS_CHALLENGE:
+ RDEBUG2("Got tunneled Access-Challenge");
+
+ /*
+ * Keep the State attribute, if necessary.
+ *
+ * Get rid of the old State, too.
+ */
+ fr_pair_list_free(&t->state);
+ fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, PW_STATE, 0, TAG_ANY);
+
+ /*
+ * PEAP takes only EAP-Message attributes inside
+ * of the tunnel. Any Reply-Message in the
+ * Access-Challenge is ignored.
+ */
+ vp = NULL;
+ fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+
+ /*
+ * Handle EAP-MSCHAP-V2, where Access-Accept's
+ * from the home server may contain MS-CHAP2-Success,
+ * which the module turns into challenges, so that
+ * the client may respond to the challenge with
+ * an "ack" packet.
+ */
+ if (t->home_access_accept && t->use_tunneled_reply) {
+ RDEBUG2("Saving tunneled attributes for later");
+
+ /*
+ * Clean up the tunneled reply.
+ */
+ fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
+
+ rad_assert(!t->accept_vps);
+ fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps, 0, 0, TAG_ANY);
+ rad_assert(!reply->vps);
+ }
+
+ /*
+ * Handle the ACK, by tunneling any necessary reply
+ * VP's back to the client.
+ */
+ if (vp) {
+ vp2eap(request, tls_session, vp);
+ fr_pair_list_free(&vp);
+ }
+
+ rcode = RLM_MODULE_HANDLED;
+ break;
+
+ default:
+ RDEBUG2("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
+ rcode = RLM_MODULE_REJECT;
+ break;
+ }
+
+ return rcode;
+}
+
+#ifdef WITH_PROXY
+/*
+ * Do post-proxy processing,
+ */
+static int CC_HINT(nonnull) eappeap_postproxy(eap_handler_t *handler, void *data)
+{
+ int rcode;
+ tls_session_t *tls_session = (tls_session_t *) data;
+ REQUEST *fake, *request = handler->request;
+
+ RDEBUG2("Passing reply from proxy back into the tunnel");
+
+ /*
+ * If there was a fake request associated with the proxied
+ * request, do more processing of it.
+ */
+ fake = (REQUEST *) request_data_get(handler->request,
+ handler->request->proxy,
+ REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);
+
+ /*
+ * Do the callback, if it exists, and if it was a success.
+ */
+ if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) {
+ peap_tunnel_t *t = tls_session->opaque;
+
+ t->home_access_accept = true;
+
+ /*
+ * Terrible hacks.
+ */
+ rad_assert(!fake->packet);
+ fake->packet = talloc_steal(fake, request->proxy);
+ fake->packet->src_ipaddr = request->packet->src_ipaddr;
+ request->proxy = NULL;
+
+ rad_assert(!fake->reply);
+ fake->reply = talloc_steal(fake, request->proxy_reply);
+ request->proxy_reply = NULL;
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ fprintf(fr_log_fp, "server %s {\n", fake->server);
+ }
+
+ fake->reply->code = PW_CODE_ACCESS_ACCEPT;
+
+ /*
+ * Perform a post-auth stage, which will get the EAP
+ * handler, too...
+ */
+ fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ RDEBUG2("Passing reply back for EAP-MS-CHAP-V2");
+ process_post_proxy(0, fake);
+
+ /*
+ * FIXME: If rcode returns fail, do something
+ * intelligent...
+ */
+ rcode = rad_postauth(fake);
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ fprintf(fr_log_fp, "} # server %s\n", fake->server);
+
+ RDEBUG("Final reply from tunneled session code %d", fake->reply->code);
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
+ }
+
+ /*
+ * Terrible hacks.
+ */
+ request->proxy = talloc_steal(request, fake->packet);
+ fake->packet = NULL;
+ request->proxy_reply = talloc_steal(request, fake->reply);
+ fake->reply = NULL;
+
+ /*
+ * And we're done with this request.
+ */
+
+ switch (rcode) {
+ case RLM_MODULE_FAIL:
+ talloc_free(fake);
+ eaptls_fail(handler, 0);
+ return 0;
+
+ default: /* Don't Do Anything */
+ RDEBUG2("Got reply %d", request->proxy_reply->code);
+ break;
+ }
+ }
+ talloc_free(fake); /* robust if !fake */
+
+ /*
+ * If there was no EAP-Message in the reply packet, then
+ * we know that we're supposed to re-run the "authenticate"
+ * stage, in order to get the right kind of handling...
+ */
+
+ /*
+ * Process the reply from the home server.
+ */
+
+ rcode = process_reply(handler, tls_session, handler->request,
+ handler->request->proxy_reply);
+
+ /*
+ * The proxy code uses the reply from the home server as
+ * the basis for the reply to the NAS. We don't want that,
+ * so we toss it, after we've had our way with it.
+ */
+ fr_pair_list_free(&handler->request->proxy_reply->vps);
+
+ switch (rcode) {
+ case RLM_MODULE_REJECT:
+ RDEBUG2("Reply was rejected");
+ eaptls_fail(handler, 0);
+ return 0;
+
+ case RLM_MODULE_HANDLED:
+ RDEBUG2("Reply was handled");
+ eaptls_request(handler->eap_ds, tls_session);
+ request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
+ return 1;
+
+ case RLM_MODULE_OK:
+ RDEBUG2("Reply was OK");
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ return eaptls_success(handler, 0);
+
+ default:
+ RDEBUG2("Reply was unknown");
+ break;
+ }
+
+ eaptls_fail(handler, 0);
+ return 0;
+}
+#endif
+
+
+static char const *peap_state(peap_tunnel_t *t)
+{
+ switch (t->status) {
+ case PEAP_STATUS_TUNNEL_ESTABLISHED:
+ return "TUNNEL ESTABLISHED";
+
+ case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE:
+ return "WAITING FOR SOH RESPONSE";
+
+ case PEAP_STATUS_INNER_IDENTITY_REQ_SENT:
+ return "WAITING FOR INNER IDENTITY";
+
+ case PEAP_STATUS_SENT_TLV_SUCCESS:
+ return "send tlv success";
+
+ case PEAP_STATUS_SENT_TLV_FAILURE:
+ return "send tlv failure";
+
+ case PEAP_STATUS_PHASE2_INIT:
+ return "phase2_init";
+
+ case PEAP_STATUS_PHASE2:
+ return "phase2";
+
+ default:
+ break;
+ }
+ return "?";
+}
+
+static void print_tunneled_data(uint8_t const *data, size_t data_len)
+{
+ size_t i;
+
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ for (i = 0; i < data_len; i++) {
+ if ((i & 0x0f) == 0) fprintf(fr_log_fp, " PEAP tunnel data in %02x: ", (int) i);
+
+ fprintf(fr_log_fp, "%02x ", data[i]);
+
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
+ }
+}
+
+
+/*
+ * Process the pseudo-EAP contents of the tunneled data.
+ */
+rlm_rcode_t eappeap_process(eap_handler_t *handler, tls_session_t *tls_session, int auth_type_eap)
+{
+ peap_tunnel_t *t = tls_session->opaque;
+ REQUEST *fake;
+ VALUE_PAIR *vp;
+ rlm_rcode_t rcode = RLM_MODULE_REJECT;
+ uint8_t const *data;
+ unsigned int data_len;
+ size_t header = 0;
+
+ REQUEST *request = handler->request;
+ EAP_DS *eap_ds = handler->eap_ds;
+
+ /*
+ * Just look at the buffer directly, without doing
+ * record_minus. This lets us avoid another data copy.
+ */
+ data_len = tls_session->clean_out.used;
+ tls_session->clean_out.used = 0;
+ data = tls_session->clean_out.data;
+
+ RDEBUG2("PEAP state %s", peap_state(t));
+
+ if ((t->status != PEAP_STATUS_TUNNEL_ESTABLISHED) &&
+ !eapmessage_verify(request, data, data_len, tls_session->peap_flag)) {
+ REDEBUG("Tunneled data is invalid");
+ if (rad_debug_lvl > 2) print_tunneled_data(data, data_len);
+ return RLM_MODULE_REJECT;
+ }
+
+ if (tls_session->peap_flag > 0) header = EAP_HEADER_LEN;
+
+ switch (t->status) {
+ case PEAP_STATUS_TUNNEL_ESTABLISHED:
+ /* FIXME: should be no data in the buffer here, check & assert? */
+
+ if (SSL_session_reused(tls_session->ssl)) {
+ RDEBUG2("Skipping Phase2 because of session resumption");
+ t->session_resumption_state = PEAP_RESUMPTION_YES;
+ if (t->soh) {
+ t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE;
+ RDEBUG2("Requesting SoH from client");
+ eappeap_soh(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+ /* we're good, send success TLV */
+ t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
+ eappeap_success(handler, tls_session);
+
+ } else {
+ /* send an identity request */
+ t->session_resumption_state = PEAP_RESUMPTION_NO;
+ t->status = PEAP_STATUS_INNER_IDENTITY_REQ_SENT;
+ tls_session->session_not_resumed = true;
+ eappeap_identity(handler, tls_session);
+ }
+ return RLM_MODULE_HANDLED;
+
+ case PEAP_STATUS_INNER_IDENTITY_REQ_SENT:
+ /* we're expecting an identity response */
+ if (data[header] != PW_EAP_IDENTITY) {
+ REDEBUG("Expected EAP-Identity, got something else");
+ return RLM_MODULE_REJECT;
+ }
+
+ /*
+ * Save it for later.
+ */
+ t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
+ rad_assert(t->username != NULL);
+
+ fr_pair_value_bstrncpy(t->username, data + header + 1, data_len - header - 1);
+
+ RDEBUG("Got inner identity '%s'", t->username->vp_strvalue);
+ if (t->soh) {
+ t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE;
+ RDEBUG2("Requesting SoH from client");
+ eappeap_soh(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+ t->status = PEAP_STATUS_PHASE2_INIT;
+ break;
+
+ case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE:
+ fake = request_alloc_fake(request);
+ rad_assert(!fake->packet->vps);
+ eapsoh_verify(fake, fake->packet, data + header, data_len - header);
+ setup_fake_request(request, fake, t);
+
+ if (t->soh_virtual_server) {
+ fake->server = t->soh_virtual_server;
+ }
+ RDEBUG("Sending SoH request to server %s", fake->server ? fake->server : "NULL");
+ rad_virtual_server(fake);
+
+ if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) {
+ RDEBUG2("SoH was rejected");
+ talloc_free(fake);
+ t->status = PEAP_STATUS_SENT_TLV_FAILURE;
+ eappeap_failure(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+
+ /* save the SoH VPs */
+ rad_assert(!t->soh_reply_vps);
+ fr_pair_list_mcopy_by_num(t, &t->soh_reply_vps, &fake->reply->vps, 0, 0, TAG_ANY);
+ rad_assert(!fake->reply->vps);
+ talloc_free(fake);
+
+ if (t->session_resumption_state == PEAP_RESUMPTION_YES) {
+ /* we're good, send success TLV */
+ t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
+ eappeap_success(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+
+ t->status = PEAP_STATUS_PHASE2_INIT;
+ break;
+
+
+ /*
+ * If we authenticated the user, then it's OK.
+ */
+ case PEAP_STATUS_SENT_TLV_SUCCESS:
+ if (eappeap_check_tlv(request, data + header, data_len - header)) {
+ RDEBUG2("Success");
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Otherwise, the client rejected the session
+ * resumption. If the session is being re-used,
+ * we need to do a full authentication.
+ *
+ * We do this by sending an EAP-Identity request
+ * inside of the PEAP tunnel.
+ */
+ if (t->session_resumption_state == PEAP_RESUMPTION_YES) {
+ RDEBUG2("Client rejected session resumption. Re-starting full authentication");
+
+ /*
+ * Mark session resumption status.
+ */
+ t->status = PEAP_STATUS_INNER_IDENTITY_REQ_SENT;
+ t->session_resumption_state = PEAP_RESUMPTION_NO;
+
+ eappeap_identity(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+
+ REDEBUG("We sent a success, but the client did not agree");
+ return RLM_MODULE_REJECT;
+
+ /*
+ * Supplicant ACKs our failure.
+ */
+ case PEAP_STATUS_SENT_TLV_FAILURE:
+ RINDENT();
+ REDEBUG("The users session was previously rejected: returning reject (again.)");
+ RDEBUG("This means you need to read the PREVIOUS messages in the debug output");
+ RDEBUG("to find out the reason why the user was rejected");
+ RDEBUG("Look for \"reject\" or \"fail\". Those earlier messages will tell you");
+ RDEBUG("what went wrong, and how to fix the problem");
+ REXDENT();
+
+ return RLM_MODULE_REJECT;
+
+ case PEAP_STATUS_PHASE2_INIT:
+ RDEBUG("In state machine in phase2 init?");
+
+ case PEAP_STATUS_PHASE2:
+ break;
+
+ default:
+ REDEBUG("Unhandled state in peap");
+ return RLM_MODULE_REJECT;
+ }
+
+ fake = request_alloc_fake(request);
+
+ rad_assert(!fake->packet->vps);
+
+ switch (t->status) {
+ /*
+ * If we're in PHASE2_INIT, the phase2 method hasn't been
+ * sent an Identity packet yet; do so from the stored
+ * username and this will kick off the phase2 eap method
+ */
+
+ case PEAP_STATUS_PHASE2_INIT: {
+ size_t len = t->username->vp_length + EAP_HEADER_LEN + 1;
+ uint8_t *q;
+
+ t->status = PEAP_STATUS_PHASE2;
+
+ vp = fr_pair_afrom_num(fake->packet, PW_EAP_MESSAGE, 0);
+ vp->vp_length = len;
+ vp->vp_octets = q = talloc_array(vp, uint8_t, vp->vp_length);
+
+ q[0] = PW_EAP_RESPONSE;
+ q[1] = eap_ds->response->id;
+ q[2] = (len >> 8) & 0xff;
+ q[3] = len & 0xff;
+ q[4] = PW_EAP_IDENTITY;
+
+ memcpy(q + EAP_HEADER_LEN + 1,
+ t->username->vp_strvalue, t->username->vp_length);
+
+ fr_pair_add(&fake->packet->vps, vp);
+
+ if (t->default_method != 0) {
+ RDEBUG2("Setting default EAP type for tunneled EAP session");
+ vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ);
+ vp->vp_integer = t->default_method;
+ }
+ break; }
+
+ case PEAP_STATUS_PHASE2:
+ fake->packet->vps = eap2vp(request, fake->packet,
+ eap_ds, data, data_len, tls_session->peap_flag);
+ if (!fake->packet->vps) {
+ talloc_free(fake);
+ RDEBUG2("Unable to convert tunneled EAP packet to internal server data structures");
+ return RLM_MODULE_REJECT;
+ }
+ break;
+
+ default:
+ REDEBUG("Invalid state change in PEAP");
+ return RLM_MODULE_REJECT;
+ }
+
+ RDEBUG2("Got tunneled request");
+ rdebug_pair_list(L_DBG_LVL_2, request, fake->packet->vps, NULL);
+
+ /*
+ * Update other items in the REQUEST data structure.
+ */
+ if (!t->username) {
+ /*
+ * There's no User-Name in the tunneled session,
+ * so we add one here, by pulling it out of the
+ * EAP-Identity packet.
+ */
+ if ((data[header] == PW_EAP_IDENTITY) && (data_len > (1 + header))) {
+ t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
+ rad_assert(t->username != NULL);
+
+ fr_pair_value_bstrncpy(t->username, data + header + 1, data_len - header - 1);
+
+ RDEBUG2("Got tunneled identity of %s", t->username->vp_strvalue);
+
+ /*
+ * If there's a default EAP type,
+ * set it here.
+ */
+ if (t->default_method != 0) {
+ RDEBUG2("Setting default EAP type for tunneled EAP session");
+ vp = fr_pair_make(fake, &fake->config, "EAP-Type", "0", T_OP_EQ);
+ vp->vp_integer = t->default_method;
+ }
+ }
+ } /* else there WAS a t->username */
+
+ setup_fake_request(request, fake, t);
+
+ if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+ fake->server = vp->vp_strvalue;
+
+ } else if (t->virtual_server) {
+ fake->server = t->virtual_server;
+
+ } /* else fake->server == request->server */
+
+ if (fake->server) {
+ RDEBUG2("Sending tunneled request to %s", fake->server);
+ } else {
+ RDEBUG2("Sending tunnelled request");
+ }
+ rdebug_pair_list(L_DBG_LVL_2, request, fake->packet->vps, NULL);
+
+ /*
+ * Call authentication recursively, which will
+ * do PAP, CHAP, MS-CHAP, etc.
+ */
+ rad_virtual_server(fake);
+
+ /*
+ * Note that we don't do *anything* with the reply
+ * attributes.
+ */
+ RDEBUG2("Got tunneled reply code %d", fake->reply->code);
+ rdebug_pair_list(L_DBG_LVL_2, request, fake->reply->vps, NULL);
+
+ /*
+ * Decide what to do with the reply.
+ */
+ switch (fake->reply->code) {
+ case 0: /* No reply code, must be proxied... */
+#ifdef WITH_PROXY
+ vp = fr_pair_find_by_num(fake->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+
+ if (vp) {
+ eap_tunnel_data_t *tunnel;
+ bool proxy_as_eap = t->proxy_tunneled_request_as_eap;
+ VALUE_PAIR *flag = fr_pair_find_by_num(fake->config, PW_PROXY_TUNNELED_REQUEST_AS_EAP, 0, TAG_ANY);
+
+ if (flag) proxy_as_eap = flag->vp_integer;
+
+ /*
+ * The tunneled request was NOT handled,
+ * it has to be proxied. This means that
+ * the "authenticate" stage was never
+ * performed.
+ *
+ * If we are told to NOT proxy the
+ * tunneled request as EAP, then this
+ * means that we've got to decode it,
+ * which means that we MUST run the
+ * "authenticate" portion by hand, here.
+ *
+ * Once the tunneled EAP session is ALMOST
+ * done, THEN we proxy it...
+ */
+ if (!proxy_as_eap) {
+ fake->options |= RAD_REQUEST_OPTION_PROXY_EAP;
+
+ /*
+ * Hmm... should we check for
+ * Auth-Type & EAP-Message here?
+ */
+
+ if (!auth_type_eap) {
+ RERROR("You must set 'inner_eap_module' in the 'peap' configuration");
+ RERROR("This is required in order to proxy the inner EAP session.");
+ rcode = RLM_MODULE_REJECT;
+ goto done;
+ }
+
+ /*
+ * Run the EAP authentication.
+ */
+ RDEBUG2("Calling authenticate in order to initiate tunneled EAP session");
+ rcode = process_authenticate(auth_type_eap, fake);
+ if (rcode == RLM_MODULE_OK) {
+ /*
+ * Authentication succeeded! Rah!
+ */
+ fake->reply->code = PW_CODE_ACCESS_ACCEPT;
+ goto do_process;
+ }
+
+ if (rcode != RLM_MODULE_HANDLED) {
+ RDEBUG("Can't handle the return code %d", rcode);
+ rcode = RLM_MODULE_REJECT;
+ goto done;
+ }
+
+ /*
+ * The module decided it wasn't
+ * done. Handle it like normal.
+ */
+ if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) == 0) {
+ RDEBUG2("Cancelling proxy to realm %s until the tunneled EAP session "
+ "has been established", vp->vp_strvalue);
+ goto do_process;
+ }
+
+ /*
+ * The module has decoded the
+ * EAP-Message into another set
+ * of attributes.
+ */
+ fr_pair_delete_by_num(&fake->packet->vps,
+ PW_EAP_MESSAGE, 0, TAG_ANY);
+ }
+
+ RDEBUG2("Tunnelled authentication will be proxied to %s", vp->vp_strvalue);
+
+ /*
+ * Tell the original request that it's going
+ * to be proxied.
+ */
+ fr_pair_list_mcopy_by_num(request, &request->config,
+ &fake->config,
+ PW_PROXY_TO_REALM, 0, TAG_ANY);
+
+ /*
+ * Seed the proxy packet with the
+ * tunneled request.
+ */
+ rad_assert(!request->proxy);
+ request->proxy = talloc_steal(request, fake->packet);
+ memset(&request->proxy->src_ipaddr, 0,
+ sizeof(request->proxy->src_ipaddr));
+ memset(&request->proxy->dst_ipaddr, 0,
+ sizeof(request->proxy->dst_ipaddr));
+ request->proxy->src_port = 0;
+ request->proxy->dst_port = 0;
+ fake->packet = NULL;
+ rad_free(&fake->reply);
+ fake->reply = NULL;
+
+ /*
+ * Set up the callbacks for the tunnel
+ */
+ tunnel = talloc_zero(request, eap_tunnel_data_t);
+ tunnel->tls_session = tls_session;
+ tunnel->callback = eappeap_postproxy;
+
+ /*
+ * Associate the callback with the request.
+ */
+ rcode = request_data_add(request,
+ request->proxy,
+ REQUEST_DATA_EAP_TUNNEL_CALLBACK,
+ tunnel, false);
+ rad_assert(rcode == 0);
+
+ /*
+ * We're not proxying it as EAP, so we've got
+ * to do the callback later.
+ */
+ if ((fake->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) {
+ RDEBUG2("Remembering to do EAP-MS-CHAP-V2 post-proxy");
+
+ /*
+ * rlm_eap.c has taken care of associating
+ * the handler with the fake request.
+ *
+ * So we associate the fake request with
+ * this request.
+ */
+ rcode = request_data_add(request, request->proxy,
+ REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
+ fake, true);
+ rad_assert(rcode == 0);
+
+ /*
+ * Do NOT free the fake request!
+ */
+ return RLM_MODULE_UPDATED;
+ }
+
+ /*
+ * Didn't authenticate the packet, but
+ * we're proxying it.
+ */
+ rcode = RLM_MODULE_UPDATED;
+
+ } else
+#endif /* WITH_PROXY */
+ {
+ REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", fake->reply->code);
+ rcode = RLM_MODULE_REJECT;
+ }
+ break;
+
+ default:
+#ifdef WITH_PROXY
+ do_process:
+#endif
+ rcode = process_reply(handler, tls_session, request,
+ fake->reply);
+ break;
+ }
+
+#ifdef WITH_PROXY
+ done:
+#endif
+ talloc_free(fake);
+
+ return rcode;
+}
+
+static int CC_HINT(nonnull) setup_fake_request(REQUEST *request, REQUEST *fake, peap_tunnel_t *t) {
+
+ VALUE_PAIR *vp;
+
+ /*
+ * Tell the request that it's a fake one.
+ */
+ fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+ if (t->username) {
+ vp = fr_pair_list_copy(fake->packet, t->username);
+ fr_pair_add(&fake->packet->vps, vp);
+ fake->username = vp;
+ RDEBUG2("Setting User-Name to %s", fake->username->vp_strvalue);
+ } else {
+ RDEBUG2("No tunnel username (SSL resumption?)");
+ }
+
+
+ /*
+ * Add the State attribute, too, if it exists.
+ */
+ if (t->state) {
+ vp = fr_pair_list_copy(fake->packet, t->state);
+ if (vp) fr_pair_add(&fake->packet->vps, vp);
+ }
+
+ /*
+ * If this is set, we copy SOME of the request attributes
+ * from outside of the tunnel to inside of the tunnel.
+ *
+ * We copy ONLY those attributes which do NOT already
+ * exist in the tunneled request.
+ *
+ * This code is copied from ../rlm_eap_ttls/ttls.c
+ */
+ if (t->copy_request_to_tunnel) {
+ VALUE_PAIR *copy;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ /*
+ * The attribute is a server-side thingy,
+ * don't copy it.
+ */
+ if ((vp->da->attr > 255) && (((vp->da->attr >> 16) & 0xffff) == 0)) {
+ continue;
+ }
+
+ /*
+ * The outside attribute is already in the
+ * tunnel, don't copy it.
+ *
+ * This works for BOTH attributes which
+ * are originally in the tunneled request,
+ * AND attributes which are copied there
+ * from below.
+ */
+ if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) continue;
+
+ /*
+ * Some attributes are handled specially.
+ */
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ /*
+ * NEVER copy Message-Authenticator,
+ * EAP-Message, or State. They're
+ * only for outside of the tunnel.
+ */
+ case PW_USER_NAME:
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_CHAP_CHALLENGE:
+ case PW_PROXY_STATE:
+ case PW_MESSAGE_AUTHENTICATOR:
+ case PW_EAP_MESSAGE:
+ case PW_STATE:
+ continue;
+
+ /*
+ * By default, copy it over.
+ */
+ default:
+ break;
+ }
+
+ /*
+ * Don't copy from the head, we've already
+ * checked it.
+ */
+ copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->attr, vp->da->vendor, TAG_ANY);
+ fr_pair_add(&fake->packet->vps, copy);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
new file mode 100644
index 0000000..d9f850c
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
@@ -0,0 +1,429 @@
+/*
+ * rlm_eap_peap.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include "eap_peap.h"
+
+typedef struct rlm_eap_peap_t {
+ char const *tls_conf_name; //!< TLS configuration.
+ fr_tls_server_conf_t *tls_conf;
+ char const *default_method_name; //!< Default tunneled EAP type.
+ int default_method;
+
+ char const *inner_eap_module; //!< module name for inner EAP
+ int auth_type_eap;
+ bool use_tunneled_reply; //!< Use the reply attributes from the tunneled session in
+ //!< the non-tunneled reply to the client.
+
+ bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the
+ //!< tunneled session in the tunneled request.
+#ifdef WITH_PROXY
+ bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated
+ //!< protocol.
+#endif
+ char const *virtual_server; //!< Virtual server for inner tunnel session.
+
+ bool soh; //!< Do we do SoH request?
+ char const *soh_virtual_server;
+ bool req_client_cert; //!< Do we do require a client cert?
+} rlm_eap_peap_t;
+
+
+static CONF_PARSER module_config[] = {
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, tls_conf_name), NULL },
+
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, default_method_name), "mschapv2" },
+
+ { "inner_eap_module", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, inner_eap_module), NULL },
+
+ { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, copy_request_to_tunnel), "no" },
+
+ { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, use_tunneled_reply), "no" },
+
+#ifdef WITH_PROXY
+ { "proxy_tunneled_request_as_eap", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, proxy_tunneled_request_as_eap), "yes" },
+#endif
+
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, virtual_server), NULL },
+
+ { "soh", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, soh), "no" },
+
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_peap_t, req_client_cert), "no" },
+
+ { "soh_virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_peap_t, soh_virtual_server), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_peap_t *inst;
+ DICT_VALUE const *dv;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_peap_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ if (!inst->virtual_server) {
+ ERROR("rlm_eap_peap: A 'virtual_server' MUST be defined for security");
+ return -1;
+ }
+
+ /*
+ * Convert the name to an integer, to make it easier to
+ * handle.
+ */
+ inst->default_method = eap_name2type(inst->default_method_name);
+ if (inst->default_method < 0) {
+ ERROR("rlm_eap_peap: Unknown EAP type %s",
+ inst->default_method_name);
+ return -1;
+ }
+
+ /*
+ * Read tls configuration, either from group given by 'tls'
+ * option, or from the eap-tls configuration.
+ */
+ inst->tls_conf = eaptls_conf_parse(cs, "tls");
+
+ if (!inst->tls_conf) {
+ ERROR("rlm_eap_peap: Failed initializing SSL context");
+ return -1;
+ }
+
+ /*
+ * Don't expose this if we don't need it.
+ */
+ if (!inst->inner_eap_module) inst->inner_eap_module = "eap";
+
+ dv = dict_valbyname(PW_AUTH_TYPE, 0, inst->inner_eap_module);
+ if (!dv) {
+ WARN("Failed to find 'Auth-Type %s' section in virtual server %s. The server cannot proxy inner-tunnel EAP packets.",
+ inst->inner_eap_module, inst->virtual_server);
+ } else {
+ inst->auth_type_eap = dv->value;
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate the PEAP per-session data
+ */
+static peap_tunnel_t *peap_alloc(TALLOC_CTX *ctx, rlm_eap_peap_t *inst)
+{
+ peap_tunnel_t *t;
+
+ t = talloc_zero(ctx, peap_tunnel_t);
+
+ t->default_method = inst->default_method;
+ t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
+ t->use_tunneled_reply = inst->use_tunneled_reply;
+#ifdef WITH_PROXY
+ t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap;
+#endif
+ t->virtual_server = inst->virtual_server;
+ t->soh = inst->soh;
+ t->soh_virtual_server = inst->soh_virtual_server;
+ t->session_resumption_state = PEAP_RESUMPTION_MAYBE;
+
+ return t;
+}
+
+/*
+ * Send an initial eap-tls request to the peer, using the libeap functions.
+ */
+static int mod_session_init(void *type_arg, eap_handler_t *handler)
+{
+ int status;
+ tls_session_t *ssn;
+ rlm_eap_peap_t *inst;
+ VALUE_PAIR *vp;
+ bool client_cert;
+ REQUEST *request = handler->request;
+
+ inst = type_arg;
+
+ handler->tls = true;
+
+ /*
+ * Check if we need a client certificate.
+ */
+
+ /*
+ * EAP-TLS-Require-Client-Cert attribute will override
+ * the require_client_cert configuration option.
+ */
+ vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
+ if (vp) {
+ client_cert = vp->vp_integer ? true : false;
+ } else {
+ client_cert = inst->req_client_cert;
+ }
+
+ /*
+ * Allow TLS 1.3, it works.
+ */
+ ssn = eaptls_session(handler, inst->tls_conf, client_cert, true);
+ if (!ssn) {
+ return 0;
+ }
+
+ handler->opaque = ((void *)ssn);
+
+ /*
+ * Set the label to a fixed string. For TLS 1.3, the
+ * label is the same for all TLS-based EAP methods. If
+ * the client is using TLS 1.3, then eaptls_success()
+ * will over-ride this label with the correct label for
+ * TLS 1.3.
+ */
+ ssn->label = "client EAP encryption";
+
+ /*
+ * As it is a poorly designed protocol, PEAP uses
+ * bits in the TLS header to indicate PEAP
+ * version numbers. For now, we only support
+ * PEAP version 0, so it doesn't matter too much.
+ * However, if we support later versions of PEAP,
+ * we will need this flag to indicate which
+ * version we're currently dealing with.
+ */
+ ssn->peap_flag = 0x00;
+
+ /*
+ * PEAP version 0 requires 'include_length = no',
+ * so rather than hoping the user figures it out,
+ * we force it here.
+ */
+ ssn->length_flag = false;
+
+ /*
+ * TLS session initialization is over. Now handle TLS
+ * related handshaking or application data.
+ */
+ status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+ if (status == 0) return 0;
+
+ /*
+ * The next stage to process the packet.
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+/*
+ * Do authentication, by letting EAP-TLS do most of the work.
+ */
+static int mod_process(void *arg, eap_handler_t *handler)
+{
+ int rcode;
+ int ret = 0;
+ fr_tls_status_t status;
+ rlm_eap_peap_t *inst = (rlm_eap_peap_t *) arg;
+ tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+ peap_tunnel_t *peap = tls_session->opaque;
+ REQUEST *request = handler->request;
+
+ /*
+ * Session resumption requires the storage of data, so
+ * allocate it if it doesn't already exist.
+ */
+ if (!tls_session->opaque) {
+ peap = tls_session->opaque = peap_alloc(tls_session, inst);
+ }
+
+ /*
+ * Negotiate PEAP versions down.
+ */
+ if ((handler->eap_ds->response->type.data[0] & 0x03) < tls_session->peap_flag) {
+ tls_session->peap_flag = handler->eap_ds->response->type.data[0] & 0x03;
+ }
+
+ status = eaptls_process(handler);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+
+ /*
+ * Make request available to any SSL callbacks
+ */
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
+ switch (status) {
+ /*
+ * EAP-TLS handshake was successful, tell the
+ * client to keep talking.
+ *
+ * If this was EAP-TLS, we would just return
+ * an EAP-TLS-Success packet here.
+ */
+ case FR_TLS_SUCCESS:
+ peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
+ break;
+
+ /*
+ * The TLS code is still working on the TLS
+ * exchange, and it's a valid TLS request.
+ * do nothing.
+ */
+ case FR_TLS_HANDLED:
+ /*
+ * FIXME: If the SSL session is established, grab the state
+ * and EAP id from the inner tunnel, and update it with
+ * the expected EAP id!
+ */
+ ret = 1;
+ goto done;
+ /*
+ * Handshake is done, proceed with decoding tunneled
+ * data.
+ */
+ case FR_TLS_OK:
+ /*
+ * TLSv1.3 makes application data immediately avaliable
+ */
+ if (tls_session->is_init_finished && (peap->status == PEAP_STATUS_INVALID)) peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
+ break;
+
+ /*
+ * Anything else: fail.
+ */
+ default:
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Session is established, proceed with decoding
+ * tunneled data.
+ */
+ RDEBUG2("Session established. Decoding tunneled attributes");
+
+ /*
+ * We may need PEAP data associated with the session, so
+ * allocate it here, if it wasn't already alloacted.
+ */
+ if (!tls_session->opaque) {
+ tls_session->opaque = peap_alloc(tls_session, inst);
+ }
+
+ /*
+ * Process the PEAP portion of the request.
+ */
+ rcode = eappeap_process(handler, tls_session, inst->auth_type_eap);
+ switch (rcode) {
+ case RLM_MODULE_REJECT:
+ eaptls_fail(handler, 0);
+ ret = 0;
+ goto done;
+
+ case RLM_MODULE_HANDLED:
+ eaptls_request(handler->eap_ds, tls_session);
+ ret = 1;
+ goto done;
+
+ case RLM_MODULE_OK:
+ /*
+ * Move the saved VP's from the Access-Accept to
+ * our Access-Accept.
+ */
+ peap = tls_session->opaque;
+ if (peap->soh_reply_vps) {
+ RDEBUG2("Using saved attributes from the SoH reply");
+ rdebug_pair_list(L_DBG_LVL_2, request, peap->soh_reply_vps, NULL);
+ fr_pair_list_mcopy_by_num(handler->request->reply,
+ &handler->request->reply->vps,
+ &peap->soh_reply_vps, 0, 0, TAG_ANY);
+ }
+ if (peap->accept_vps) {
+ RDEBUG2("Using saved attributes from the original Access-Accept");
+ rdebug_pair_list(L_DBG_LVL_2, request, peap->accept_vps, NULL);
+ fr_pair_list_mcopy_by_num(handler->request->reply,
+ &handler->request->reply->vps,
+ &peap->accept_vps, 0, 0, TAG_ANY);
+ } else if (peap->use_tunneled_reply) {
+ RDEBUG2("No saved attributes in the original Access-Accept");
+ }
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ ret = eaptls_success(handler, 0);
+ goto done;
+
+ /*
+ * No response packet, MUST be proxying it.
+ * The main EAP module will take care of discovering
+ * that the request now has a "proxy" packet, and
+ * will proxy it, rather than returning an EAP packet.
+ */
+ case RLM_MODULE_UPDATED:
+#ifdef WITH_PROXY
+ rad_assert(handler->request->proxy != NULL);
+#endif
+ ret = 1;
+ goto done;
+
+ default:
+ break;
+ }
+
+ eaptls_fail(handler, 0);
+
+done:
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
+
+ return ret;
+}
+
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_peap;
+rlm_eap_module_t rlm_eap_peap = {
+ .name = "eap_peap",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore b/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/README.md b/src/modules/rlm_eap/types/rlm_eap_pwd/README.md
new file mode 100644
index 0000000..e7ea14b
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/README.md
@@ -0,0 +1,11 @@
+# rlm_eap_pwd
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements EAP-PWD as described by [RFC 5931](https://tools.ietf.org/html/rfc5931).
+
+EAP-PWD allows authentication using a PSK (the user's password). The PSK is not sent in the clear, instead each side
+proves knowledge of the password using Elliptic Curve cryptography.
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in
new file mode 100644
index 0000000..e04ec27
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/all.mk.in
@@ -0,0 +1,16 @@
+TARGETNAME := @targetname@
+
+ifneq "$(OPENSSL_LIBS)" ""
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+endif
+
+SOURCES := $(TARGETNAME).c eap_pwd.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/configure b/src/modules/rlm_eap/types/rlm_eap_pwd/configure
new file mode 100755
index 0000000..d108e97
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/configure
@@ -0,0 +1,4271 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap_pwd.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap_pwd
+with_openssl_lib_dir
+with_openssl_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap_pwd build without rlm_eap_pwd
+ --with-openssl-lib-dir=DIR
+ directory for LDAP library files
+ --with-openssl-include-dir=DIR
+ directory for LDAP include files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap_pwd
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap_pwd was given.
+if test "${with_rlm_eap_pwd+set}" = set; then :
+ withval=$with_rlm_eap_pwd;
+fi
+
+
+
+mod_ldflags=
+mod_cflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap_pwd" != xno; then
+
+
+
+openssl_lib_dir=
+
+# Check whether --with-openssl-lib-dir was given.
+if test "${with_openssl_lib_dir+set}" = set; then :
+ withval=$with_openssl_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need openssl-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+openssl_include_dir=
+
+# Check whether --with-openssl-include-dir was given.
+if test "${with_openssl_include_dir+set}" = set; then :
+ withval=$with_openssl_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need openssl-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir=$openssl_include_dir
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "openssl/ec.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+ for _dir in $smart_try_dir; do
+ _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+ done
+
+ for _dir in $smart_include_dir; do
+ _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+ done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5
+$as_echo_n "checking for openssl/ec.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/openssl/ec.h" >&5
+$as_echo_n "checking for ${_prefix}/openssl/ec.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem ${_prefix}/"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h" >&5
+$as_echo_n "checking for openssl/ec.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ec.h in $try" >&5
+$as_echo_n "checking for openssl/ec.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <openssl/ec.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_openssl_ec_h" != "yes"; then
+
+fail="$fail openssl/ec.h"
+
+fi
+
+smart_try_dir=$openssl_lib_dir
+
+
+sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "EVP_CIPHER_CTX_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EVP_CIPHER_CTX_new in -lcrypto in $try" >&5
+$as_echo_n "checking for EVP_CIPHER_CTX_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char EVP_CIPHER_CTX_new();
+int
+main ()
+{
+EVP_CIPHER_CTX_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then
+
+fail="$fail libssl"
+
+else
+ for ac_func in EVP_sha256
+do :
+ ac_fn_c_check_func "$LINENO" "EVP_sha256" "ac_cv_func_EVP_sha256"
+if test "x$ac_cv_func_EVP_sha256" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_EVP_SHA256 1
+_ACEOF
+
+fi
+done
+
+ if test "x$ac_cv_func_EVP_sha256" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: EVP_sha256 not found, may have issues with WiMAX certificates" >&5
+$as_echo "$as_me: WARNING: EVP_sha256 not found, may have issues with WiMAX certificates" >&2;}
+ fi
+
+ for ac_func in EC_GROUP_free
+do :
+ ac_fn_c_check_func "$LINENO" "EC_GROUP_free" "ac_cv_func_EC_GROUP_free"
+if test "x$ac_cv_func_EC_GROUP_free" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_EC_GROUP_FREE 1
+_ACEOF
+
+fi
+done
+
+ if test "x$ac_cv_func_EC_GROUP_free" != "xyes"; then
+
+fail="$fail EC_GROUP_free"
+
+ fi
+fi
+
+
+ targetname=rlm_eap_pwd
+else
+ targetname=
+ echo \*\*\* module rlm_eap_pwd is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap_pwd to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_pwd." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap_pwd." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_pwd requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap_pwd requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac b/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac
new file mode 100644
index 0000000..1833b38
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/configure.ac
@@ -0,0 +1,80 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap_pwd.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap_pwd])
+
+mod_ldflags=
+mod_cflags=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-openssl-lib-dir
+openssl_lib_dir=
+AC_ARG_WITH(openssl-lib-dir,
+ [AS_HELP_STRING([--with-openssl-lib-dir=DIR],
+ [directory for LDAP library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need openssl-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-openssl-include-dir
+openssl_include_dir=
+AC_ARG_WITH(openssl-include-dir,
+ [AS_HELP_STRING([--with-openssl-include-dir=DIR],
+ [directory for LDAP include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need openssl-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ openssl_include_dir="$withval"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir=$openssl_include_dir
+FR_SMART_CHECK_INCLUDE(openssl/ec.h)
+if test "$ac_cv_header_openssl_ec_h" != "yes"; then
+ FR_MODULE_FAIL([openssl/ec.h])
+fi
+
+smart_try_dir=$openssl_lib_dir
+FR_SMART_CHECK_LIB(crypto, EVP_CIPHER_CTX_new)
+if test "x$ac_cv_lib_crypto_EVP_CIPHER_CTX_new" != "xyes"; then
+ FR_MODULE_FAIL([libssl])
+else
+ AC_CHECK_FUNCS(EVP_sha256)
+ if test "x$ac_cv_func_EVP_sha256" != "xyes"; then
+ AC_MSG_WARN([EVP_sha256 not found, may have issues with WiMAX certificates])
+ fi
+
+ AC_CHECK_FUNCS(EC_GROUP_free)
+ if test "x$ac_cv_func_EC_GROUP_free" != "xyes"; then
+ FR_MODULE_FAIL([EC_GROUP_free])
+ fi
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h b/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h
new file mode 100644
index 0000000..b717dd5
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/const_time.h
@@ -0,0 +1,190 @@
+/*
+ * Helper functions for constant time operations
+ * Copyright (c) 2019, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * These helper functions can be used to implement logic that needs to minimize
+ * externally visible differences in execution path by avoiding use of branches,
+ * avoiding early termination or other time differences, and forcing same memory
+ * access pattern regardless of values.
+ */
+
+#ifndef CONST_TIME_H
+#define CONST_TIME_H
+
+
+#if defined(__clang__)
+#define NO_UBSAN_UINT_OVERFLOW \
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+#define NO_UBSAN_UINT_OVERFLOW
+#endif
+
+/**
+ * const_time_fill_msb - Fill all bits with MSB value
+ * @param val Input value
+ * @return Value with all the bits set to the MSB of the input val
+ */
+static inline unsigned int const_time_fill_msb(unsigned int val)
+{
+ /* Move the MSB to LSB and multiple by -1 to fill in all bits. */
+ return (val >> (sizeof(val) * 8 - 1)) * ~0U;
+}
+
+
+/* @return -1 if val is zero; 0 if val is not zero */
+static inline unsigned int const_time_is_zero(unsigned int val)
+ NO_UBSAN_UINT_OVERFLOW
+{
+ /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
+ return const_time_fill_msb(~val & (val - 1));
+}
+
+
+/* @return -1 if a == b; 0 if a != b */
+static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
+{
+ return const_time_is_zero(a ^ b);
+}
+
+
+/* @return -1 if a == b; 0 if a != b */
+static inline unsigned char const_time_eq_u8(unsigned int a, unsigned int b)
+{
+ return (unsigned char) const_time_eq(a, b);
+}
+
+
+/**
+ * const_time_eq_bin - Constant time memory comparison
+ * @param a First buffer to compare
+ * @param b Second buffer to compare
+ * @param len Number of octets to compare
+ * @return -1 if buffers are equal, 0 if not
+ *
+ * This function is meant for comparing passwords or hash values where
+ * difference in execution time or memory access pattern could provide external
+ * observer information about the location of the difference in the memory
+ * buffers. The return value does not behave like memcmp(), i.e.,
+ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
+ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
+ * contents of the compared memory buffers, but only on the total compared
+ * length.
+ */
+static inline unsigned int const_time_eq_bin(const void *a, const void *b,
+ size_t len)
+{
+ const unsigned char *aa = a;
+ const unsigned char *bb = b;
+ size_t i;
+ unsigned char res = 0;
+
+ for (i = 0; i < len; i++)
+ res |= aa[i] ^ bb[i];
+
+ return const_time_is_zero(res);
+}
+
+
+/**
+ * const_time_select - Constant time unsigned int selection
+ * @param mask 0 (false) or -1 (true) to identify which value to select
+ * @param true_val Value to select for the true case
+ * @param false_val Value to select for the false case
+ * @return true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned int const_time_select(unsigned int mask,
+ unsigned int true_val,
+ unsigned int false_val)
+{
+ return (mask & true_val) | (~mask & false_val);
+}
+
+
+/**
+ * const_time_select_int - Constant time int selection
+ * @param mask 0 (false) or -1 (true) to identify which value to select
+ * @param true_val Value to select for the true case
+ * @param false_val Value to select for the false case
+ * @return true_val if mask == -1, false_val if mask == 0
+ */
+static inline int const_time_select_int(unsigned int mask, int true_val,
+ int false_val)
+{
+ return (int) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_u8 - Constant time u8 selection
+ * @param mask 0 (false) or -1 (true) to identify which value to select
+ * @param true_val Value to select for the true case
+ * @param false_val Value to select for the false case
+ * @return true_val if mask == -1, false_val if mask == 0
+ */
+static inline unsigned char const_time_select_u8(unsigned char mask, unsigned char true_val, unsigned char false_val)
+{
+ return (unsigned char) const_time_select(mask, true_val, false_val);
+}
+
+
+/**
+ * const_time_select_s8 - Constant time s8 selection
+ * @param mask 0 (false) or -1 (true) to identify which value to select
+ * @param true_val Value to select for the true case
+ * @param false_val Value to select for the false case
+ * @return true_val if mask == -1, false_val if mask == 0
+ */
+static inline char const_time_select_s8(char mask, char true_val, char false_val)
+{
+ return (char) const_time_select(mask, (unsigned int) true_val,
+ (unsigned int) false_val);
+}
+
+
+/**
+ * const_time_select_bin - Constant time binary buffer selection copy
+ * @param mask 0 (false) or -1 (true) to identify which value to copy
+ * @param true_val Buffer to copy for the true case
+ * @param false_val Buffer to copy for the false case
+ * @param len Number of octets to copy
+ * @param dst Destination buffer for the copy
+ *
+ * This function copies the specified buffer into the destination buffer using
+ * operations with identical memory access pattern regardless of which buffer
+ * is being copied.
+ */
+static inline void const_time_select_bin(unsigned char mask, const unsigned char *true_val,
+ const unsigned char *false_val, size_t len,
+ unsigned char *dst)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
+}
+
+
+static inline int const_time_memcmp(const void *a, const void *b, size_t len)
+{
+ const unsigned char *aa = a;
+ const unsigned char *bb = b;
+ int diff, res = 0;
+ unsigned int mask;
+
+ if (len == 0)
+ return 0;
+ do {
+ len--;
+ diff = (int) aa[len] - (int) bb[len];
+ mask = const_time_is_zero((unsigned int) diff);
+ res = const_time_select_int(mask, res, diff);
+ } while (len);
+
+ return res;
+}
+
+#endif /* CONST_TIME_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
new file mode 100644
index 0000000..2626052
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.c
@@ -0,0 +1,933 @@
+/**
+ * copyright holder grants permission for redistribution and use in source
+ * and binary forms, with or without modification, provided that the
+ * following conditions are met:
+ * 1. Redistribution of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in all source files.
+ * 2. Redistribution in binary form must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * "DISCLAIMER OF LIABILITY
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE."
+ *
+ * This license and distribution terms cannot be changed. In other words,
+ * this code cannot simply be copied and put under a different distribution
+ * license (including the GNU public license).
+ *
+ * @copyright (c) Dan Harkins, 2012
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include "eap_pwd.h"
+#include "const_time.h"
+#include <freeradius-devel/openssl3.h>
+
+static uint8_t allzero[SHA256_DIGEST_LENGTH] = { 0x00 };
+
+/* The random function H(x) = HMAC-SHA256(0^32, x) */
+static void pwd_hmac_final(HMAC_CTX *hmac_ctx, uint8_t *digest)
+{
+ unsigned int mdlen = SHA256_DIGEST_LENGTH;
+ HMAC_Final(hmac_ctx, digest, &mdlen);
+// HMAC_CTX_reset(hmac_ctx);
+}
+
+/* a counter-based KDF based on NIST SP800-108 */
+static void eap_pwd_kdf(uint8_t *key, int keylen, char const *label,
+ int label_len, uint8_t *result, int result_bit_len)
+{
+ HMAC_CTX *hmac_ctx;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ uint16_t i, ctr, L;
+ int result_byte_len, len = 0;
+ unsigned int mdlen = SHA256_DIGEST_LENGTH;
+ uint8_t mask = 0xff;
+
+ MEM(hmac_ctx = HMAC_CTX_new());
+ result_byte_len = (result_bit_len + 7) / 8;
+
+ ctr = 0;
+ L = htons(result_bit_len);
+ while (len < result_byte_len) {
+ ctr++; i = htons(ctr);
+
+ HMAC_Init_ex(hmac_ctx, key, keylen, EVP_sha256(), NULL);
+ if (ctr > 1) HMAC_Update(hmac_ctx, digest, mdlen);
+ HMAC_Update(hmac_ctx, (uint8_t *) &i, sizeof(uint16_t));
+ HMAC_Update(hmac_ctx, (uint8_t const *)label, label_len);
+ HMAC_Update(hmac_ctx, (uint8_t *) &L, sizeof(uint16_t));
+ HMAC_Final(hmac_ctx, digest, &mdlen);
+ if ((len + (int) mdlen) > result_byte_len) {
+ memcpy(result + len, digest, result_byte_len - len);
+ } else {
+ memcpy(result + len, digest, mdlen);
+ }
+ len += mdlen;
+// HMAC_CTX_reset(hmac_ctx);
+ }
+
+ /* since we're expanding to a bit length, mask off the excess */
+ if (result_bit_len % 8) {
+ mask <<= (8 - (result_bit_len % 8));
+ result[result_byte_len - 1] &= mask;
+ }
+
+ HMAC_CTX_free(hmac_ctx);
+}
+
+static BIGNUM *consttime_BN (void)
+{
+ BIGNUM *bn;
+
+ bn = BN_new();
+ if (bn) BN_set_flags(bn, BN_FLG_CONSTTIME);
+ return bn;
+}
+
+/*
+ * compute the legendre symbol in constant time
+ */
+static int legendre(BIGNUM *a, BIGNUM *p, BN_CTX *bnctx)
+{
+ int symbol;
+ unsigned int mask;
+ BIGNUM *res, *pm1over2;
+
+ pm1over2 = consttime_BN();
+ res = consttime_BN();
+
+ if (!BN_sub(pm1over2, p, BN_value_one()) ||
+ !BN_rshift1(pm1over2, pm1over2) ||
+ !BN_mod_exp_mont_consttime(res, a, pm1over2, p, bnctx, NULL)) {
+ BN_free(pm1over2);
+ BN_free(res);
+ return -2;
+ }
+
+ symbol = -1;
+ mask = const_time_eq(BN_is_word(res, 1), 1);
+ symbol = const_time_select_int(mask, 1, symbol);
+ mask = const_time_eq(BN_is_zero(res), 1);
+ symbol = const_time_select_int(mask, -1, symbol);
+
+ BN_free(pm1over2);
+ BN_free(res);
+
+ return symbol;
+}
+
+static void do_equation(EC_GROUP *group, BIGNUM *y2, BIGNUM *x, BN_CTX *bnctx)
+{
+ BIGNUM *p, *a, *b, *tmp1, *pm1;
+
+ tmp1 = BN_new();
+ pm1 = BN_new();
+ p = BN_new();
+ a = BN_new();
+ b = BN_new();
+ EC_GROUP_get_curve(group, p, a, b, bnctx);
+
+ BN_sub(pm1, p, BN_value_one());
+
+ /*
+ * y2 = x^3 + ax + b
+ */
+ BN_mod_sqr(tmp1, x, p, bnctx);
+ BN_mod_mul(y2, tmp1, x, p, bnctx);
+ BN_mod_mul(tmp1, a, x, p, bnctx);
+ BN_mod_add_quick(y2, y2, tmp1, p);
+ BN_mod_add_quick(y2, y2, b, p);
+
+ BN_free(tmp1);
+ BN_free(pm1);
+ BN_free(p);
+ BN_free(a);
+ BN_free(b);
+
+ return;
+}
+
+static int is_quadratic_residue(BIGNUM *val, BIGNUM *p, BIGNUM *qr, BIGNUM *qnr, BN_CTX *bnctx)
+{
+ int offset, check, ret = 0;
+ BIGNUM *r = NULL, *pm1 = NULL, *res = NULL, *qr_or_qnr = NULL;
+ unsigned int mask;
+ unsigned char *qr_bin = NULL, *qnr_bin = NULL, *qr_or_qnr_bin = NULL;
+
+ if (((r = consttime_BN()) == NULL) ||
+ ((res = consttime_BN()) == NULL) ||
+ ((qr_or_qnr = consttime_BN()) == NULL) ||
+ ((pm1 = consttime_BN()) == NULL)) {
+ ret = -2;
+ goto fail;
+ }
+
+ if (((qr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) ||
+ ((qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL) ||
+ ((qr_or_qnr_bin = (unsigned char *)malloc(BN_num_bytes(p))) == NULL)) {
+ ret = -2;
+ goto fail;
+ }
+
+ /*
+ * we select binary in constant time so make them binary
+ */
+ memset(qr_bin, 0, BN_num_bytes(p));
+ memset(qnr_bin, 0, BN_num_bytes(p));
+ memset(qr_or_qnr_bin, 0, BN_num_bytes(p));
+
+ offset = BN_num_bytes(p) - BN_num_bytes(qr);
+ BN_bn2bin(qr, qr_bin + offset);
+
+ offset = BN_num_bytes(p) - BN_num_bytes(qnr);
+ BN_bn2bin(qnr, qnr_bin + offset);
+
+ /*
+ * r = (random() mod p-1) + 1
+ */
+ BN_sub(pm1, p, BN_value_one());
+ BN_rand_range(r, pm1);
+ BN_add(r, r, BN_value_one());
+
+ BN_copy(res, val);
+
+ /*
+ * res = val * r * r which ensures res != val but has same quadratic residocity
+ */
+ BN_mod_mul(res, res, r, p, bnctx);
+ BN_mod_mul(res, res, r, p, bnctx);
+
+ /*
+ * if r is even (mask is -1) then multiply by qnr and our check is qnr
+ * otherwise multiply by qr and our check is qr
+ */
+ mask = const_time_is_zero(BN_is_odd(r));
+ const_time_select_bin(mask, qnr_bin, qr_bin, BN_num_bytes(p), qr_or_qnr_bin);
+ BN_bin2bn(qr_or_qnr_bin, BN_num_bytes(p), qr_or_qnr);
+ BN_mod_mul(res, res, qr_or_qnr, p, bnctx);
+ check = const_time_select_int(mask, -1, 1);
+
+ if ((ret = legendre(res, p, bnctx)) == -2) {
+ ret = -1; /* just say no it's not */
+ goto fail;
+ }
+ mask = const_time_eq(ret, check);
+ ret = const_time_select_int(mask, 1, 0);
+
+fail:
+ if (qr_bin != NULL) free(qr_bin);
+ if (qnr_bin != NULL) free(qnr_bin);
+ if (qr_or_qnr_bin != NULL) free(qr_or_qnr_bin);
+ BN_free(r);
+ BN_free(res);
+ BN_free(qr_or_qnr);
+ BN_free(pm1);
+
+ return ret;
+}
+
+int compute_password_element (REQUEST *request, pwd_session_t *session, uint16_t grp_num,
+ char const *password, int password_len,
+ char const *id_server, int id_server_len,
+ char const *id_peer, int id_peer_len,
+ uint32_t *token)
+{
+ BIGNUM *x_candidate = NULL, *rnd = NULL, *y_sqrd = NULL, *qr = NULL, *qnr = NULL, *y1 = NULL, *y2 = NULL, *y = NULL, *exp = NULL;
+ EVP_MD_CTX *hmac_ctx;
+ EVP_PKEY *hmac_pkey;
+ uint8_t pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, *xbuf = NULL, *pm1buf = NULL, *y1buf = NULL, *y2buf = NULL, *ybuf = NULL, ctr;
+ int nid, is_odd, primebitlen, primebytelen, ret = 0, found = 0, mask;
+ int save, i, rbits, qr_or_qnr, save_is_odd = 0, cmp;
+ unsigned int skip;
+
+ MEM(hmac_ctx = EVP_MD_CTX_new());
+ MEM(hmac_pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, allzero, sizeof(allzero)));
+
+ switch (grp_num) { /* from IANA registry for IKE D-H groups */
+ case 19:
+ nid = NID_X9_62_prime256v1;
+ break;
+
+ case 20:
+ nid = NID_secp384r1;
+ break;
+
+ case 21:
+ nid = NID_secp521r1;
+ break;
+
+ case 25:
+ nid = NID_X9_62_prime192v1;
+ break;
+
+ case 26:
+ nid = NID_secp224r1;
+ break;
+
+ default:
+ DEBUG("unknown group %d", grp_num);
+ goto fail;
+ }
+
+ session->pwe = NULL;
+ session->order = NULL;
+ session->prime = NULL;
+
+ if ((session->group = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+ DEBUG("unable to create EC_GROUP");
+ goto fail;
+ }
+
+ if (((rnd = consttime_BN()) == NULL) ||
+ ((session->pwe = EC_POINT_new(session->group)) == NULL) ||
+ ((session->order = consttime_BN()) == NULL) ||
+ ((session->prime = consttime_BN()) == NULL) ||
+ ((qr = consttime_BN()) == NULL) ||
+ ((qnr = consttime_BN()) == NULL) ||
+ ((x_candidate = consttime_BN()) == NULL) ||
+ ((y_sqrd = consttime_BN()) == NULL) ||
+ ((y1 = consttime_BN()) == NULL) ||
+ ((y2 = consttime_BN()) == NULL) ||
+ ((y = consttime_BN()) == NULL) ||
+ ((exp = consttime_BN()) == NULL)) {
+ DEBUG("unable to create bignums");
+ goto fail;
+ }
+
+ if (!EC_GROUP_get_curve(session->group, session->prime, NULL, NULL, NULL)) {
+ DEBUG("unable to get prime for GFp curve");
+ goto fail;
+ }
+
+ if (!EC_GROUP_get_order(session->group, session->order, NULL)) {
+ DEBUG("unable to get order for curve");
+ goto fail;
+ }
+
+ primebitlen = BN_num_bits(session->prime);
+ primebytelen = BN_num_bytes(session->prime);
+ if ((prfbuf = talloc_zero_array(session, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for prf buffer");
+ goto fail;
+ }
+ if ((xbuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for x buffer");
+ goto fail;
+ }
+ if ((pm1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for pm1 buffer");
+ goto fail;
+ }
+ if ((y1buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for y1 buffer");
+ goto fail;
+ }
+ if ((y2buf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for y2 buffer");
+ goto fail;
+ }
+ if ((ybuf = talloc_zero_array(request, uint8_t, primebytelen)) == NULL) {
+ DEBUG("unable to alloc space for y buffer");
+ goto fail;
+ }
+
+
+ /*
+ * derive random quadradic residue and quadratic non-residue
+ */
+ do {
+ BN_rand_range(qr, session->prime);
+ } while (legendre(qr, session->prime, session->bnctx) != 1);
+
+ do {
+ BN_rand_range(qnr, session->prime);
+ } while (legendre(qnr, session->prime, session->bnctx) != -1);
+
+ if (!BN_sub(rnd, session->prime, BN_value_one())) {
+ goto fail;
+ }
+ BN_bn2bin(rnd, pm1buf);
+
+ save_is_odd = 0;
+ found = 0;
+ memset(xbuf, 0, primebytelen);
+ ctr = 0;
+ while (ctr < 40) {
+ ctr++;
+
+ /*
+ * compute counter-mode password value and stretch to prime
+ * pwd-seed = H(token | peer-id | server-id | password |
+ * counter)
+ */
+ EVP_DigestSignInit(hmac_ctx, NULL, EVP_sha256(), NULL, hmac_pkey);
+ EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)token, sizeof(*token));
+ EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_peer, id_peer_len);
+ EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)id_server, id_server_len);
+ EVP_DigestSignUpdate(hmac_ctx, (uint8_t const *)password, password_len);
+ EVP_DigestSignUpdate(hmac_ctx, (uint8_t *)&ctr, sizeof(ctr));
+
+ {
+ size_t mdlen = SHA256_DIGEST_LENGTH;
+
+ EVP_DigestSignFinal(hmac_ctx, pwe_digest, &mdlen);
+ EVP_MD_CTX_reset(hmac_ctx);
+ }
+
+ BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd);
+ eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, "EAP-pwd Hunting And Pecking",
+ strlen("EAP-pwd Hunting And Pecking"), prfbuf, primebitlen);
+
+ /*
+ * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+ * BN_bin2bn will treat that string of bits as a big endian
+ * number. If the primebitlen is not an even multiple of 8
+ * then excessive bits-- those _after_ primebitlen-- so now
+ * we have to shift right the amount we masked off.
+ */
+ if (primebitlen % 8) {
+ rbits = 8 - (primebitlen % 8);
+ for (i = primebytelen - 1; i > 0; i--) {
+ prfbuf[i] = (prfbuf[i - 1] << (8 - rbits)) | (prfbuf[i] >> rbits);
+ }
+ prfbuf[0] >>= rbits;
+ }
+ BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+ /*
+ * it would've been better if the spec reduced the candidate
+ * modulo the prime but it didn't. So if the candidate >= prime
+ * we need to skip it but still run through the operations below
+ */
+ cmp = const_time_memcmp(pm1buf, prfbuf, primebytelen);
+ skip = const_time_fill_msb((unsigned int)cmp);
+
+ /*
+ * need to unambiguously identify the solution, if there is
+ * one..
+ */
+ is_odd = BN_is_odd(rnd);
+
+ /*
+ * check whether x^3 + a*x + b is a quadratic residue
+ *
+ * save the first quadratic residue we find in the loop but do
+ * it in constant time.
+ */
+ do_equation(session->group, y_sqrd, x_candidate, session->bnctx);
+ qr_or_qnr = is_quadratic_residue(y_sqrd, session->prime, qr, qnr, session->bnctx);
+
+ /*
+ * if the candidate >= prime then we want to skip it
+ */
+ qr_or_qnr = const_time_select(skip, 0, qr_or_qnr);
+
+ /*
+ * if we haven't found PWE yet (found = 0) then mask will be true,
+ * if we have found PWE then mask will be false
+ */
+ mask = const_time_select(found, 0, -1);
+
+ /*
+ * save will be 1 if we want to save this value-- i.e. we haven't
+ * found PWE yet and this is a quadratic residue-- and 0 otherwise
+ */
+ save = const_time_select(mask, qr_or_qnr, 0);
+
+ /*
+ * mask will be true (-1) if we want to save this and false (0)
+ * otherwise
+ */
+ mask = const_time_eq(save, 1);
+
+ const_time_select_bin(mask, prfbuf, xbuf, primebytelen, xbuf);
+ save_is_odd = const_time_select(mask, is_odd, save_is_odd);
+ found = const_time_select(mask, -1, found);
+ }
+
+ /*
+ * now we can savely construct PWE
+ */
+ BN_bin2bn(xbuf, primebytelen, x_candidate);
+ do_equation(session->group, y_sqrd, x_candidate, session->bnctx);
+ if ( !BN_add(exp, session->prime, BN_value_one()) ||
+ !BN_rshift(exp, exp, 2) ||
+ !BN_mod_exp_mont_consttime(y1, y_sqrd, exp, session->prime, session->bnctx, NULL) ||
+ !BN_sub(y2, session->prime, y1) ||
+ !BN_bn2bin(y1, y1buf) ||
+ !BN_bn2bin(y2, y2buf)) {
+ DEBUG("unable to compute y");
+ goto fail;
+ }
+ mask = const_time_eq(save_is_odd, BN_is_odd(y1));
+ const_time_select_bin(mask, y1buf, y2buf, primebytelen, ybuf);
+ if (BN_bin2bn(ybuf, primebytelen, y) == NULL ||
+ !EC_POINT_set_affine_coordinates(session->group, session->pwe, x_candidate, y, session->bnctx)) {
+ DEBUG("unable to set point coordinate");
+ goto fail;
+ }
+
+ session->group_num = grp_num;
+ if (0) {
+ fail: /* DON'T free session, it's in handler->opaque */
+ ret = -1;
+ }
+
+ /* cleanliness and order.... */
+ BN_clear_free(x_candidate);
+ BN_clear_free(y_sqrd);
+ BN_clear_free(qr);
+ BN_clear_free(qnr);
+ BN_clear_free(rnd);
+ BN_clear_free(y1);
+ BN_clear_free(y2);
+ BN_clear_free(y);
+ BN_clear_free(exp);
+
+ if (prfbuf) talloc_free(prfbuf);
+ if (xbuf) talloc_free(xbuf);
+ if (pm1buf) talloc_free(pm1buf);
+ if (y1buf) talloc_free(y1buf);
+ if (y2buf) talloc_free(y2buf);
+ if (ybuf) talloc_free(ybuf);
+
+ EVP_MD_CTX_free(hmac_ctx);
+ EVP_PKEY_free(hmac_pkey);
+
+ return ret;
+}
+
+int compute_scalar_element(REQUEST *request, pwd_session_t *session, BN_CTX *bn_ctx)
+{
+ BIGNUM *mask = NULL;
+ int ret = -1;
+
+ MEM(session->private_value = BN_new());
+ MEM(session->my_element = EC_POINT_new(session->group));
+ MEM(session->my_scalar = BN_new());
+
+ MEM(mask = BN_new());
+
+ if (BN_rand_range(session->private_value, session->order) != 1) {
+ REDEBUG("Unable to get randomness for private_value");
+ goto error;
+ }
+ if (BN_rand_range(mask, session->order) != 1) {
+ REDEBUG("Unable to get randomness for mask");
+ goto error;
+ }
+ BN_add(session->my_scalar, session->private_value, mask);
+ BN_mod(session->my_scalar, session->my_scalar, session->order, bn_ctx);
+
+ if (!EC_POINT_mul(session->group, session->my_element, NULL, session->pwe, mask, bn_ctx)) {
+ REDEBUG("Server element allocation failed");
+ goto error;
+ }
+
+ if (!EC_POINT_invert(session->group, session->my_element, bn_ctx)) {
+ REDEBUG("Server element inversion failed");
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+ BN_clear_free(mask);
+
+ return ret;
+}
+
+int process_peer_commit(REQUEST *request, pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bn_ctx)
+{
+ uint8_t *ptr;
+ size_t data_len;
+ BIGNUM *x = NULL, *y = NULL, *cofactor = NULL;
+ EC_POINT *K = NULL, *point = NULL;
+ int ret = 1;
+
+ MEM(session->peer_scalar = BN_new());
+ MEM(session->k = BN_new());
+ MEM(session->peer_element = EC_POINT_new(session->group));
+ MEM(point = EC_POINT_new(session->group));
+ MEM(K = EC_POINT_new(session->group));
+
+ MEM(cofactor = BN_new());
+ MEM(x = BN_new());
+ MEM(y = BN_new());
+
+ if (!EC_GROUP_get_cofactor(session->group, cofactor, NULL)) {
+ REDEBUG("Unable to get group co-factor");
+ goto finish;
+ }
+
+ /* element, x then y, followed by scalar */
+ ptr = (uint8_t *)in;
+ data_len = BN_num_bytes(session->prime);
+
+ /*
+ * Did the peer send enough data?
+ */
+ if (in_len < (2 * data_len + BN_num_bytes(session->order))) {
+ REDEBUG("Invalid commit packet");
+ goto finish;
+ }
+
+ BN_bin2bn(ptr, data_len, x);
+ ptr += data_len;
+ BN_bin2bn(ptr, data_len, y);
+ ptr += data_len;
+
+ data_len = BN_num_bytes(session->order);
+ BN_bin2bn(ptr, data_len, session->peer_scalar);
+
+ /* validate received scalar */
+ if (BN_is_zero(session->peer_scalar) ||
+ BN_is_one(session->peer_scalar) ||
+ BN_cmp(session->peer_scalar, session->order) >= 0) {
+ REDEBUG("Peer's scalar is not within the allowed range");
+ goto finish;
+ }
+
+ if (!EC_POINT_set_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
+ REDEBUG("Unable to get coordinates of peer's element");
+ goto finish;
+ }
+
+ /* validate received element */
+ if (!EC_POINT_is_on_curve(session->group, session->peer_element, bn_ctx) ||
+ EC_POINT_is_at_infinity(session->group, session->peer_element)) {
+ REDEBUG("Peer's element is not a point on the elliptic curve");
+ goto finish;
+ }
+
+ /* check to ensure peer's element is not in a small sub-group */
+ if (BN_cmp(cofactor, BN_value_one())) {
+ if (!EC_POINT_mul(session->group, point, NULL, session->peer_element, cofactor, NULL)) {
+ REDEBUG("Unable to multiply element by co-factor");
+ goto finish;
+ }
+
+ if (EC_POINT_is_at_infinity(session->group, point)) {
+ REDEBUG("Peer's element is in small sub-group");
+ goto finish;
+ }
+ }
+
+ /* detect reflection attacks */
+ if (BN_cmp(session->peer_scalar, session->my_scalar) == 0 ||
+ EC_POINT_cmp(session->group, session->peer_element, session->my_element, bn_ctx) == 0) {
+ REDEBUG("Reflection attack detected");
+ goto finish;
+ }
+
+ /* compute the shared key, k */
+ if ((!EC_POINT_mul(session->group, K, NULL, session->pwe, session->peer_scalar, bn_ctx)) ||
+ (!EC_POINT_add(session->group, K, K, session->peer_element, bn_ctx)) ||
+ (!EC_POINT_mul(session->group, K, NULL, K, session->private_value, bn_ctx))) {
+ REDEBUG("Unable to compute shared key, k");
+ goto finish;
+ }
+
+ /* ensure that the shared key isn't in a small sub-group */
+ if (BN_cmp(cofactor, BN_value_one())) {
+ if (!EC_POINT_mul(session->group, K, NULL, K, cofactor, NULL)) {
+ REDEBUG("Unable to multiply k by co-factor");
+ goto finish;
+ }
+ }
+
+ /*
+ * This check is strictly speaking just for the case above where
+ * co-factor > 1 but it was suggested that even though this is probably
+ * never going to happen it is a simple and safe check "just to be
+ * sure" so let's be safe.
+ */
+ if (EC_POINT_is_at_infinity(session->group, K)) {
+ REDEBUG("K is point-at-infinity");
+ goto finish;
+ }
+
+ if (!EC_POINT_get_affine_coordinates(session->group, K, session->k, NULL, bn_ctx)) {
+ REDEBUG("Unable to get shared secret from K");
+ goto finish;
+ }
+ ret = 0;
+
+finish:
+ EC_POINT_clear_free(K);
+ EC_POINT_clear_free(point);
+ BN_clear_free(cofactor);
+ BN_clear_free(x);
+ BN_clear_free(y);
+
+ return ret;
+}
+
+int compute_server_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
+{
+ BIGNUM *x = NULL, *y = NULL;
+ HMAC_CTX *hmac_ctx = NULL;
+ uint8_t *cruft = NULL;
+ int offset, req = -1;
+
+ /*
+ * Each component of the cruft will be at most as big as the prime
+ */
+ MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
+ MEM(x = BN_new());
+ MEM(y = BN_new());
+
+ /*
+ * commit is H(k | server_element | server_scalar | peer_element |
+ * peer_scalar | ciphersuite)
+ */
+ MEM(hmac_ctx = HMAC_CTX_new());
+ HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+
+ /*
+ * Zero the memory each time because this is mod prime math and some
+ * value may start with a few zeros and the previous one did not.
+ *
+ * First is k
+ */
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
+ BN_bn2bin(session->k, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * next is server element: x, y
+ */
+ if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
+ REDEBUG("Unable to get coordinates of server element");
+ goto finish;
+ }
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * and server scalar
+ */
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
+ BN_bn2bin(session->my_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+
+ /*
+ * next is peer element: x, y
+ */
+ if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
+ REDEBUG("Unable to get coordinates of peer's element");
+ goto finish;
+ }
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * and peer scalar
+ */
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
+ BN_bn2bin(session->peer_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+
+ /*
+ * finally, ciphersuite
+ */
+ HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
+
+ pwd_hmac_final(hmac_ctx, out);
+
+ req = 0;
+
+finish:
+ HMAC_CTX_free(hmac_ctx);
+ talloc_free(cruft);
+ BN_free(x);
+ BN_free(y);
+
+ return req;
+}
+
+int compute_peer_confirm(REQUEST *request, pwd_session_t *session, uint8_t *out, BN_CTX *bn_ctx)
+{
+ BIGNUM *x = NULL, *y = NULL;
+ HMAC_CTX *hmac_ctx = NULL;
+ uint8_t *cruft = NULL;
+ int offset, req = -1;
+
+ /*
+ * Each component of the cruft will be at most as big as the prime
+ */
+ MEM(cruft = talloc_zero_array(session, uint8_t, BN_num_bytes(session->prime)));
+ MEM(x = BN_new());
+ MEM(y = BN_new());
+
+ /*
+ * commit is H(k | server_element | server_scalar | peer_element |
+ * peer_scalar | ciphersuite)
+ */
+ MEM(hmac_ctx = HMAC_CTX_new());
+ HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+
+ /*
+ * Zero the memory each time because this is mod prime math and some
+ * value may start with a few zeros and the previous one did not.
+ *
+ * First is k
+ */
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
+ BN_bn2bin(session->k, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * then peer element: x, y
+ */
+ if (!EC_POINT_get_affine_coordinates(session->group, session->peer_element, x, y, bn_ctx)) {
+ REDEBUG("Unable to get coordinates of peer's element");
+ goto finish;
+ }
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * and peer scalar
+ */
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
+ BN_bn2bin(session->peer_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+
+ /*
+ * then server element: x, y
+ */
+ if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y, bn_ctx)) {
+ REDEBUG("Unable to get coordinates of server element");
+ goto finish;
+ }
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ /*
+ * and server scalar
+ */
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
+ BN_bn2bin(session->my_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+
+ /*
+ * finally, ciphersuite
+ */
+ HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
+
+ pwd_hmac_final(hmac_ctx, out);
+
+ req = 0;
+finish:
+ HMAC_CTX_free(hmac_ctx);
+ talloc_free(cruft);
+ BN_free(x);
+ BN_free(y);
+
+ return req;
+}
+
+int compute_keys(UNUSED REQUEST *request, pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
+{
+ HMAC_CTX *hmac_ctx;
+ uint8_t mk[SHA256_DIGEST_LENGTH], *cruft;
+ uint8_t session_id[SHA256_DIGEST_LENGTH + 1];
+ uint8_t msk_emsk[128]; /* 64 each */
+ int offset;
+
+ MEM(cruft = talloc_array(session, uint8_t, BN_num_bytes(session->prime)));
+ MEM(hmac_ctx = HMAC_CTX_new());
+
+ /*
+ * first compute the session-id = TypeCode | H(ciphersuite | scal_p |
+ * scal_s)
+ */
+ session_id[0] = PW_EAP_PWD;
+ HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+ HMAC_Update(hmac_ctx, (uint8_t *)&session->ciphersuite, sizeof(session->ciphersuite));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->peer_scalar);
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ BN_bn2bin(session->peer_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ BN_bn2bin(session->my_scalar, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->order));
+ pwd_hmac_final(hmac_ctx, (uint8_t *)&session_id[1]);
+
+ /* then compute MK = H(k | commit-peer | commit-server) */
+ HMAC_Init_ex(hmac_ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256(), NULL);
+
+ memset(cruft, 0, BN_num_bytes(session->prime));
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(session->k);
+ BN_bn2bin(session->k, cruft + offset);
+ HMAC_Update(hmac_ctx, cruft, BN_num_bytes(session->prime));
+
+ HMAC_Update(hmac_ctx, peer_confirm, SHA256_DIGEST_LENGTH);
+
+ HMAC_Update(hmac_ctx, session->my_confirm, SHA256_DIGEST_LENGTH);
+
+ pwd_hmac_final(hmac_ctx, mk);
+
+ /* stretch the mk with the session-id to get MSK | EMSK */
+ eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, (char const *)session_id,
+ SHA256_DIGEST_LENGTH + 1, msk_emsk, 1024); /* it's bits, ((64 + 64) * 8) */
+
+ memcpy(msk, msk_emsk, 64);
+ memcpy(emsk, msk_emsk + 64, 64);
+
+ HMAC_CTX_free(hmac_ctx);
+ talloc_free(cruft);
+ return 0;
+}
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
new file mode 100644
index 0000000..a40a346
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) Dan Harkins, 2012
+ *
+ * Copyright holder grants permission for redistribution and use in source
+ * and binary forms, with or without modification, provided that the
+ * following conditions are met:
+ * 1. Redistribution of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in all source files.
+ * 2. Redistribution in binary form must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * "DISCLAIMER OF LIABILITY
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE."
+ *
+ * This license and distribution terms cannot be changed. In other words,
+ * this code cannot simply be copied and put under a different distribution
+ * license (including the GNU public license).
+ */
+
+#ifndef _EAP_PWD_H
+#define _EAP_PWD_H
+
+RCSIDH(eap_pwd_h, "$Id$")
+#include "eap.h"
+
+#include <openssl/bn.h>
+#include <openssl/sha.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+typedef struct _pwd_hdr {
+ uint8_t lm_exchange;
+#define EAP_PWD_EXCH_ID 1
+#define EAP_PWD_EXCH_COMMIT 2
+#define EAP_PWD_EXCH_CONFIRM 3
+// uint16_t total_length; /* there if the L-bit is set */
+ uint8_t data[];
+} CC_HINT(packed) pwd_hdr;
+
+#define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exchange & 0x80)
+#define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exchange |= 0x80)
+#define EAP_PWD_GET_MORE_BIT(x) ((x)->lm_exchange & 0x40)
+#define EAP_PWD_SET_MORE_BIT(x) ((x)->lm_exchange |= 0x40)
+#define EAP_PWD_GET_EXCHANGE(x) ((x)->lm_exchange & 0x3f)
+#define EAP_PWD_SET_EXCHANGE(x,y) ((x)->lm_exchange |= (y))
+
+typedef struct _pwd_id_packet {
+ uint16_t group_num;
+ uint8_t random_function;
+#define EAP_PWD_DEF_RAND_FUN 1
+ uint8_t prf;
+#define EAP_PWD_DEF_PRF 1
+ uint8_t token[4];
+ uint8_t prep;
+#define EAP_PWD_PREP_NONE 0
+#define EAP_PWD_PREP_MS 1
+#define EAP_PWD_PREP_SASL 2
+ char identity[];
+} CC_HINT(packed) pwd_id_packet_t;
+
+typedef struct _pwd_session_t {
+ uint16_t state;
+#define PWD_STATE_ID_REQ 1
+#define PWD_STATE_COMMIT 2
+#define PWD_STATE_CONFIRM 3
+ uint16_t group_num;
+ uint32_t ciphersuite;
+ uint32_t token;
+ char peer_id[MAX_STRING_LEN];
+ size_t peer_id_len;
+ size_t mtu;
+ uint8_t *in; /* reassembled fragments */
+ size_t in_pos;
+ size_t in_len;
+ uint8_t *out; /* message to fragment */
+ size_t out_pos;
+ size_t out_len;
+ BN_CTX *bnctx;
+ EC_GROUP *group;
+ EC_POINT *pwe;
+ BIGNUM *order;
+ BIGNUM *prime;
+ BIGNUM *k;
+ BIGNUM *private_value;
+ BIGNUM *peer_scalar;
+ BIGNUM *my_scalar;
+ EC_POINT *my_element;
+ EC_POINT *peer_element;
+ uint8_t my_confirm[SHA256_DIGEST_LENGTH];
+ uint8_t prep;
+ uint8_t salt_present;
+ uint8_t salt_len;
+ uint8_t salt[255];
+} pwd_session_t;
+
+int compute_password_element(REQUEST *request, pwd_session_t *sess, uint16_t grp_num,
+ char const *password, int password_len,
+ char const *id_server, int id_server_len,
+ char const *id_peer, int id_peer_len,
+ uint32_t *token);
+int compute_scalar_element(REQUEST *request, pwd_session_t *sess, BN_CTX *bnctx);
+int process_peer_commit(REQUEST *request, pwd_session_t *sess, uint8_t *in, size_t in_len, BN_CTX *bnctx);
+int compute_server_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx);
+int compute_peer_confirm(REQUEST *request, pwd_session_t *sess, uint8_t *out, BN_CTX *bnctx);
+int compute_keys(REQUEST *request, pwd_session_t *sess, uint8_t *peer_confirm,
+ uint8_t *msk, uint8_t *emsk);
+#ifdef PRINTBUF
+void print_buf(char *str, uint8_t *buf, int len);
+#endif /* PRINTBUF */
+
+#endif /* _EAP_PWD_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
new file mode 100644
index 0000000..4992a2a
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) Dan Harkins, 2012
+ *
+ * Copyright holder grants permission for redistribution and use in source
+ * and binary forms, with or without modification, provided that the
+ * following conditions are met:
+ * 1. Redistribution of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in all source files.
+ * 2. Redistribution in binary form must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * "DISCLAIMER OF LIABILITY
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE."
+ *
+ * This license and distribution terms cannot be changed. In other words,
+ * this code cannot simply be copied and put under a different distribution
+ * license (including the GNU public license).
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include "rlm_eap_pwd.h"
+
+#include "eap_pwd.h"
+
+#define MPPE_KEY_LEN 32
+#define MSK_EMSK_LEN (2*MPPE_KEY_LEN)
+
+/* EAP-PWD can use different preprocessing (prep) modes to mangle the password
+ * before proving to both parties that they both know the same (mangled) password.
+ *
+ * The server advertises a preprocessing mode to the client. Only "none" is
+ * mandatory to implement.
+ *
+ * What is a good selection on the preprocessing mode?
+ *
+ * a) the server uses a hashed password
+ * b) the client uses a hashed password
+ *
+ * a | b | result
+ * --+---+---------------------------------------
+ * n | n | none
+ * n | y | hint needed (cannot know automatically)
+ * y | n | select by hash given
+ * y | y | only works if both have the same hash; select by hash given
+ *
+ * Which hash functions does the server or client need to implement?
+ *
+ * a | b | server | client
+ * --+---+------------------------+----------------------
+ * n | n | none | none
+ * n | y | as configured | none
+ * y | n | none | as selected by server
+ * y | y | none | none
+ *
+ * RFC 5931 defines 3 and RFC 8146 another 8 hash functions to implement.
+ * Can we avoid implementing them all? Only if they are provided as hash by some
+ * other module, e.g. in SQL or statically in password database.
+ *
+ * Therefore we select the preprocessing mode by the type of password given if
+ * in automatic mode:
+ * a) Cleartext-Password or User-Password: None.
+ * If the client only supports a hash (e.g. on Windows it might only have an
+ * NT-Password), do not provide a Cleartext-Password attribute but instead
+ * preprocess the password externally (e.g. hash the Cleartext-Password
+ * into an NT-Password and drop the Cleartext-Password).
+ * b) NT-Password: rfc2759 (prep=MS).
+ * The NT-Password Hash is hashed into a HashNTPasswordHash hash.
+ * c) EAP-Pwd-Password-Hash - provides hash as binary
+ * EAP-Pwd-Password-Salt - (optional) salt to be transmitted to client
+ * (RFC 8146)
+ * EAP-Pwd-Password-Prep - constant to transmit to client in prep field
+ *
+ * Though, there is one issue left. The method needs to be selected in
+ * EAP-PWD-ID/Request, that is the first message from server and thus before
+ * the client sent its peer-id. This is feasable using the EAP-Identity frame
+ * (outer identity); EAP-PWD does transmit its peer-id in plaintext anyway.
+ * So we need a toggle for this, in case anybody needs rlm_eap_pwd to use
+ * only the peer_id (inner identity). This toogle is an integer to also support
+ * setting currently unknown nor not implemented preprocessing methods.
+ *
+ * The toogle is named "prep", is a module configuration item, and accepts the
+ * following values:
+ * prep | meaning
+ * -------+--------------------------------------------------------------------
+ * -1 | [automatic] discover using method described above from EAP-Identity
+ * | as User-Name before EAP-PWD-Id/Request
+ * 0..255 | [static] Fixed password preprocessing method. Expects virtual
+ * | server to provide matching password given EAP-PWD
+ * | peer-id as User-Name. The virtual server is provided
+ * | with EAP-Pwd-Password-Prep containing the configured
+ * | prep value.
+ * else | reserved/invalid
+ *
+ * Attributes to provide Password/Password-Hash and possibly salt.
+ * prep | accepted attributes
+ * -------+--------------------------------------------------------------------
+ * -1 | see above for automatic discovery
+ * 0 | Use Cleartext-Password or give cleartext in EAP-Pwd-Password-Hash
+ * 1 | Use NT-Password, Cleartext-Password, User-Password or
+ * | give hashed NT-Password hash in EAP-Pwd-Password-Hash
+ * 2..255 | Use EAP-Pwd-Password-Hash and possibly EAP-Pwd-Pasword-Salt.
+ *
+ * To be able to pass EAP-Pwd-Password-Hash and EAP-Pwd-Password-Salt als hex
+ * string, they are decoded as hex if module config option unhex=1 (default).
+ * Set it to zero if you provide binary input.
+ */
+
+static CONF_PARSER pwd_module_config[] = {
+ { "group", FR_CONF_OFFSET(PW_TYPE_INTEGER, eap_pwd_t, group), "19" },
+ { "fragment_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, eap_pwd_t, fragment_size), "1020" },
+ { "server_id", FR_CONF_OFFSET(PW_TYPE_STRING, eap_pwd_t, server_id), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, eap_pwd_t, virtual_server), NULL },
+ { "prep", FR_CONF_OFFSET(PW_TYPE_SIGNED, eap_pwd_t, prep), "0" },
+ { "unhex", FR_CONF_OFFSET(PW_TYPE_SIGNED, eap_pwd_t, unhex), "1" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate (CONF_SECTION *cs, void **instance)
+{
+ eap_pwd_t *inst;
+
+ *instance = inst = talloc_zero(cs, eap_pwd_t);
+ if (!inst) return -1;
+
+ if (cf_section_parse(cs, inst, pwd_module_config) < 0) {
+ return -1;
+ }
+
+ if (inst->fragment_size < 100) {
+ cf_log_err_cs(cs, "Fragment size is too small");
+ return -1;
+ }
+
+ if (inst->prep < -1 || inst->prep > 255) {
+ cf_log_err_cs(cs, "Invalid value for password preparation method: %d", inst->prep);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _free_pwd_session (pwd_session_t *session)
+{
+ BN_clear_free(session->private_value);
+ BN_clear_free(session->peer_scalar);
+ BN_clear_free(session->my_scalar);
+ BN_clear_free(session->k);
+ EC_POINT_clear_free(session->my_element);
+ EC_POINT_clear_free(session->peer_element);
+ EC_GROUP_free(session->group);
+ EC_POINT_clear_free(session->pwe);
+ BN_clear_free(session->order);
+ BN_clear_free(session->prime);
+ BN_CTX_free(session->bnctx);
+
+ return 0;
+}
+
+static int send_pwd_request (pwd_session_t *session, EAP_DS *eap_ds)
+{
+ size_t len;
+ uint16_t totlen;
+ pwd_hdr *hdr;
+
+ len = (session->out_len - session->out_pos) + sizeof(pwd_hdr);
+ rad_assert(len > 0);
+ eap_ds->request->code = PW_EAP_REQUEST;
+ eap_ds->request->type.num = PW_EAP_PWD;
+ eap_ds->request->type.length = (len > session->mtu) ? session->mtu : len;
+ eap_ds->request->type.data = talloc_zero_array(eap_ds->request, uint8_t, eap_ds->request->type.length);
+ hdr = (pwd_hdr *)eap_ds->request->type.data;
+
+ switch (session->state) {
+ case PWD_STATE_ID_REQ:
+ EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_ID);
+ break;
+
+ case PWD_STATE_COMMIT:
+ EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_COMMIT);
+ break;
+
+ case PWD_STATE_CONFIRM:
+ EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_CONFIRM);
+ break;
+
+ default:
+ ERROR("rlm_eap_pwd: PWD state is invalid. Can't send request");
+ return 0;
+ }
+ /*
+ * are we fragmenting?
+ */
+ if (((session->out_len - session->out_pos) + sizeof(pwd_hdr)) > session->mtu) {
+ EAP_PWD_SET_MORE_BIT(hdr);
+ if (session->out_pos == 0) {
+ /*
+ * the first fragment, add the total length
+ */
+ EAP_PWD_SET_LENGTH_BIT(hdr);
+ totlen = ntohs(session->out_len);
+ memcpy(hdr->data, (char *)&totlen, sizeof(totlen));
+ memcpy(hdr->data + sizeof(uint16_t),
+ session->out,
+ session->mtu - sizeof(pwd_hdr) - sizeof(uint16_t));
+ session->out_pos += (session->mtu - sizeof(pwd_hdr) - sizeof(uint16_t));
+ } else {
+ /*
+ * an intermediate fragment
+ */
+ memcpy(hdr->data, session->out + session->out_pos, (session->mtu - sizeof(pwd_hdr)));
+ session->out_pos += (session->mtu - sizeof(pwd_hdr));
+ }
+ } else {
+ /*
+ * either it's not a fragment or it's the last fragment.
+ * The out buffer isn't needed anymore though so get rid of it.
+ */
+ memcpy(hdr->data, session->out + session->out_pos,
+ (session->out_len - session->out_pos));
+ talloc_free(session->out);
+ session->out = NULL;
+ session->out_pos = session->out_len = 0;
+ }
+ return 1;
+}
+
+static void normify(REQUEST *request, VALUE_PAIR *vp)
+{
+ size_t decoded;
+ size_t expected_len;
+ uint8_t *buffer;
+
+ rad_assert((vp->da->type == PW_TYPE_OCTETS) || (vp->da->type == PW_TYPE_STRING));
+
+ if (vp->vp_length % 2 != 0 || vp->vp_length == 0) return;
+
+ expected_len = vp->vp_length / 2;
+ buffer = talloc_zero_array(request, uint8_t, expected_len);
+ rad_assert(buffer);
+
+ decoded = fr_hex2bin(buffer, expected_len, vp->vp_strvalue, vp->vp_length);
+ if (decoded == expected_len) {
+ RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->vp_length, decoded);
+ fr_pair_value_memcpy(vp, buffer, decoded);
+ } else {
+ RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes failed, got %zu bytes",
+ vp->da->name, vp->vp_length, expected_len, decoded);
+ }
+
+ talloc_free(buffer);
+}
+
+static int fetch_and_process_password(pwd_session_t *session, REQUEST *request, eap_pwd_t *inst) {
+ REQUEST *fake;
+ VALUE_PAIR *vp, *pw;
+ const char *pwbuf;
+ int pw_len;
+ uint8_t nthash[MD4_DIGEST_LENGTH];
+ uint8_t nthashash[MD4_DIGEST_LENGTH];
+ int ret = -1;
+ eap_type_t old_eap_type = 0;
+
+ if ((fake = request_alloc_fake(request)) == NULL) {
+ RDEBUG("pwd unable to create fake request!");
+ return ret;
+ }
+ fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0);
+ if (!fake->username) {
+ RDEBUG("Failed creating pair for peer id");
+ goto out;
+ }
+ fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len);
+ fr_pair_add(&fake->packet->vps, fake->username);
+
+ if (inst->prep >= 0) {
+ vp = fr_pair_afrom_num(fake->packet, PW_EAP_PWD_PASSWORD_PREP, 0);
+ rad_assert(vp != NULL);
+ vp->vp_byte = inst->prep;
+ fr_pair_add(&fake->packet->vps, vp);
+ }
+
+ if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+ fake->server = vp->vp_strvalue;
+ } else if (inst->virtual_server) {
+ fake->server = inst->virtual_server;
+ } /* else fake->server == request->server */
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY)) != NULL) {
+ /* EAP-Type = NAK here if inst->prep == -1.
+ * But this does not help the virtual server to differentiate
+ * based on which EAP method was selected, that is to properly
+ * prepare session-state: for PWD.
+ * So fake EAP-Type = PWD here for the time of the inner request.
+ */
+ old_eap_type = vp->vp_integer;
+ vp->vp_integer = PW_EAP_PWD;
+ }
+ RDEBUG("Sending tunneled request");
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
+
+ if (fake->server) {
+ RDEBUG("server %s {", fake->server);
+ } else {
+ RDEBUG("server {");
+ }
+
+ /*
+ * Call authorization recursively, which will
+ * get the password.
+ */
+ RINDENT();
+ process_authorize(0, fake);
+ REXDENT();
+
+ /*
+ * Note that we don't do *anything* with the reply
+ * attributes.
+ */
+ if (fake->server) {
+ RDEBUG("} # server %s", fake->server);
+ } else {
+ RDEBUG("}");
+ }
+
+ RDEBUG("Got tunneled reply code %d", fake->reply->code);
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
+
+ if (old_eap_type && (vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY)) != NULL) {
+ vp->vp_integer = old_eap_type;
+ }
+
+ pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (!pw) {
+ pw = fr_pair_find_by_num(fake->config, PW_USER_PASSWORD, 0, TAG_ANY);
+ }
+
+ if (pw && (inst->prep < 0 || inst->prep == EAP_PWD_PREP_NONE)) {
+ VERIFY_VP(pw);
+ session->prep = EAP_PWD_PREP_NONE;
+
+ RDEBUG("Use Cleartext-Password or User-Password for %s to do pwd authentication",
+ session->peer_id);
+
+ pwbuf = pw->vp_strvalue;
+ pw_len = pw->vp_length;
+
+ goto success;
+ }
+
+ pw = fr_pair_find_by_num(fake->config, PW_NT_PASSWORD, 0, TAG_ANY);
+
+ if (pw && (inst->prep < 0 || inst->prep == EAP_PWD_PREP_MS)) {
+ VERIFY_VP(pw);
+ session->prep = EAP_PWD_PREP_MS;
+
+ RDEBUG("Use NT-Password for %s to do pwd authentication",
+ session->peer_id);
+
+ if (pw->vp_length != MD4_DIGEST_LENGTH) {
+ RDEBUG("NT-Password invalid length");
+ goto out;
+ }
+
+ fr_md4_calc(nthashash, pw->vp_octets, pw->vp_length);
+ pwbuf = (const char*) nthashash;
+ pw_len = MD4_DIGEST_LENGTH;
+
+ goto success;
+ }
+
+ pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+ if (!pw) {
+ pw = fr_pair_find_by_num(fake->config, PW_USER_PASSWORD, 0, TAG_ANY);
+ }
+
+ if (pw && inst->prep == EAP_PWD_PREP_MS) {
+ VERIFY_VP(pw);
+ session->prep = EAP_PWD_PREP_NONE;
+
+ RDEBUG("Use Cleartext-Password or User-Password as NT-Password for %s to do pwd authentication",
+ session->peer_id);
+
+ // compute NT-Hash from Cleartext-Password
+ ssize_t len;
+ uint8_t ucs2_password[512];
+ len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), pw->vp_strvalue, pw->vp_length);
+ if (len < 0) {
+ ERROR("rlm_eap_pwd: Error converting password to UCS2");
+ goto out;
+ }
+ fr_md4_calc(nthash, ucs2_password, len);
+
+ fr_md4_calc(nthashash, nthash, MD4_DIGEST_LENGTH);
+ pwbuf = (const char*) nthashash;
+ pw_len = MD4_DIGEST_LENGTH;
+
+ goto success;
+ }
+
+ vp = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_PREP, 0, TAG_ANY);
+ if (vp) {
+ VERIFY_VP(vp);
+ }
+ if (vp && inst->prep < 0) {
+ RDEBUG("Use EAP-Pwd-Password-Prep %u for %s to do pwd authentication",
+ vp->vp_byte, session->peer_id);
+ session->prep = vp->vp_byte;
+ } else if (vp && inst->prep != vp->vp_byte) {
+ RDEBUG2("Mismatch of configured password preparation method and provided EAP-Pwd-Password-Prep attribute type for %s",
+ session->peer_id);
+ goto out;
+ } else if (inst->prep < 0) {
+ RDEBUG2("Missing EAP-Pwd-Password-Prep for %s",
+ session->peer_id);
+ goto out;
+ }
+
+ pw = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_SALT, 0, TAG_ANY);
+ if (pw) {
+ VERIFY_VP(pw);
+
+ RDEBUG("Use EAP-Pwd-Password-Salt for %s to do pwd authentication",
+ session->peer_id);
+
+ if (inst->unhex) normify(request, pw);
+
+ if (pw->vp_length > 255) {
+ /* salt len is 1 byte */
+ RDEBUG("EAP-Pwd-Password-Salt too long (more than 255 octets)");
+ goto out;
+ }
+ rad_assert(pw->vp_length <= sizeof(session->salt));
+
+ session->salt_present = 1;
+ session->salt_len = pw->vp_length;
+ memcpy(session->salt, pw->vp_octets, pw->vp_length);
+ }
+
+ pw = fr_pair_find_by_num(fake->config, PW_EAP_PWD_PASSWORD_HASH, 0, TAG_ANY);
+ if (pw) {
+ VERIFY_VP(pw);
+
+ RDEBUG("Use EAP-Pwd-Password-Hash for %s to do pwd authentication",
+ session->peer_id);
+
+ if (inst->unhex) normify(request, pw);
+
+ pwbuf = (const char*) pw->vp_octets;
+ pw_len = pw->vp_length;
+
+ goto success;
+ }
+
+ RDEBUG2("Mismatch of password preparation method and provided password attribute type for %s",
+ session->peer_id);
+ goto out;
+
+success:
+ if (RDEBUG_ENABLED4) {
+ char outbuf[1024];
+ char *p = outbuf;
+ for (int i = 0; i < pw_len && p < outbuf + sizeof(outbuf) - 3; i++) {
+ p += sprintf(p, "%02hhX", pwbuf[i]);
+ }
+ RDEBUG4("hex pw data: %s (%d)", outbuf, pw_len);
+ }
+
+ if (compute_password_element(request, session, session->group_num,
+ pwbuf, pw_len,
+ inst->server_id, strlen(inst->server_id),
+ session->peer_id, strlen(session->peer_id),
+ &session->token)) {
+ RDEBUG("failed to obtain password element");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ talloc_free(fake);
+ return ret;
+}
+
+static int mod_session_init (void *instance, eap_handler_t *handler)
+{
+ pwd_session_t *session;
+ eap_pwd_t *inst = (eap_pwd_t *)instance;
+ VALUE_PAIR *vp;
+ pwd_id_packet_t *packet;
+ REQUEST *request;
+
+ if (!inst || !handler) {
+ ERROR("rlm_eap_pwd: Initiate, NULL data provided");
+ return 0;
+ }
+
+ request = handler->request;
+ if (!request) {
+ ERROR("rlm_eap_pwd: NULL request provided");
+ return 0;
+ }
+
+ /*
+ * make sure the server's been configured properly
+ */
+ if (!inst->server_id) {
+ ERROR("rlm_eap_pwd: Server ID is not configured");
+ return 0;
+ }
+ switch (inst->group) {
+ case 19:
+ case 20:
+ case 21:
+ case 25:
+ case 26:
+ break;
+
+ default:
+ ERROR("rlm_eap_pwd: Group is not supported");
+ return 0;
+ }
+
+ if ((session = talloc_zero(handler, pwd_session_t)) == NULL) return 0;
+ talloc_set_destructor(session, _free_pwd_session);
+ /*
+ * set things up so they can be free'd reliably
+ */
+ session->group_num = inst->group;
+ session->private_value = NULL;
+ session->peer_scalar = NULL;
+ session->my_scalar = NULL;
+ session->k = NULL;
+ session->my_element = NULL;
+ session->peer_element = NULL;
+ session->group = NULL;
+ session->pwe = NULL;
+ session->order = NULL;
+ session->prime = NULL;
+
+ session->bnctx = BN_CTX_new();
+ if (session->bnctx == NULL) {
+ ERROR("rlm_eap_pwd: Failed to get BN context");
+ return 0;
+ }
+
+ /*
+ * The admin can dynamically change the MTU.
+ */
+ session->mtu = inst->fragment_size;
+ vp = fr_pair_find_by_num(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY);
+
+ /*
+ * session->mtu is *our* MTU. We need to subtract off the EAP
+ * overhead.
+ *
+ * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type)
+ *
+ * The fragmentation code deals with the included length
+ * so we don't need to subtract that here.
+ */
+ if (vp && (vp->vp_integer > 100) && (vp->vp_integer < session->mtu)) {
+ session->mtu = vp->vp_integer - 9;
+ }
+
+ session->state = PWD_STATE_ID_REQ;
+ session->in = NULL;
+ session->out_pos = 0;
+ handler->opaque = session;
+
+ session->token = fr_rand();
+ if (inst->prep < 0) {
+ RDEBUG2("using outer identity %s to configure EAP-PWD", handler->identity);
+ session->peer_id_len = strlen(handler->identity);
+ if (session->peer_id_len >= sizeof(session->peer_id)) {
+ RDEBUG("identity is malformed");
+ return 0;
+ }
+ memcpy(session->peer_id, handler->identity, session->peer_id_len);
+ session->peer_id[session->peer_id_len] = '\0';
+
+ /*
+ * make fake request to get the password for the usable ID
+ * in order to identity prep
+ */
+ if (fetch_and_process_password(session, handler->request, inst) < 0) {
+ RDEBUG("failed to find password for %s to do pwd authentication (init)",
+ session->peer_id);
+ return 0;
+ }
+ } else {
+ session->prep = inst->prep;
+ }
+
+ /*
+ * construct an EAP-pwd-ID/Request
+ */
+ session->out_len = sizeof(pwd_id_packet_t) + strlen(inst->server_id);
+ if ((session->out = talloc_zero_array(session, uint8_t, session->out_len)) == NULL) {
+ return 0;
+ }
+
+ packet = (pwd_id_packet_t *)session->out;
+ packet->group_num = htons(session->group_num);
+ packet->random_function = EAP_PWD_DEF_RAND_FUN;
+ packet->prf = EAP_PWD_DEF_PRF;
+ memcpy(packet->token, (char *)&session->token, 4);
+ packet->prep = session->prep;
+ memcpy(packet->identity, inst->server_id, session->out_len - sizeof(pwd_id_packet_t) );
+
+ handler->stage = PROCESS;
+
+ return send_pwd_request(session, handler->eap_ds);
+}
+
+static int mod_process(void *arg, eap_handler_t *handler)
+{
+ pwd_session_t *session;
+ pwd_hdr *hdr;
+ pwd_id_packet_t *packet;
+ REQUEST *request;
+ eap_packet_t *response;
+ EAP_DS *eap_ds;
+ size_t in_len, peer_id_len;
+ int ret = 0;
+ eap_pwd_t *inst = (eap_pwd_t *)arg;
+ uint16_t offset;
+ uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
+ uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
+ char *peer_id;
+
+ if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0;
+
+ session = (pwd_session_t *)handler->opaque;
+ request = handler->request;
+ response = handler->eap_ds->response;
+ hdr = (pwd_hdr *)response->type.data;
+
+ /*
+ * The header must be at least one byte.
+ */
+ if (!hdr || (response->type.length < sizeof(pwd_hdr))) {
+ RDEBUG("Packet with insufficient data");
+ return 0;
+ }
+
+ in = hdr->data;
+ in_len = response->type.length - sizeof(pwd_hdr);
+
+ /*
+ * see if we're fragmenting, if so continue until we're done
+ */
+ if (session->out_pos) {
+ if (in_len) RDEBUG2("pwd got something more than an ACK for a fragment");
+
+ return send_pwd_request(session, eap_ds);
+ }
+
+ /*
+ * the first fragment will have a total length, make a
+ * buffer to hold all the fragments
+ */
+ if (EAP_PWD_GET_LENGTH_BIT(hdr)) {
+ if (session->in) {
+ RDEBUG2("pwd already alloced buffer for fragments");
+ return 0;
+ }
+
+ if (in_len < 2) {
+ RDEBUG("Invalid packet: length bit set, but no length field");
+ return 0;
+ }
+
+ session->in_len = ntohs(in[0] * 256 | in[1]);
+ if ((session->in = talloc_zero_array(session, uint8_t, session->in_len)) == NULL) {
+ RDEBUG2("pwd cannot allocate %zd buffer to hold fragments",
+ session->in_len);
+ return 0;
+ }
+ memset(session->in, 0, session->in_len);
+ session->in_pos = 0;
+ in += sizeof(uint16_t);
+ in_len -= sizeof(uint16_t);
+ }
+
+ /*
+ * all fragments, including the 1st will have the M(ore) bit set,
+ * buffer those fragments!
+ */
+ if (EAP_PWD_GET_MORE_BIT(hdr)) {
+ if (!session->in) {
+ RDEBUG2("Unexpected fragment.");
+ return 0;
+ }
+
+ if ((session->in_pos + in_len) > session->in_len) {
+ RDEBUG2("Fragment overflows packet.");
+ return 0;
+ }
+
+ memcpy(session->in + session->in_pos, in, in_len);
+ session->in_pos += in_len;
+
+ /*
+ * send back an ACK for this fragment
+ */
+ exch = EAP_PWD_GET_EXCHANGE(hdr);
+ eap_ds->request->code = PW_EAP_REQUEST;
+ eap_ds->request->type.num = PW_EAP_PWD;
+ eap_ds->request->type.length = sizeof(pwd_hdr);
+ if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) {
+ return 0;
+ }
+ hdr = (pwd_hdr *)eap_ds->request->type.data;
+ EAP_PWD_SET_EXCHANGE(hdr, exch);
+ return 1;
+ }
+
+
+ if (session->in) {
+ /*
+ * the last fragment...
+ */
+ if ((session->in_pos + in_len) > session->in_len) {
+ RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent");
+ return 0;
+ }
+ memcpy(session->in + session->in_pos, in, in_len);
+ in = session->in;
+ in_len = session->in_len;
+ }
+
+ switch (session->state) {
+ case PWD_STATE_ID_REQ:
+ {
+ BIGNUM *x = NULL, *y = NULL;
+
+ if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) {
+ RDEBUG2("pwd exchange is incorrect: not ID");
+ return 0;
+ }
+
+ packet = (pwd_id_packet_t *) in;
+ if (in_len < sizeof(*packet)) {
+ RDEBUG("Packet is too small (%zd < %zd).", in_len, sizeof(*packet));
+ return 0;
+ }
+
+ if ((packet->prf != EAP_PWD_DEF_PRF) ||
+ (packet->random_function != EAP_PWD_DEF_RAND_FUN) ||
+ (packet->prep != session->prep) ||
+ (CRYPTO_memcmp(packet->token, &session->token, 4)) ||
+ (packet->group_num != ntohs(session->group_num))) {
+ RDEBUG2("pwd id response is invalid");
+ return 0;
+ }
+ /*
+ * we've agreed on the ciphersuite, record it...
+ */
+ ptr = (uint8_t *)&session->ciphersuite;
+ memcpy(ptr, (char *)&packet->group_num, sizeof(uint16_t));
+ ptr += sizeof(uint16_t);
+ *ptr = EAP_PWD_DEF_RAND_FUN;
+ ptr += sizeof(uint8_t);
+ *ptr = EAP_PWD_DEF_PRF;
+
+ peer_id_len = in_len - sizeof(pwd_id_packet_t);
+ if (peer_id_len >= sizeof(session->peer_id)) {
+ RDEBUG2("pwd id response is malformed");
+ return 0;
+ }
+ peer_id = packet->identity;
+
+ if (inst->prep >= 0) {
+ /*
+ * make fake request to get the password for the usable ID
+ */
+
+ session->peer_id_len = peer_id_len;
+ memcpy(session->peer_id, peer_id, peer_id_len);
+ session->peer_id[peer_id_len] = '\0';
+
+ if (fetch_and_process_password(session, request, inst) < 0) {
+ RDEBUG2("failed to find password for %s to do pwd authentication",
+ session->peer_id);
+ return 0;
+ }
+ } else {
+ /* verify inner identity == outer identity */
+ if (session->peer_id_len != peer_id_len ||
+ memcmp(session->peer_id, peer_id, peer_id_len) != 0) {
+ char buf[sizeof(session->peer_id)];
+ memcpy(buf, peer_id, peer_id_len);
+ buf[peer_id_len] = '\0';
+
+ RDEBUG2("inner identity(peer_id) %s does not match outer identity %s",
+ buf, session->peer_id);
+ return 0;
+ }
+ RDEBUG2("inner identity matched for %s", session->peer_id);
+ }
+
+ /*
+ * compute our scalar and element
+ */
+ if (compute_scalar_element(request, session, session->bnctx)) {
+ DEBUG2("failed to compute server's scalar and element");
+ return 0;
+ }
+
+ MEM(x = BN_new());
+ MEM(y = BN_new());
+
+ /*
+ * element is a point, get both coordinates: x and y
+ */
+ if (!EC_POINT_get_affine_coordinates(session->group, session->my_element, x, y,
+ session->bnctx)) {
+ DEBUG2("server point assignment failed");
+ BN_clear_free(x);
+ BN_clear_free(y);
+ return 0;
+ }
+
+ /*
+ * construct request
+ */
+ session->out_len = BN_num_bytes(session->order) + (2 * BN_num_bytes(session->prime));
+ if (session->salt_present)
+ session->out_len += 1 + session->salt_len;
+
+ if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) {
+ return 0;
+ }
+ memset(session->out, 0, session->out_len);
+
+ ptr = session->out;
+ if (session->salt_present) {
+ *ptr = session->salt_len;
+ ptr++;
+
+ memcpy(ptr, session->salt, session->salt_len);
+ ptr += session->salt_len;
+ }
+
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(x);
+ BN_bn2bin(x, ptr + offset);
+ BN_clear_free(x);
+
+ ptr += BN_num_bytes(session->prime);
+ offset = BN_num_bytes(session->prime) - BN_num_bytes(y);
+ BN_bn2bin(y, ptr + offset);
+ BN_clear_free(y);
+
+ ptr += BN_num_bytes(session->prime);
+ offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar);
+ BN_bn2bin(session->my_scalar, ptr + offset);
+
+ session->state = PWD_STATE_COMMIT;
+ ret = send_pwd_request(session, eap_ds);
+ }
+ break;
+
+ case PWD_STATE_COMMIT:
+ if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) {
+ RDEBUG2("pwd exchange is incorrect: not commit!");
+ return 0;
+ }
+
+ /*
+ * process the peer's commit and generate the shared key, k
+ */
+ if (process_peer_commit(request, session, in, in_len, session->bnctx)) {
+ RDEBUG2("failed to process peer's commit");
+ return 0;
+ }
+
+ /*
+ * compute our confirm blob
+ */
+ if (compute_server_confirm(request, session, session->my_confirm, session->bnctx)) {
+ ERROR("rlm_eap_pwd: failed to compute confirm!");
+ return 0;
+ }
+
+ /*
+ * construct a response...which is just our confirm blob
+ */
+ session->out_len = SHA256_DIGEST_LENGTH;
+ if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) {
+ return 0;
+ }
+
+ memset(session->out, 0, session->out_len);
+ memcpy(session->out, session->my_confirm, SHA256_DIGEST_LENGTH);
+
+ session->state = PWD_STATE_CONFIRM;
+ ret = send_pwd_request(session, eap_ds);
+ break;
+
+ case PWD_STATE_CONFIRM:
+ if (in_len < SHA256_DIGEST_LENGTH) {
+ RDEBUG("Peer confirm is too short (%zd < %d)",
+ in_len, SHA256_DIGEST_LENGTH);
+ return 0;
+ }
+
+ if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) {
+ RDEBUG2("pwd exchange is incorrect: not commit!");
+ return 0;
+ }
+ if (compute_peer_confirm(request, session, peer_confirm, session->bnctx)) {
+ RDEBUG2("pwd exchange cannot compute peer's confirm");
+ return 0;
+ }
+ if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) {
+ RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
+ return 0;
+ }
+ if (compute_keys(request, session, peer_confirm, msk, emsk)) {
+ RDEBUG2("pwd exchange cannot generate (E)MSK!");
+ return 0;
+ }
+ eap_ds->request->code = PW_EAP_SUCCESS;
+ /*
+ * return the MSK (in halves)
+ */
+ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN);
+ eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk + MPPE_KEY_LEN, MPPE_KEY_LEN);
+
+ ret = 1;
+ break;
+
+ default:
+ RDEBUG2("unknown PWD state");
+ return 0;
+ }
+
+ /*
+ * we processed the buffered fragments, get rid of them
+ */
+ if (session->in) {
+ talloc_free(session->in);
+ session->in = NULL;
+ }
+
+ return ret;
+}
+
+extern rlm_eap_module_t rlm_eap_pwd;
+rlm_eap_module_t rlm_eap_pwd = {
+ .name = "eap_pwd",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Create the initial request */
+ .process = mod_process, /* Process next round of EAP method */
+};
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h
new file mode 100644
index 0000000..966646c
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) Dan Harkins, 2012
+ *
+ * Copyright holder grants permission for redistribution and use in source
+ * and binary forms, with or without modification, provided that the
+ * following conditions are met:
+ * 1. Redistribution of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in all source files.
+ * 2. Redistribution in binary form must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * "DISCLAIMER OF LIABILITY
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE."
+ *
+ * This license and distribution terms cannot be changed. In other words,
+ * this code cannot simply be copied and put under a different distribution
+ * license (including the GNU public license).
+ */
+
+#ifndef _RLM_EAP_PWD_H
+#define _RLM_EAP_PWD_H
+
+#include "eap_pwd.h"
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+typedef struct _eap_pwd_t {
+ uint32_t group;
+ uint32_t fragment_size;
+ char const *server_id;
+ char const *virtual_server;
+ int32_t prep;
+ int32_t unhex;
+} eap_pwd_t;
+
+#endif /* _RLM_EAP_PWD_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore b/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/README.md b/src/modules/rlm_eap/types/rlm_eap_sim/README.md
new file mode 100644
index 0000000..76e83e8
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/README.md
@@ -0,0 +1,9 @@
+# rlm_eap_aka
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 4186](https://tools.ietf.org/html/rfc4186) EAP-SIM authentication. EAP-SIM provides authentication
+and session keying material for 802.11i (WPA/2 Enterprise) using SIM triplets.
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in
new file mode 100644
index 0000000..c13b2ef
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/all.mk.in
@@ -0,0 +1,12 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/configure b/src/modules/rlm_eap/types/rlm_eap_sim/configure
new file mode 100755
index 0000000..aa7d6ca
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/configure
@@ -0,0 +1,2929 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap_sim.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap_sim
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap_sim build without rlm_eap_sim
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap_sim
+echo
+
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap_sim was given.
+if test "${with_rlm_eap_sim+set}" = set; then :
+ withval=$with_rlm_eap_sim;
+fi
+
+
+
+mod_ldflags=
+mod_cflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap_sim" != xno; then
+
+
+
+ targetname=rlm_eap_sim
+else
+ targetname=
+ echo \*\*\* module rlm_eap_sim is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap_sim to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_sim." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap_sim." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_sim requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap_sim requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac b/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac
new file mode 100644
index 0000000..e3dac84
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/configure.ac
@@ -0,0 +1,18 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap_sim.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap_sim])
+
+mod_ldflags=
+mod_cflags=
+
+FR_MODULE_START_TESTS
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c
new file mode 100644
index 0000000..38fe997
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_sim/rlm_eap_sim.c
@@ -0,0 +1,697 @@
+/*
+ * rlm_eap_sim.c Handles that are called from eap for SIM
+ *
+ * The development of the EAP/SIM support was funded by Internet Foundation
+ * Austria (http://www.nic.at/ipa).
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
+ * Copyright 2003,2006 The FreeRADIUS server project
+ *
+ */
+
+RCSID("$Id$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../eap.h"
+#include "eap_types.h"
+#include "eap_sim.h"
+#include "comp128.h"
+
+#include <freeradius-devel/rad_assert.h>
+
+typedef struct eap_sim_server_state {
+ enum eapsim_serverstates state;
+ struct eapsim_keys keys;
+ int sim_id;
+} eap_sim_state_t;
+
+static int eap_sim_sendstart(eap_handler_t *handler)
+{
+ VALUE_PAIR **vps, *newvp;
+ uint16_t words[3];
+ eap_sim_state_t *ess;
+ RADIUS_PACKET *packet;
+ uint8_t *p;
+
+ rad_assert(handler->request != NULL);
+ rad_assert(handler->request->reply);
+
+ ess = (eap_sim_state_t *)handler->opaque;
+
+ /* these are the outgoing attributes */
+ packet = handler->request->reply;
+ vps = &packet->vps;
+ rad_assert(vps != NULL);
+
+
+ /*
+ * Add appropriate TLVs for the EAP things we wish to send.
+ */
+
+ /* the version list. We support only version 1. */
+ words[0] = htons(sizeof(words[1]));
+ words[1] = htons(EAP_SIM_VERSION);
+ words[2] = 0;
+
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_VERSION_LIST, 0);
+ fr_pair_value_memcpy(newvp, (uint8_t const *) words, sizeof(words));
+
+ fr_pair_add(vps, newvp);
+
+ /* set the EAP_ID - new value */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_ID, 0);
+ newvp->vp_integer = ess->sim_id++;
+ fr_pair_replace(vps, newvp);
+
+ /* record it in the ess */
+ ess->keys.versionlistlen = 2;
+ memcpy(ess->keys.versionlist, words + 1, ess->keys.versionlistlen);
+
+ /* the ANY_ID attribute. We do not support re-auth or pseudonym */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_FULLAUTH_ID_REQ, 0);
+ newvp->vp_length = 2;
+ newvp->vp_octets = p = talloc_array(newvp, uint8_t, 2);
+
+ p[0] = 0;
+ p[0] = 1;
+ fr_pair_add(vps, newvp);
+
+ /* the SUBTYPE, set to start. */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_SUBTYPE, 0);
+ newvp->vp_integer = EAPSIM_START;
+ fr_pair_replace(vps, newvp);
+
+ return 1;
+}
+
+static int eap_sim_get_challenge(eap_handler_t *handler, VALUE_PAIR *vps, int idx, eap_sim_state_t *ess)
+{
+ REQUEST *request = handler->request;
+ VALUE_PAIR *vp, *ki, *algo_version;
+
+ rad_assert(idx >= 0 && idx < 3);
+
+ /*
+ * Generate a new RAND value, and derive Kc and SRES from Ki
+ */
+ ki = fr_pair_find_by_num(vps, PW_EAP_SIM_KI, 0, TAG_ANY);
+ if (ki) {
+ int i;
+
+ /*
+ * Check to see if have a Ki for the IMSI, this allows us to generate the rest
+ * of the triplets.
+ */
+ algo_version = fr_pair_find_by_num(vps, PW_EAP_SIM_ALGO_VERSION, 0, TAG_ANY);
+ if (!algo_version) {
+ REDEBUG("Found Ki, but missing EAP-Sim-Algo-Version");
+ return 0;
+ }
+
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ ess->keys.rand[idx][i] = fr_rand();
+ }
+
+ switch (algo_version->vp_integer) {
+ case 1:
+ comp128v1(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx]);
+ break;
+
+ case 2:
+ comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
+ true);
+ break;
+
+ case 3:
+ comp128v23(ess->keys.sres[idx], ess->keys.Kc[idx], ki->vp_octets, ess->keys.rand[idx],
+ false);
+ break;
+
+ case 4:
+ REDEBUG("Comp128-4 algorithm is not supported as details have not yet been published. "
+ "If you have details of this algorithm please contact the FreeRADIUS "
+ "maintainers");
+ return 0;
+
+ default:
+ REDEBUG("Unknown/unsupported algorithm Comp128-%i", algo_version->vp_integer);
+ }
+
+ if (RDEBUG_ENABLED2) {
+ char buffer[33]; /* 32 hexits (16 bytes) + 1 */
+ char *p;
+
+ RDEBUG2("Generated following triplets for round %i:", idx);
+
+ RINDENT();
+ p = buffer;
+ for (i = 0; i < EAPSIM_RAND_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.rand[idx][i]);
+ }
+ RDEBUG2("RAND : 0x%s", buffer);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_SRES_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.sres[idx][i]);
+ }
+ RDEBUG2("SRES : 0x%s", buffer);
+
+ p = buffer;
+ for (i = 0; i < EAPSIM_KC_SIZE; i++) {
+ p += sprintf(p, "%02x", ess->keys.Kc[idx][i]);
+ }
+ RDEBUG2("Kc : 0x%s", buffer);
+ REXDENT();
+ }
+ return 1;
+ }
+
+ /*
+ * Use known RAND, SRES, and Kc values, these may of been pulled in from an AuC,
+ * or created by sending challenges to the SIM directly.
+ */
+ vp = fr_pair_find_by_num(vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY);
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_RAND1 + idx, 0, TAG_ANY);
+ }
+ if (!vp) {
+ /* bad, we can't find stuff! */
+ REDEBUG("EAP-SIM-RAND%i not found", idx + 1);
+ return 0;
+ }
+ if (vp->vp_length != EAPSIM_RAND_SIZE) {
+ REDEBUG("EAP-SIM-RAND%i is not " STRINGIFY(EAPSIM_RAND_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->vp_length);
+ return 0;
+ }
+ memcpy(ess->keys.rand[idx], vp->vp_strvalue, EAPSIM_RAND_SIZE);
+
+ vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY);
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_SRES1 + idx, 0, TAG_ANY);
+ }
+ if (!vp) {
+ /* bad, we can't find stuff! */
+ REDEBUG("EAP-SIM-SRES%i not found", idx + 1);
+ return 0;
+ }
+
+ if (vp->vp_length != EAPSIM_SRES_SIZE) {
+ REDEBUG("EAP-SIM-SRES%i is not " STRINGIFY(EAPSIM_SRES_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->vp_length);
+ return 0;
+ }
+ memcpy(ess->keys.sres[idx], vp->vp_strvalue, EAPSIM_SRES_SIZE);
+
+ vp = fr_pair_find_by_num(vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ /* Hack for backwards compatibility */
+ if (!vp) {
+ vp = fr_pair_find_by_num(request->reply->vps, PW_EAP_SIM_KC1 + idx, 0, TAG_ANY);
+ }
+
+ if (!vp) {
+ /* bad, we can't find stuff! */
+ REDEBUG("EAP-SIM-Kc%i not found", idx + 1);
+ return 0;
+ }
+ if (vp->vp_length != EAPSIM_KC_SIZE) {
+ REDEBUG("EAP-SIM-Kc%i is not " STRINGIFY(EAPSIM_KC_SIZE) " bytes, got %zu bytes",
+ idx + 1, vp->vp_length);
+ return 0;
+ }
+ memcpy(ess->keys.Kc[idx], vp->vp_strvalue, EAPSIM_KC_SIZE);
+
+ return 1;
+}
+
+/** Send the challenge itself
+ *
+ * Challenges will come from one of three places eventually:
+ *
+ * 1 from attributes like PW_EAP_SIM_RANDx
+ * (these might be retrieved from a database)
+ *
+ * 2 from internally implemented SIM authenticators
+ * (a simple one based upon XOR will be provided)
+ *
+ * 3 from some kind of SS7 interface.
+ *
+ * For now, they only come from attributes.
+ * It might be that the best way to do 2/3 will be with a different
+ * module to generate/calculate things.
+ *
+ */
+static int eap_sim_sendchallenge(eap_handler_t *handler)
+{
+ REQUEST *request = handler->request;
+ eap_sim_state_t *ess;
+ VALUE_PAIR **invps, **outvps, *newvp;
+ RADIUS_PACKET *packet;
+ uint8_t *p;
+
+ ess = (eap_sim_state_t *)handler->opaque;
+ rad_assert(handler->request != NULL);
+ rad_assert(handler->request->reply);
+
+ /*
+ * Invps is the data from the client but this is for non-protocol data here.
+ * We should already have consumed any client originated data.
+ */
+ invps = &handler->request->packet->vps;
+
+ /*
+ * Outvps is the data to the client
+ */
+ packet = handler->request->reply;
+ outvps = &packet->vps;
+
+ if (RDEBUG_ENABLED2) {
+ RDEBUG2("EAP-SIM decoded packet");
+ rdebug_pair_list(L_DBG_LVL_2, request, *invps, NULL);
+ }
+
+ /*
+ * Okay, we got the challenges! Put them into an attribute.
+ */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_RAND, 0);
+ newvp->vp_length = 2 + (EAPSIM_RAND_SIZE * 3);
+ newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->vp_length);
+
+ memset(p, 0, 2); /* clear reserved bytes */
+ p += 2;
+ memcpy(p, ess->keys.rand[0], EAPSIM_RAND_SIZE);
+ p += EAPSIM_RAND_SIZE;
+ memcpy(p, ess->keys.rand[1], EAPSIM_RAND_SIZE);
+ p += EAPSIM_RAND_SIZE;
+ memcpy(p, ess->keys.rand[2], EAPSIM_RAND_SIZE);
+ fr_pair_add(outvps, newvp);
+
+ /*
+ * Set the EAP_ID - new value
+ */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_ID, 0);
+ newvp->vp_integer = ess->sim_id++;
+ fr_pair_replace(outvps, newvp);
+
+ /*
+ * Make a copy of the identity
+ */
+ ess->keys.identitylen = strlen(handler->identity);
+ memcpy(ess->keys.identity, handler->identity, ess->keys.identitylen);
+
+ /*
+ * Use the SIM identity, if available
+ */
+ newvp = fr_pair_find_by_num(*invps, PW_EAP_SIM_IDENTITY, 0, TAG_ANY);
+ if (newvp && newvp->vp_length > 2) {
+ uint16_t len;
+
+ memcpy(&len, newvp->vp_octets, sizeof(uint16_t));
+ len = ntohs(len);
+ if (len <= newvp->vp_length - 2 && len <= MAX_STRING_LEN) {
+ ess->keys.identitylen = len;
+ memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen);
+ }
+ }
+
+ /*
+ * All set, calculate keys!
+ */
+ eapsim_calculate_keys(&ess->keys);
+
+#ifdef EAP_SIM_DEBUG_PRF
+ eapsim_dump_mk(&ess->keys);
+#endif
+
+ /*
+ * Need to include an AT_MAC attribute so that it will get
+ * calculated. The NONCE_MT and the MAC are both 16 bytes, so
+ * We store the NONCE_MT in the MAC for the encoder, which
+ * will pull it out before it does the operation.
+ */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_MAC, 0);
+ fr_pair_value_memcpy(newvp, ess->keys.nonce_mt, 16);
+ fr_pair_replace(outvps, newvp);
+
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_KEY, 0);
+ fr_pair_value_memcpy(newvp, ess->keys.K_aut, 16);
+ fr_pair_replace(outvps, newvp);
+
+ /* the SUBTYPE, set to challenge. */
+ newvp = fr_pair_afrom_num(packet, PW_EAP_SIM_SUBTYPE, 0);
+ newvp->vp_integer = EAPSIM_CHALLENGE;
+ fr_pair_replace(outvps, newvp);
+
+ return 1;
+}
+
+#ifndef EAPTLS_MPPE_KEY_LEN
+#define EAPTLS_MPPE_KEY_LEN 32
+#endif
+
+/*
+ * this code sends the success message.
+ *
+ * the only work to be done is the add the appropriate SEND/RECV
+ * radius attributes derived from the MSK.
+ *
+ */
+static int eap_sim_sendsuccess(eap_handler_t *handler)
+{
+ unsigned char *p;
+ eap_sim_state_t *ess;
+ VALUE_PAIR *vp;
+ RADIUS_PACKET *packet;
+
+ /* outvps is the data to the client. */
+ packet = handler->request->reply;
+ ess = (eap_sim_state_t *)handler->opaque;
+
+ /* set the EAP_ID - new value */
+ vp = fr_pair_afrom_num(packet, PW_EAP_ID, 0);
+ vp->vp_integer = ess->sim_id++;
+ fr_pair_replace(&handler->request->reply->vps, vp);
+
+ p = ess->keys.msk;
+ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
+ p += EAPTLS_MPPE_KEY_LEN;
+ eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN);
+
+ return 1;
+}
+
+
+/** Run the server state machine
+ *
+ */
+static void eap_sim_state_enter(REQUEST *request, eap_handler_t *handler,
+ eap_sim_state_t *ess,
+ enum eapsim_serverstates newstate)
+{
+ switch (newstate) {
+ /*
+ * Send the EAP-SIM Start message, listing the versions that we support.
+ */
+ case EAPSIM_SERVER_START:
+ eap_sim_sendstart(handler);
+ break;
+ /*
+ * Send the EAP-SIM Challenge message.
+ */
+ case EAPSIM_SERVER_CHALLENGE:
+ eap_sim_sendchallenge(handler);
+ break;
+
+ /*
+ * Send the EAP Success message
+ */
+ case EAPSIM_SERVER_SUCCESS:
+ eap_sim_sendsuccess(handler);
+ handler->eap_ds->request->code = PW_EAP_SUCCESS;
+ break;
+ /*
+ * Nothing to do for this transition.
+ */
+ default:
+
+ break;
+ }
+
+ ess->state = newstate;
+
+ /* build the target packet */
+ /* we will set the ID on requests, since we have to HMAC it */
+ handler->eap_ds->set_request_id = 1;
+
+ if (!map_eapsim_basictypes(handler->request->reply,
+ handler->eap_ds->request)) {
+ REDEBUG("Failed encoding EAP-SIM packet");
+ }
+}
+
+/*
+ * Initiate the EAP-SIM session by starting the state machine
+ * and initiating the state.
+ */
+static int mod_session_init(UNUSED void *instance, eap_handler_t *handler)
+{
+ REQUEST *request = handler->request;
+ eap_sim_state_t *ess;
+ time_t n;
+
+ ess = talloc_zero(handler, eap_sim_state_t);
+ if (!ess) {
+ RDEBUG2("No space for EAP-SIM state");
+ return 0;
+ }
+
+ handler->opaque = ess;
+ handler->stage = PROCESS;
+
+ /*
+ * Save the keying material, because it could change on a subsequent retrival.
+ */
+ if (!eap_sim_get_challenge(handler, request->config, 0, ess) ||
+ !eap_sim_get_challenge(handler, request->config, 1, ess) ||
+ !eap_sim_get_challenge(handler, request->config, 2, ess)) {
+ return 0; /* already printed error */
+ }
+
+ /*
+ * This value doesn't have be strong, but it is good if it is different now and then.
+ */
+ time(&n);
+ ess->sim_id = (n & 0xff);
+
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
+
+ return 1;
+}
+
+
+/** Process an EAP-Sim/Response/Start
+ *
+ * Verify that client chose a version, and provided a NONCE_MT,
+ * and if so, then change states to challenge, and send the new
+ * challenge, else, resend the Request/Start.
+ */
+static int process_eap_sim_start(eap_handler_t *handler, VALUE_PAIR *vps)
+{
+ REQUEST *request = handler->request;
+ VALUE_PAIR *nonce_vp, *selectedversion_vp;
+ eap_sim_state_t *ess;
+ uint16_t simversion;
+ ess = (eap_sim_state_t *)handler->opaque;
+
+ nonce_vp = fr_pair_find_by_num(vps, PW_EAP_SIM_NONCE_MT, 0, TAG_ANY);
+ selectedversion_vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SELECTED_VERSION, 0, TAG_ANY);
+ if (!nonce_vp || !selectedversion_vp) {
+ RDEBUG2("Client did not select a version and send a NONCE");
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
+ return 1;
+ }
+
+ /*
+ * Okay, good got stuff that we need. Check the version we found.
+ */
+ if (selectedversion_vp->vp_length < 2) {
+ REDEBUG("EAP-SIM version field is too short");
+ return 0;
+ }
+ memcpy(&simversion, selectedversion_vp->vp_strvalue, sizeof(simversion));
+ simversion = ntohs(simversion);
+ if(simversion != EAP_SIM_VERSION) {
+ REDEBUG("EAP-SIM version %i is unknown", simversion);
+ return 0;
+ }
+
+ /*
+ * Record it for later keying
+ */
+ memcpy(ess->keys.versionselect, selectedversion_vp->vp_strvalue, sizeof(ess->keys.versionselect));
+
+ /*
+ * Double check the nonce size.
+ */
+ if(nonce_vp->vp_length != 18) {
+ REDEBUG("EAP-SIM nonce_mt must be 16 bytes (+2 bytes padding), not %zu", nonce_vp->vp_length);
+ return 0;
+ }
+ memcpy(ess->keys.nonce_mt, nonce_vp->vp_strvalue + 2, 16);
+
+ /*
+ * Everything looks good, change states
+ */
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE);
+
+ return 1;
+}
+
+
+/** Process an EAP-Sim/Response/Challenge
+ *
+ * Verify that MAC that we received matches what we would have
+ * calculated from the packet with the SRESx appended.
+ *
+ */
+static int process_eap_sim_challenge(eap_handler_t *handler, VALUE_PAIR *vps)
+{
+ REQUEST *request = handler->request;
+ eap_sim_state_t *ess = handler->opaque;
+
+ uint8_t srescat[EAPSIM_SRES_SIZE * 3];
+ uint8_t *p = srescat;
+
+ uint8_t calcmac[EAPSIM_CALCMAC_SIZE];
+
+ memcpy(p, ess->keys.sres[0], EAPSIM_SRES_SIZE);
+ p += EAPSIM_SRES_SIZE;
+ memcpy(p, ess->keys.sres[1], EAPSIM_SRES_SIZE);
+ p += EAPSIM_SRES_SIZE;
+ memcpy(p, ess->keys.sres[2], EAPSIM_SRES_SIZE);
+
+ /*
+ * Verify the MAC, now that we have all the keys
+ */
+ if (eapsim_checkmac(handler, vps, ess->keys.K_aut, srescat, sizeof(srescat), calcmac)) {
+ RDEBUG2("MAC check succeed");
+ } else {
+ int i, j;
+ char macline[20*3];
+ char *m = macline;
+
+ j=0;
+ for (i = 0; i < EAPSIM_CALCMAC_SIZE; i++) {
+ if(j==4) {
+ *m++ = '_';
+ j=0;
+ }
+ j++;
+
+ sprintf(m, "%02x", calcmac[i]);
+ m = m + strlen(m);
+ }
+ REDEBUG("Calculated MAC (%s) did not match", macline);
+ return 0;
+ }
+
+ /* everything looks good, change states */
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_SUCCESS);
+ return 1;
+}
+
+
+/** Authenticate a previously sent challenge
+ *
+ */
+static int mod_process(UNUSED void *arg, eap_handler_t *handler)
+{
+ REQUEST *request = handler->request;
+ eap_sim_state_t *ess = handler->opaque;
+
+ VALUE_PAIR *vp, *vps;
+
+ enum eapsim_subtype subtype;
+
+ int success;
+
+ /*
+ * VPS is the data from the client
+ */
+ vps = handler->request->packet->vps;
+
+ success = unmap_eapsim_basictypes(handler->request->packet,
+ handler->eap_ds->response->type.data,
+ handler->eap_ds->response->type.length);
+
+ if (!success) {
+ REDEBUG("Failed decoding EAP-SIM packet: %s", fr_strerror());
+ return 0;
+ }
+
+ /*
+ * See what kind of message we have gotten
+ */
+ vp = fr_pair_find_by_num(vps, PW_EAP_SIM_SUBTYPE, 0, TAG_ANY);
+ if (!vp) {
+ REDEBUG2("No subtype attribute was created, message dropped");
+ return 0;
+ }
+ subtype = vp->vp_integer;
+
+ /*
+ * Client error supersedes anything else.
+ */
+ if (subtype == EAPSIM_CLIENT_ERROR) {
+ return 0;
+ }
+
+ switch (ess->state) {
+ case EAPSIM_SERVER_START:
+ switch (subtype) {
+ /*
+ * Pretty much anything else here is illegal, so we will retransmit the request.
+ */
+ default:
+
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_START);
+ return 1;
+ /*
+ * A response to our EAP-Sim/Request/Start!
+ */
+ case EAPSIM_START:
+ return process_eap_sim_start(handler, vps);
+ }
+
+ case EAPSIM_SERVER_CHALLENGE:
+ switch (subtype) {
+ /*
+ * Pretty much anything else here is illegal, so we will retransmit the request.
+ */
+ default:
+ eap_sim_state_enter(request, handler, ess, EAPSIM_SERVER_CHALLENGE);
+ return 1;
+ /*
+ * A response to our EAP-Sim/Request/Challenge!
+ */
+ case EAPSIM_CHALLENGE:
+ return process_eap_sim_challenge(handler, vps);
+ }
+
+ default:
+ rad_assert(0 == 1);
+ }
+
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_sim;
+rlm_eap_module_t rlm_eap_sim = {
+ .name = "eap_sim",
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process, /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/README.md b/src/modules/rlm_eap/types/rlm_eap_tls/README.md
new file mode 100644
index 0000000..afb80f2
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tls/README.md
@@ -0,0 +1,9 @@
+# rlm_eap_tls
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 5216](https://tools.ietf.org/html/rfc5216) EAP-TLS authentication. EAP-TLS provides mutual
+authentication and session keying material for 802.11i (WPA/2 Enterprise) using certificates.
diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/all.mk b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk
new file mode 100644
index 0000000..fdb7c4b
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tls/all.mk
@@ -0,0 +1,10 @@
+TARGETNAME := rlm_eap_tls
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c
new file mode 100644
index 0000000..d327c57
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c
@@ -0,0 +1,303 @@
+/*
+ * rlm_eap_tls.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ *
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
+
+#ifdef HAVE_OPENSSL_EVP_H
+#include <openssl/evp.h>
+#endif
+
+#include "rlm_eap_tls.h"
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+static CONF_PARSER module_config[] = {
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name), NULL },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_tls_t, virtual_server), NULL },
+ { "configurable_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_tls_t, configurable_client_cert), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Attach the EAP-TLS module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_tls_t *inst;
+
+ /*
+ * Parse the config file & get all the configured values
+ */
+ *instance = inst = talloc_zero(cs, rlm_eap_tls_t);
+ if (!inst) return -1;
+
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ inst->tls_conf = eaptls_conf_parse(cs, "tls");
+
+ if (!inst->tls_conf) {
+ ERROR("rlm_eap_tls: Failed initializing SSL context");
+ return -1;
+ }
+
+#ifdef TLS1_3_VERSION
+ if ((inst->tls_conf->max_version == TLS1_3_VERSION) ||
+ (inst->tls_conf->min_version == TLS1_3_VERSION)) {
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! Most supplicants do not support EAP-TLS with TLS 1.3");
+ WARN("!! Please set tls_max_version = \"1.2\"");
+ WARN("!! FreeRADIUS only supports TLS 1.3 for special builds of wpa_supplicant and Windows");
+ WARN("!! This limitation is likely to change in late 2021.");
+ WARN("!! If you are using this version of FreeRADIUS after 2021, you will probably need to upgrade");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Send an initial eap-tls request to the peer, using the libeap functions.
+ */
+static int mod_session_init(void *type_arg, eap_handler_t *handler)
+{
+ int status;
+ tls_session_t *ssn;
+ rlm_eap_tls_t *inst;
+ REQUEST *request = handler->request;
+ bool require_client_cert = true;
+
+ inst = type_arg;
+
+ handler->tls = true;
+
+ /*
+ * Respect EAP-TLS-Require-Client-Cert, but only if
+ * enabled in the module configuration.
+ *
+ * We can't change behavior of existing systems, so this
+ * change has to be enabled via a new configuration
+ * option.
+ */
+ if (inst->configurable_client_cert) {
+ VALUE_PAIR *vp;
+
+ vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
+ if (vp && !vp->vp_integer) require_client_cert = false;
+ }
+
+ /*
+ * EAP-TLS always requires a client certificate, and
+ * allows for TLS 1.3 if permitted.
+ */
+ ssn = eaptls_session(handler, inst->tls_conf, require_client_cert, true);
+ if (!ssn) {
+ return 0;
+ }
+
+ handler->opaque = ((void *)ssn);
+ ssn->quick_session_tickets = true; /* send as soon as we've seen the client cert */
+
+ /*
+ * TLS session initialization is over. Now handle TLS
+ * related handshaking or application data.
+ */
+ status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+ if (status == 0) return 0;
+
+ /*
+ * The next stage to process the packet.
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+/*
+ * Do authentication, by letting EAP-TLS do most of the work.
+ */
+static int CC_HINT(nonnull) mod_process(void *type_arg, eap_handler_t *handler)
+{
+ fr_tls_status_t status;
+ int ret;
+ tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+ REQUEST *request = handler->request;
+ rlm_eap_tls_t *inst;
+
+ inst = type_arg;
+
+ status = eaptls_process(handler);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+
+
+ /*
+ * Make request available to any SSL callbacks
+ */
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
+ switch (status) {
+ /*
+ * EAP-TLS handshake was successful, return an
+ * EAP-TLS-Success packet here.
+ *
+ * If a virtual server was configured, check that
+ * it accepts the certificates, too.
+ */
+ case FR_TLS_SUCCESS:
+ if (inst->virtual_server) {
+ VALUE_PAIR *vp;
+ REQUEST *fake;
+
+ /* create a fake request */
+ fake = request_alloc_fake(request);
+ rad_assert(!fake->packet->vps);
+
+ fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps);
+
+ /* set the virtual server to use */
+ if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+ fake->server = vp->vp_strvalue;
+ } else {
+ fake->server = inst->virtual_server;
+ }
+
+ RDEBUG2("Validating certificate");
+ rad_virtual_server(fake);
+
+ /* copy the reply vps back to our reply */
+ fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps,
+ &fake->reply->vps, 0, 0, TAG_ANY);
+
+ /* reject if virtual server didn't return accept */
+ if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) {
+ RDEBUG2("Certificate rejected by the virtual server");
+ talloc_free(fake);
+ eaptls_fail(handler, 0);
+ ret = 0;
+ goto done;
+ }
+
+ talloc_free(fake);
+ /* success */
+ }
+
+ /*
+ * Set the label to a fixed string. For TLS 1.3,
+ * the label is the same for all TLS-based EAP
+ * methods.
+ */
+ tls_session->label = "client EAP encryption";
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ ret = eaptls_success(handler, 0);
+ break;
+
+ /*
+ * The TLS code is still working on the TLS
+ * exchange, and it's a valid TLS request.
+ * do nothing.
+ */
+ case FR_TLS_HANDLED:
+ ret = 1;
+ break;
+
+ /*
+ * Handshake is done, proceed with decoding tunneled
+ * data.
+ */
+ case FR_TLS_OK:
+ RDEBUG2("Received unexpected tunneled data after successful handshake");
+#ifndef NDEBUG
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ unsigned int i;
+ unsigned int data_len;
+ unsigned char buffer[1024];
+
+ data_len = (tls_session->record_minus)(&tls_session->dirty_in,
+ buffer, sizeof(buffer));
+ DEBUG(" Tunneled data (%u bytes)", data_len);
+ for (i = 0; i < data_len; i++) {
+ if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, " %x: ", i);
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+
+ fprintf(fr_log_fp, "%02x ", buffer[i]);
+ }
+ fprintf(fr_log_fp, "\n");
+ }
+#endif
+
+ eaptls_fail(handler, 0);
+ ret = 0;
+ break;
+
+ /*
+ * Anything else: fail.
+ *
+ * Also, remove the session from the cache so that
+ * the client can't re-use it.
+ */
+ default:
+ tls_fail(tls_session);
+ ret = 0;
+ }
+
+done:
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
+
+ return ret;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_tls;
+rlm_eap_module_t rlm_eap_tls = {
+ .name = "eap_tls",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h
new file mode 100644
index 0000000..550cbbd
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.h
@@ -0,0 +1,52 @@
+/*
+ * rlm_eap_tls.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _RLM_EAP_TLS_H
+#define _RLM_EAP_TLS_H
+
+RCSIDH(rlm_eap_tls_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "eap_tls.h"
+
+typedef struct rlm_eap_tls_t {
+ /*
+ * TLS configuration
+ */
+ char const *tls_conf_name;
+ fr_tls_server_conf_t *tls_conf;
+
+ /*
+ * Virtual server for checking certificates
+ */
+ char const *virtual_server;
+
+ /*
+ * Configurable EAP-TLS-Require-Client-Cert
+ */
+ bool configurable_client_cert;
+} rlm_eap_tls_t;
+
+#endif /* _RLM_EAP_TLS_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore b/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/README.md b/src/modules/rlm_eap/types/rlm_eap_tnc/README.md
new file mode 100644
index 0000000..ed23d8d
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/README.md
@@ -0,0 +1,9 @@
+# rlm_eap_tnc
+## Metadata
+<dl>
+ <dt>category</dt><dd>obsolete</dd>
+</dl>
+
+## Summary
+Implements EAP-TNC. Has not been tested in years and should not be
+used.
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in b/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in
new file mode 100644
index 0000000..59b902e
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/all.mk.in
@@ -0,0 +1,14 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/configure b/src/modules/rlm_eap/types/rlm_eap_tnc/configure
new file mode 100755
index 0000000..cbb7d20
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/configure
@@ -0,0 +1,4199 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_eap_tnc.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_eap_tnc
+with_eap_tnc_include_dir
+with_eap_tnc_lib_dir
+with_eap_tnc_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_eap_tnc build without rlm_eap_tnc
+ --with-eap-tnc-include-dir=DIR
+ Directory where the libtnc includes may be found
+ --with-eap-tnc-lib-dir=DIR
+ Directory where the libtnc libraries may be found
+ --with-eap-tnc-dir=DIR Base directory where libtnc is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_eap_tnc
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_eap_tnc was given.
+if test "${with_rlm_eap_tnc+set}" = set; then :
+ withval=$with_rlm_eap_tnc;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_eap_tnc" != xno; then
+
+
+eap_tnc_include_dir=
+
+# Check whether --with-eap-tnc-include-dir was given.
+if test "${with_eap_tnc_include_dir+set}" = set; then :
+ withval=$with_eap_tnc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-tnc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+eap_tnc_lib_dir=
+
+# Check whether --with-eap-tnc-lib-dir was given.
+if test "${with_eap_tnc_lib_dir+set}" = set; then :
+ withval=$with_eap_tnc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-tnc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-eap-tnc-dir was given.
+if test "${with_eap_tnc_dir+set}" = set; then :
+ withval=$with_eap_tnc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need eap-tnc-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_lib_dir="$withval/lib"
+ eap_tnc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir="$eap_tnc_include_dir"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "naaeap/naaeap.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+ for _dir in $smart_try_dir; do
+ _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+ done
+
+ for _dir in $smart_include_dir; do
+ _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+ done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for naaeap/naaeap.h in $try" >&5
+$as_echo_n "checking for naaeap/naaeap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <naaeap/naaeap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/naaeap/naaeap.h" >&5
+$as_echo_n "checking for ${_prefix}/naaeap/naaeap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <naaeap/naaeap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem ${_prefix}/"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for naaeap/naaeap.h" >&5
+$as_echo_n "checking for naaeap/naaeap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <naaeap/naaeap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for naaeap/naaeap.h in $try" >&5
+$as_echo_n "checking for naaeap/naaeap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <naaeap/naaeap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "x$ac_cv_header_naaeap_naaeap_h" != "xyes"; then
+
+fail="$fail naaeap.h"
+
+fi
+
+
+smart_try_dir="$eap_tnc_lib_dir"
+
+
+sm_lib_safe=`echo "naaeap" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "processEAPTNCData" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap in $try" >&5
+$as_echo_n "checking for processEAPTNCData in -lnaaeap in $try... " >&6; }
+ LIBS="-lnaaeap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char processEAPTNCData();
+int
+main ()
+{
+processEAPTNCData()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lnaaeap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap" >&5
+$as_echo_n "checking for processEAPTNCData in -lnaaeap... " >&6; }
+ LIBS="-lnaaeap $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char processEAPTNCData();
+int
+main ()
+{
+processEAPTNCData()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lnaaeap"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for processEAPTNCData in -lnaaeap in $try" >&5
+$as_echo_n "checking for processEAPTNCData in -lnaaeap in $try... " >&6; }
+ LIBS="-lnaaeap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char processEAPTNCData();
+int
+main ()
+{
+processEAPTNCData()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lnaaeap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+if test "x$ac_cv_lib_naaeap_processEAPTNCData" != "xyes"; then
+
+fail="$fail libnaaeap"
+
+fi
+
+
+ targetname=rlm_eap_tnc
+else
+ targetname=
+ echo \*\*\* module rlm_eap_tnc is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_eap_tnc to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_eap_tnc." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_eap_tnc." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_eap_tnc requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_eap_tnc requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+if test x"$fail" != x""; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Required libraries are available from https://github.com/trustatfhh/tnc-fhh" >&5
+$as_echo "$as_me: WARNING: Required libraries are available from https://github.com/trustatfhh/tnc-fhh" >&2;};
+
+fi
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac b/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac
new file mode 100644
index 0000000..ae20ddd
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/configure.ac
@@ -0,0 +1,90 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_eap_tnc.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_eap_tnc])
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-eap-tnc-include-dir=DIR
+eap_tnc_include_dir=
+AC_ARG_WITH(eap-tnc-include-dir,
+ [AS_HELP_STRING([--with-eap-tnc-include-dir=DIR],
+ [Directory where the libtnc includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-tnc-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-eap-tnc-lib-dir=DIR
+eap_tnc_lib_dir=
+AC_ARG_WITH(eap-tnc-lib-dir,
+[AS_HELP_STRING([--with-eap-tnc-lib-dir=DIR],
+ [Directory where the libtnc libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-tnc-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-eap-tnc-dir=DIR
+AC_ARG_WITH(eap-tnc-dir,
+[AS_HELP_STRING([--with-eap-tnc-dir=DIR],
+ [Base directory where libtnc is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need eap-tnc-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ eap_tnc_lib_dir="$withval/lib"
+ eap_tnc_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for eap-tnc includes
+dnl ############################################################
+
+smart_try_dir="$eap_tnc_include_dir"
+FR_SMART_CHECK_INCLUDE([naaeap/naaeap.h])
+if test "x$ac_cv_header_naaeap_naaeap_h" != "xyes"; then
+ FR_MODULE_FAIL([naaeap.h])
+fi
+
+dnl ############################################################
+dnl # Check for eap-tnc library
+dnl ############################################################
+
+smart_try_dir="$eap_tnc_lib_dir"
+FR_SMART_CHECK_LIB([naaeap],[processEAPTNCData])
+if test "x$ac_cv_lib_naaeap_processEAPTNCData" != "xyes"; then
+ FR_MODULE_FAIL([libnaaeap])
+fi
+
+FR_MODULE_END_TESTS
+
+FR_MODULE_TEST_FAIL_DO([
+ AC_MSG_WARN([Required libraries are available from https://github.com/trustatfhh/tnc-fhh]);
+])
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c
new file mode 100644
index 0000000..a1fdbc0
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c
@@ -0,0 +1,357 @@
+/*
+ * Portions of this code unrelated to FreeRADIUS are available
+ * separately under a commercial license. If you require an
+ * implementation of EAP-TNC that is not under the GPLv2, please
+ * contact trust@f4-i.fh-hannover.de for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/**
+ * $Id$
+ * @file rlm_eap_tnc.c
+ * @brief Interfaces with the naeap library to provide EAP-TNC inner method.
+ *
+ * @copyright 2013 The FreeRADIUS project
+ * @copyright 2007 Alan DeKok <aland@deployingradius.com>
+ * @copyright 2006-2009 FH Hannover
+ */
+
+/*
+ * EAP-TNC Packet with EAP Header, general structure
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | Ver | Data Length |
+ * | |L M S R R| =1 | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data Length | Data ...
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <freeradius-devel/rad_assert.h>
+
+#include "eap.h"
+#include <naaeap/naaeap.h>
+#include <netinet/in.h>
+
+#define VERSION "0.7.0"
+#define SET_START(x) ((x) | (0x20))
+
+typedef struct rlm_eap_tnc {
+ char const *connection_string;
+} rlm_eap_tnc_t;
+
+static CONF_PARSER module_config[] = {
+ { "connection_string", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_eap_tnc_t, connection_string), "NAS Port: %{NAS-Port} NAS IP: %{NAS-IP-Address} NAS_PORT_TYPE: %{NAS-Port-Type}" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_tnc_t *inst;
+ TNC_Result result;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_tnc_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ result = initializeDefault();
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP initializeDefault returned an "
+ "error code");
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mod_detach(void *instance)
+{
+ TNC_Result result;
+
+ talloc_free(instance);
+
+ result = terminate();
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP terminate returned an "
+ "error code whilst detaching");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function is called when the first EAP_IDENTITY_RESPONSE message
+ * was received.
+ *
+ * Initiates the EPA_TNC session by sending the first EAP_TNC_RESPONSE
+ * to the peer. The packet has the Start-Bit set and contains no data.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | Ver |
+ * | |0 0 1 0 0|0 0 1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * For this package, only 'Identifier' has to be set dynamically. Any
+ * other information is static.
+ */
+static int mod_session_init(void *instance, eap_handler_t *handler)
+{
+ rlm_eap_tnc_t *inst = instance;
+ REQUEST *request = NULL;
+
+ char buff[71];
+ ssize_t len = 0;
+
+ TNC_Result result;
+ TNC_ConnectionID conn_id;
+
+ TNC_BufferReference eap_tnc_request;
+ TNC_BufferReference eap_tnc_user;
+
+ VALUE_PAIR *username;
+
+ /*
+ * Check if we run inside a secure EAP method.
+ * FIXME check concrete outer EAP method.
+ */
+ if (!handler->request || !handler->request->parent) {
+ ERROR("rlm_eap_tnc: EAP_TNC must only be used as an "
+ "inner method within a protected tunneled EAP created "
+ "by an outer EAP method");
+
+ return 0;
+ }
+
+ request = handler->request->parent;
+
+ /*
+ * Build the connection string
+ */
+ len = radius_xlat(buff, sizeof(buff), request, inst->connection_string, NULL, NULL);
+ if (len < 0){
+ return 0;
+ }
+
+ RDEBUG("Getting connection from NAA-EAP");
+
+ /*
+ * Get connection (uses a function from the NAA-EAP-library)
+ */
+ result = getConnection(buff, &conn_id);
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP getConnection returned an "
+ "error code");
+
+ return 0;
+ }
+
+ /*
+ * Previous code manually parsed the EAP identity response
+ * this was wrong. rlm_eap will *always* create the Username
+ * from the EAP Identity response.
+ *
+ * Something has gone very wrong if the User-Name doesn't exist.
+ */
+ username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+
+ RDEBUG("Username for TNC connection: %s", username->vp_strvalue);
+
+ /*
+ * Stores the username associated with the connection
+ *
+ * What becomes of username? Who knows... but we don't free it
+ * so not safe to use talloc.
+ */
+ MEM(eap_tnc_user = (TNC_BufferReference) strdup(username->vp_strvalue));
+
+ result = storeUsername(conn_id, eap_tnc_user, username->vp_length);
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP storeUsername returned an "
+ "error code");
+
+ return 0;
+ }
+
+ /*
+ * Set connection ID
+ */
+ handler->opaque = talloc(handler, TNC_ConnectionID);
+ memcpy(handler->opaque, &conn_id, sizeof(TNC_ConnectionID));
+
+ /*
+ * Bild first EAP TNC request
+ */
+
+ MEM(eap_tnc_request = talloc_array(handler->eap_ds->request, uint8_t, 1));
+ *eap_tnc_request = SET_START(1);
+
+ handler->eap_ds->request->code = PW_EAP_REQUEST;
+ handler->eap_ds->request->type.num = PW_EAP_TNC;
+
+ handler->eap_ds->request->type.length = 1;
+
+ talloc_free(handler->eap_ds->request->type.data);
+ handler->eap_ds->request->type.data = eap_tnc_request;
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+/**
+ * This function is called when a EAP_TNC_RESPONSE was received.
+ * It basically forwards the EAP_TNC data to NAA-TNCS and forms
+ * and appropriate EAP_RESPONSE. Furthermore, it sets the VlanID
+ * based on the TNC_ConnectionState determined by NAA-TNCS.
+ *
+ * @param instance The configuration data.
+ * @param handler The eap_handler_t.
+ * @return True, if successfully, else false.
+ */
+static int mod_process(UNUSED void *instance, eap_handler_t *handler)
+{
+ TNC_ConnectionID conn_id;
+ TNC_Result result;
+
+ TNC_BufferReference data = NULL;
+ TNC_UInt32 datalen = 0;
+
+ TNC_ConnectionState connection_state;
+ uint8_t code = 0;
+ REQUEST *request = handler->request;
+
+ if (handler->eap_ds->response->type.num != PW_EAP_TNC) {
+ ERROR("rlm_eap_tnc: Incorrect response type");
+
+ return 0;
+ }
+
+ /*
+ * Retrieve connection ID
+ */
+ conn_id = *((TNC_ConnectionID *) (handler->opaque));
+
+ RDEBUG2("Starting authentication for connection ID %lX",
+ conn_id);
+
+ /*
+ * Pass EAP_TNC data to NAA-EAP and get answer data
+ */
+ connection_state = TNC_CONNECTION_STATE_CREATE;
+
+ /*
+ * Forwards the eap_tnc data to NAA-EAP and gets the response
+ */
+ result = processEAPTNCData(conn_id, handler->eap_ds->response->type.data,
+ handler->eap_ds->response->type.length,
+ &data, &datalen, &connection_state);
+ if (result != TNC_RESULT_SUCCESS) {
+ RDEBUG("NAA-EAP processEAPTNCData returned "
+ "an error code");
+
+ return 0;
+ }
+ /*
+ * Determine eap code for the response
+ */
+ switch (connection_state) {
+ case TNC_CONNECTION_STATE_HANDSHAKE:
+ code = PW_EAP_REQUEST;
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_NONE:
+ code = PW_EAP_FAILURE;
+ pair_make_config("TNC-Status", "None", T_OP_SET);
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
+ code = PW_EAP_SUCCESS;
+ pair_make_config("TNC-Status", "Access", T_OP_SET);
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
+ code = PW_EAP_SUCCESS;
+ pair_make_config("TNC-Status", "Isolate", T_OP_SET);
+ break;
+
+ default:
+ ERROR("rlm_eap_tnc: Invalid connection state");
+ return 0;
+ }
+
+ /*
+ * Build the TNC EAP request
+ */
+ handler->eap_ds->request->code = code;
+ handler->eap_ds->request->type.num = PW_EAP_TNC;
+
+ handler->eap_ds->request->type.length = datalen;
+
+ talloc_free(handler->eap_ds->request->type.data);
+
+ /*
+ * "data" is not talloc'd memory.
+ */
+ handler->eap_ds->request->type.data = talloc_array(handler->eap_ds->request,
+ uint8_t, datalen);
+ memcpy(handler->eap_ds->request->type.data, data, datalen);
+ free(data);
+
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_tnc;
+rlm_eap_module_t rlm_eap_tnc = {
+ .name = "eap_tnc",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process, /* Process next round of EAP method */
+ .detach = mod_detach /* detach */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/README.md b/src/modules/rlm_eap/types/rlm_eap_ttls/README.md
new file mode 100644
index 0000000..fe89c6e
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ttls/README.md
@@ -0,0 +1,10 @@
+# rlm_eap_ttls
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+Implements [RFC 5281](https://tools.ietf.org/html/rfc5281) EAP-TTLS authentication. EAP-TTLS provides mutual
+authentication and session keying material for 802.11i (WPA/2 Enterprise) using an inner method, and optionally,
+client certificates.
diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk b/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk
new file mode 100644
index 0000000..2c7af7d
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ttls/all.mk
@@ -0,0 +1,10 @@
+TARGETNAME := rlm_eap_ttls
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c ttls.c
+
+SRC_INCDIRS := ../../ ../../libeap/
+TGT_PREREQS := libfreeradius-eap.a
diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h b/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h
new file mode 100644
index 0000000..ff9a814
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ttls/eap_ttls.h
@@ -0,0 +1,46 @@
+/*
+ * eap_ttls.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+#ifndef _EAP_TTLS_H
+#define _EAP_TTLS_H
+
+RCSIDH(eap_ttls_h, "$Id$")
+
+#include "eap_tls.h"
+
+typedef struct ttls_tunnel_t {
+ VALUE_PAIR *username;
+ VALUE_PAIR *state;
+ VALUE_PAIR *accept_vps;
+ bool authenticated;
+ int default_method;
+ bool copy_request_to_tunnel;
+ bool use_tunneled_reply;
+ char const *virtual_server;
+} ttls_tunnel_t;
+
+/*
+ * Process the TTLS portion of an EAP-TTLS request.
+ */
+int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session) CC_HINT(nonnull);
+
+#endif /* _EAP_TTLS_H */
diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
new file mode 100644
index 0000000..4e53c92
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ttls/rlm_eap_ttls.c
@@ -0,0 +1,392 @@
+/*
+ * rlm_eap_ttls.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include "eap_ttls.h"
+
+typedef struct rlm_eap_ttls_t {
+ /*
+ * TLS configuration
+ */
+ char const *tls_conf_name;
+ fr_tls_server_conf_t *tls_conf;
+
+ /*
+ * Default tunneled EAP type
+ */
+ char const *default_method_name;
+ int default_method;
+
+ /*
+ * Use the reply attributes from the tunneled session in
+ * the non-tunneled reply to the client.
+ */
+ bool use_tunneled_reply;
+
+ /*
+ * Use SOME of the request attributes from outside of the
+ * tunneled session in the tunneled request
+ */
+ bool copy_request_to_tunnel;
+
+ /*
+ * RFC 5281 (TTLS) says that the length field MUST NOT be
+ * in fragments after the first one. However, we've done
+ * it that way for years, and no one has complained.
+ *
+ * In the interests of allowing the server to follow the
+ * RFC, we add the option here. If set to "no", it sends
+ * the length field in ONLY the first fragment.
+ */
+ bool include_length;
+
+ /*
+ * Virtual server for inner tunnel session.
+ */
+ char const *virtual_server;
+
+ /*
+ * Do we do require a client cert?
+ */
+ bool req_client_cert;
+} rlm_eap_ttls_t;
+
+
+static CONF_PARSER module_config[] = {
+ { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL },
+ { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" },
+ { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" },
+ { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" },
+ { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL },
+ { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" },
+ { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Attach the module.
+ */
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_ttls_t *inst;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_ttls_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ if (!inst->virtual_server) {
+ ERROR("rlm_eap_ttls: A 'virtual_server' MUST be defined for security");
+ return -1;
+ }
+
+ /*
+ * Convert the name to an integer, to make it easier to
+ * handle.
+ */
+ inst->default_method = eap_name2type(inst->default_method_name);
+ if (inst->default_method < 0) {
+ ERROR("rlm_eap_ttls: Unknown EAP type %s",
+ inst->default_method_name);
+ return -1;
+ }
+
+ /*
+ * Read tls configuration, either from group given by 'tls'
+ * option, or from the eap-tls configuration.
+ */
+ inst->tls_conf = eaptls_conf_parse(cs, "tls");
+
+ if (!inst->tls_conf) {
+ ERROR("rlm_eap_ttls: Failed initializing SSL context");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate the TTLS per-session data
+ */
+static ttls_tunnel_t *ttls_alloc(TALLOC_CTX *ctx, rlm_eap_ttls_t *inst)
+{
+ ttls_tunnel_t *t;
+
+ t = talloc_zero(ctx, ttls_tunnel_t);
+
+ t->default_method = inst->default_method;
+ t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
+ t->use_tunneled_reply = inst->use_tunneled_reply;
+ t->virtual_server = inst->virtual_server;
+ return t;
+}
+
+
+/*
+ * Send an initial eap-tls request to the peer, using the libeap functions.
+ */
+static int mod_session_init(void *type_arg, eap_handler_t *handler)
+{
+ int status;
+ tls_session_t *ssn;
+ rlm_eap_ttls_t *inst;
+ VALUE_PAIR *vp;
+ bool client_cert;
+ REQUEST *request = handler->request;
+
+ inst = type_arg;
+
+ handler->tls = true;
+
+ /*
+ * Check if we need a client certificate.
+ */
+
+ /*
+ * EAP-TLS-Require-Client-Cert attribute will override
+ * the require_client_cert configuration option.
+ */
+ vp = fr_pair_find_by_num(handler->request->config, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
+ if (vp) {
+ client_cert = vp->vp_integer ? true : false;
+ } else {
+ client_cert = inst->req_client_cert;
+ }
+
+ /*
+ * Allow TLS 1.3, it works.
+ */
+ ssn = eaptls_session(handler, inst->tls_conf, client_cert, true);
+ if (!ssn) {
+ return 0;
+ }
+
+ handler->opaque = ((void *)ssn);
+
+ /*
+ * Set the label to a fixed string. For TLS 1.3, the
+ * label is the same for all TLS-based EAP methods. If
+ * the client is using TLS 1.3, then eaptls_success()
+ * will over-ride this label with the correct label for
+ * TLS 1.3.
+ */
+ ssn->label = "ttls keying material";
+
+ /*
+ * TLS session initialization is over. Now handle TLS
+ * related handshaking or application data.
+ */
+ status = eaptls_start(handler->eap_ds, ssn->peap_flag);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls start] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+ if (status == 0) return 0;
+
+ /*
+ * The next stage to process the packet.
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+
+/*
+ * Do authentication, by letting EAP-TLS do most of the work.
+ */
+static int mod_process(void *arg, eap_handler_t *handler)
+{
+ int rcode;
+ int ret = 0;
+ fr_tls_status_t status;
+ rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
+ tls_session_t *tls_session = (tls_session_t *) handler->opaque;
+ ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
+ REQUEST *request = handler->request;
+
+ RDEBUG2("Authenticate");
+
+ tls_session->length_flag = inst->include_length;
+
+ /*
+ * Process TLS layer until done.
+ */
+ status = eaptls_process(handler);
+ if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
+ REDEBUG("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ } else {
+ RDEBUG3("[eaptls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
+ }
+
+ /*
+ * Make request available to any SSL callbacks
+ */
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, request);
+ switch (status) {
+ /*
+ * EAP-TLS handshake was successful, tell the
+ * client to keep talking.
+ *
+ * If this was EAP-TLS, we would just return
+ * an EAP-TLS-Success packet here.
+ */
+ case FR_TLS_SUCCESS:
+ if (SSL_session_reused(tls_session->ssl)) {
+ RDEBUG("Skipping Phase2 due to session resumption");
+ goto do_keys;
+ }
+
+ if (t && t->authenticated) {
+ if (t->accept_vps) {
+ RDEBUG2("Using saved attributes from the original Access-Accept");
+ rdebug_pair_list(L_DBG_LVL_2, request, t->accept_vps, NULL);
+ fr_pair_list_mcopy_by_num(handler->request->reply,
+ &handler->request->reply->vps,
+ &t->accept_vps, 0, 0, TAG_ANY);
+ } else if (t->use_tunneled_reply) {
+ RDEBUG2("No saved attributes in the original Access-Accept");
+ }
+
+ do_keys:
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ ret = eaptls_success(handler, 0);
+ goto done;
+ } else {
+ eaptls_request(handler->eap_ds, tls_session);
+ }
+ ret = 1;
+ goto done;
+
+ /*
+ * The TLS code is still working on the TLS
+ * exchange, and it's a valid TLS request.
+ * do nothing.
+ */
+ case FR_TLS_HANDLED:
+ ret = 1;
+ goto done;
+
+ /*
+ * Handshake is done, proceed with decoding tunneled
+ * data.
+ */
+ case FR_TLS_OK:
+ break;
+
+ /*
+ * Anything else: fail.
+ */
+ default:
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Session is established, proceed with decoding
+ * tunneled data.
+ */
+ RDEBUG2("Session established. Proceeding to decode tunneled attributes");
+
+ /*
+ * We may need TTLS data associated with the session, so
+ * allocate it here, if it wasn't already alloacted.
+ */
+ if (!tls_session->opaque) {
+ tls_session->opaque = ttls_alloc(tls_session, inst);
+ }
+
+ /*
+ * Process the TTLS portion of the request.
+ */
+ rcode = eapttls_process(handler, tls_session);
+ switch (rcode) {
+ case PW_CODE_ACCESS_REJECT:
+ eaptls_fail(handler, 0);
+ ret = 0;
+ goto done;
+
+ /*
+ * Access-Challenge, continue tunneled conversation.
+ */
+ case PW_CODE_ACCESS_CHALLENGE:
+ eaptls_request(handler->eap_ds, tls_session);
+ ret = 1;
+ goto done;
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ case PW_CODE_ACCESS_ACCEPT:
+ goto do_keys;
+
+ /*
+ * No response packet, MUST be proxying it.
+ * The main EAP module will take care of discovering
+ * that the request now has a "proxy" packet, and
+ * will proxy it, rather than returning an EAP packet.
+ */
+ case PW_CODE_STATUS_CLIENT:
+#ifdef WITH_PROXY
+ rad_assert(handler->request->proxy != NULL);
+#endif
+ ret = 1;
+ goto done;
+
+ default:
+ break;
+ }
+
+ /*
+ * Something we don't understand: Reject it.
+ */
+ eaptls_fail(handler, 0);
+
+done:
+ SSL_set_ex_data(tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, NULL);
+
+ return ret;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_ttls;
+rlm_eap_module_t rlm_eap_ttls = {
+ .name = "eap_ttls",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process /* Process next round of EAP method */
+};
diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c
new file mode 100644
index 0000000..cbe4239
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c
@@ -0,0 +1,1321 @@
+/*
+ * rlm_eap_ttls.c contains the interfaces that are called from eap
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003 Alan DeKok <aland@freeradius.org>
+ * Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include "eap_ttls.h"
+#include "eap_chbind.h"
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | AVP Code |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V M r r r r r r| AVP Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Vendor-ID (opt) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data ...
+ * +-+-+-+-+-+-+-+-+
+ */
+
+/*
+ * Verify that the diameter packet is valid.
+ */
+static int diameter_verify(REQUEST *request, uint8_t const *data, unsigned int data_len)
+{
+ uint32_t attr;
+ uint32_t length;
+ unsigned int hdr_len;
+ unsigned int remaining = data_len;
+
+ while (remaining > 0) {
+ hdr_len = 12;
+
+ if (remaining < hdr_len) {
+ RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
+ return 0;
+ }
+
+ memcpy(&attr, data, sizeof(attr));
+ attr = ntohl(attr);
+ memcpy(&length, data + 4, sizeof(length));
+ length = ntohl(length);
+
+ if ((data[4] & 0x80) != 0) {
+ if (remaining < 16) {
+ RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
+ return 0;
+ }
+
+ hdr_len = 16;
+ }
+
+ /*
+ * Get the length. If it's too big, die.
+ */
+ length &= 0x00ffffff;
+
+ /*
+ * Too short or too long is bad.
+ */
+ if (length <= (hdr_len - 4)) {
+ RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
+ length, hdr_len);
+ return 0;
+ }
+
+ if (length > remaining) {
+ RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
+ length, remaining);
+ return 0;
+ }
+
+ /*
+ * Check for broken implementations, which don't
+ * pad the AVP to a 4-octet boundary.
+ */
+ if (remaining == length) break;
+
+ /*
+ * The length does NOT include the padding, so
+ * we've got to account for it here by rounding up
+ * to the nearest 4-byte boundary.
+ */
+ length += 0x03;
+ length &= ~0x03;
+
+ /*
+ * If the rest of the diameter packet is larger than
+ * this attribute, continue.
+ *
+ * Otherwise, if the attribute over-flows the end
+ * of the packet, die.
+ */
+ if (remaining < length) {
+ REDEBUG2("Diameter attribute overflows packet!");
+ return 0;
+ }
+
+ /*
+ * remaining > length, continue.
+ */
+ remaining -= length;
+ data += length;
+ }
+
+ /*
+ * We got this far. It looks OK.
+ */
+ return 1;
+}
+
+
+/*
+ * Convert diameter attributes to our VALUE_PAIR's
+ */
+static VALUE_PAIR *diameter2vp(REQUEST *request, REQUEST *fake, SSL *ssl,
+ uint8_t const *data, size_t data_len)
+{
+ uint32_t attr;
+ uint32_t vendor;
+ uint32_t length;
+ size_t offset;
+ size_t size;
+ size_t data_left = data_len;
+ VALUE_PAIR *first = NULL;
+ VALUE_PAIR *vp = NULL;
+ RADIUS_PACKET *packet = fake->packet; /* FIXME: api issues */
+ vp_cursor_t out;
+ DICT_ATTR const *da;
+
+ fr_cursor_init(&out, &first);
+
+ /*
+ * Parse while there's still data.
+ */
+ while (data_left >= 9) {
+ size_t attr_len;
+
+ rad_assert(data_left <= data_len);
+ memcpy(&attr, data, sizeof(attr));
+ data += 4;
+ attr = ntohl(attr);
+ vendor = 0;
+
+ memcpy(&length, data, sizeof(length));
+ data += 4;
+ length = ntohl(length);
+
+ /*
+ * Length is *value* length. The actual
+ * attributes are aligned on 4 octets.
+ */
+ attr_len = length & 0x00ffffff;
+ attr_len += 0x03;
+ attr_len &= ~(uint32_t) 0x03;
+
+ /*
+ * A "vendor" flag, with a vendor ID of zero,
+ * is equivalent to no vendor. This is stupid.
+ */
+ offset = 8;
+ if ((length & ((uint32_t)1 << 31)) != 0) {
+ memcpy(&vendor, data, sizeof(vendor));
+ vendor = ntohl(vendor);
+
+ data += 4; /* skip the vendor field, it's zero */
+ offset += 4; /* offset to value field */
+
+ if (attr > 65535) {
+ DEBUG("Skipping Diameter attribute %08x", attr);
+ goto next_attr;
+ }
+ if (vendor > FR_MAX_VENDOR) {
+ DEBUG("Skipping large vendor ID %08x", vendor);
+ goto next_attr;
+ }
+ }
+
+ /*
+ * FIXME: Handle the M bit. For now, we assume that
+ * some other module takes care of any attribute
+ * with the M bit set.
+ */
+
+ /*
+ * Get the length.
+ */
+ length &= 0x00ffffff;
+
+ /*
+ * Get the size of the value portion of the
+ * attribute.
+ */
+ size = length - offset;
+
+ /*
+ * Vendor attributes can be larger than 255.
+ * Normal attributes cannot be.
+ */
+ if ((attr > 255) && (vendor == 0)) {
+ RWDEBUG2("Skipping Diameter attribute %u", attr);
+ goto next_attr;
+ }
+
+ /*
+ * EAP-Message AVPs can be larger than 253 octets.
+ *
+ * For now, we rely on the main decoder in
+ * src/lib/radius to decode data into VPs. This
+ * means putting the data into a RADIUS attribute
+ * format. It also means that we can't handle
+ * "extended" attributes in the Diameter space. Oh well...
+ */
+ if ((size > 253) && !((vendor == 0) && (attr == PW_EAP_MESSAGE))) {
+ RWDEBUG2("diameter2vp skipping long attribute %u", attr);
+ goto next_attr;
+ }
+
+ /*
+ * RADIUS VSAs are handled as Diameter attributes
+ * with Vendor-Id == 0, and the VSA data packed
+ * into the "String" field as per normal.
+ *
+ * EXCEPT for the MS-CHAP attributes.
+ */
+ if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
+ ssize_t decoded;
+ uint8_t buffer[256];
+
+ buffer[0] = PW_VENDOR_SPECIFIC;
+ buffer[1] = size + 2;
+ memcpy(buffer + 2, data, size);
+
+ vp = NULL;
+ decoded = rad_attr2vp(packet, NULL, NULL, NULL,
+ buffer, size + 2, &vp);
+ if (decoded < 0) {
+ REDEBUG2("diameter2vp failed decoding attr: %s",
+ fr_strerror());
+ goto raw;
+ }
+
+ if ((size_t) decoded != size + 2) {
+ REDEBUG2("diameter2vp failed to entirely decode VSA");
+ fr_pair_list_free(&vp);
+ goto raw;
+ }
+
+ fr_cursor_merge(&out, vp);
+
+ goto next_attr;
+ }
+
+ /*
+ * Create it. If this fails, it's because we're OOM.
+ */
+ da = dict_attrbyvalue(attr, vendor);
+ if (!da) goto raw;
+
+ vp = fr_pair_afrom_da(packet, da);
+ if (!vp) {
+ RDEBUG2("Failure in creating VP");
+ fr_pair_list_free(&first);
+ return NULL;
+ }
+
+ /*
+ * If it's a type from our dictionary, then
+ * we need to put the data in a relevant place.
+ *
+ * @todo: Export the lib/radius.c decoder, and use it here!
+ */
+ switch (vp->da->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ if (size != vp->vp_length) {
+ /*
+ * Bad format. Create a "raw"
+ * attribute.
+ */
+ raw:
+ if (vp) fr_pair_list_free(&vp);
+ da = dict_unknown_afrom_fields(packet, attr, vendor);
+ if (!da) return NULL;
+ vp = fr_pair_afrom_da(packet, da);
+ if (!vp) return NULL;
+ fr_pair_value_memcpy(vp, data, size);
+ break;
+ }
+ memcpy(&vp->vp_integer, data, vp->vp_length);
+
+ /*
+ * Stored in host byte order: change it.
+ */
+ vp->vp_integer = ntohl(vp->vp_integer);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ if (size != vp->vp_length) goto raw;
+ memcpy(&vp->vp_integer64, data, vp->vp_length);
+
+ /*
+ * Stored in host byte order: change it.
+ */
+ vp->vp_integer64 = ntohll(vp->vp_integer64);
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ if (size != vp->vp_length) {
+ RDEBUG2("Invalid length attribute %d",
+ attr);
+ fr_pair_list_free(&first);
+ fr_pair_list_free(&vp);
+ return NULL;
+ }
+ memcpy(&vp->vp_ipaddr, data, vp->vp_length);
+
+ /*
+ * Stored in network byte order: don't change it.
+ */
+ break;
+
+ case PW_TYPE_BYTE:
+ if (size != vp->vp_length) goto raw;
+ vp->vp_byte = data[0];
+ break;
+
+ case PW_TYPE_SHORT:
+ if (size != vp->vp_length) goto raw;
+ vp->vp_short = (data[0] * 256) + data[1];
+ break;
+
+ case PW_TYPE_SIGNED:
+ if (size != vp->vp_length) goto raw;
+ memcpy(&vp->vp_signed, data, vp->vp_length);
+ vp->vp_signed = ntohl(vp->vp_signed);
+ break;
+
+ case PW_TYPE_IPV6_ADDR:
+ if (size != vp->vp_length) goto raw;
+ memcpy(&vp->vp_ipv6addr, data, vp->vp_length);
+ break;
+
+ case PW_TYPE_IPV6_PREFIX:
+ if (size != vp->vp_length) goto raw;
+ memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
+ break;
+
+ case PW_TYPE_STRING:
+ fr_pair_value_bstrncpy(vp, data, size);
+ vp->vp_length = strlen(vp->vp_strvalue); /* embedded zeros are NOT allowed */
+ break;
+
+ /*
+ * Copy it over verbatim.
+ */
+ case PW_TYPE_OCTETS:
+ default:
+ fr_pair_value_memcpy(vp, data, size);
+ break;
+ }
+
+ /*
+ * Ensure that the client is using the
+ * correct challenge. This weirdness is
+ * to protect against against replay
+ * attacks, where anyone observing the
+ * CHAP exchange could pose as that user,
+ * by simply choosing to use the same
+ * challenge.
+ *
+ * By using a challenge based on
+ * information from the current session,
+ * we can guarantee that the client is
+ * not *choosing* a challenge.
+ *
+ * We're a little forgiving in that we
+ * have loose checks on the length, and
+ * we do NOT check the Id (first octet of
+ * the response to the challenge)
+ *
+ * But if the client gets the challenge correct,
+ * we're not too worried about the Id.
+ */
+ if (((vp->da->vendor == 0) && (vp->da->attr == PW_CHAP_CHALLENGE)) ||
+ ((vp->da->vendor == VENDORPEC_MICROSOFT) && (vp->da->attr == PW_MSCHAP_CHALLENGE))) {
+ uint8_t challenge[17];
+
+ if ((vp->vp_length < 8) ||
+ (vp->vp_length > 16)) {
+ RDEBUG("Tunneled challenge has invalid length");
+ fr_pair_list_free(&first);
+ fr_pair_list_free(&vp);
+ return NULL;
+ }
+
+ /*
+ * TLSv1.3 exports a different key depending on the length
+ * requested so ask for *exactly* what the spec requires
+ */
+ eapttls_gen_challenge(ssl, challenge, vp->vp_length + 1);
+
+ if (memcmp(challenge, vp->vp_octets,
+ vp->vp_length) != 0) {
+ RDEBUG("Tunneled challenge is incorrect");
+ fr_pair_list_free(&first);
+ fr_pair_list_free(&vp);
+ return NULL;
+ }
+ }
+
+ /*
+ * Update the list.
+ */
+ fr_cursor_insert(&out, vp);
+
+ next_attr:
+ if (data_left <= attr_len) break;
+
+ data_left -= attr_len;
+ data += (attr_len - offset);
+ }
+
+ /*
+ * We got this far. It looks OK.
+ */
+ return first;
+}
+
+/*
+ * Convert VALUE_PAIR's to diameter attributes, and write them
+ * to an SSL session.
+ *
+ * The ONLY VALUE_PAIR's which may be passed to this function
+ * are ones which can go inside of a RADIUS (i.e. diameter)
+ * packet. So no server-configuration attributes, or the like.
+ */
+static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first)
+{
+ /*
+ * RADIUS packets are no more than 4k in size, so if
+ * we've got more than 4k of data to write, it's very
+ * bad.
+ */
+ uint8_t buffer[4096];
+ uint8_t *p;
+ uint32_t attr;
+ uint32_t length;
+ uint32_t vendor;
+ size_t total;
+ uint64_t attr64;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ p = buffer;
+ total = 0;
+
+ for (vp = fr_cursor_init(&cursor, &first); vp; vp = fr_cursor_next(&cursor)) {
+ /*
+ * Too much data: die.
+ */
+ if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
+ RDEBUG2("output buffer is full!");
+ return 0;
+ }
+
+ /*
+ * Hmm... we don't group multiple EAP-Messages
+ * together. Maybe we should...
+ */
+
+ length = vp->vp_length;
+ vendor = vp->da->vendor;
+ if (vendor != 0) {
+ attr = vp->da->attr & 0xffff;
+ length |= ((uint32_t)1 << 31);
+ } else {
+ attr = vp->da->attr;
+ }
+
+ /*
+ * Hmm... set the M bit for all attributes?
+ */
+ length |= (1 << 30);
+
+ attr = ntohl(attr);
+
+ memcpy(p, &attr, sizeof(attr));
+ p += 4;
+ total += 4;
+
+ length += 8; /* includes 8 bytes of attr & length */
+
+ if (vendor != 0) {
+ length += 4; /* include 4 bytes of vendor */
+
+ length = ntohl(length);
+ memcpy(p, &length, sizeof(length));
+ p += 4;
+ total += 4;
+
+ vendor = ntohl(vendor);
+ memcpy(p, &vendor, sizeof(vendor));
+ p += 4;
+ total += 4;
+ } else {
+ length = ntohl(length);
+ memcpy(p, &length, sizeof(length));
+ p += 4;
+ total += 4;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ attr = htonl(vp->vp_integer); /* stored in host order */
+ memcpy(p, &attr, sizeof(attr));
+ length = 4;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ attr64 = htonll(vp->vp_integer64); /* stored in host order */
+ memcpy(p, &attr64, sizeof(attr64));
+ length = 8;
+ break;
+
+ case PW_TYPE_IPV4_ADDR:
+ memcpy(p, &vp->vp_ipaddr, 4); /* network order */
+ length = 4;
+ break;
+
+ case PW_TYPE_STRING:
+ case PW_TYPE_OCTETS:
+ default:
+ memcpy(p, vp->vp_strvalue, vp->vp_length);
+ length = vp->vp_length;
+ break;
+ }
+
+ /*
+ * Skip to the end of the data.
+ */
+ p += length;
+ total += length;
+
+ /*
+ * Align the data to a multiple of 4 bytes.
+ */
+ if ((total & 0x03) != 0) {
+ size_t i;
+
+ length = 4 - (total & 0x03);
+ for (i = 0; i < length; i++) {
+ *p = '\0';
+ p++;
+ total++;
+ }
+ }
+ } /* loop over the VP's to write. */
+
+ /*
+ * Write the data in the buffer to the SSL session.
+ */
+ if (total > 0) {
+#ifndef NDEBUG
+ size_t i;
+
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ for (i = 0; i < total; i++) {
+ if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data out %04x: ", (int) i);
+
+ fprintf(fr_log_fp, "%02x ", buffer[i]);
+
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n");
+ }
+#endif
+
+ (tls_session->record_plus)(&tls_session->clean_in, buffer, total);
+
+ /*
+ * FIXME: Check the return code.
+ */
+ tls_handshake_send(request, tls_session);
+ }
+
+ /*
+ * Everything's OK.
+ */
+ return 1;
+}
+
+/*
+ * Use a reply packet to determine what to do.
+ */
+static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session,
+ REQUEST *request, RADIUS_PACKET *reply)
+{
+ rlm_rcode_t rcode = RLM_MODULE_REJECT;
+ VALUE_PAIR *vp;
+ ttls_tunnel_t *t = tls_session->opaque;
+
+ rad_assert(handler->request == request);
+
+ /*
+ * If the response packet was Access-Accept, then
+ * we're OK. If not, die horribly.
+ *
+ * FIXME: Take MS-CHAP2-Success attribute, and
+ * tunnel it back to the client, to authenticate
+ * ourselves to the client.
+ *
+ * FIXME: If we have an Access-Challenge, then
+ * the Reply-Message is tunneled back to the client.
+ *
+ * FIXME: If we have an EAP-Message, then that message
+ * must be tunneled back to the client.
+ *
+ * FIXME: If we have an Access-Challenge with a State
+ * attribute, then do we tunnel that to the client, or
+ * keep track of it ourselves?
+ *
+ * FIXME: EAP-Messages can only start with 'identity',
+ * NOT 'eap start', so we should check for that....
+ */
+ switch (reply->code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ tls_session->authentication_success = true;
+ RDEBUG("Got tunneled Access-Accept");
+
+ rcode = RLM_MODULE_OK;
+
+ /*
+ * Always delete MPPE keys & encryption policy
+ * from the tunneled reply. These never get sent
+ * back to the user.
+ */
+ fr_pair_delete_by_num(&reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ /*
+ * MS-CHAP2-Success means that we do NOT return
+ * an Access-Accept, but instead tunnel that
+ * attribute to the client, and keep going with
+ * the TTLS session. Once the client accepts
+ * our identity, it will respond with an empty
+ * packet, and we will send EAP-Success.
+ */
+ vp = NULL;
+ fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (vp) {
+ RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
+ rcode = RLM_MODULE_HANDLED;
+ t->authenticated = true;
+
+ /*
+ * Use the tunneled reply, but not now.
+ */
+ if (t->use_tunneled_reply) {
+ rad_assert(!t->accept_vps);
+ fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps,
+ 0, 0, TAG_ANY);
+ rad_assert(!reply->vps);
+ }
+
+ } else { /* no MS-CHAP2-Success */
+ /*
+ * Can only have EAP-Message if there's
+ * no MS-CHAP2-Success.
+ *
+ * We also do NOT tunnel the EAP-Success
+ * attribute back to the client, as the client
+ * can figure it out, from the non-tunneled
+ * EAP-Success packet.
+ */
+ fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ fr_pair_list_free(&vp);
+ }
+
+ /* move channel binding responses; we need to send them */
+ fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY);
+ if (fr_pair_find_by_num(vp, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY) != NULL) {
+ t->authenticated = true;
+ /*
+ * Use the tunneled reply, but not now.
+ */
+ if (t->use_tunneled_reply) {
+ rad_assert(!t->accept_vps);
+ fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps,
+ 0, 0, TAG_ANY);
+ rad_assert(!reply->vps);
+ }
+ rcode = RLM_MODULE_HANDLED;
+ }
+
+ /*
+ * Handle the ACK, by tunneling any necessary reply
+ * VP's back to the client.
+ */
+ if (vp) {
+ RDEBUG("Sending tunneled reply attributes");
+ rdebug_pair_list(L_DBG_LVL_1, request, vp, NULL);
+
+ vp2diameter(request, tls_session, vp);
+ fr_pair_list_free(&vp);
+ }
+
+ /*
+ * If we've been told to use the attributes from
+ * the reply, then do so.
+ *
+ * WARNING: This may leak information about the
+ * tunneled user!
+ */
+ if (t->use_tunneled_reply) {
+ fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
+ fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps,
+ &reply->vps, 0, 0, TAG_ANY);
+ }
+ break;
+
+
+ case PW_CODE_ACCESS_REJECT:
+ RDEBUG("Got tunneled Access-Reject");
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ /*
+ * Handle Access-Challenge, but only if we
+ * send tunneled reply data. This is because
+ * an Access-Challenge means that we MUST tunnel
+ * a Reply-Message to the client.
+ */
+ case PW_CODE_ACCESS_CHALLENGE:
+ RDEBUG("Got tunneled Access-Challenge");
+
+ /*
+ * Keep the State attribute, if necessary.
+ *
+ * Get rid of the old State, too.
+ */
+ fr_pair_list_free(&t->state);
+ fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, PW_STATE, 0, TAG_ANY);
+
+ /*
+ * We should really be a bit smarter about this,
+ * and move over only those attributes which
+ * are relevant to the authentication request,
+ * but that's a lot more work, and this "dumb"
+ * method works in 99.9% of the situations.
+ */
+ vp = NULL;
+ fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+
+ /*
+ * There MUST be a Reply-Message in the challenge,
+ * which we tunnel back to the client.
+ *
+ * If there isn't one in the reply VP's, then
+ * we MUST create one, with an empty string as
+ * it's value.
+ */
+ fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_REPLY_MESSAGE, 0, TAG_ANY);
+
+ /* also move chbind messages, if any */
+ fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA,
+ TAG_ANY);
+
+ /*
+ * Handle the ACK, by tunneling any necessary reply
+ * VP's back to the client.
+ */
+ if (vp) {
+ vp2diameter(request, tls_session, vp);
+ fr_pair_list_free(&vp);
+ }
+ rcode = RLM_MODULE_HANDLED;
+ break;
+
+ default:
+ RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
+ rcode = RLM_MODULE_INVALID;
+ break;
+ }
+
+ return rcode;
+}
+
+
+#ifdef WITH_PROXY
+/*
+ * Do post-proxy processing,
+ */
+static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data)
+{
+ int rcode;
+ tls_session_t *tls_session = (tls_session_t *) data;
+ REQUEST *fake, *request = handler->request;
+
+ RDEBUG("Passing reply from proxy back into the tunnel");
+
+ /*
+ * If there was a fake request associated with the proxied
+ * request, do more processing of it.
+ */
+ fake = (REQUEST *) request_data_get(handler->request,
+ handler->request->proxy,
+ REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);
+
+ /*
+ * Do the callback, if it exists, and if it was a success.
+ */
+ if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) {
+ /*
+ * Terrible hacks.
+ */
+ rad_assert(!fake->packet);
+ fake->packet = talloc_steal(fake, request->proxy);
+ fake->packet->src_ipaddr = request->packet->src_ipaddr;
+ request->proxy = NULL;
+
+ rad_assert(!fake->reply);
+ fake->reply = talloc_steal(fake, request->proxy_reply);
+ request->proxy_reply = NULL;
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ fprintf(fr_log_fp, "server %s {\n",
+ (!fake->server) ? "" : fake->server);
+ }
+
+ /*
+ * Perform a post-auth stage for the tunneled
+ * session.
+ */
+ fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
+ rcode = rad_postauth(fake);
+ RDEBUG2("post-auth returns %d", rcode);
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ fprintf(fr_log_fp, "} # server %s\n",
+ (!fake->server) ? "" : fake->server);
+
+ RDEBUG("Final reply from tunneled session code %d", fake->reply->code);
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
+ }
+
+ /*
+ * Terrible hacks.
+ */
+ request->proxy = talloc_steal(request, fake->packet);
+ fake->packet = NULL;
+ request->proxy_reply = talloc_steal(request, fake->reply);
+ fake->reply = NULL;
+
+ /*
+ * And we're done with this request.
+ */
+
+ switch (rcode) {
+ case RLM_MODULE_FAIL:
+ talloc_free(fake);
+ eaptls_fail(handler, 0);
+ return 0;
+
+ default: /* Don't Do Anything */
+ RDEBUG2("Got reply %d",
+ request->proxy_reply->code);
+ break;
+ }
+ }
+ talloc_free(fake); /* robust if !fake */
+
+ /*
+ * Process the reply from the home server.
+ */
+ rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply);
+
+ /*
+ * The proxy code uses the reply from the home server as
+ * the basis for the reply to the NAS. We don't want that,
+ * so we toss it, after we've had our way with it.
+ */
+ fr_pair_list_free(&handler->request->proxy_reply->vps);
+
+ switch (rcode) {
+ case RLM_MODULE_REJECT:
+ RDEBUG("Reply was rejected");
+ break;
+
+ case RLM_MODULE_HANDLED:
+ RDEBUG("Reply was handled");
+ eaptls_request(handler->eap_ds, tls_session);
+ request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
+ return 1;
+
+ case RLM_MODULE_OK:
+ RDEBUG("Reply was OK");
+
+ /*
+ * Success: Automatically return MPPE keys.
+ */
+ return eaptls_success(handler, 0);
+
+ default:
+ RDEBUG("Reply was unknown");
+ break;
+ }
+
+ eaptls_fail(handler, 0);
+ return 0;
+}
+
+#endif /* WITH_PROXY */
+
+/*
+ * Process the "diameter" contents of the tunneled data.
+ */
+int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session)
+{
+ PW_CODE code = PW_CODE_ACCESS_REJECT;
+ rlm_rcode_t rcode;
+ REQUEST *fake;
+ VALUE_PAIR *vp;
+ ttls_tunnel_t *t;
+ uint8_t const *data;
+ size_t data_len;
+ REQUEST *request = handler->request;
+ chbind_packet_t *chbind;
+
+ /*
+ * Just look at the buffer directly, without doing
+ * record_minus.
+ */
+ data_len = tls_session->clean_out.used;
+ tls_session->clean_out.used = 0;
+ data = tls_session->clean_out.data;
+
+ t = (ttls_tunnel_t *) tls_session->opaque;
+
+ /*
+ * If there's no data, maybe this is an ACK to an
+ * MS-CHAP2-Success.
+ */
+ if (data_len == 0) {
+ if (t->authenticated) {
+ RDEBUG("Got ACK, and the user was already authenticated");
+ return PW_CODE_ACCESS_ACCEPT;
+ } /* else no session, no data, die. */
+
+ /*
+ * FIXME: Call SSL_get_error() to see what went
+ * wrong.
+ */
+ RDEBUG2("SSL_read Error");
+ return PW_CODE_ACCESS_REJECT;
+ }
+
+#ifndef NDEBUG
+ if ((rad_debug_lvl > 2) && fr_log_fp) {
+ size_t i;
+
+ for (i = 0; i < data_len; i++) {
+ if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data in %04x: ", (int) i);
+
+ fprintf(fr_log_fp, "%02x ", data[i]);
+
+ if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+ }
+ if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
+ }
+#endif
+
+ if (!diameter_verify(request, data, data_len)) {
+ return PW_CODE_ACCESS_REJECT;
+ }
+
+ /*
+ * Allocate a fake REQUEST structure.
+ */
+ fake = request_alloc_fake(request);
+
+ rad_assert(!fake->packet->vps);
+
+ /*
+ * Add the tunneled attributes to the fake request.
+ */
+ fake->packet->vps = diameter2vp(request, fake, tls_session->ssl, data, data_len);
+ if (!fake->packet->vps) {
+ talloc_free(fake);
+ return PW_CODE_ACCESS_REJECT;
+ }
+
+ /*
+ * Tell the request that it's a fake one.
+ */
+ fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
+
+ RDEBUG("Got tunneled request");
+ rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
+
+ /*
+ * Update other items in the REQUEST data structure.
+ */
+ fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ fake->password = fr_pair_find_by_num(fake->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+
+ /*
+ * No User-Name, try to create one from stored data.
+ */
+ if (!fake->username) {
+ /*
+ * No User-Name in the stored data, look for
+ * an EAP-Identity, and pull it out of there.
+ */
+ if (!t->username) {
+ vp = fr_pair_find_by_num(fake->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
+ if (vp &&
+ (vp->vp_length >= EAP_HEADER_LEN + 2) &&
+ (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
+ (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
+ (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
+ /*
+ * Create & remember a User-Name
+ */
+ t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
+ rad_assert(t->username != NULL);
+
+ fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);
+
+ RDEBUG("Got tunneled identity of %s",
+ t->username->vp_strvalue);
+
+ /*
+ * If there's a default EAP type,
+ * set it here.
+ */
+ if (t->default_method != 0) {
+ RDEBUG("Setting default EAP type for tunneled EAP session");
+ vp = fr_pair_afrom_num(fake, PW_EAP_TYPE, 0);
+ rad_assert(vp != NULL);
+ vp->vp_integer = t->default_method;
+ fr_pair_add(&fake->config, vp);
+ }
+
+ } else {
+ /*
+ * Don't reject the request outright,
+ * as it's permitted to do EAP without
+ * user-name.
+ */
+ RWDEBUG2("No EAP-Identity found to start EAP conversation");
+ }
+ } /* else there WAS a t->username */
+
+ if (t->username) {
+ vp = fr_pair_list_copy(fake->packet, t->username);
+ fr_pair_add(&fake->packet->vps, vp);
+ fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ }
+ } /* else the request ALREADY had a User-Name */
+
+ /*
+ * Add the State attribute, too, if it exists.
+ */
+ if (t->state) {
+ vp = fr_pair_list_copy(fake->packet, t->state);
+ if (vp) fr_pair_add(&fake->packet->vps, vp);
+ }
+
+ /*
+ * If this is set, we copy SOME of the request attributes
+ * from outside of the tunnel to inside of the tunnel.
+ *
+ * We copy ONLY those attributes which do NOT already
+ * exist in the tunneled request.
+ */
+ if (t->copy_request_to_tunnel) {
+ VALUE_PAIR *copy;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) {
+ /*
+ * The attribute is a server-side thingy,
+ * don't copy it.
+ */
+ if ((vp->da->attr > 255) &&
+ (vp->da->vendor == 0)) {
+ continue;
+ }
+
+ /*
+ * The outside attribute is already in the
+ * tunnel, don't copy it.
+ *
+ * This works for BOTH attributes which
+ * are originally in the tunneled request,
+ * AND attributes which are copied there
+ * from below.
+ */
+ if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) {
+ continue;
+ }
+
+ /*
+ * Some attributes are handled specially.
+ */
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ /*
+ * NEVER copy Message-Authenticator,
+ * EAP-Message, or State. They're
+ * only for outside of the tunnel.
+ */
+ case PW_USER_NAME:
+ case PW_USER_PASSWORD:
+ case PW_CHAP_PASSWORD:
+ case PW_CHAP_CHALLENGE:
+ case PW_PROXY_STATE:
+ case PW_MESSAGE_AUTHENTICATOR:
+ case PW_EAP_MESSAGE:
+ case PW_STATE:
+ continue;
+
+ /*
+ * By default, copy it over.
+ */
+ default:
+ break;
+ }
+
+ /*
+ * Don't copy from the head, we've already
+ * checked it.
+ */
+ copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->attr, vp->da->vendor, TAG_ANY);
+ fr_pair_add(&fake->packet->vps, copy);
+ }
+ }
+
+ if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
+ fake->server = vp->vp_strvalue;
+
+ } else if (t->virtual_server) {
+ fake->server = t->virtual_server;
+
+ } /* else fake->server == request->server */
+
+
+ if ((rad_debug_lvl > 0) && fr_log_fp) {
+ RDEBUG("Sending tunneled request");
+ }
+
+ /*
+ * Process channel binding.
+ */
+ chbind = eap_chbind_vp2packet(fake, fake->packet->vps);
+ if (chbind) {
+ PW_CODE chbind_code;
+ CHBIND_REQ *req = talloc_zero(fake, CHBIND_REQ);
+
+ RDEBUG("received chbind request");
+ req->request = chbind;
+ if (fake->username) {
+ req->username = fake->username;
+ } else {
+ req->username = NULL;
+ }
+ chbind_code = chbind_process(request, req);
+
+ /* encapsulate response here */
+ if (req->response) {
+ RDEBUG("sending chbind response");
+ fr_pair_add(&fake->reply->vps,
+ eap_chbind_packet2vp(fake->reply, req->response));
+ } else {
+ RDEBUG("no chbind response");
+ }
+
+ /* clean up chbind req */
+ talloc_free(req);
+
+ if (chbind_code != PW_CODE_ACCESS_ACCEPT) {
+ return chbind_code;
+ }
+ }
+
+ /*
+ * Call authentication recursively, which will
+ * do PAP, CHAP, MS-CHAP, etc.
+ */
+ rad_virtual_server(fake);
+
+ /*
+ * Decide what to do with the reply.
+ */
+ switch (fake->reply->code) {
+ case 0: /* No reply code, must be proxied... */
+#ifdef WITH_PROXY
+ vp = fr_pair_find_by_num(fake->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
+ if (vp) {
+ eap_tunnel_data_t *tunnel;
+ RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue);
+
+ /*
+ * Tell the original request that it's going
+ * to be proxied.
+ */
+ fr_pair_list_mcopy_by_num(request, &request->config,
+ &fake->config,
+ PW_PROXY_TO_REALM, 0, TAG_ANY);
+
+ /*
+ * Seed the proxy packet with the
+ * tunneled request.
+ */
+ rad_assert(!request->proxy);
+ request->proxy = talloc_steal(request, fake->packet);
+ memset(&request->proxy->src_ipaddr, 0,
+ sizeof(request->proxy->src_ipaddr));
+ memset(&request->proxy->src_ipaddr, 0,
+ sizeof(request->proxy->src_ipaddr));
+ request->proxy->src_port = 0;
+ request->proxy->dst_port = 0;
+ fake->packet = NULL;
+ rad_free(&fake->reply);
+ fake->reply = NULL;
+
+ /*
+ * Set up the callbacks for the tunnel
+ */
+ tunnel = talloc_zero(request, eap_tunnel_data_t);
+ tunnel->tls_session = tls_session;
+ tunnel->callback = eapttls_postproxy;
+
+ /*
+ * Associate the callback with the request.
+ */
+ code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
+ tunnel, false);
+ rad_assert(code == 0);
+
+ /*
+ * rlm_eap.c has taken care of associating
+ * the handler with the fake request.
+ *
+ * So we associate the fake request with
+ * this request.
+ */
+ code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
+ fake, true);
+ rad_assert(code == 0);
+ fake = NULL;
+
+ /*
+ * Didn't authenticate the packet, but
+ * we're proxying it.
+ */
+ code = PW_CODE_STATUS_CLIENT;
+
+ } else
+#endif /* WITH_PROXY */
+ {
+ RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",
+ request->number);
+ code = PW_CODE_ACCESS_REJECT;
+ }
+ break;
+
+ default:
+ /*
+ * Returns RLM_MODULE_FOO, and we want to return PW_FOO
+ */
+ rcode = process_reply(handler, tls_session, request, fake->reply);
+ switch (rcode) {
+ case RLM_MODULE_REJECT:
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+
+ case RLM_MODULE_HANDLED:
+ code = PW_CODE_ACCESS_CHALLENGE;
+ break;
+
+ case RLM_MODULE_OK:
+ code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ default:
+ code = PW_CODE_ACCESS_REJECT;
+ break;
+ }
+ break;
+ }
+
+ talloc_free(fake);
+
+ return code;
+}
diff --git a/src/modules/rlm_example/.gitignore b/src/modules/rlm_example/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_example/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_example/Makefile.clean b/src/modules/rlm_example/Makefile.clean
new file mode 100644
index 0000000..c4ec10e
--- /dev/null
+++ b/src/modules/rlm_example/Makefile.clean
@@ -0,0 +1,11 @@
+TARGET = rlm_example
+SRCS = rlm_example.c other.c
+HEADERS = config.h other.h
+RLM_CFLAGS =
+RLM_LIBS =
+
+include ../rules.mak
+
+$(STATIC_OBJS): $(HEADERS)
+
+$(DYNAMIC_OBJS): $(HEADERS)
diff --git a/src/modules/rlm_example/README.md b/src/modules/rlm_example/README.md
new file mode 100644
index 0000000..63b5492
--- /dev/null
+++ b/src/modules/rlm_example/README.md
@@ -0,0 +1,10 @@
+# rlm_example
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+An example module for programming purposes only. Not useful in any
+installed version of the server.
diff --git a/src/modules/rlm_example/all.mk.in b/src/modules/rlm_example/all.mk.in
new file mode 100644
index 0000000..e66afe7
--- /dev/null
+++ b/src/modules/rlm_example/all.mk.in
@@ -0,0 +1,44 @@
+#######################################################################
+#
+# TARGET should be set by autoconf only. Don't touch it.
+#
+# The SOURCES definition should list ALL source files.
+#
+# SRC_CFLAGS defines addition C compiler flags. You usually don't
+# want to modify this, though. Get it from autoconf.
+#
+# The TGT_LDLIBS definition should list ALL required libraries.
+#
+#######################################################################
+
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+#
+# If the target has documentation in man format it should be set here
+#
+#MAN := example.8
+
+#
+# Install targets are automagically created for libraries and binary targets,
+# you only need to create manual targets for things like example scripts, and
+# support files.
+#
+# The installation directory target should always be listed first, and should
+# be one of:
+# * install.raddbdir
+# * install.bindir
+# * install.sbindir
+
+#install: install.raddbdir $(R)$(raddbdir)/example.sh
+
+#$(R)$(raddbdir)/example.pl: src/modules/$(TARGETNAME)/example.sh
+# @$(INSTALL) -m 755 src/modules/$(TARGETNAME)/example.sh $(R)$(raddbdir)/
diff --git a/src/modules/rlm_example/config.h.in b/src/modules/rlm_example/config.h.in
new file mode 100644
index 0000000..b429c2f
--- /dev/null
+++ b/src/modules/rlm_example/config.h.in
@@ -0,0 +1 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
diff --git a/src/modules/rlm_example/configure b/src/modules/rlm_example/configure
new file mode 100755
index 0000000..594d1e5
--- /dev/null
+++ b/src/modules/rlm_example/configure
@@ -0,0 +1,4424 @@
+#! /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_example.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_example
+'
+ 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_example build without rlm_example
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_example
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_example was given.
+if test "${with_rlm_example+set}" = set; then :
+ withval=$with_rlm_example;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_example" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+sm_lib_safe=`echo "c" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "printf" | 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 printf in -lc in $try" >&5
+$as_echo_n "checking for printf in -lc in $try... " >&6; }
+ LIBS="-lc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char printf();
+int
+main ()
+{
+printf()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lc"
+ 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 printf in -lc" >&5
+$as_echo_n "checking for printf in -lc... " >&6; }
+ LIBS="-lc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char printf();
+int
+main ()
+{
+printf()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lc"
+ { $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 printf in -lc in $try" >&5
+$as_echo_n "checking for printf in -lc in $try... " >&6; }
+ LIBS="-lc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char printf();
+int
+main ()
+{
+printf()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lc"
+ 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_c_printf" != "xyes"; then
+
+fail="$fail libc"
+
+fi
+
+
+
+ac_safe=`echo "stdio.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 stdio.h in $try" >&5
+$as_echo_n "checking for stdio.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.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}/stdio.h" >&5
+$as_echo_n "checking for ${_prefix}/stdio.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.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 stdio.h" >&5
+$as_echo_n "checking for stdio.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.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 stdio.h in $try" >&5
+$as_echo_n "checking for stdio.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdio.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_stdio_h" != "yes"; then
+
+fail="$fail stdio.h"
+
+fi
+
+
+ targetname=rlm_example
+else
+ targetname=
+ echo \*\*\* module rlm_example is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_example to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_example." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_example." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_example requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_example requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_example/configure.ac b/src/modules/rlm_example/configure.ac
new file mode 100644
index 0000000..d828d0c
--- /dev/null
+++ b/src/modules/rlm_example/configure.ac
@@ -0,0 +1,32 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_example.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_example])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_SMART_CHECK_LIB(c, printf)
+if test "x$ac_cv_lib_c_printf" != "xyes"; then
+ FR_MODULE_FAIL([libc])
+fi
+
+FR_SMART_CHECK_INCLUDE(stdio.h)
+if test "$ac_cv_header_stdio_h" != "yes"; then
+ FR_MODULE_FAIL([stdio.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_example/rlm_example.c b/src/modules/rlm_example/rlm_example.c
new file mode 100644
index 0000000..ed94bba
--- /dev/null
+++ b/src/modules/rlm_example/rlm_example.c
@@ -0,0 +1,216 @@
+/*
+ * 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_example.c
+ * @brief Example module code.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 your name \<your address\>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_example_t {
+ bool boolean;
+ uint32_t value;
+ char const *string;
+ fr_ipaddr_t ipaddr;
+} rlm_example_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER module_config[] = {
+ { "integer", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_example_t, value), "1" },
+ { "boolean", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_example_t, boolean), "no" },
+ { "string", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_example_t, string), NULL },
+ { "ipaddr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_example_t, ipaddr), "*" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int rlm_example_cmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ rad_assert(check->da->type == PW_TYPE_STRING);
+
+ RINFO("Example-Paircmp called with \"%s\"", check->vp_strvalue);
+
+ if (strcmp(check->vp_strvalue, "yes") == 0) return 0;
+ return 1;
+}
+
+/*
+ * Do any per-module initialization that is separate to each
+ * configured instance of the module. e.g. set up connections
+ * to external databases, read configuration files, set up
+ * dictionary entries, etc.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_example_t *inst = instance;
+ ATTR_FLAGS flags;
+
+ memset(&flags, 0, sizeof(flags));
+ /*
+ * Do more work here
+ */
+ if (!inst->boolean) {
+ cf_log_err_cs(conf, "Boolean is false: forcing error!");
+ return -1;
+ }
+
+ if (dict_addattr("Example-Paircmp", -1, 0, PW_TYPE_STRING, flags) < 0) {
+ ERROR("Failed creating paircmp attribute: %s", fr_strerror());
+
+ return -1;
+ }
+
+ paircompare_register(dict_attrbyname("Example-Paircmp"), dict_attrbyvalue(PW_USER_NAME, 0), false,
+ rlm_example_cmp, inst);
+
+ return 0;
+}
+
+/*
+ * 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(UNUSED void *instance, REQUEST *request)
+{
+ VALUE_PAIR *state;
+
+ /*
+ * Look for the 'state' attribute.
+ */
+ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (state != NULL) {
+ RDEBUG("Found reply to access challenge");
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Create the challenge, and add it to the reply.
+ */
+ pair_make_reply("Reply-Message", "This is a challenge", T_OP_EQ);
+ pair_make_reply("State", "0", T_OP_EQ);
+
+ /*
+ * Mark the packet as an Access-Challenge packet.
+ *
+ * The server will take care of sending it to the user.
+ */
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ RDEBUG("Sending Access-Challenge");
+
+ return RLM_MODULE_HANDLED;
+}
+
+/*
+ * Authenticate the user with the given password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Massage the request before recording it or proxying it
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Write accounting information to this modules database.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+/*
+ * See if a user is already logged in. Sets request->simul_count to the
+ * current session count for this user and sets request->simul_mpp to 2
+ * if it looks like a multilink attempt based on the requested IP
+ * address, otherwise leaves request->simul_mpp alone.
+ *
+ * Check twice. If on the first pass the user exceeds his
+ * max. number of logins, do a second pass and validate all
+ * logins by querying the terminal server (using eg. SNMP).
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(UNUSED void *instance, REQUEST *request)
+{
+ request->simul_count=0;
+
+ return RLM_MODULE_OK;
+}
+#endif
+
+
+/*
+ * Only free memory we allocated. The strings allocated via
+ * cf_section_parse() do not need to be freed.
+ */
+static int mod_detach(UNUSED void *instance)
+{
+ /* free things here */
+ 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_example;
+module_t rlm_example = {
+ .magic = RLM_MODULE_INIT,
+ .name = "example",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_example_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_ACCOUNTING
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_SESSION] = mod_checksimul
+#endif
+ },
+};
diff --git a/src/modules/rlm_exec/README.md b/src/modules/rlm_exec/README.md
new file mode 100644
index 0000000..611d42c
--- /dev/null
+++ b/src/modules/rlm_exec/README.md
@@ -0,0 +1,11 @@
+# rlm_exec
+## Metadata
+<dl>
+ <dt>category</dt><dd>languages</dd>
+</dl>
+
+## Summary
+
+Executes an external script, passing in FreeRADIUS attributes as environmental variables or as arguments.
+
+Scripts may pass back attributes by echoing AVPs in string format to stdout.
diff --git a/src/modules/rlm_exec/all.mk b/src/modules/rlm_exec/all.mk
new file mode 100644
index 0000000..e580abb
--- /dev/null
+++ b/src/modules/rlm_exec/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_exec.a
+SOURCES := rlm_exec.c
diff --git a/src/modules/rlm_exec/rlm_exec.c b/src/modules/rlm_exec/rlm_exec.c
new file mode 100644
index 0000000..f7e2362
--- /dev/null
+++ b/src/modules/rlm_exec/rlm_exec.c
@@ -0,0 +1,487 @@
+/*
+ * 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_exec.c
+ * @brief Execute commands and parse the results.
+ *
+ * @copyright 2002,2006 The FreeRADIUS server project
+ * @copyright 2002 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * Define a structure for our module configuration.
+ */
+typedef struct rlm_exec_t {
+ char const *xlat_name;
+ int bare;
+ bool wait;
+ char const *program;
+ char const *input;
+ char const *output;
+ pair_lists_t input_list;
+ pair_lists_t output_list;
+ char const *packet_type;
+ unsigned int packet_code;
+ bool shell_escape;
+ uint32_t timeout;
+} rlm_exec_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "wait", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_exec_t, wait), "yes" },
+ { "program", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_exec_t, program), NULL },
+ { "input_pairs", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, input), NULL },
+ { "output_pairs", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, output), NULL },
+ { "packet_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_exec_t, packet_type), NULL },
+ { "shell_escape", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_exec_t, shell_escape), "yes" },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_exec_t, timeout), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static char const special[] = "\\'\"`<>|; \t\r\n()[]?#$^&*=";
+
+/*
+ * Escape special characters
+ */
+static size_t rlm_exec_shell_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in,
+ UNUSED void *inst)
+{
+ char *q, *end;
+ char const *p;
+
+ q = out;
+ end = out + outlen;
+ p = in;
+
+ while (*p) {
+ if ((q + 3) >= end) break;
+
+ if (strchr(special, *p) != NULL) {
+ *(q++) = '\\';
+ }
+ *(q++) = *(p++);
+ }
+
+ *q = '\0';
+ return q - out;
+}
+
+/** Process the exit code returned by one of the exec functions
+ *
+ * @param request Current request.
+ * @param answer Output string from exec call.
+ * @param len length of data in answer.
+ * @param status code returned by exec call.
+ * @return One of the RLM_MODULE_* values.
+ */
+static rlm_rcode_t rlm_exec_status2rcode(REQUEST *request, char *answer, size_t len, int status)
+{
+ if (status < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Exec'd programs are meant to return exit statuses that correspond
+ * to the standard RLM_MODULE_* + 1.
+ *
+ * This frees up 0, for success where it'd normally be reject.
+ */
+ if (status == 0) {
+ RDEBUG("Program executed successfully");
+
+ return RLM_MODULE_OK;
+ }
+
+ if (status > RLM_MODULE_NUMCODES) {
+ REDEBUG("Program returned invalid code (greater than max rcode) (%i > %i): %s",
+ status, RLM_MODULE_NUMCODES, answer);
+ goto fail;
+ }
+
+ status--; /* Lets hope no one ever re-enumerates RLM_MODULE_* */
+
+ if (status == RLM_MODULE_FAIL) {
+ fail:
+
+ if (len > 0) {
+ char *p = &answer[len - 1];
+
+ /*
+ * Trim off trailing returns
+ */
+ while((p > answer) && ((*p == '\r') || (*p == '\n'))) {
+ *p-- = '\0';
+ }
+
+ module_failure_msg(request, "%s", answer);
+ }
+
+ return RLM_MODULE_FAIL;
+ }
+
+ return status;
+}
+
+/*
+ * Do xlat of strings.
+ */
+static ssize_t exec_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ int result;
+ rlm_exec_t *inst = instance;
+ VALUE_PAIR **input_pairs = NULL;
+ char *p;
+
+ if (!inst->wait) {
+ REDEBUG("'wait' must be enabled to use exec xlat");
+ *out = '\0';
+ return -1;
+ }
+
+ if (inst->input_list) {
+ input_pairs = radius_list(request, inst->input_list);
+ if (!input_pairs) {
+ REDEBUG("Failed to find input pairs for xlat");
+ *out = '\0';
+ return -1;
+ }
+ }
+
+ /*
+ * This function does it's own xlat of the input program
+ * to execute.
+ */
+ result = radius_exec_program(request, out, outlen, NULL, request, fmt, input_pairs ? *input_pairs : NULL,
+ inst->wait, inst->shell_escape, inst->timeout);
+ if (result != 0) {
+ out[0] = '\0';
+ return -1;
+ }
+
+ for (p = out; *p != '\0'; p++) {
+ if (*p < ' ') *p = ' ';
+ }
+
+ return strlen(out);
+}
+
+/*
+ * 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_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ char const *p;
+ rlm_exec_t *inst = instance;
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) {
+ inst->xlat_name = cf_section_name1(conf);
+ inst->bare = 1;
+ }
+
+ xlat_register(inst->xlat_name, exec_xlat, rlm_exec_shell_escape, inst);
+
+ if (inst->input) {
+ p = inst->input;
+ p += radius_list_name(&inst->input_list, p, PAIR_LIST_UNKNOWN);
+ if ((inst->input_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
+ cf_log_err_cs(conf, "Invalid input list '%s'", inst->input);
+ return -1;
+ }
+ }
+
+ if (inst->output) {
+ p = inst->output;
+ p += radius_list_name(&inst->output_list, p, PAIR_LIST_UNKNOWN);
+ if ((inst->output_list == PAIR_LIST_UNKNOWN) || (*p != '\0')) {
+ cf_log_err_cs(conf, "Invalid output list '%s'", inst->output);
+ return -1;
+ }
+ }
+
+ /*
+ * Sanity check the config. If we're told to NOT wait,
+ * then the output pairs must not be defined.
+ */
+ if (!inst->wait && (inst->output != NULL)) {
+ cf_log_err_cs(conf, "Cannot read output pairs if wait = no");
+ return -1;
+ }
+
+ /*
+ * Get the packet type on which to execute
+ */
+ if (!inst->packet_type) {
+ inst->packet_code = 0;
+ } else {
+ DICT_VALUE *dval;
+
+ dval = dict_valbyname(PW_PACKET_TYPE, 0, inst->packet_type);
+ if (!dval) {
+ cf_log_err_cs(conf, "Unknown packet type %s: See list of VALUEs for Packet-Type in "
+ "share/dictionary", inst->packet_type);
+ return -1;
+ }
+ inst->packet_code = dval->value;
+ }
+
+ /*
+ * Get the time to wait before killing the child
+ */
+ if (!inst->timeout) {
+ inst->timeout = EXEC_TIMEOUT;
+ }
+ if (inst->timeout < 1) {
+ cf_log_err_cs(conf, "Timeout '%d' is too small (minimum: 1)", inst->timeout);
+ return -1;
+ }
+ /*
+ * Blocking a request longer than max_request_time isn't going to help anyone.
+ */
+ if (inst->timeout > main_config.max_request_time) {
+ cf_log_err_cs(conf, "Timeout '%d' is too large (maximum: %d)", inst->timeout, main_config.max_request_time);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Dispatch an exec method
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_exec_dispatch(void *instance, REQUEST *request)
+{
+ rlm_exec_t *inst = (rlm_exec_t *)instance;
+ rlm_rcode_t rcode;
+ int status;
+
+ VALUE_PAIR **input_pairs = NULL, **output_pairs = NULL;
+ VALUE_PAIR *answer = NULL;
+ TALLOC_CTX *ctx = NULL;
+ char out[1024];
+
+ /*
+ * We need a program to execute.
+ */
+ if (!inst->program) {
+ ERROR("rlm_exec (%s): We require a program to execute", inst->xlat_name);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * See if we're supposed to execute it now.
+ */
+ if (!((inst->packet_code == 0) || (request->packet->code == inst->packet_code) ||
+ (request->reply->code == inst->packet_code)
+#ifdef WITH_PROXY
+ || (request->proxy && (request->proxy->code == inst->packet_code)) ||
+ (request->proxy_reply && (request->proxy_reply->code == inst->packet_code))
+#endif
+ )) {
+ RDEBUG2("Packet type is not %s. Not executing.", inst->packet_type);
+
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Decide what input/output the program takes.
+ */
+ if (inst->input) {
+ input_pairs = radius_list(request, inst->input_list);
+ if (!input_pairs) {
+ return RLM_MODULE_INVALID;
+ }
+ }
+
+ if (inst->output) {
+ output_pairs = radius_list(request, inst->output_list);
+ if (!output_pairs) {
+ return RLM_MODULE_INVALID;
+ }
+
+ ctx = radius_list_ctx(request, inst->output_list);
+ }
+
+ /*
+ * This function does it's own xlat of the input program
+ * to execute.
+ */
+ status = radius_exec_program(ctx, out, sizeof(out), inst->output ? &answer : NULL, request,
+ inst->program, inst->input ? *input_pairs : NULL,
+ inst->wait, inst->shell_escape, inst->timeout);
+ rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
+
+ /*
+ * Move the answer over to the output pairs.
+ *
+ * If we're not waiting, then there are no output pairs.
+ */
+ if (inst->output) {
+ fr_pair_list_move(ctx, output_pairs, &answer, T_OP_ADD);
+ }
+ fr_pair_list_free(&answer);
+
+ return rcode;
+}
+
+
+/*
+ * First, look for Exec-Program && Exec-Program-Wait.
+ *
+ * Then, call exec_dispatch.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_exec_t *inst = (rlm_exec_t *) instance;
+ rlm_rcode_t rcode;
+ int status;
+
+ char out[1024];
+ bool we_wait = false;
+ VALUE_PAIR *vp, *tmp;
+
+ vp = fr_pair_find_by_num(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
+ if (vp) {
+ we_wait = false;
+ } else if ((vp = fr_pair_find_by_num(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != NULL) {
+ we_wait = true;
+ }
+ if (!vp) {
+ if (!inst->program) {
+ return RLM_MODULE_NOOP;
+ }
+
+ rcode = mod_exec_dispatch(instance, request);
+ goto finish;
+ }
+
+ tmp = NULL;
+ status = radius_exec_program(request, out, sizeof(out), &tmp, request, vp->vp_strvalue, request->packet->vps,
+ we_wait, inst->shell_escape, inst->timeout);
+ rcode = rlm_exec_status2rcode(request, out, strlen(out), status);
+
+ /*
+ * Always add the value-pairs to the reply.
+ */
+ fr_pair_list_move(request->reply, &request->reply->vps, &tmp, T_OP_ADD);
+ fr_pair_list_free(&tmp);
+
+ finish:
+ switch (rcode) {
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ case RLM_MODULE_REJECT:
+ request->reply->code = PW_CODE_ACCESS_REJECT;
+ break;
+
+ default:
+ break;
+ }
+
+ return rcode;
+}
+
+/*
+ * First, look for Exec-Program && Exec-Program-Wait.
+ *
+ * Then, call exec_dispatch.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_exec_t *inst = (rlm_exec_t *) instance;
+ int status;
+
+ char out[1024];
+ bool we_wait = false;
+ VALUE_PAIR *vp;
+
+ /*
+ * The "bare" exec module takes care of handling
+ * Exec-Program and Exec-Program-Wait.
+ */
+ if (!inst->bare) {
+ return mod_exec_dispatch(instance, request);
+ }
+
+ vp = fr_pair_find_by_num(request->reply->vps, PW_EXEC_PROGRAM, 0, TAG_ANY);
+ if (vp) {
+ we_wait = true;
+ } else if ((vp = fr_pair_find_by_num(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0, TAG_ANY)) != NULL) {
+ we_wait = false;
+ }
+ if (!vp) {
+ return RLM_MODULE_NOOP;
+ }
+
+ status = radius_exec_program(request, out, sizeof(out), NULL, request, vp->vp_strvalue, request->packet->vps,
+ we_wait, inst->shell_escape, inst->timeout);
+ return rlm_exec_status2rcode(request, out, strlen(out), status);
+}
+
+/*
+ * 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_exec;
+module_t rlm_exec = {
+ .magic = RLM_MODULE_INIT,
+ .name = "exec",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_exec_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_exec_dispatch,
+ [MOD_AUTHORIZE] = mod_exec_dispatch,
+ [MOD_PREACCT] = mod_exec_dispatch,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_PRE_PROXY] = mod_exec_dispatch,
+ [MOD_POST_PROXY] = mod_exec_dispatch,
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_exec_dispatch,
+ [MOD_SEND_COA] = mod_exec_dispatch
+#endif
+ },
+};
diff --git a/src/modules/rlm_expiration/README.md b/src/modules/rlm_expiration/README.md
new file mode 100644
index 0000000..92e0228
--- /dev/null
+++ b/src/modules/rlm_expiration/README.md
@@ -0,0 +1,11 @@
+# rlm_expiration
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Implements support for the account expiration. Decreases the
+`Session-Timeout` attribute based on the date in the `Expiration`
+attribute.
diff --git a/src/modules/rlm_expiration/all.mk b/src/modules/rlm_expiration/all.mk
new file mode 100644
index 0000000..6bbd6b9
--- /dev/null
+++ b/src/modules/rlm_expiration/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_expiration.a
+SOURCES := rlm_expiration.c
diff --git a/src/modules/rlm_expiration/rlm_expiration.c b/src/modules/rlm_expiration/rlm_expiration.c
new file mode 100644
index 0000000..0768405
--- /dev/null
+++ b/src/modules/rlm_expiration/rlm_expiration.c
@@ -0,0 +1,131 @@
+/*
+ * 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_expiration.c
+ * @brief Lockout user accounts based on control attributes.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2004 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include <ctype.h>
+
+/*
+ * Check if account has expired, and if user may login now.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ VALUE_PAIR *vp, *check_item;
+ char date[50];
+
+ check_item = fr_pair_find_by_num(request->config, PW_EXPIRATION, 0, TAG_ANY);
+ if (!check_item) return RLM_MODULE_NOOP;
+
+ /*
+ * Has this user's password expired?
+ *
+ * If so, remove ALL reply attributes,
+ * and add our own Reply-Message, saying
+ * why they're being rejected.
+ */
+ if (((time_t) check_item->vp_date) <= request->timestamp) {
+ vp_prints_value(date, sizeof(date), check_item, 0);
+ REDEBUG("Account expired at '%s'", date);
+
+ return RLM_MODULE_USERLOCK;
+ } else {
+ if (RDEBUG_ENABLED) {
+ vp_prints_value(date, sizeof(date), check_item, 0);
+ RDEBUG("Account will expire at '%s'", date);
+ }
+ }
+
+ /*
+ * Else the account hasn't expired, but it may do so
+ * in the future. Set Session-Timeout.
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp);
+ } else if (vp->vp_date > ((uint32_t) (((time_t) check_item->vp_date) - request->timestamp))) {
+ vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp);
+ }
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Compare the expiration date.
+ */
+static int expirecmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ time_t now = 0;
+
+ now = (req) ? req->timestamp : time(NULL);
+
+ if (now <= ((time_t) check->vp_date))
+ return 0;
+ return +1;
+}
+
+
+/*
+ * Do any per-module initialization that is separate to each
+ * configured instance of the module. e.g. set up connections
+ * to external databases, read configuration files, set up
+ * dictionary entries, etc.
+ *
+ * If configuration information is given in the config section
+ * that must be referenced in later calls, store a handle to it
+ * in *instance otherwise put a null pointer there.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ /*
+ * Register the expiration comparison operation.
+ */
+ paircompare_register(dict_attrbyvalue(PW_EXPIRATION, 0), NULL, false, expirecmp, instance);
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ *
+ * If the module needs to temporarily modify it's instantiation
+ * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ * The server will then take care of ensuring that the module
+ * is single-threaded.
+ */
+extern module_t rlm_expiration;
+module_t rlm_expiration = {
+ .magic = RLM_MODULE_INIT,
+ .name = "expiration",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_POST_AUTH] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_expr/README.md b/src/modules/rlm_expr/README.md
new file mode 100644
index 0000000..111be53
--- /dev/null
+++ b/src/modules/rlm_expr/README.md
@@ -0,0 +1,12 @@
+# rlm_expr
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Support for mathematical calculations via the 'expr' XLAT. Also
+adds many other useful XLATs that are not available in the server
+core, such as random numbers, tolower/toupper, escaping, MD5/SHA and
+base64 encoding.
diff --git a/src/modules/rlm_expr/all.mk b/src/modules/rlm_expr/all.mk
new file mode 100644
index 0000000..3b67160
--- /dev/null
+++ b/src/modules/rlm_expr/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_expr.a
+SOURCES := rlm_expr.c paircmp.c
diff --git a/src/modules/rlm_expr/paircmp.c b/src/modules/rlm_expr/paircmp.c
new file mode 100644
index 0000000..cc69cc1
--- /dev/null
+++ b/src/modules/rlm_expr/paircmp.c
@@ -0,0 +1,231 @@
+/*
+ * paircmp.c Valuepair functions for various attributes
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+#include "rlm_expr.h"
+
+/*
+ * Compare prefix/suffix.
+ *
+ * If they compare:
+ * - if PW_STRIP_USER_NAME is present in check_pairs,
+ * strip the username of prefix/suffix.
+ * - if PW_STRIP_USER_NAME is not present in check_pairs,
+ * add a PW_STRIPPED_USER_NAME to the request.
+ */
+static int presufcmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ VALUE_PAIR *vp;
+ char const *name;
+ char rest[MAX_STRING_LEN];
+ int len, namelen;
+ int ret = -1;
+
+ if (!request->username) {
+ return -1;
+ }
+
+ VERIFY_VP(request->username);
+ VERIFY_VP(check);
+ rad_assert(request->username->da->type == PW_TYPE_STRING);
+
+ name = request->username->vp_strvalue;
+
+#if 0 /* DEBUG */
+ printf("Comparing %s and %s, check->attr is %d\n", name, check->vp_strvalue, check->attribute);
+#endif
+
+ len = strlen(check->vp_strvalue);
+ if (check->da->vendor == 0) switch (check->da->attr) {
+ case PW_PREFIX:
+ ret = strncmp(name, check->vp_strvalue, len);
+ if (ret == 0)
+ strlcpy(rest, name + len, sizeof(rest));
+ break;
+ case PW_SUFFIX:
+ namelen = strlen(name);
+ if (namelen < len)
+ break;
+ ret = strcmp(name + namelen - len,
+ check->vp_strvalue);
+ if (ret == 0) {
+ strlcpy(rest, name, namelen - len + 1);
+ }
+ break;
+ }
+ if (ret != 0) {
+ return ret;
+ }
+
+ /*
+ * If Strip-User-Name == No, then don't do any more.
+ */
+ vp = fr_pair_find_by_num(check_pairs, PW_STRIP_USER_NAME, 0, TAG_ANY);
+ if (vp && !vp->vp_integer) return ret;
+
+ /*
+ * See where to put the stripped user name.
+ */
+ vp = fr_pair_find_by_num(check_pairs, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_STRIPPED_USER_NAME, 0);
+ if (!vp) return ret;
+ request->username = vp;
+ }
+
+ fr_pair_value_strcpy(vp, rest);
+
+ return ret;
+}
+
+
+/*
+ * Compare the request packet type.
+ */
+static int packetcmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if (request->packet->code == check->vp_integer) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compare the response packet type.
+ */
+static int responsecmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if (request->reply->code == check->vp_integer) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Generic comparisons, via xlat.
+ */
+static int genericcmp(UNUSED void *instance,
+ REQUEST *request,
+ VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if ((check->op != T_OP_REG_EQ) &&
+ (check->op != T_OP_REG_NE)) {
+ int rcode;
+ char name[1024];
+ char value[1024];
+ VALUE_PAIR *vp;
+
+ snprintf(name, sizeof(name), "%%{%s}", check->da->name);
+
+ if (radius_xlat(value, sizeof(value), request, name, NULL, NULL) < 0) {
+ return 0;
+ }
+ vp = fr_pair_make(req, NULL, check->da->name, value, check->op);
+
+ /*
+ * Paircmp returns 0 for failed comparison,
+ * 1 for succeeded.
+ */
+ rcode = fr_pair_cmp(check, vp);
+
+ /*
+ * We're being called from radius_callback_compare,
+ * which wants 0 for success, and 1 for fail (sigh)
+ *
+ * We should really fix the API so that it is
+ * consistent. i.e. the comparison callbacks should
+ * return ONLY the resut of comparing A to B.
+ * The radius_callback_cmp function should then
+ * take care of using the operator to see if the
+ * condition (A OP B) is true or not.
+ *
+ * This would also allow "<", etc. to work in the
+ * callback functions...
+ *
+ * See rlm_ldap, ...groupcmp() for something that
+ * returns 0 for matched, and 1 for didn't match.
+ */
+ rcode = !rcode;
+ fr_pair_list_free(&vp);
+
+ return rcode;
+ }
+
+ /*
+ * Will do the xlat for us
+ */
+ return radius_compare_vps(request, check, req);
+}
+
+static int generic_attrs[] = {
+ PW_CLIENT_IP_ADDRESS,
+ PW_PACKET_SRC_IP_ADDRESS,
+ PW_PACKET_DST_IP_ADDRESS,
+ PW_PACKET_SRC_PORT,
+ PW_PACKET_DST_PORT,
+ PW_REQUEST_PROCESSING_STAGE,
+ PW_PACKET_SRC_IPV6_ADDRESS,
+ PW_PACKET_DST_IPV6_ADDRESS,
+ PW_VIRTUAL_SERVER,
+ 0
+};
+
+/*
+ * Register server-builtin special attributes.
+ */
+void pair_builtincompare_add(void *instance)
+{
+ int i;
+
+ paircompare_register(dict_attrbyvalue(PW_PREFIX, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, presufcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_SUFFIX, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, presufcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_PACKET_TYPE, 0), NULL, true, packetcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_RESPONSE_PACKET_TYPE, 0), NULL, true, responsecmp, instance);
+
+ for (i = 0; generic_attrs[i] != 0; i++) {
+ paircompare_register(dict_attrbyvalue(generic_attrs[i], 0), NULL, true, genericcmp, instance);
+ }
+}
diff --git a/src/modules/rlm_expr/rlm_expr.c b/src/modules/rlm_expr/rlm_expr.c
new file mode 100644
index 0000000..1aad02d
--- /dev/null
+++ b/src/modules/rlm_expr/rlm_expr.c
@@ -0,0 +1,1924 @@
+/*
+ * 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_expr.c
+ * @brief Register many xlat expansions including the expr expansion.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2002 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/sha1.h>
+#include <freeradius-devel/base64.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#ifdef HAVE_OPENSSL_EVP_H
+# include <openssl/evp.h>
+#endif
+
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif
+
+#include <ctype.h>
+
+#include "rlm_expr.h"
+
+/*
+ * Define a structure for our module configuration.
+ */
+typedef struct rlm_expr_t {
+ char const *xlat_name;
+ char const *allowed_chars;
+} rlm_expr_t;
+
+static const CONF_PARSER module_config[] = {
+ { "safe_characters", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_expr_t, allowed_chars), "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Lookup tables for randstr char classes
+ */
+static char randstr_punc[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
+static char randstr_salt[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz/.";
+
+/*
+ * Characters humans rarely confuse. Reduces char set considerably
+ * should only be used for things such as one time passwords.
+ */
+static char randstr_otp[] = "469ACGHJKLMNPQRUVWXYabdfhijkprstuvwxyz";
+
+static char const hextab[] = "0123456789abcdef";
+
+/** Calculate powers
+ *
+ * @author Orson Peters
+ * @note Borrowed from the gist here: https://gist.github.com/nightcracker/3551590.
+ *
+ * @param base a 32bit signed integer.
+ * @param exp amount to raise base by.
+ * @return base ^ pow, or 0 on underflow/overflow.
+ */
+static int64_t fr_pow(int64_t base, int64_t exp)
+{
+ static const uint8_t highest_bit_set[] = {
+ 0, 1, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6 // anything past 63 is a guaranteed overflow with base > 1
+ };
+
+ int64_t result = 1;
+
+ if (exp > 63) {
+ if (base == 1) {
+ return 1;
+ }
+
+ if (base == -1) {
+ return 1 - 2 * (exp & 1);
+ }
+ return 0; /* overflow */
+ }
+
+ switch (highest_bit_set[exp]) {
+ case 6:
+ if (exp & 1) result *= base;
+ exp >>= 1;
+ base *= base;
+ /* FALL-THROUGH */
+ case 5:
+ if (exp & 1) result *= base;
+ exp >>= 1;
+ base *= base;
+ /* FALL-THROUGH */
+ case 4:
+ if (exp & 1) result *= base;
+ exp >>= 1;
+ base *= base;
+ /* FALL-THROUGH */
+ case 3:
+ if (exp & 1) result *= base;
+ exp >>= 1;
+ base *= base;
+ /* FALL-THROUGH */
+ case 2:
+ if (exp & 1) result *= base;
+ exp >>= 1;
+ base *= base;
+ /* FALL-THROUGH */
+ case 1:
+ if (exp & 1) result *= base;
+ /* FALL-THROUGH */
+ default:
+ return result;
+ }
+}
+
+/*
+ * Start of expression calculator.
+ */
+typedef enum expr_token_t {
+ TOKEN_NONE = 0,
+ TOKEN_INTEGER,
+
+ TOKEN_AND,
+ TOKEN_OR,
+
+ TOKEN_LSHIFT,
+ TOKEN_RSHIFT,
+
+ TOKEN_ADD,
+ TOKEN_SUBTRACT,
+
+ TOKEN_DIVIDE,
+ TOKEN_REMAINDER,
+ TOKEN_MULTIPLY,
+
+ TOKEN_POWER,
+ TOKEN_LAST
+} expr_token_t;
+
+static int precedence[TOKEN_LAST + 1] = {
+ 0, 0, 1, 1, /* and or */
+ 2, 2, 3, 3, /* shift add */
+ 4, 4, 4, 5, /* mul, pow */
+ 0
+};
+
+typedef struct expr_map_t {
+ char op;
+ expr_token_t token;
+} expr_map_t;
+
+static expr_map_t map[] =
+{
+ {'+', TOKEN_ADD },
+ {'-', TOKEN_SUBTRACT },
+ {'/', TOKEN_DIVIDE },
+ {'*', TOKEN_MULTIPLY },
+ {'%', TOKEN_REMAINDER },
+ {'&', TOKEN_AND },
+ {'|', TOKEN_OR },
+ {'^', TOKEN_POWER },
+ {0, TOKEN_LAST}
+};
+
+static bool get_expression(REQUEST *request, char const **string, int64_t *answer, expr_token_t prev);
+
+static bool get_number(REQUEST *request, char const **string, int64_t *answer)
+{
+ int64_t x;
+ bool invert = false;
+ bool negative = false;
+ char const *p = *string;
+
+ /*
+ * Look for a number.
+ */
+ while (isspace((uint8_t) *p)) p++;
+
+ /*
+ * ~1 == 0xff...ffe
+ */
+ if (*p == '~') {
+ invert = true;
+ p++;
+ }
+
+ /*
+ * No algrebraic operator found, the next thing
+ * MUST be a number.
+ *
+ * If it isn't, then we die.
+ */
+ if ((*p == '0') && (p[1] == 'x')) {
+ char *end;
+
+ x = strtoul(p, &end, 16);
+ p = end;
+ goto done;
+ }
+
+ if (*p == '-') {
+ negative = true;
+ p++;
+ }
+
+ /*
+ * Look for an attribute.
+ */
+ if (*p == '&') {
+ ssize_t slen;
+ VALUE_PAIR *vp;
+ vp_tmpl_t vpt;
+
+ p += 1;
+
+ slen = tmpl_from_attr_substr(&vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ REDEBUG("Failed parsing attribute name '%s': %s", p, fr_strerror());
+ return false;
+ }
+
+ p += slen;
+
+ if (tmpl_find_vp(&vp, request, &vpt) < 0) {
+ RWDEBUG("Can't find &%.*s. Using 0 as operand value", (int)vpt.len, vpt.name);
+ x = 0;
+ goto done;
+ }
+
+ if (vp->da->type != PW_TYPE_INTEGER64) {
+ value_data_t value;
+
+ if (value_data_cast(vp, &value, PW_TYPE_INTEGER64, NULL, vp->da->type, vp->da, &vp->data, vp->vp_length) < 0) {
+ REDEBUG("Failed converting &%.*s to an integer value: %s", (int) vpt.len,
+ vpt.name, fr_strerror());
+ return false;
+ }
+ if (value.integer64 > INT64_MAX) {
+ overflow:
+ REDEBUG("Value of &%.*s would overflow a signed 64bit integer "
+ "(our internal arithmetic type)", (int)vpt.len, vpt.name);
+ return false;
+ }
+ x = (int64_t)value.integer64;
+
+ RINDENT();
+ RDEBUG3("&%.*s --> %" PRIu64, (int)vpt.len, vpt.name, x);
+ REXDENT();
+ } else {
+ if (vp->vp_integer64 > INT64_MAX) goto overflow;
+ x = (int64_t)vp->vp_integer64;
+ }
+
+ goto done;
+ }
+
+ /*
+ * Do brackets recursively
+ */
+ if (*p == '(') {
+ p++;
+ if (!get_expression(request, &p, &x, TOKEN_NONE)) return false;
+
+ if (*p != ')') {
+ RDEBUG("No trailing ')'");
+ return false;
+ }
+ p++;
+ goto done;
+ }
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if ((*p < '0') || (*p > '9')) {
+ RDEBUG2("Not a number at \"%s\"", p);
+ return false;
+ }
+
+ /*
+ * This is doing it the hard way, but it also allows
+ * us to increment 'p'.
+ */
+ x = 0;
+ while ((*p >= '0') && (*p <= '9')) {
+ x *= 10;
+ x += (*p - '0');
+ p++;
+ }
+
+done:
+ if (invert) x = ~x;
+
+ if (negative) x = -x;
+
+ *string = p;
+ *answer = x;
+ return true;
+}
+
+static bool calc_result(REQUEST *request, int64_t lhs, expr_token_t op, int64_t rhs, int64_t *answer)
+{
+ switch (op) {
+ default:
+ case TOKEN_ADD:
+ *answer = lhs + rhs;
+ break;
+
+ case TOKEN_SUBTRACT:
+ *answer = lhs - rhs;
+ break;
+
+ case TOKEN_DIVIDE:
+ if (rhs == 0) {
+ RDEBUG("Division by zero!");
+ return false;
+ } else {
+ *answer = lhs / rhs;
+ }
+ break;
+
+ case TOKEN_REMAINDER:
+ if (rhs == 0) {
+ RDEBUG("Division by zero!");
+ return false;
+ }
+
+ *answer = lhs % rhs;
+ break;
+
+ case TOKEN_MULTIPLY:
+ *answer = lhs * rhs;
+ break;
+
+ case TOKEN_LSHIFT:
+ if (rhs > 63) {
+ RDEBUG("Shift must be less than 63 (was %lld)", (long long int) rhs);
+ return false;
+ }
+
+ *answer = lhs << rhs;
+ break;
+
+ case TOKEN_RSHIFT:
+ if (rhs > 63) {
+ RDEBUG("Shift must be less than 63 (was %lld)", (long long int) rhs);
+ return false;
+ }
+
+ *answer = lhs >> rhs;
+ break;
+
+ case TOKEN_AND:
+ *answer = lhs & rhs;
+ break;
+
+ case TOKEN_OR:
+ *answer = lhs | rhs;
+ break;
+
+ case TOKEN_POWER:
+ if (rhs > 63) {
+ REDEBUG("Exponent must be between 0-63 (was %lld)", (long long int) rhs);
+ return false;
+ }
+
+ if (lhs > 65535) {
+ REDEBUG("Base must be between 0-65535 (was %lld)", (long long int) lhs);
+ return false;
+ }
+
+ *answer = fr_pow(lhs, rhs);
+ break;
+ }
+
+ return true;
+}
+
+static bool get_operator(REQUEST *request, char const **string, expr_token_t *op)
+{
+ int i;
+ char const *p = *string;
+
+ /*
+ * All tokens are one character.
+ */
+ for (i = 0; map[i].token != TOKEN_LAST; i++) {
+ if (*p == map[i].op) {
+ *op = map[i].token;
+ *string = p + 1;
+ return true;
+ }
+ }
+
+ if ((p[0] == '<') && (p[1] == '<')) {
+ *op = TOKEN_LSHIFT;
+ *string = p + 2;
+ return true;
+ }
+
+ if ((p[0] == '>') && (p[1] == '>')) {
+ *op = TOKEN_RSHIFT;
+ *string = p + 2;
+ return true;
+ }
+
+ RDEBUG("Expected operator at \"%s\"", p);
+ return false;
+}
+
+
+static bool get_expression(REQUEST *request, char const **string, int64_t *answer, expr_token_t prev)
+{
+ int64_t lhs, rhs;
+ char const *p, *op_p;
+ expr_token_t this;
+
+ p = *string;
+
+ if (!get_number(request, &p, &lhs)) return false;
+
+redo:
+ while (isspace((uint8_t) *p)) p++;
+
+ /*
+ * A number by itself is OK.
+ */
+ if (!*p || (*p == ')')) {
+ *answer = lhs;
+ *string = p;
+ return true;
+ }
+
+ /*
+ * Peek at the operator.
+ */
+ op_p = p;
+ if (!get_operator(request, &p, &this)) return false;
+
+ /*
+ * a + b + c ... = (a + b) + c ...
+ * a * b + c ... = (a * b) + c ...
+ *
+ * Feed the current number to the caller, who will take
+ * care of continuing.
+ */
+ if (precedence[this] <= precedence[prev]) {
+ *answer = lhs;
+ *string = op_p;
+ return true;
+ }
+
+ /*
+ * a + b * c ... = a + (b * c) ...
+ */
+ if (!get_expression(request, &p, &rhs, this)) return false;
+
+ if (!calc_result(request, lhs, this, rhs, answer)) return false;
+
+ /*
+ * There may be more to calculate. The answer we
+ * calculated here is now the LHS of the lower priority
+ * operation which follows the current expression. e.g.
+ *
+ * a * b + c ... = (a * b) + c ...
+ * = d + c ...
+ */
+ lhs = *answer;
+ goto redo;
+}
+
+/*
+ * Do xlat of strings!
+ */
+static ssize_t expr_xlat(UNUSED void *instance, REQUEST *request, char const *fmt,
+ char *out, size_t outlen)
+{
+ int64_t result;
+ char const *p;
+
+ p = fmt;
+
+ if (!get_expression(request, &p, &result, TOKEN_NONE)) {
+ return -1;
+ }
+
+ if (*p) {
+ RDEBUG("Invalid text after expression: %s", p);
+ return -1;
+ }
+
+ snprintf(out, outlen, "%lld", (long long int) result);
+ return strlen(out);
+}
+
+/** Generate a random integer value
+ *
+ */
+static ssize_t rand_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt,
+ char *out, size_t outlen)
+{
+ int64_t result;
+
+ result = atoi(fmt);
+
+ /*
+ * Too small or too big.
+ */
+ if (result <= 0) {
+ *out = '\0';
+ return -1;
+ }
+ if (result >= (1 << 30)) result = (1 << 30);
+
+ result *= fr_rand(); /* 0..2^32-1 */
+ result >>= 32;
+
+ snprintf(out, outlen, "%ld", (long int) result);
+ return strlen(out);
+}
+
+/** Generate a string of random chars
+ *
+ * Build strings of random chars, useful for generating tokens and passcodes
+ * Format similar to String::Random.
+ */
+static ssize_t randstr_xlat(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *p;
+ unsigned int result;
+ unsigned int number;
+ size_t freespace = outlen;
+
+ if (outlen <= 1) return 0;
+
+ *out = '\0';
+
+ p = fmt;
+ while (*p && (--freespace > 0)) {
+ number = 0;
+
+ /*
+ * Modifiers are polite.
+ *
+ * But we limit it to 100, because we don't want
+ * utter stupidity.
+ */
+ while (isdigit((uint8_t) *p)) {
+ if (number >= 100) {
+ p++;
+ continue;
+ }
+
+ number *= 10;
+ number += *p - '0';
+ p++;
+ }
+
+ redo:
+ result = fr_rand();
+
+ switch (*p) {
+ /*
+ * Lowercase letters
+ */
+ case 'c':
+ *out++ = 'a' + (result % 26);
+ break;
+
+ /*
+ * Uppercase letters
+ */
+ case 'C':
+ *out++ = 'A' + (result % 26);
+ break;
+
+ /*
+ * Numbers
+ */
+ case 'n':
+ *out++ = '0' + (result % 10);
+ break;
+
+ /*
+ * Alpha numeric
+ */
+ case 'a':
+ *out++ = randstr_salt[result % (sizeof(randstr_salt) - 3)];
+ break;
+
+ /*
+ * Punctuation
+ */
+ case '!':
+ *out++ = randstr_punc[result % (sizeof(randstr_punc) - 1)];
+ break;
+
+ /*
+ * Alpa numeric + punctuation
+ */
+ case '.':
+ *out++ = '!' + (result % 95);
+ break;
+
+ /*
+ * Alpha numeric + salt chars './'
+ */
+ case 's':
+ *out++ = randstr_salt[result % (sizeof(randstr_salt) - 1)];
+ break;
+
+ /*
+ * Chars suitable for One Time Password tokens.
+ * Alpha numeric with easily confused char pairs removed.
+ */
+ case 'o':
+ *out++ = randstr_otp[result % (sizeof(randstr_otp) - 1)];
+ break;
+
+ /*
+ * Binary data as hexits (we don't really support
+ * non printable chars).
+ */
+ case 'h':
+ if (freespace < 2) {
+ break;
+ }
+
+ snprintf(out, 3, "%02x", result % 256);
+
+ /* Already decremented */
+ freespace -= 1;
+ out += 2;
+ break;
+
+ /*
+ * Binary data with uppercase hexits
+ */
+ case 'H':
+ if (freespace < 2) {
+ break;
+ }
+
+ snprintf(out, 3, "%02X", result % 256);
+
+ /* Already decremented */
+ freespace -= 1;
+ out += 2;
+ break;
+
+ default:
+ ERROR("rlm_expr: invalid character class '%c'", *p);
+
+ return -1;
+ }
+
+ if (number > 0) {
+ number--;
+ goto redo;
+ }
+
+ p++;
+ }
+
+ *out++ = '\0';
+
+ return outlen - freespace;
+}
+
+/** URLencode special characters
+ *
+ * Example: "%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47"
+ */
+static ssize_t urlquote_xlat(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *p;
+ size_t freespace = outlen;
+
+ if (outlen <= 1) return 0;
+
+ p = fmt;
+ while (*p && (--freespace > 0)) {
+ if (isalnum(*p)) {
+ *out++ = *p++;
+ continue;
+ }
+
+ switch (*p) {
+ case '-':
+ case '_':
+ case '.':
+ case '~':
+ *out++ = *p++;
+ break;
+
+ default:
+ if (freespace < 3)
+ break;
+
+ /* MUST be upper case hex to be compliant */
+ snprintf(out, 4, "%%%02X", (uint8_t) *p++); /* %XX */
+
+ /* Already decremented */
+ freespace -= 2;
+ out += 3;
+ }
+ }
+
+ *out = '\0';
+
+ return outlen - freespace;
+}
+
+/** URLdecode special characters
+ *
+ * Example: "%{urlunquote:http%%3A%%47%%47example.org%%47}" == "http://example.org/"
+ *
+ * Remember to escape % with %% in strings, else xlat will try to parse it.
+ */
+static ssize_t urlunquote_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *p;
+ char *c1, *c2;
+ size_t freespace = outlen;
+
+ if (outlen <= 1) return 0;
+
+ p = fmt;
+ while (*p && (--freespace > 0)) {
+ if (*p != '%') {
+ *out++ = *p++;
+ continue;
+ }
+ /* Is a % char */
+
+ /* Don't need \0 check, as it won't be in the hextab */
+ if (!(c1 = memchr(hextab, tolower((uint8_t) *++p), 16)) ||
+ !(c2 = memchr(hextab, tolower((uint8_t) *++p), 16))) {
+ REMARKER(fmt, p - fmt, "None hex char in % sequence");
+ return -1;
+ }
+ p++;
+ *out++ = ((c1 - hextab) << 4) + (c2 - hextab);
+ }
+
+ *out = '\0';
+
+ return outlen - freespace;
+}
+
+/** Equivalent to the old safe_characters functionality in rlm_sql but with utf8 support
+ *
+ * @verbatim Example: "%{escape:<img>foo.jpg</img>}" == "=60img=62foo.jpg=60/img=62" @endverbatim
+ */
+static ssize_t escape_xlat(void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ rlm_expr_t *inst = instance;
+ char const *p = fmt;
+ size_t freespace = outlen;
+
+ while (p[0]) {
+ int chr_len = 1;
+ int ret = 1; /* -Werror=uninitialized */
+
+ if (fr_utf8_strchr(&chr_len, inst->allowed_chars, p) == NULL) {
+ /*
+ * '=' 1 + ([hex]{2}) * chr_len)
+ */
+ if (freespace <= (size_t)(1 + (chr_len * 3))) break;
+
+ switch (chr_len) {
+ case 4:
+ ret = snprintf(out, freespace, "=%02X=%02X=%02X=%02X",
+ (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]);
+ break;
+
+ case 3:
+ ret = snprintf(out, freespace, "=%02X=%02X=%02X",
+ (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2]);
+ break;
+
+ case 2:
+ ret = snprintf(out, freespace, "=%02X=%02X", (uint8_t)p[0], (uint8_t)p[1]);
+ break;
+
+ case 1:
+ ret = snprintf(out, freespace, "=%02X", (uint8_t)p[0]);
+ break;
+ }
+
+ p += chr_len;
+ out += ret;
+ freespace -= ret;
+ continue;
+ }
+
+ /*
+ * Only one byte left.
+ */
+ if (freespace <= 1) break;
+
+ /*
+ * Allowed character (copy whole mb chars at once)
+ */
+ memcpy(out, p, chr_len);
+ out += chr_len;
+ p += chr_len;
+ freespace -= chr_len;
+ }
+ *out = '\0';
+
+ return outlen - freespace;
+}
+
+/** Equivalent to the old safe_characters functionality in rlm_sql
+ *
+ * @verbatim Example: "%{unescape:=60img=62foo.jpg=60/img=62}" == "<img>foo.jpg</img>" @endverbatim
+ */
+static ssize_t unescape_xlat(UNUSED void *instance, UNUSED REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char const *p;
+ char *c1, *c2, c3;
+ size_t freespace = outlen;
+
+ if (outlen <= 1) return 0;
+
+ p = fmt;
+ while (*p && (--freespace > 0)) {
+ if (*p != '=') {
+ next:
+
+ *out++ = *p++;
+ continue;
+ }
+
+ /* Is a = char */
+
+ if (!(c1 = memchr(hextab, tolower((uint8_t) *(p + 1)), 16)) ||
+ !(c2 = memchr(hextab, tolower((uint8_t) *(p + 2)), 16))) goto next;
+ c3 = ((c1 - hextab) << 4) + (c2 - hextab);
+
+ *out++ = c3;
+ p += 3;
+ }
+
+ *out = '\0';
+
+ return outlen - freespace;
+}
+
+/** Convert a string to lowercase
+ *
+ * Example: "%{tolower:Bar}" == "bar"
+ *
+ * Probably only works for ASCII
+ */
+static ssize_t tolower_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ char *q;
+ char const *p;
+
+ if (outlen <= 1) return 0;
+
+ for (p = fmt, q = out; *p != '\0'; p++, outlen--) {
+ if (outlen <= 1) break;
+
+ *(q++) = tolower((uint8_t) *p);
+ }
+
+ *q = '\0';
+
+ return strlen(out);
+}
+
+/** Convert a string to uppercase
+ *
+ * Example: "%{toupper:Foo}" == "FOO"
+ *
+ * Probably only works for ASCII
+ */
+static ssize_t toupper_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ char *q;
+ char const *p;
+
+ if (outlen <= 1) return 0;
+
+ for (p = fmt, q = out; *p != '\0'; p++, outlen--) {
+ if (outlen <= 1) break;
+
+ *(q++) = toupper((uint8_t) *p);
+ }
+
+ *q = '\0';
+
+ return strlen(out);
+}
+
+/** Calculate the MD5 hash of a string or attribute.
+ *
+ * Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"
+ */
+static ssize_t md5_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t digest[16];
+ ssize_t i, len, inlen;
+ uint8_t const *p;
+ FR_MD5_CTX ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ fr_md5_init(&ctx);
+ fr_md5_update(&ctx, p, inlen);
+ fr_md5_final(digest, &ctx);
+ fr_md5_destroy(&ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL.
+ */
+ len = (outlen / 2) - 1;
+ if (len > 16) len = 16;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+
+ return strlen(out);
+}
+
+/** Calculate the MD4 hash of a string or attribute.
+ *
+ * Example: "%{md4:foo}" == "0ac6700c491d70fb8650940b1ca1e4b2"
+ */
+static ssize_t md4_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t digest[16];
+ ssize_t i, len, inlen;
+ uint8_t const *p;
+ FR_MD4_CTX ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ fr_md4_init(&ctx);
+ fr_md4_update(&ctx, p, inlen);
+ fr_md4_final(digest, &ctx);
+ fr_md4_destroy(&ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL.
+ */
+ len = (outlen / 2) - 1;
+ if (len > 16) len = 16;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+
+ return strlen(out);
+}
+
+/** Calculate the SHA1 hash of a string or attribute.
+ *
+ * Example: "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
+ */
+static ssize_t sha1_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t digest[20];
+ ssize_t i, len, inlen;
+ uint8_t const *p;
+ fr_sha1_ctx ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ fr_sha1_init(&ctx);
+ fr_sha1_update(&ctx, p, inlen);
+ fr_sha1_final(digest, &ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL. SHA1 is 160 bits (20 bytes)
+ */
+ len = (outlen / 2) - 1;
+ if (len > 20) len = 20;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+
+ return strlen(out);
+}
+
+/** Calculate any digest supported by OpenSSL EVP_MD
+ *
+ * Example: "%{sha256:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
+ */
+#ifdef HAVE_OPENSSL_EVP_H
+static ssize_t evp_md_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen, EVP_MD const *md)
+{
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digestlen, i, len;
+ ssize_t inlen;
+ uint8_t const *p;
+
+ EVP_MD_CTX *ctx;
+
+ /*
+ * We need room for at least one octet of output.
+ */
+ if (outlen < 3) {
+ *out = '\0';
+ return 0;
+ }
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ ctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(ctx, md, NULL);
+ EVP_DigestUpdate(ctx, p, inlen);
+ EVP_DigestFinal_ex(ctx, digest, &digestlen);
+ EVP_MD_CTX_destroy(ctx);
+
+ /*
+ * Each digest octet takes two hex digits, plus one for
+ * the terminating NUL.
+ */
+ len = (outlen / 2) - 1;
+ if (len > digestlen) len = digestlen;
+
+ for (i = 0; i < len; i++) {
+ snprintf(out + i * 2, 3, "%02x", digest[i]);
+ }
+ return strlen(out);
+}
+
+# define EVP_MD_XLAT(_md) \
+static ssize_t _md##_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)\
+{\
+ return evp_md_xlat(instance, request, fmt, out, outlen, EVP_##_md());\
+}
+
+EVP_MD_XLAT(sha256)
+EVP_MD_XLAT(sha512)
+#endif
+
+/** Generate the HMAC-MD5 of a string or attribute
+ *
+ * Example: "%{hmacmd5:foo bar}" == "Zm9v"
+ */
+static ssize_t hmac_md5_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t const *data, *key;
+ char const *p;
+ ssize_t data_len, key_len;
+ uint8_t digest[MD5_DIGEST_LENGTH];
+ char data_ref[256];
+
+ if (outlen <= (sizeof(digest) * 2)) {
+ REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes",
+ (sizeof(digest) * 2) + 1, outlen);
+ return -1;
+ }
+
+ p = strchr(fmt, ' ');
+ if (!p) {
+ REDEBUG("HMAC requires exactly two arguments (&data &key)");
+ return -1;
+ }
+
+ if ((size_t)(p - fmt) >= sizeof(data_ref)) {
+ REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes",
+ (p - fmt) + 1, sizeof(data_ref));
+
+ return -1;
+ }
+ strlcpy(data_ref, fmt, (p - fmt) + 1);
+
+ data_len = xlat_fmt_to_ref(&data, request, data_ref);
+ if (data_len < 0) return -1;
+
+ while (isspace((uint8_t) *p) && p++);
+
+ key_len = xlat_fmt_to_ref(&key, request, p);
+ if (key_len < 0) return -1;
+
+ fr_hmac_md5(digest, data, data_len, key, key_len);
+
+ return fr_bin2hex(out, digest, sizeof(digest));
+}
+
+/** Generate the HMAC-SHA1 of a string or attribute
+ *
+ * Example: "%{hmacsha1:foo bar}" == "Zm9v"
+ */
+static ssize_t hmac_sha1_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t const *data, *key;
+ char const *p;
+ ssize_t data_len, key_len;
+ uint8_t digest[SHA1_DIGEST_LENGTH];
+ char data_ref[256];
+
+ if (outlen <= (sizeof(digest) * 2)) {
+ REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes",
+ (sizeof(digest) * 2) + 1, outlen);
+ return -1;
+ }
+
+ p = strchr(fmt, ' ');
+ if (!p) {
+ REDEBUG("HMAC requires exactly two arguments (&data &key)");
+ return -1;
+ }
+
+ if ((size_t)(p - fmt) >= sizeof(data_ref)) {
+ REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes",
+ (p - fmt) + 1, sizeof(data_ref));
+
+ return -1;
+ }
+ strlcpy(data_ref, fmt, (p - fmt) + 1);
+
+ data_len = xlat_fmt_to_ref(&data, request, data_ref);
+ if (data_len < 0) return -1;
+
+ while (isspace((uint8_t) *p) && p++);
+
+ key_len = xlat_fmt_to_ref(&key, request, p);
+ if (key_len < 0) return -1;
+
+ fr_hmac_sha1(digest, data, data_len, key, key_len);
+
+ return fr_bin2hex(out, digest, sizeof(digest));
+}
+
+/** Crypt a string or attribute.
+ *
+ * Example: "%{crypt:ab:foo}" == "abQ9KY.KfrYrc"
+ * Example: "%{crypt:$1$abcdefgh:foo}" == "$1$abcdefgh$XxzGe9Muun7wTYbZO4sdr0"
+ * Example: "%{crypt:$1$%{randstr:aaaaaaaa}:&User-Password}" -> "$1$Z9hrfzst$hRkQwmSUApr/r10kb/d3W0"
+ */
+#ifdef HAVE_CRYPT_R
+static ssize_t crypt_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ ssize_t inlen;
+ size_t len;
+ uint8_t const *salt;
+ uint8_t const *pass;
+ char *p;
+ struct crypt_data cdata;
+
+ cdata.initialized = 0;
+
+ /*
+ * DES passwords will be at least 13 chars long.
+ */
+ if (outlen < 14) {
+ *out = '\0';
+ return 0;
+ }
+
+ p = strchr(fmt, ':');
+ if (!p) {
+ REDEBUG("No salt specified in crypt xlat");
+ return -1;
+ }
+
+ *p = '\0';
+ p++;
+
+ /*
+ * Get salt
+ */
+ inlen = xlat_fmt_to_ref(&salt, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ /*
+ * Get cleartext password
+ */
+ inlen = xlat_fmt_to_ref(&pass, request, p);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ p = crypt_r((const char *) pass, (const char *) salt, &cdata);
+
+ if (!p) {
+ switch (errno) {
+ case EINVAL:
+ REDEBUG("Crypt salt has the wrong format: '%s'", salt);
+ break;
+ default:
+ REDEBUG("Crypt error");
+ }
+ return -1;
+ }
+
+ len = strlen(p);
+ if (outlen < len) {
+ *out = '\0';
+ return 0;
+ }
+
+ strncpy(out, p, outlen);
+
+ return len;
+}
+#else
+static ssize_t crypt_xlat(UNUSED void *instance, REQUEST *request,
+ UNUSED char const *fmt, UNUSED char *out,
+ UNUSED size_t outlen)
+{
+ RERROR("Crypt not available at compile time (no 'crypt_r' support)");
+ return 0;
+}
+#endif
+
+/** Encode attributes as a series of string attribute/value pairs
+ *
+ * This is intended to serialize one or more attributes as a comma
+ * delimited string.
+ *
+ * Example: "%{pairs:request:}" == "User-Name = 'foo', User-Password = 'bar'"
+ */
+static ssize_t pairs_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ vp_tmpl_t vpt;
+ vp_cursor_t cursor;
+ size_t len, freespace = outlen;
+ char *p = out;
+
+ VALUE_PAIR *vp;
+
+ if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
+ REDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
+ vp;
+ vp = tmpl_cursor_next(&cursor, &vpt)) {
+ FR_TOKEN op = vp->op;
+
+ vp->op = T_OP_EQ;
+ len = vp_prints(p, freespace, vp);
+ vp->op = op;
+
+ if (is_truncated(len, freespace)) {
+ no_space:
+ REDEBUG("Insufficient space to store pair string, needed %zu bytes have %zu bytes",
+ (p - out) + len, outlen);
+ *out = '\0';
+ return -1;
+ }
+ p += len;
+ freespace -= len;
+
+ if (freespace < 2) {
+ len = 2;
+ goto no_space;
+ }
+
+ *p++ = ',';
+ *p++ = ' ';
+ freespace -= 2;
+ }
+
+ /* Trim the trailing ', ' */
+ if (p != out) p -= 2;
+ *p = '\0';
+
+ return (p - out);
+}
+
+/** Encode string or attribute as base64
+ *
+ * Example: "%{base64:foo}" == "Zm9v"
+ */
+static ssize_t base64_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ ssize_t inlen;
+ uint8_t const *p;
+
+ inlen = xlat_fmt_to_ref(&p, request, fmt);
+ if (inlen < 0) {
+ return -1;
+ }
+
+ /*
+ * We can accurately calculate the length of the output string
+ * if it's larger than outlen, the output would be useless so abort.
+ */
+ if ((inlen < 0) || ((FR_BASE64_ENC_LENGTH(inlen) + 1) > (ssize_t) outlen)) {
+ REDEBUG("xlat failed");
+ *out = '\0';
+ return -1;
+ }
+
+ return fr_base64_encode(out, outlen, p, inlen);
+}
+
+/** Convert base64 to hex
+ *
+ * Example: "%{base64tohex:Zm9v}" == "666f6f"
+ */
+static ssize_t base64_to_hex_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ uint8_t decbuf[1024];
+
+ ssize_t declen;
+ ssize_t len = strlen(fmt);
+
+ *out = '\0';
+
+ declen = fr_base64_decode(decbuf, sizeof(decbuf), fmt, len);
+ if (declen < 0) {
+ REDEBUG("Base64 string invalid");
+ return -1;
+ }
+
+ if ((size_t)((declen * 2) + 1) > outlen) {
+ REDEBUG("Base64 conversion failed, output buffer exhausted, needed %zd bytes, have %zd bytes",
+ (declen * 2) + 1, outlen);
+ return -1;
+ }
+
+ return fr_bin2hex(out, decbuf, declen);
+}
+
+/** Split an attribute into multiple new attributes based on a delimiter
+ *
+ * @todo should support multibyte delimiter for string types.
+ *
+ * Example: "%{explode:&ref <delim>}"
+ */
+static ssize_t explode_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ vp_tmpl_t vpt;
+ vp_cursor_t cursor, to_merge;
+ VALUE_PAIR *vp, *head = NULL;
+ ssize_t slen;
+ int count = 0;
+ char const *p = fmt;
+ char delim;
+
+ /*
+ * Trim whitespace
+ */
+ while (isspace((uint8_t) *p) && p++);
+
+ slen = tmpl_from_attr_substr(&vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ REDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ p += slen;
+
+ if (*p++ != ' ') {
+ arg_error:
+ REDEBUG("explode needs exactly two arguments: &ref <delim>");
+ return -1;
+ }
+
+ if (*p == '\0') goto arg_error;
+
+ delim = *p;
+
+ fr_cursor_init(&to_merge, &head);
+
+ for (vp = tmpl_cursor_init(NULL, &cursor, request, &vpt);
+ vp;
+ vp = tmpl_cursor_next(&cursor, &vpt)) {
+ VALUE_PAIR *new;
+ char const *end;
+ char const *q;
+
+ /*
+ * This can theoretically operate on lists too
+ * so we need to check the type of each attribute.
+ */
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ case PW_TYPE_STRING:
+ break;
+
+ default:
+ continue;
+ }
+
+ p = vp->data.ptr;
+ end = p + vp->vp_length;
+ while (p < end) {
+ q = memchr(p, delim, end - p);
+ if (!q) {
+ /* Delimiter not present in attribute */
+ if (p == vp->data.ptr) goto next;
+ q = end;
+ }
+
+ /* Skip zero length */
+ if (q == p) {
+ p = q + 1;
+ continue;
+ }
+
+ new = fr_pair_afrom_da(talloc_parent(vp), vp->da);
+ if (!new) {
+ fr_pair_list_free(&head);
+ return -1;
+ }
+ new->tag = vp->tag;
+
+ switch (vp->da->type) {
+ case PW_TYPE_OCTETS:
+ {
+ uint8_t *buff;
+
+ buff = talloc_array(new, uint8_t, q - p);
+ memcpy(buff, p, q - p);
+ fr_pair_value_memsteal(new, buff);
+ }
+ break;
+
+ case PW_TYPE_STRING:
+ {
+ char *buff;
+
+ buff = talloc_array(new, char, (q - p) + 1);
+ memcpy(buff, p, q - p);
+ buff[q - p] = '\0';
+ fr_pair_value_strsteal(new, (char *)buff);
+ }
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ fr_cursor_insert(&to_merge, new);
+
+ p = q + 1; /* next */
+
+ count++;
+ }
+
+ /*
+ * Remove the unexploded version
+ */
+ vp = fr_cursor_remove(&cursor);
+ talloc_free(vp);
+
+ next:
+ continue; /* Apparently goto labels aren't allowed at the end of loops? */
+ }
+
+ fr_cursor_merge(&cursor, head);
+
+ return snprintf(out, outlen, "%i", count);
+}
+
+/** Calculate number of seconds until the next n hour(s), day(s), week(s), year(s).
+ *
+ * For example, if it were 16:18 %{nexttime:1h} would expand to 2520.
+ *
+ * The envisaged usage for this function is to limit sessions so that they don't
+ * cross billing periods. The output of the xlat should be combined with %{rand:} to create
+ * some jitter, unless the desired effect is every subscriber on the network
+ * re-authenticating at the same time.
+ */
+static ssize_t next_time_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ long num;
+
+ char const *p;
+ char *q;
+ time_t now;
+ struct tm *local, local_buff;
+
+ now = time(NULL);
+ local = localtime_r(&now, &local_buff);
+
+ p = fmt;
+
+ num = strtoul(p, &q, 10);
+ if (!q || *q == '\0') {
+ REDEBUG("nexttime: <int> must be followed by period specifier (h|d|w|m|y)");
+ return -1;
+ }
+
+ if (p == q) {
+ num = 1;
+ } else {
+ p += q - p;
+ }
+
+ local->tm_sec = 0;
+ local->tm_min = 0;
+
+ switch (*p) {
+ case 'h':
+ local->tm_hour += num;
+ break;
+
+ case 'd':
+ local->tm_hour = 0;
+ local->tm_mday += num;
+ break;
+
+ case 'w':
+ local->tm_hour = 0;
+ local->tm_mday += (7 - local->tm_wday) + (7 * (num-1));
+ break;
+
+ case 'm':
+ local->tm_hour = 0;
+ local->tm_mday = 1;
+ local->tm_mon += num;
+ break;
+
+ case 'y':
+ local->tm_hour = 0;
+ local->tm_mday = 1;
+ local->tm_mon = 0;
+ local->tm_year += num;
+ break;
+
+ default:
+ REDEBUG("nexttime: Invalid period specifier '%c', must be h|d|w|m|y", *p);
+ return -1;
+ }
+
+ return snprintf(out, outlen, "%" PRIu64, (uint64_t)(mktime(local) - now));
+}
+
+/** Calculate number of seconds until the previous n hour(s), day(s), week(s), year(s).
+ *
+ * For example, if it were 16:18 %{lasttime:1h} would expand to -2520.
+ */
+static ssize_t last_time_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ long num;
+
+ char const *p;
+ char *q;
+ time_t now;
+ struct tm *local, local_buff;
+
+ now = time(NULL);
+ local = localtime_r(&now, &local_buff);
+
+ p = fmt;
+
+ num = strtoul(p, &q, 10);
+ if (!q || *q == '\0') {
+ REDEBUG("nexttime: <int> must be followed by period specifier (h|d|w|m|y)");
+ return -1;
+ }
+
+ if (p == q) {
+ num = 1;
+ } else {
+ p += q - p;
+ }
+
+ local->tm_sec = 0;
+ local->tm_min = 0;
+
+ switch (*p) {
+ case 'h':
+ local->tm_hour -= num;
+ break;
+
+ case 'd':
+ local->tm_hour = 0;
+ local->tm_mday -= num;
+ break;
+
+ case 'w':
+ local->tm_hour = 0;
+ local->tm_mday -= (7 - local->tm_wday) + (7 * (num-1));
+ break;
+
+ case 'm':
+ local->tm_hour = 0;
+ local->tm_mday = 1;
+ local->tm_mon -= num;
+ break;
+
+ case 'y':
+ local->tm_hour = 0;
+ local->tm_mday = 1;
+ local->tm_mon = 0;
+ local->tm_year -= num;
+ break;
+
+ default:
+ REDEBUG("lasttime: Invalid period specifier '%c', must be h|d|w|m|y", *p);
+ return -1;
+ }
+
+ return snprintf(out, outlen, "%" PRIu64, (uint64_t)(now - mktime(local)));
+}
+
+
+/*
+ * Parse the 3 arguments to lpad / rpad.
+ */
+static bool parse_pad(REQUEST *request, char const *fmt,
+ vp_tmpl_t **pvpt, size_t *plength,
+ char *fill)
+{
+ ssize_t slen;
+ unsigned long length;
+ char const *p;
+ char *end;
+ vp_tmpl_t *vpt;
+
+ *fill = ' '; /* the default */
+
+ p = fmt;
+ while (isspace((uint8_t) *p)) p++;
+
+ if (*p != '&') {
+ RDEBUG("First argument must be an attribute reference");
+ return false;
+ }
+
+ vpt = talloc(request, vp_tmpl_t);
+ if (!vpt) return false;
+
+ slen = tmpl_from_attr_substr(vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ talloc_free(vpt);
+ RDEBUG("Failed expanding string: %s", fr_strerror());
+ return false;
+ }
+
+ p = fmt + slen;
+
+ while (isspace((uint8_t) *p)) p++;
+
+ length = strtoul(p, &end, 10);
+ if ((length == ULONG_MAX) || (length > 8192)) {
+ talloc_free(vpt);
+ RDEBUG("Invalid length found at: %s", p);
+ return false;
+ }
+
+ p += (end - p);
+
+ /*
+ * The fill character is optional.
+ *
+ * But we must have a space after the previous number,
+ * and we must have only ONE fill character.
+ */
+ if (*p) {
+ if (!isspace((uint8_t) *p)) {
+ talloc_free(vpt);
+ RDEBUG("Invalid text found at: %s", p);
+ return false;
+ }
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if (p[1] != '\0') {
+ talloc_free(vpt);
+ RDEBUG("Invalid text found at: %s", p);
+ return false;
+ }
+
+ *fill = *p;
+ }
+
+ *pvpt = vpt;
+ *plength = length;
+
+ return true;
+}
+
+
+/** left pad a string
+ *
+ * %{lpad:&Attribute-Name length 'x'}
+ */
+static ssize_t lpad_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char fill;
+ size_t pad;
+ ssize_t len;
+ vp_tmpl_t *vpt;
+
+ *out = '\0';
+ if (!parse_pad(request, fmt, &vpt, &pad, &fill)) {
+ return 0;
+ }
+
+ if (outlen <= pad) {
+ RWARN("Output is too short! Result will be truncated");
+ pad = outlen - 1;
+ }
+
+ /*
+ * Print the attribute (left justified). If it's too
+ * big, we're done.
+ */
+ len = tmpl_expand(NULL, out, pad + 1, request, vpt, NULL, NULL);
+ if (len <= 0) return 0;
+
+ if ((size_t) len >= pad) return pad;
+
+ /*
+ * We have to shift the string to the right, and pad with
+ * "fill" characters.
+ */
+ memmove(out + (pad - len), out, len + 1);
+ memset(out, fill, pad - len);
+
+ return pad;
+}
+
+
+/** right pad a string
+ *
+ * %{rpad:&Attribute-Name length 'x'}
+ */
+static ssize_t rpad_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ char fill;
+ size_t pad;
+ ssize_t len;
+ vp_tmpl_t *vpt;
+
+ *out = '\0';
+
+ if (!parse_pad(request, fmt, &vpt, &pad, &fill)) {
+ return 0;
+ }
+
+ if (outlen <= pad) {
+ RWARN("Output is too short! Result will be truncated");
+ pad = outlen - 1;
+ }
+
+ /*
+ * Print the attribute (left justified). If it's too
+ * big, we're done.
+ */
+ len = tmpl_expand(NULL, out, pad + 1, request, vpt, NULL, NULL);
+ if (len <= 0) return 0;
+
+ if ((size_t) len >= pad) return pad;
+
+ /*
+ * We have to pad with "fill" characters.
+ */
+ memset(out + len, fill, pad - len);
+ out[pad] = '\0';
+
+ return pad;
+}
+
+
+/*
+ * 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_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_expr_t *inst = instance;
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) {
+ inst->xlat_name = cf_section_name1(conf);
+ }
+
+ xlat_register(inst->xlat_name, expr_xlat, NULL, inst);
+
+ xlat_register("rand", rand_xlat, NULL, inst);
+ xlat_register("randstr", randstr_xlat, NULL, inst);
+ xlat_register("urlquote", urlquote_xlat, NULL, inst);
+ xlat_register("urlunquote", urlunquote_xlat, NULL, inst);
+ xlat_register("escape", escape_xlat, NULL, inst);
+ xlat_register("unescape", unescape_xlat, NULL, inst);
+ xlat_register("tolower", tolower_xlat, NULL, inst);
+ xlat_register("toupper", toupper_xlat, NULL, inst);
+ xlat_register("md4", md4_xlat, NULL, inst);
+ xlat_register("md5", md5_xlat, NULL, inst);
+ xlat_register("sha1", sha1_xlat, NULL, inst);
+#ifdef HAVE_OPENSSL_EVP_H
+ xlat_register("sha256", sha256_xlat, NULL, inst);
+ xlat_register("sha512", sha512_xlat, NULL, inst);
+#endif
+ xlat_register("hmacmd5", hmac_md5_xlat, NULL, inst);
+ xlat_register("hmacsha1", hmac_sha1_xlat, NULL, inst);
+ xlat_register("crypt", crypt_xlat, NULL, inst);
+ xlat_register("pairs", pairs_xlat, NULL, inst);
+
+ xlat_register("base64", base64_xlat, NULL, inst);
+ xlat_register("base64tohex", base64_to_hex_xlat, NULL, inst);
+
+ xlat_register("explode", explode_xlat, NULL, inst);
+
+ xlat_register("nexttime", next_time_xlat, NULL, inst);
+ xlat_register("lasttime", last_time_xlat, NULL, inst);
+ xlat_register("lpad", lpad_xlat, NULL, inst);
+ xlat_register("rpad", rpad_xlat, NULL, inst);
+
+ /*
+ * Initialize various paircompare functions
+ */
+ pair_builtincompare_add(instance);
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ *
+ * If the module needs to temporarily modify it's instantiation
+ * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ * The server will then take care of ensuring that the module
+ * is single-threaded.
+ */
+extern module_t rlm_expr;
+module_t rlm_expr = {
+ .magic = RLM_MODULE_INIT,
+ .name = "expr",
+ .inst_size = sizeof(rlm_expr_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+};
diff --git a/src/modules/rlm_expr/rlm_expr.h b/src/modules/rlm_expr/rlm_expr.h
new file mode 100644
index 0000000..7c0fa8a
--- /dev/null
+++ b/src/modules/rlm_expr/rlm_expr.h
@@ -0,0 +1,25 @@
+#ifndef _RLM_EXPR_H
+#define _RLM_EXPR_H
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2007 The FreeRADIUS server project
+ * Copyright 2007 Alan DeKok <aland@ox.org>
+ */
+RCSIDH(rlm_expr_h, "$Id$")
+
+void pair_builtincompare_add(void *instance);
+
+#endif
diff --git a/src/modules/rlm_files/README.md b/src/modules/rlm_files/README.md
new file mode 100644
index 0000000..36d0140
--- /dev/null
+++ b/src/modules/rlm_files/README.md
@@ -0,0 +1,13 @@
+# rlm_files
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Implements a traditional Livingston-style users file.
+
+Entries in the users file can check for certain attributes and
+values in the current request, and add new attributes if they're
+found.
diff --git a/src/modules/rlm_files/all.mk b/src/modules/rlm_files/all.mk
new file mode 100644
index 0000000..5a83c26
--- /dev/null
+++ b/src/modules/rlm_files/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_files.a
+SOURCES := rlm_files.c
diff --git a/src/modules/rlm_files/rlm_files.c b/src/modules/rlm_files/rlm_files.c
new file mode 100644
index 0000000..08679e6
--- /dev/null
+++ b/src/modules/rlm_files/rlm_files.c
@@ -0,0 +1,550 @@
+/*
+ * 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_files.c
+ * @brief Process simple 'users' policy files.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Jeff Carneal <jeff@apex.net>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+
+typedef struct rlm_files_t {
+ char const *compat_mode;
+
+ char const *key;
+
+ char const *filename;
+ rbtree_t *common;
+
+ /* autz */
+ char const *usersfile;
+ rbtree_t *users;
+
+
+ /* authenticate */
+ char const *auth_usersfile;
+ rbtree_t *auth_users;
+
+ /* preacct */
+ char const *acctusersfile;
+ rbtree_t *acctusers;
+
+#ifdef WITH_PROXY
+ /* pre-proxy */
+ char const *preproxy_usersfile;
+ rbtree_t *preproxy_users;
+
+ /* post-proxy */
+ char const *postproxy_usersfile;
+ rbtree_t *postproxy_users;
+#endif
+
+ /* post-authenticate */
+ char const *postauth_usersfile;
+ rbtree_t *postauth_users;
+} rlm_files_t;
+
+
+/*
+ * See if a VALUE_PAIR list contains Fall-Through = Yes
+ */
+static int fall_through(VALUE_PAIR *vp)
+{
+ VALUE_PAIR *tmp;
+ tmp = fr_pair_find_by_num(vp, PW_FALL_THROUGH, 0, TAG_ANY);
+
+ return tmp ? tmp->vp_integer : 0;
+}
+
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, filename), NULL },
+ { "usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, usersfile), NULL },
+ { "acctusersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, acctusersfile), NULL },
+#ifdef WITH_PROXY
+ { "preproxy_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, preproxy_usersfile), NULL },
+ { "postproxy_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, postproxy_usersfile), NULL },
+#endif
+ { "auth_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, auth_usersfile), NULL },
+ { "postauth_usersfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_files_t, postauth_usersfile), NULL },
+ { "compat", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_files_t, compat_mode), NULL },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_files_t, key), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static int pairlist_cmp(void const *a, void const *b)
+{
+ return strcmp(((PAIR_LIST const *)a)->name,
+ ((PAIR_LIST const *)b)->name);
+}
+
+static int getusersfile(TALLOC_CTX *ctx, char const *filename, rbtree_t **ptree, char const *compat_mode_str)
+{
+ int rcode;
+ PAIR_LIST *users = NULL;
+ PAIR_LIST *entry, *next;
+ PAIR_LIST *user_list, *default_list, **default_tail;
+ rbtree_t *tree;
+
+ if (!filename) {
+ *ptree = NULL;
+ return 0;
+ }
+
+ rcode = pairlist_read(ctx, filename, &users, 1);
+ if (rcode < 0) {
+ return -1;
+ }
+
+ /*
+ * Walk through the 'users' file list, if we're debugging,
+ * or if we're in compat_mode.
+ */
+ if ((rad_debug_lvl) ||
+ (compat_mode_str && (strcmp(compat_mode_str, "cistron") == 0))) {
+ VALUE_PAIR *vp;
+ bool compat_mode = false;
+
+ if (compat_mode_str && (strcmp(compat_mode_str, "cistron") == 0)) {
+ compat_mode = true;
+ }
+
+ entry = users;
+ while (entry) {
+ vp_cursor_t cursor;
+ if (compat_mode) {
+ DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...",
+ filename, entry->lineno,
+ entry->name);
+ }
+
+ /*
+ * Look for improper use of '=' in the
+ * check items. They should be using
+ * '==' for on-the-wire RADIUS attributes,
+ * and probably ':=' for server
+ * configuration items.
+ */
+ for (vp = fr_cursor_init(&cursor, &entry->check); vp; vp = fr_cursor_next(&cursor)) {
+ /*
+ * Ignore attributes which are set
+ * properly.
+ */
+ if (vp->op != T_OP_EQ) {
+ continue;
+ }
+
+ /*
+ * If it's a vendor attribute,
+ * or it's a wire protocol,
+ * ensure it has '=='.
+ */
+ if ((vp->da->vendor != 0) ||
+ (vp->da->attr < 0x100)) {
+ if (!compat_mode) {
+ WARN("[%s]:%d Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
+ filename, entry->lineno,
+ vp->da->name, vp->da->name,
+ entry->name);
+ } else {
+ DEBUG("\tChanging '%s =' to '%s =='",
+ vp->da->name, vp->da->name);
+ }
+ vp->op = T_OP_CMP_EQ;
+ continue;
+ }
+
+ /*
+ * Cistron Compatibility mode.
+ *
+ * Re-write selected attributes
+ * to be '+=', instead of '='.
+ *
+ * All others get set to '=='
+ */
+ if (compat_mode) {
+ /*
+ * Non-wire attributes become +=
+ *
+ * On the write attributes
+ * become ==
+ */
+ if ((vp->da->attr >= 0x100) &&
+ (vp->da->attr <= 0xffff) &&
+ (vp->da->attr != PW_HINT) &&
+ (vp->da->attr != PW_HUNTGROUP_NAME)) {
+ DEBUG("\tChanging '%s =' to '%s +='", vp->da->name, vp->da->name);
+
+ vp->op = T_OP_ADD;
+ } else {
+ DEBUG("\tChanging '%s =' to '%s =='", vp->da->name, vp->da->name);
+
+ vp->op = T_OP_CMP_EQ;
+ }
+ }
+ } /* end of loop over check items */
+
+ /*
+ * Look for server configuration items
+ * in the reply list.
+ *
+ * It's a common enough mistake, that it's
+ * worth doing.
+ */
+ for (vp = fr_cursor_init(&cursor, &entry->reply); vp; vp = fr_cursor_next(&cursor)) {
+ /*
+ * If it's NOT a vendor attribute,
+ * and it's NOT a wire protocol
+ * and we ignore Fall-Through,
+ * then bitch about it, giving a
+ * good warning message.
+ */
+ if ((vp->da->vendor == 0) &&
+ (vp->da->attr > 1000)) {
+ WARN("[%s]:%d Check item \"%s\"\n"
+ "\tfound in reply item list for user \"%s\".\n"
+ "\tThis attribute MUST go on the first line"
+ " with the other check items", filename, entry->lineno, vp->da->name,
+ entry->name);
+ }
+ }
+
+ entry = entry->next;
+ }
+ }
+
+ tree = rbtree_create(ctx, pairlist_cmp, NULL, RBTREE_FLAG_NONE);
+ if (!tree) {
+ pairlist_free(&users);
+ return -1;
+ }
+
+ default_list = NULL;
+ default_tail = &default_list;
+
+ /*
+ * We've read the entries in linearly, but putting them
+ * into an indexed data structure would be much faster.
+ * Let's go fix that now.
+ */
+ for (entry = users; entry != NULL; entry = next) {
+ /*
+ * Remove this entry from the input list.
+ */
+ next = entry->next;
+ entry->next = NULL;
+ (void) talloc_steal(tree, entry);
+
+ /*
+ * DEFAULT entries get their own list.
+ */
+ if (strcmp(entry->name, "DEFAULT") == 0) {
+ if (!default_list) {
+ default_list = entry;
+
+ /*
+ * Insert the first DEFAULT into the tree.
+ */
+ if (!rbtree_insert(tree, entry)) {
+ error:
+ pairlist_free(&entry);
+ pairlist_free(&next);
+ rbtree_free(tree);
+ return -1;
+ }
+
+ } else {
+ /*
+ * Tack this entry onto the tail
+ * of the DEFAULT list.
+ */
+ *default_tail = entry;
+ }
+
+ default_tail = &entry->next;
+ continue;
+ }
+
+ /*
+ * Not DEFAULT, must be a normal user.
+ */
+ user_list = rbtree_finddata(tree, entry);
+ if (!user_list) {
+ /*
+ * Insert the first one.
+ */
+ if (!rbtree_insert(tree, entry)) goto error;
+ } else {
+ /*
+ * Find the tail of this list, and add it
+ * there.
+ */
+ while (user_list->next) user_list = user_list->next;
+
+ user_list->next = entry;
+ }
+ }
+
+ *ptree = tree;
+
+ return 0;
+}
+
+
+
+/*
+ * (Re-)read the "users" file into memory.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_files_t *inst = instance;
+
+#undef READFILE
+#define READFILE(_x, _y) do { if (getusersfile(inst, inst->_x, &inst->_y, inst->compat_mode) != 0) { ERROR("Failed reading %s", inst->_x); return -1;} } while (0)
+
+ READFILE(filename, common);
+ READFILE(usersfile, users);
+ READFILE(acctusersfile, acctusers);
+
+#ifdef WITH_PROXY
+ READFILE(preproxy_usersfile, preproxy_users);
+ READFILE(postproxy_usersfile, postproxy_users);
+#endif
+
+ READFILE(auth_usersfile, auth_users);
+ READFILE(postauth_usersfile, postauth_users);
+
+ return 0;
+}
+
+/*
+ * Common code called by everything below.
+ */
+static rlm_rcode_t file_common(rlm_files_t *inst, REQUEST *request, char const *filename, rbtree_t *tree,
+ RADIUS_PACKET *request_packet, RADIUS_PACKET *reply_packet)
+{
+ char const *name;
+ VALUE_PAIR *check_tmp = NULL;
+ VALUE_PAIR *reply_tmp = NULL;
+ PAIR_LIST const *user_pl, *default_pl;
+ bool found = false;
+ PAIR_LIST my_pl;
+ char buffer[256];
+
+ /*
+ * Certain post-proxy fail situations can cause there not to be
+ * a valid request_packet to lookup check pairs in.
+ * Test here in case there are other situations where this happens.
+ */
+ if (!request_packet) return RLM_MODULE_NOOP;
+
+ if (!inst->key) {
+ VALUE_PAIR *namepair;
+
+ namepair = request->username;
+ name = namepair ? namepair->vp_strvalue : "NONE";
+ } else {
+ int len;
+
+ len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL);
+ if (len < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ name = len ? buffer : "NONE";
+ }
+
+ if (!tree) return RLM_MODULE_NOOP;
+
+ my_pl.name = name;
+ user_pl = rbtree_finddata(tree, &my_pl);
+ my_pl.name = "DEFAULT";
+ default_pl = rbtree_finddata(tree, &my_pl);
+
+ /*
+ * Find the entry for the user.
+ */
+ while (user_pl || default_pl) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ PAIR_LIST const *pl;
+
+ /*
+ * Figure out which entry to match on.
+ */
+ if (!default_pl && user_pl) {
+ pl = user_pl;
+ user_pl = user_pl->next;
+
+ } else if (!user_pl && default_pl) {
+ pl = default_pl;
+ default_pl = default_pl->next;
+
+ } else if (user_pl->order < default_pl->order) {
+ pl = user_pl;
+ user_pl = user_pl->next;
+
+ } else {
+ pl = default_pl;
+ default_pl = default_pl->next;
+ }
+
+ if (pl->check) {
+ check_tmp = fr_pair_list_copy(request, pl->check);
+ for (vp = fr_cursor_init(&cursor, &check_tmp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (radius_xlat_do(request, vp) < 0) {
+ RWARN("Failed parsing expanded value for check item, skipping entry: %s", fr_strerror());
+ fr_pair_list_free(&check_tmp);
+ continue;
+ }
+ }
+ }
+
+ if (paircompare(request, request_packet->vps, check_tmp, &reply_packet->vps) == 0) {
+ RDEBUG2("%s: Matched entry %s at line %d", filename, pl->name, pl->lineno);
+ found = true;
+
+ /* ctx may be reply or proxy */
+ reply_tmp = fr_pair_list_copy(reply_packet, pl->reply);
+ if (reply_tmp) radius_pairmove(request, &reply_packet->vps, reply_tmp, true);
+
+ fr_pair_list_move(request, &request->config, &check_tmp, T_OP_ADD);
+ fr_pair_list_free(&check_tmp);
+
+ /*
+ * Fallthrough?
+ */
+ if (!fall_through(pl->reply)) break;
+ }
+ }
+
+ /*
+ * Remove server internal parameters.
+ */
+ fr_pair_delete_by_num(&reply_packet->vps, PW_FALL_THROUGH, 0, TAG_ANY);
+
+ /*
+ * See if we succeeded.
+ */
+ if (!found) return RLM_MODULE_NOOP; /* on to the next module */
+
+ return RLM_MODULE_OK;
+
+}
+
+
+/*
+ * Find the named user in the database. Create the
+ * set of attribute-value pairs to check and reply with
+ * for this user from the database. The main 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_files_t *inst = instance;
+
+ return file_common(inst, request, "users",
+ inst->users ? inst->users : inst->common,
+ request->packet, request->reply);
+}
+
+
+/*
+ * Pre-Accounting - read the acct_users file for check_items and
+ * config. Reply items are Not Recommended(TM) in acct_users,
+ * except for Fallthrough, which should work
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
+{
+ rlm_files_t *inst = instance;
+
+ return file_common(inst, request, "acct_users",
+ inst->acctusers ? inst->acctusers : inst->common,
+ request->packet, request->reply);
+}
+
+#ifdef WITH_PROXY
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ rlm_files_t *inst = instance;
+
+ return file_common(inst, request, "preproxy_users",
+ inst->preproxy_users ? inst->preproxy_users : inst->common,
+ request->packet, request->proxy);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
+{
+ rlm_files_t *inst = instance;
+
+ return file_common(inst, request, "postproxy_users",
+ inst->postproxy_users ? inst->postproxy_users : inst->common,
+ request->proxy_reply, request->reply);
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_files_t *inst = instance;
+
+ return file_common(inst, request, "auth_users",
+ inst->auth_users ? inst->auth_users : inst->common,
+ request->packet, request->reply);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_files_t *inst = instance;
+
+ return file_common(inst, request, "postauth_users",
+ inst->postauth_users ? inst->postauth_users : inst->common,
+ request->packet, request->reply);
+}
+
+
+/* globally exported name */
+extern module_t rlm_files;
+module_t rlm_files = {
+ .magic = RLM_MODULE_INIT,
+ .name = "files",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_files_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
+
diff --git a/src/modules/rlm_idn/.gitignore b/src/modules/rlm_idn/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_idn/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_idn/README.md b/src/modules/rlm_idn/README.md
new file mode 100644
index 0000000..4ca5552
--- /dev/null
+++ b/src/modules/rlm_idn/README.md
@@ -0,0 +1,13 @@
+# rlm_idn
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Converts internationalized domain names to ASCII.
+
+Internationalized domain names can have multiple equivalent
+representations. The idn module converts all of those
+representations into one canonical ASCII format.
diff --git a/src/modules/rlm_idn/all.mk.in b/src/modules/rlm_idn/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_idn/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_idn/configure b/src/modules/rlm_idn/configure
new file mode 100755
index 0000000..bdde91a
--- /dev/null
+++ b/src/modules/rlm_idn/configure
@@ -0,0 +1,4306 @@
+#! /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_idn.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_idn
+'
+ 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_idn build without rlm_idn
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_idn
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_idn was given.
+if test "${with_rlm_idn+set}" = set; then :
+ withval=$with_rlm_idn;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_idn" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+sm_lib_safe=`echo "idn" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "idna_to_ascii_8z" | 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 idna_to_ascii_8z in -lidn in $try" >&5
+$as_echo_n "checking for idna_to_ascii_8z in -lidn in $try... " >&6; }
+ LIBS="-lidn $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char idna_to_ascii_8z();
+int
+main ()
+{
+idna_to_ascii_8z()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lidn"
+ 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 idna_to_ascii_8z in -lidn" >&5
+$as_echo_n "checking for idna_to_ascii_8z in -lidn... " >&6; }
+ LIBS="-lidn $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char idna_to_ascii_8z();
+int
+main ()
+{
+idna_to_ascii_8z()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lidn"
+ { $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 idna_to_ascii_8z in -lidn in $try" >&5
+$as_echo_n "checking for idna_to_ascii_8z in -lidn in $try... " >&6; }
+ LIBS="-lidn $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char idna_to_ascii_8z();
+int
+main ()
+{
+idna_to_ascii_8z()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lidn"
+ 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_idn_idna_to_ascii_8z" != "xyes"; then
+
+fail="$fail libidn"
+
+fi
+
+
+
+ac_safe=`echo "idna.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 idna.h in $try" >&5
+$as_echo_n "checking for idna.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <idna.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}/idna.h" >&5
+$as_echo_n "checking for ${_prefix}/idna.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <idna.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 idna.h" >&5
+$as_echo_n "checking for idna.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <idna.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 idna.h in $try" >&5
+$as_echo_n "checking for idna.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <idna.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_idna_h" != "yes"; then
+
+fail="$fail idna.h"
+
+fi
+
+
+ targetname=rlm_idn
+else
+ targetname=
+ echo \*\*\* module rlm_idn is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_idn to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_idn." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_idn." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_idn requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_idn requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/src/modules/rlm_idn/configure.ac b/src/modules/rlm_idn/configure.ac
new file mode 100644
index 0000000..7f713c2
--- /dev/null
+++ b/src/modules/rlm_idn/configure.ac
@@ -0,0 +1,32 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_idn.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_idn])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_SMART_CHECK_LIB(idn, idna_to_ascii_8z)
+if test "x$ac_cv_lib_idn_idna_to_ascii_8z" != "xyes"; then
+ FR_MODULE_FAIL([libidn])
+fi
+
+FR_SMART_CHECK_INCLUDE(idna.h)
+if test "$ac_cv_header_idna_h" != "yes"; then
+ FR_MODULE_FAIL([idna.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
+
diff --git a/src/modules/rlm_idn/rlm_idn.c b/src/modules/rlm_idn/rlm_idn.c
new file mode 100644
index 0000000..c0ce436
--- /dev/null
+++ b/src/modules/rlm_idn/rlm_idn.c
@@ -0,0 +1,158 @@
+/*
+ * 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_idn.c
+ * @brief Internationalized Domain Name encoding for DNS aka IDNA aka RFC3490
+ *
+ * @copyright 2013 Brian S. Julin <bjulin@clarku.edu>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include <idna.h>
+
+/*
+ * Structure for module configuration
+ */
+typedef struct rlm_idn_t {
+ char const *xlat_name;
+ bool use_std3_ascii_rules;
+ bool allow_unassigned;
+} rlm_idn_t;
+
+/*
+ * The primary use case for this module is DNS-safe encoding of realms
+ * appearing in requests for a DDDS scheme. Some notes on that usage
+ * scenario:
+ *
+ * RFC2865 5.1 User-Name may be one of:
+ *
+ * 1) UTF-8 text: in which case this conversion is needed
+ *
+ * 2) realm part of an NAI: in which case this conversion should do nothing
+ * since only ASCII digits, ASCII alphas, ASCII dots, and ASCII hyphens
+ * are allowed.
+ *
+ * 3) "A name in ASN.1 form used in Public Key authentication systems.":
+ * I count four things in that phrase that are rather ... vague.
+ * However, most X.509 docs yell at you to IDNA internationalized
+ * domain names to IA5String, so if it is coming from inside an X.509
+ * certificate IDNA should be idempotent in the encode direction.
+ *
+ * Except for that last loophole, which we will leave up to the user
+ * to sort out, we should be safe in processing the realm as UTF-8.
+ */
+
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER mod_config[] = {
+ /*
+ * If a STRINGPREP profile other than NAMEPREP is ever desired,
+ * we can implement an option, and it will default to NAMEPREP settings.
+ * ...and if we want raw punycode or to tweak Bootstring parameters,
+ * we can do similar things. All defaults should result in IDNA
+ * ToASCII with the use_std3_ascii_rules flag set, allow_unassigned unset,
+ * because that is the forseeable use case.
+ *
+ * Note that doing anything much different will require choosing the
+ * appropriate libidn API functions, as we currently call the IDNA
+ * convenience functions.
+ *
+ * Also note that right now we do not provide ToUnicode, which may or
+ * may not be useful as an xlat... depends on how the results need to
+ * be used.
+ */
+
+ { "allow_unassigned", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, allow_unassigned), "no" },
+ { "use_std3_ascii_rules", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_idn_t, use_std3_ascii_rules), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+static ssize_t xlat_idna(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_idn_t *inst = instance;
+ char *idna = NULL;
+ int res;
+ size_t len;
+ int flags = 0;
+
+ if (inst->use_std3_ascii_rules) {
+ flags |= IDNA_USE_STD3_ASCII_RULES;
+ }
+ if (inst->allow_unassigned) {
+ flags |= IDNA_ALLOW_UNASSIGNED;
+ }
+
+ res = idna_to_ascii_8z(fmt, &idna, flags);
+ if (res) {
+ if (idna) {
+ free (idna); /* Docs unclear, be safe. */
+ }
+
+ REDEBUG("%s", idna_strerror(res));
+ return -1;
+ }
+
+ len = strlen(idna);
+
+ /* 253 is max DNS length */
+ if (!((len < (freespace - 1)) && (len <= 253))) {
+ /* Never provide a truncated result, as it may be queried. */
+ REDEBUG("Conversion was truncated");
+
+ free(idna);
+ return -1;
+
+ }
+
+ strlcpy(out, idna, freespace);
+ free(idna);
+
+ return len;
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_idn_t *inst = instance;
+ char const *xlat_name;
+
+ xlat_name = cf_section_name2(conf);
+ if (!xlat_name) {
+ xlat_name = cf_section_name1(conf);
+ }
+
+ inst->xlat_name = xlat_name;
+
+ xlat_register(inst->xlat_name, xlat_idna, NULL, inst);
+
+ return 0;
+}
+
+extern module_t rlm_idn;
+module_t rlm_idn = {
+ .magic = RLM_MODULE_INIT,
+ .name = "idn",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_idn_t),
+ .config = mod_config,
+ .bootstrap = mod_bootstrap
+};
diff --git a/src/modules/rlm_ippool/.gitignore b/src/modules/rlm_ippool/.gitignore
new file mode 100644
index 0000000..ea4a919
--- /dev/null
+++ b/src/modules/rlm_ippool/.gitignore
@@ -0,0 +1,3 @@
+all.mk
+config.h
+rlm_ippool_tool
diff --git a/src/modules/rlm_ippool/README.md b/src/modules/rlm_ippool/README.md
new file mode 100644
index 0000000..13c6275
--- /dev/null
+++ b/src/modules/rlm_ippool/README.md
@@ -0,0 +1,11 @@
+# rlm_ippool
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Server support for IP address pools based on local files. This
+uses a GDBM database and as such using the `rlm_sqlippool` module
+instead of this is recommended.
diff --git a/src/modules/rlm_ippool/all.mk.in b/src/modules/rlm_ippool/all.mk.in
new file mode 100644
index 0000000..9c70ab4
--- /dev/null
+++ b/src/modules/rlm_ippool/all.mk.in
@@ -0,0 +1,12 @@
+#
+# $Id$
+#
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+SUBMAKEFILES := rlm_ippool.mk rlm_ippool_tool.mk
+
+# Used by SUBMAKEFILES
+rlm_ippool_CFLAGS := @mod_cflags@
+rlm_ippool_LDLIBS := @mod_ldflags@
+endif
diff --git a/src/modules/rlm_ippool/config.h.in b/src/modules/rlm_ippool/config.h.in
new file mode 100644
index 0000000..8a4b8b4
--- /dev/null
+++ b/src/modules/rlm_ippool/config.h.in
@@ -0,0 +1,7 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* do we have gdbm_fdesc */
+#undef HAVE_GDBM_FDESC
+
+/* do we need GDBM_SYNC */
+#undef NEED_GDBM_SYNC
diff --git a/src/modules/rlm_ippool/configure b/src/modules/rlm_ippool/configure
new file mode 100755
index 0000000..9cfa745
--- /dev/null
+++ b/src/modules/rlm_ippool/configure
@@ -0,0 +1,4679 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_ippool.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+ippool_install
+ippool_utils
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_ippool
+'
+ 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_ippool build without rlm_ippool
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_ippool
+echo
+
+
+# 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_ippool was given.
+if test "${with_rlm_ippool+set}" = set; then :
+ withval=$with_rlm_ippool;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_ippool" != 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
+
+
+
+
+
+ac_safe=`echo "gdbm.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 gdbm.h in $try" >&5
+$as_echo_n "checking for gdbm.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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}/gdbm.h" >&5
+$as_echo_n "checking for ${_prefix}/gdbm.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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 gdbm.h" >&5
+$as_echo_n "checking for gdbm.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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 gdbm.h in $try" >&5
+$as_echo_n "checking for gdbm.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <gdbm.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=
+
+
+
+sm_lib_safe=`echo "gdbm" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "gdbm_open" | 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 gdbm_open in -lgdbm in $try" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm in $try... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ 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 gdbm_open in -lgdbm" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ { $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 gdbm_open in -lgdbm in $try" >&5
+$as_echo_n "checking for gdbm_open in -lgdbm in $try... " >&6; }
+ LIBS="-lgdbm $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char gdbm_open();
+int
+main ()
+{
+gdbm_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lgdbm"
+ 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_gdbm_gdbm_open" != "xyes"; then
+
+fail="$fail libgdbm"
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see GDBM_SYNC status" >&5
+$as_echo_n "checking to see GDBM_SYNC status... " >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <gdbm.h>
+#ifdef GDBM_SYNC
+ found-gdbm-sync!
+#else
+ not found. This version must use sync by default.
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "found-gdbm-sync" >/dev/null 2>&1; then :
+
+
+$as_echo "#define NEED_GDBM_SYNC yes" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: needs it." >&5
+$as_echo "needs it." >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: SYNCs by default." >&5
+$as_echo "SYNCs by default." >&6; }
+
+
+fi
+rm -f conftest*
+
+fi
+
+old_LIBS=$LIBS
+LIBS="$LIBS $SMART_LIBS"
+ac_fn_c_check_func "$LINENO" "gdbm_fdesc" "ac_cv_func_gdbm_fdesc"
+if test "x$ac_cv_func_gdbm_fdesc" = xyes; then :
+
+fi
+
+if test "x$ac_cv_func_gdbm_fdesc" = "xyes";
+then
+
+$as_echo "#define HAVE_GDBM_FDESC /**/" >>confdefs.h
+
+fi
+LIBS=$old_LIBS
+
+
+ targetname=rlm_ippool
+else
+ targetname=
+ echo \*\*\* module rlm_ippool is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_ippool to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_ippool." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_ippool." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_ippool requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_ippool requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+if test x"$fail" = x""; then :
+
+ ippool_utils="rlm_ippool_tool"
+ ippool_install="rlm_ippool_install"
+
+fi
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_ippool/configure.ac b/src/modules/rlm_ippool/configure.ac
new file mode 100644
index 0000000..c5ad38b
--- /dev/null
+++ b/src/modules/rlm_ippool/configure.ac
@@ -0,0 +1,60 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_ippool.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_ippool])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_SMART_CHECK_INCLUDE(gdbm.h)
+FR_SMART_CHECK_LIB(gdbm, gdbm_open)
+if test "x$ac_cv_lib_gdbm_gdbm_open" != "xyes"; then
+ FR_MODULE_FAIL([libgdbm])
+else
+ AC_MSG_CHECKING(to see GDBM_SYNC status)
+ AC_EGREP_CPP(found-gdbm-sync, [
+#include <gdbm.h>
+#ifdef GDBM_SYNC
+ found-gdbm-sync!
+#else
+ not found. This version must use sync by default.
+#endif
+ ], [
+ AC_DEFINE(NEED_GDBM_SYNC, yes, [do we need GDBM_SYNC])
+ AC_MSG_RESULT(needs it.)
+ ], [
+ AC_MSG_RESULT(SYNCs by default.)
+ ]
+ )
+fi
+
+old_LIBS=$LIBS
+LIBS="$LIBS $SMART_LIBS"
+AC_CHECK_FUNC(gdbm_fdesc)
+if test "x$ac_cv_func_gdbm_fdesc" = "xyes";
+then
+ AC_DEFINE(HAVE_GDBM_FDESC, [], [do we have gdbm_fdesc])
+fi
+LIBS=$old_LIBS
+
+FR_MODULE_END_TESTS
+
+FR_MODULE_TEST_PASS_DO([
+ ippool_utils="rlm_ippool_tool"
+ ippool_install="rlm_ippool_install"
+])
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+AC_SUBST(ippool_utils)
+AC_SUBST(ippool_install)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_ippool/rlm_ippool.c b/src/modules/rlm_ippool/rlm_ippool.c
new file mode 100644
index 0000000..e289bc2
--- /dev/null
+++ b/src/modules/rlm_ippool/rlm_ippool.c
@@ -0,0 +1,834 @@
+/*
+ * 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_ippool.c
+ * @brief Allocates an IPv4 address from a pool stored in a GDBM database.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2002 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "config.h"
+#include <ctype.h>
+
+#ifdef WITH_DHCP
+#include <freeradius-devel/dhcp.h>
+#endif
+
+#include "../../include/md5.h"
+
+#include <gdbm.h>
+
+#ifdef NEEDS_GDBM_SYNC
+# define GDBM_SYNCOPT GDBM_SYNC
+#else
+# define GDBM_SYNCOPT 0
+#endif
+
+#ifdef GDBM_NOLOCK
+#define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT | GDBM_NOLOCK)
+#else
+#define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT)
+#endif
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_ippool_t {
+ char const *filename;
+ char const *ip_index;
+ char const *name;
+ char const *key;
+
+ fr_ipaddr_t range_start_addr;
+ fr_ipaddr_t range_stop_addr;
+ fr_ipaddr_t netmask_addr;
+ uint32_t range_start;
+ uint32_t range_stop;
+ uint32_t netmask;
+
+ uint32_t max_timeout;
+ uint32_t cache_size;
+ bool override;
+ GDBM_FILE gdbm;
+ GDBM_FILE ip;
+#ifdef HAVE_PTHREAD_H
+ pthread_mutex_t op_mutex;
+#endif
+} rlm_ippool_t;
+
+#ifndef HAVE_PTHREAD_H
+/*
+ * This is easier than ifdef's throughout the code.
+ */
+#define pthread_mutex_init(_x, _y)
+#define pthread_mutex_destroy(_x)
+#define pthread_mutex_lock(_x)
+#define pthread_mutex_unlock(_x)
+#endif
+
+typedef struct ippool_info {
+ uint32_t ipaddr;
+ char active;
+ char cli[32];
+ char extra;
+ time_t timestamp;
+ time_t timeout;
+} ippool_info;
+
+typedef struct ippool_key {
+ char key[16];
+} ippool_key;
+
+static const CONF_PARSER module_config[] = {
+ { "session-db", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_DEPRECATED, rlm_ippool_t, filename), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_ippool_t, filename), NULL },
+
+ { "ip-index", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_ippool_t, ip_index), NULL },
+ { "ip_index", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_ippool_t, ip_index), NULL },
+
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_ippool_t, key), "%{NAS-IP-Address} %{NAS-Port}" },
+
+ { "range-start", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR | PW_TYPE_DEPRECATED, rlm_ippool_t, range_start_addr), NULL },
+ { "range_start", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, range_start_addr), "0" },
+
+ { "range-stop", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR | PW_TYPE_DEPRECATED, rlm_ippool_t, range_stop_addr), NULL },
+ { "range_stop", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, range_stop_addr), "0" },
+
+ { "netmask", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_ippool_t, netmask_addr), "0" },
+
+ { "cache-size", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_ippool_t, cache_size), NULL },
+ { "cache_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ippool_t, cache_size), "1000" },
+
+ { "override", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ippool_t, override), "no" },
+
+ { "maximum-timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_ippool_t, max_timeout), NULL },
+ { "maximum_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ippool_t, max_timeout), "0" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * 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_ippool_t *inst = instance;
+ int cache_size;
+ ippool_info entry;
+ ippool_key key;
+ datum key_datum;
+ datum data_datum;
+
+ char const *cli = "0";
+ char const *pool_name = NULL;
+
+ int rcode;
+ uint32_t i, j;
+ uint32_t or_result;
+ char str[32];
+ char init_str[17];
+
+ /*
+ * Add the ip pool name
+ */
+ inst->name = NULL;
+ pool_name = cf_section_name2(conf);
+ if (pool_name != NULL) {
+ inst->name = talloc_typed_strdup(inst, pool_name);
+ }
+
+ cache_size = inst->cache_size;
+
+ rad_assert(inst->filename && *inst->filename);
+ rad_assert(inst->ip_index && *inst->ip_index);
+
+ inst->range_start = htonl(*((uint32_t *)(&(inst->range_start_addr.ipaddr.ip4addr))));
+ inst->range_stop = htonl(*((uint32_t *)(&(inst->range_stop_addr.ipaddr.ip4addr))));
+ inst->netmask = htonl(*((uint32_t *)(&(inst->netmask_addr.ipaddr.ip4addr))));
+ if (inst->range_start == 0 || inst->range_stop == 0 || \
+ inst->range_start >= inst->range_stop ) {
+ cf_log_err_cs(conf, "Invalid data range");
+ return -1;
+ }
+
+ {
+ char *file;
+
+ memcpy(&file, &inst->filename, sizeof(file));
+ inst->gdbm = gdbm_open(file, sizeof(int),
+ GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ }
+
+ if (!inst->gdbm) {
+ ERROR("rlm_ippool: Failed to open file %s: %s", inst->filename, fr_syserror(errno));
+
+ return -1;
+ }
+
+ {
+ char *file;
+
+ memcpy(&file, &inst->ip_index, sizeof(file));
+ inst->ip = gdbm_open(file, sizeof(int),
+ GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
+ }
+
+ if (!inst->ip) {
+ ERROR("rlm_ippool: Failed to open file %s: %s", inst->ip_index, fr_syserror(errno));
+
+ return -1;
+ }
+
+ if (gdbm_setopt(inst->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1) {
+ ERROR("rlm_ippool: Failed to set cache size");
+ }
+
+ if (gdbm_setopt(inst->ip, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1) {
+ ERROR("rlm_ippool: Failed to set cache size");
+ }
+
+ pthread_mutex_init(&inst->op_mutex, NULL);
+
+ key_datum = gdbm_firstkey(inst->gdbm);
+ if (key_datum.dptr) {
+ free(key_datum.dptr);
+ return 0;
+ }
+
+ /*
+ * If the database does not exist initialize it.
+ * We set the nas/port pairs to not existent values and
+ * active = 0
+ */
+ DEBUG("rlm_ippool: Initializing database");
+ for (i = inst->range_start, j=~0; i <= inst->range_stop; i++, j--){
+ /*
+ * Net and Broadcast addresses are excluded
+ */
+ or_result = i | inst->netmask;
+ if (~inst->netmask != 0 && (or_result == inst->netmask || (~or_result == 0))) {
+ DEBUG("rlm_ippool: IP %s excluded", ip_ntoa(str, ntohl(i)));
+ continue;
+ }
+
+ sprintf(init_str,"%016d",j);
+ DEBUG("rlm_ippool: Initialized bucket: %s",init_str);
+ memcpy(key.key, init_str,16);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+
+ entry.ipaddr = ntohl(i);
+ entry.active = 0;
+ entry.extra = 0;
+ entry.timestamp = 0;
+ entry.timeout = 0;
+ strcpy(entry.cli,cli);
+
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ ERROR("rlm_ippool: Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ gdbm_close(inst->gdbm);
+ gdbm_close(inst->ip);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/** Decrease allocated count from the ip index
+ *
+ */
+static int decrease_allocated_count(rlm_ippool_t *inst, REQUEST *request, ippool_info *entry, datum *save_datum)
+{
+ datum data_datum;
+ datum key_datum;
+ int num;
+
+
+ key_datum.dptr = (char *) &(entry->ipaddr);
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(inst->ip, key_datum);
+ if (!data_datum.dptr) {
+ return 0;
+ }
+ memcpy(&num, data_datum.dptr, sizeof(int));
+ free(data_datum.dptr);
+ if (num > 0){
+ int rcode;
+
+ num--;
+
+ RDEBUG("Allocated count now: %i", num);
+ data_datum.dptr = (char *) &num;
+ data_datum.dsize = sizeof(int);
+ rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ RDEBUG("Failed storing data to %s: %s", inst->ip_index, gdbm_strerror(gdbm_errno));
+ return -1;
+ }
+ if ((num > 0) && entry->extra == 1){
+ /*
+ * We are doing MPPP and we still have nas/port entries referencing
+ * this ip. Delete this entry so that eventually we only keep one
+ * reference to this ip.
+ */
+ gdbm_delete(inst->gdbm, *save_datum);
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Check for an Accounting-Stop
+ * If we find one and we have allocated an IP to this nas/port combination, deallocate it.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_ippool_t *inst = instance;
+
+ datum key_datum;
+ ippool_key key;
+ datum data_datum;
+ ippool_info entry;
+ datum save_datum;
+
+ int rcode;
+ VALUE_PAIR *vp;
+
+ char str[32];
+ uint8_t key_str[17];
+ char hex_str[35];
+ char xlat_str[MAX_STRING_LEN];
+ int ret;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
+ if (!vp) {
+ RDEBUG2("Could not find account status type in packet");
+ return RLM_MODULE_INVALID;
+ }
+
+ switch (vp->vp_integer) {
+ case PW_STATUS_STOP:
+ {
+ FR_MD5_CTX md5_context;
+ if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, (uint8_t *)xlat_str, strlen(xlat_str));
+ fr_md5_final(key_str, &md5_context);
+ fr_md5_destroy(&md5_context);
+
+ key_str[16] = '\0';
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+
+ RDEBUG2("MD5 on 'key' directive maps to: %s", hex_str);
+ memcpy(key.key, key_str, 16);
+ break;
+ }
+
+ default:
+ /* We don't care about any other accounting packet */
+ RDEBUG2("This is not an Accounting-Stop");
+
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("Searching for an entry for key: '%s'", xlat_str);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+
+ pthread_mutex_lock(&inst->op_mutex);
+ data_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (data_datum.dptr == NULL) {
+ pthread_mutex_unlock(&inst->op_mutex);
+ RDEBUG2("Entry not found");
+
+ return RLM_MODULE_NOTFOUND;
+ }
+
+ /*
+ * If the entry was found set active to zero
+ */
+ memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
+
+ RDEBUG("Deallocated entry for ip: %s", ip_ntoa(str, entry.ipaddr));
+ entry.active = 0;
+ entry.timestamp = 0;
+ entry.timeout = 0;
+
+ /*
+ * Save the reference to the entry
+ */
+ save_datum.dptr = key_datum.dptr;
+ save_datum.dsize = key_datum.dsize;
+
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ pthread_mutex_unlock(&inst->op_mutex);
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Decrease allocated count from the ip index
+ */
+ ret = decrease_allocated_count(inst, request, &entry, &save_datum);
+ pthread_mutex_unlock(&inst->op_mutex);
+ if (ret < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_ippool_t *inst = instance;
+
+ datum key_datum;
+ ippool_key key;
+ datum nextkey;
+ datum data_datum;
+ ippool_info entry;
+ datum save_datum;
+
+ int delete = 0;
+ bool found = false;
+ int mppp = 0;
+ int extra = 0;
+ int rcode;
+ int num = 0;
+
+ VALUE_PAIR *vp;
+ char const *cli = NULL;
+ char str[32];
+ uint8_t key_str[17];
+ char hex_str[35];
+ char xlat_str[MAX_STRING_LEN];
+ FR_MD5_CTX md5_context;
+
+#ifdef WITH_DHCP
+ bool dhcp = false;
+#endif
+ int attr_ipaddr = PW_FRAMED_IP_ADDRESS;
+ int attr_ipmask = PW_FRAMED_IP_NETMASK;
+ int vendor_ipaddr = 0;
+
+ /*
+ * Check if Pool-Name attribute exists. If it exists check our name and
+ * run only if they match
+ */
+ vp = fr_pair_find_by_num(request->config, PW_POOL_NAME, 0, TAG_ANY);
+ if (vp != NULL){
+ if (!inst->name || (strcmp(inst->name,vp->vp_strvalue) && strcmp(vp->vp_strvalue,"DEFAULT")))
+ return RLM_MODULE_NOOP;
+ } else {
+ RDEBUG("Could not find Pool-Name attribute");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Find the caller id
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY);
+ if (vp != NULL) {
+ cli = vp->vp_strvalue;
+ }
+
+#ifdef WITH_DHCP
+ if (request->listener->type == RAD_LISTEN_DHCP) {
+ dhcp = 1;
+ attr_ipaddr = PW_DHCP_YOUR_IP_ADDRESS;
+ vendor_ipaddr = DHCP_MAGIC_VENDOR;
+ attr_ipmask = PW_DHCP_SUBNET_MASK;
+ }
+#endif
+
+ if (radius_xlat(xlat_str, sizeof(xlat_str), request, inst->key, NULL, NULL) < 0){
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, (uint8_t *)xlat_str, strlen(xlat_str));
+ fr_md5_final(key_str, &md5_context);
+ fr_md5_destroy(&md5_context);
+ key_str[16] = '\0';
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+
+ RDEBUG("MD5 on 'key' directive maps to: %s", hex_str);
+ memcpy(key.key, key_str, 16);
+
+ RDEBUG("Searching for an entry for key: '%s'", hex_str);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+
+ pthread_mutex_lock(&inst->op_mutex);
+ data_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (data_datum.dptr != NULL){
+ /*
+ * If there is a corresponding entry in the database with active=1 it is stale.
+ * Set active to zero
+ */
+ found = true;
+ memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
+
+ if (entry.active){
+ int ret;
+ RDEBUG("Found a stale entry for ip: %s",ip_ntoa(str,entry.ipaddr));
+ entry.active = 0;
+ entry.timestamp = 0;
+ entry.timeout = 0;
+
+ /*
+ * Save the reference to the entry
+ */
+ save_datum.dptr = key_datum.dptr;
+ save_datum.dsize = key_datum.dsize;
+
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&inst->op_mutex);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Decrease allocated count for the ip
+ */
+ ret = decrease_allocated_count(inst, request, &entry, &save_datum);
+ pthread_mutex_unlock(&inst->op_mutex);
+ if (ret < 0) {
+ return RLM_MODULE_FAIL;
+ }
+ }
+ }
+
+ pthread_mutex_unlock(&inst->op_mutex);
+
+ /*
+ * If there is a Framed-IP-Address (or Dhcp-Your-IP-Address)
+ * attribute in the reply, check for override
+ */
+ if (fr_pair_find_by_num(request->reply->vps, attr_ipaddr, vendor_ipaddr, TAG_ANY) != NULL) {
+ RDEBUG("Found IP address attribute in reply attribute list");
+ if (!inst->override) {
+ RDEBUG("override is set to no. Return NOOP");
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG("Override supplied IP address");
+ fr_pair_delete_by_num(&request->reply->vps, attr_ipaddr, vendor_ipaddr, TAG_ANY);
+ }
+
+ /*
+ * Walk through the database searching for an active=0 entry.
+ * We search twice. Once to see if we have an active entry with the same caller_id
+ * so that MPPP can work ok and then once again to find a free entry.
+ */
+ pthread_mutex_lock(&inst->op_mutex);
+ key_datum.dptr = NULL;
+ if (cli != NULL){
+ key_datum = gdbm_firstkey(inst->gdbm);
+ while (key_datum.dptr) {
+ data_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (data_datum.dptr){
+ memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
+ /*
+ * If we find an entry for the same caller-id with active=1
+ * then we use that for multilink (MPPP) to work properly.
+ */
+ if (strcmp(entry.cli,cli) == 0 && entry.active){
+ mppp = 1;
+ break;
+ }
+ }
+
+ nextkey = gdbm_nextkey(inst->gdbm, key_datum);
+ free(key_datum.dptr);
+ key_datum = nextkey;
+ }
+ }
+
+ if (!key_datum.dptr){
+ key_datum = gdbm_firstkey(inst->gdbm);
+ while(key_datum.dptr){
+ data_datum = gdbm_fetch(inst->gdbm, key_datum);
+ if (data_datum.dptr){
+ memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
+
+ /*
+ * Find an entry with active == 0
+ * or an entry that has expired
+ */
+ if (entry.active == 0 || (entry.timestamp && ((entry.timeout &&
+ request->timestamp >= (entry.timestamp + entry.timeout)) ||
+ (inst->max_timeout && request->timestamp >= (entry.timestamp + inst->max_timeout))))){
+ datum tmp;
+
+ tmp.dptr = (char *) &entry.ipaddr;
+ tmp.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(inst->ip, tmp);
+
+ /*
+ * If we find an entry in the ip index and the number is zero (meaning
+ * that we haven't allocated the same ip address to another nas/port pair)
+ * or if we don't find an entry then delete the session entry so
+ * that we can change the key
+ * Else we don't delete the session entry since we haven't yet deallocated the
+ * corresponding ip address and we continue our search.
+ */
+
+ if (data_datum.dptr){
+ memcpy(&num,data_datum.dptr, sizeof(int));
+ free(data_datum.dptr);
+ if (num == 0){
+ delete = 1;
+ break;
+ }
+ }
+ else{
+ delete = 1;
+ break;
+ }
+ }
+ }
+ nextkey = gdbm_nextkey(inst->gdbm, key_datum);
+ free(key_datum.dptr);
+ key_datum = nextkey;
+ }
+ }
+ /*
+ * If we have found a free entry set active to 1 then add a Framed-IP-Address attribute to
+ * the reply
+ * We keep the operation mutex locked until after we have set the corresponding entry active
+ */
+ if (key_datum.dptr){
+ if (found && !mppp){
+ /*
+ * Found == 1 means we have the nas/port combination entry in our database
+ * We exchange the ip address between the nas/port entry and the free entry
+ * Afterwards we will save the free ip address to the nas/port entry.
+ * That is:
+ * ---------------------------------------------
+ * - NAS/PORT Entry |||| Free Entry ||| Time
+ * - IP1 IP2(Free) BEFORE
+ * - IP2(Free) IP1 AFTER
+ * ---------------------------------------------
+ *
+ * We only do this if we are NOT doing MPPP
+ *
+ */
+ datum key_datum_tmp;
+ datum data_datum_tmp;
+ ippool_key key_tmp;
+
+ memcpy(key_tmp.key,key_str,16);
+ key_datum_tmp.dptr = (char *) &key_tmp;
+ key_datum_tmp.dsize = sizeof(ippool_key);
+
+ data_datum_tmp = gdbm_fetch(inst->gdbm, key_datum_tmp);
+ if (data_datum_tmp.dptr != NULL){
+
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum_tmp, GDBM_REPLACE);
+ free(data_datum_tmp.dptr);
+ if (rcode < 0) {
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&inst->op_mutex);
+ return RLM_MODULE_FAIL;
+ }
+ }
+ } else{
+ /*
+ * We have not found the nas/port combination
+ */
+ if (delete) {
+ /*
+ * Delete the entry so that we can change the key
+ * All is well. We delete one entry and we add one entry
+ */
+ gdbm_delete(inst->gdbm, key_datum);
+ } else{
+ /*
+ * We are doing MPPP. (mppp should be 1)
+ * We don't do anything.
+ * We will create an extra not needed entry in the database in this case
+ * but we don't really care since we always also use the ip_index database
+ * when we search for a free entry.
+ * We will also delete that entry on the accounting section so that we only
+ * have one nas/port entry referencing each ip
+ */
+ if (mppp) {
+ extra = 1;
+ }
+ if (!mppp) {
+ REDEBUG("mppp is not one. Please report this behaviour");
+ }
+ }
+ }
+ free(key_datum.dptr);
+ entry.active = 1;
+ entry.timestamp = request->timestamp;
+ if ((vp = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY)) != NULL) {
+ entry.timeout = (time_t) vp->vp_integer;
+#ifdef WITH_DHCP
+ if (dhcp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ PW_DHCP_IP_ADDRESS_LEASE_TIME, DHCP_MAGIC_VENDOR);
+ vp->vp_integer = entry.timeout;
+ fr_pair_delete_by_num(&request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ }
+#endif
+ } else {
+ entry.timeout = 0;
+ }
+ if (extra) {
+ entry.extra = 1;
+ }
+
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+ memcpy(key.key, key_str, 16);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+
+ RDEBUG2("Allocating ip to key: '%s'",hex_str);
+ rcode = gdbm_store(inst->gdbm, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ REDEBUG("Failed storing data to %s: %s", inst->filename, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&inst->op_mutex);
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Increase the ip index count */
+ key_datum.dptr = (char *) &entry.ipaddr;
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(inst->ip, key_datum);
+ if (data_datum.dptr){
+ memcpy(&num,data_datum.dptr,sizeof(int));
+ free(data_datum.dptr);
+ } else {
+ num = 0;
+ }
+
+ num++;
+ RDEBUG("num: %d",num);
+ data_datum.dptr = (char *) &num;
+ data_datum.dsize = sizeof(int);
+ rcode = gdbm_store(inst->ip, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ REDEBUG("Failed storing data to %s: %s", inst->ip_index, gdbm_strerror(gdbm_errno));
+ pthread_mutex_unlock(&inst->op_mutex);
+ return RLM_MODULE_FAIL;
+ }
+ pthread_mutex_unlock(&inst->op_mutex);
+
+ RDEBUG("Allocated ip %s to client key: %s",ip_ntoa(str,entry.ipaddr),hex_str);
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ attr_ipaddr, vendor_ipaddr);
+ vp->vp_ipaddr = entry.ipaddr;
+
+ /*
+ * If there is no Framed-Netmask attribute in the
+ * reply, add one
+ */
+ if (fr_pair_find_by_num(request->reply->vps, attr_ipmask, vendor_ipaddr, TAG_ANY) == NULL) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ attr_ipmask, vendor_ipaddr);
+ vp->vp_ipaddr = ntohl(inst->netmask);
+ }
+
+ }
+ else{
+ pthread_mutex_unlock(&inst->op_mutex);
+ RDEBUG("No available ip addresses in pool");
+ return RLM_MODULE_NOTFOUND;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static int mod_detach(void *instance)
+{
+ rlm_ippool_t *inst = instance;
+
+ gdbm_close(inst->gdbm);
+ gdbm_close(inst->ip);
+ pthread_mutex_destroy(&inst->op_mutex);
+ 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_ippool;
+module_t rlm_ippool = {
+ .magic = RLM_MODULE_INIT,
+ .name = "ippool",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_ippool_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_ippool/rlm_ippool.mk b/src/modules/rlm_ippool/rlm_ippool.mk
new file mode 100644
index 0000000..566adfa
--- /dev/null
+++ b/src/modules/rlm_ippool/rlm_ippool.mk
@@ -0,0 +1,9 @@
+#
+# $Id$
+#
+
+SOURCES := rlm_ippool.c
+TARGET := rlm_ippool.a
+
+SRC_CFLAGS := $(rlm_ippool_CFLAGS)
+TGT_LDLIBS := $(rlm_ippool_LDLIBS)
diff --git a/src/modules/rlm_ippool/rlm_ippool_tool.8 b/src/modules/rlm_ippool/rlm_ippool_tool.8
new file mode 100644
index 0000000..61383e5
--- /dev/null
+++ b/src/modules/rlm_ippool/rlm_ippool_tool.8
@@ -0,0 +1,122 @@
+.TH RLM_IPPOOL_TOOL 8
+.SH NAME
+rlm_ippool_tool - dump the contents of the FreeRadius ippool database files
+.SH SYNOPSIS
+.P
+If an ipaddress is specified then that address is used to
+limit the actions or output.
+
+.B rlm_ippool_tool
+.RB [ \-a ]
+.RB [ \-c ]
+.RB [ \-o ]
+.RB [ \-v ]
+\fIsession-db\fP \fIindex-db\fP [\fIipaddress\fP]
+
+.P
+Mark the entry nasIP/nasPort as having ipaddress
+
+.B rlm_ippool_tool
+\-n \fIsession-db\fP \fIindex-db\fP \fIipaddress\fP \fInasIP\fP \fInasPort\fP
+
+.P
+Update old format database to new.
+
+.B rlm_ippool_tool
+\-u \fIsession-db\fP \fInew-session-db\fP
+
+.SH DESCRIPTION
+\fBrlm_ippool_tool\fP dumps the contents of the FreeRADIUS ippool databases for
+analyses or for removal of active (stuck?) entries.
+.P
+Or with the \fB\-n\fP argument adds a usage entry to the FreeRADIUS ippool databases.
+
+
+.SH OPTIONS
+
+.IP \-a
+Print all active entries.
+.IP \-c
+Report number of active entries.
+.IP \-r
+Remove active entries.
+.IP \-v
+Verbose report of all entries.
+.IP \-o
+Assume old database format (nas/port pair, not md5 output).
+.IP \-n
+Mark the entry nasIP/nasPort as having ipaddress.
+.IP \-u
+Update old format database to new.
+
+.SH EXAMPLES
+
+.P
+Given the syntax in the FreeRadius radiusd.conf:
+.IP
+.nf
+ ippool myippool {
+ range-start = 192.0.2.0
+ range-stop = 192.0.2.255
+ [...]
+ session-db = ${raddbdir}/ip-pool.db
+ ip-index = ${raddbdir}/ip-index.db
+ }
+.fi
+.P
+To see the number of active entries in this pool, use:
+.IP
+.nf
+ $ rlm_ippool_tool -c ip-pool.db ip-index.db
+ 13
+.fi
+.P
+To see all active entries in this pool, use:
+.IP
+.nf
+ $ rlm_ippool_tool -a ip-pool.db ip-index.db
+ 192.0.2.5
+ 192.0.2.82
+ 192.0.2.244
+ 192.0.2.57
+ 192.0.2.120
+ 192.0.2.27
+ [...]
+.fi
+.P
+To see all information about the active entries in the use, use:
+.IP
+.nf
+ $ rlm_ippool_tool -av ip-pool.db ip-index.db
+ NAS:172.16.1.1 port:0x2e8 - ipaddr:192.0.2.5 active:1 cli:0 num:1
+ NAS:172.16.1.1 port:0x17c - ipaddr:192.0.2.82 active:1 cli:0 num:1
+ NAS:172.16.1.1 port:0x106 - ipaddr:192.0.2.244 active:1 cli:0 num:1
+ NAS:172.16.1.1 port:0x157 - ipaddr:192.0.2.57 active:1 cli:0 num:1
+ NAS:172.16.1.1 port:0x2d8 - ipaddr:192.0.2.120 active:1 cli:0 num:1
+ NAS:172.16.1.1 port:0x162 - ipaddr:192.0.2.27 active:1 cli:0 num:1
+ [...]
+.fi
+.P
+To see only information of one entry, use:
+.IP
+.nf
+ $ rlm_ippool_tool -v ip-pool.db ip-index.db 192.0.2.1
+ NAS:172.16.1.1 port:0x90 - ipaddr:192.0.2.1 active:0 cli:0 num:0
+.fi
+.P
+To add an IP address usage entry, use:
+.IP
+.nf
+ $ rlm_ippool_tool -n ip-pool.db ip-index.db 192.0.0.1 172.16.1.1 0x90
+ rlm_ippool_tool: Allocating ip to nas/port: 172.16.1.1/144
+ rlm_ippool_tool: num: 1
+ rlm_ippool_tool: Allocated ip 192.0.2.1 to client on nas 172.16.1.1,port 144
+.fi
+
+.SH SEE ALSO
+radiusd(8)
+.SH AUTHORS
+Currently part of the FreeRADIUS Project (http://www.freeradius.org)
+Originally by Edwin Groothuis, edwin@mavetju.org (http://www.mavetju.org)
+
+Mailing list details are at http://www.freeradius.org/
diff --git a/src/modules/rlm_ippool/rlm_ippool_tool.c b/src/modules/rlm_ippool/rlm_ippool_tool.c
new file mode 100644
index 0000000..94f6161
--- /dev/null
+++ b/src/modules/rlm_ippool/rlm_ippool_tool.c
@@ -0,0 +1,645 @@
+/*
+ * rlm_ippool_tool.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2003, 2006 FreeRADIUS Project, http://www.freeradius.org/
+ * Copyright 2003 Edwin Groothuis, edwin@mavetju.org
+ * Permission from Edwin Groothuis for release under GPL is archived here:
+ * http://lists.cistron.nl/archives/freeradius-devel/2003/09/frm00247.html
+ *
+ */
+
+/*
+ The original license follows. This license applies to the tarball at
+ http://www.mavetju.org/unix/general.php
+
+ Copyright 2003 by Edwin Groothuis, edwin@mavetju.org
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <fcntl.h>
+#include <gdbm.h>
+#include "../../include/md5.h"
+
+static int active = 0;
+
+static int aflag = 0;
+static int cflag = 0;
+static int rflag = 0;
+static int vflag = 0;
+static int nflag = 0;
+static int oflag = 0;
+static int uflag = 0;
+
+typedef struct ippool_info {
+ uint32_t ipaddr;
+ char active;
+ char cli[32];
+ char extra;
+} ippool_info;
+
+
+#define MAX_NAS_NAME_SIZE 64
+
+typedef struct old_ippool_key {
+ char nas[MAX_NAS_NAME_SIZE];
+ uint16_t port;
+} old_ippool_key;
+
+typedef struct ippool_key {
+ char key[16];
+} ippool_key;
+
+#define MATCH_IP(ip1, ip2) ((ip1) == NULL || strcmp((ip1), (ip2)) == 0)
+#define MATCH_ACTIVE(info) ((info).active == 1 || !aflag)
+
+void addip(char *sessiondbname, char *indexdbname, char *ipaddress,
+ char *NASname, char *NASport, int old);
+
+void viewdb(char *sessiondbname, char *indexdbname, char *ipaddress, int old);
+
+void tonewformat(char *sessiondbname, char *newsessiondbname);
+
+void usage(char *argv0);
+
+void addip(char *sessiondbname, char *indexdbname, char *ipaddress,
+ char *NASname, char *NASport, int old)
+{
+ GDBM_FILE sessiondb;
+ GDBM_FILE indexdb;
+ datum key_datum, data_datum, save_datum;
+ datum nextkey;
+
+ ippool_key key;
+ old_ippool_key old_key;
+
+ ippool_info entry;
+ struct in_addr ipaddr;
+ uint8_t key_str[17];
+ char hex_str[35];
+ int num = 0;
+ int mppp = 0;
+ int mode = GDBM_WRITER;
+ int rcode;
+ int delete = 0;
+ uint16_t port;
+ bool found = false;
+
+ memset(&key, 0, sizeof(key)); /* -Winitialize */
+
+ sessiondb = gdbm_open(sessiondbname, 512, mode, 0,NULL);
+ indexdb = gdbm_open(indexdbname, 512, mode, 0,NULL);
+
+ if (inet_aton(ipaddress, &ipaddr) == 0) {
+ printf("rlm_ippool_tool: Unable to convert IP address '%s'\n", ipaddress);
+ return;
+ }
+
+ if (!sessiondb) {
+ printf("rlm_ippool_tool: Unable to open DB '%s'\n", sessiondbname);
+ return;
+ }
+
+ if (!indexdb) {
+ printf("rlm_ippool_tool: Unable to open DB '%s'\n", indexdbname);
+ return;
+ }
+
+ port = strtoul(NASport, NULL, 0);
+
+ /* Basically from rlm_ippool.c */
+
+ if (old){
+ strlcpy(old_key.nas, NASname, sizeof(old_key.nas));
+ old_key.port = port;
+ key_datum.dptr = (char *) &old_key;
+ key_datum.dsize = sizeof(old_ippool_key);
+ } else {
+ char md5_input_str[MAX_STRING_LEN];
+ FR_MD5_CTX md5_context;
+
+ snprintf(md5_input_str, MAX_STRING_LEN, "%s %s", NASname, NASport);
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str));
+ fr_md5_final(key_str, &md5_context);
+
+ memcpy(key.key, key_str, 16);
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+ }
+
+
+ data_datum = gdbm_fetch(sessiondb, key_datum);
+ if (data_datum.dptr != NULL){
+ found = true;
+ memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+
+ if (entry.active){
+ if (old) {
+ printf("rlm_ippool_tool: Deleting stale entry for ip/port %s/%u",
+ ipaddress, port);
+ } else {
+ printf("rlm_ippool_tool: Deleting stale entry for key: '%s'", hex_str);
+ }
+
+ entry.active = 0;
+ save_datum.dptr = key_datum.dptr;
+ save_datum.dsize = key_datum.dsize;
+
+ data_datum.dptr = (char*) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+
+ rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
+ sessiondbname, gdbm_strerror(gdbm_errno));
+ goto close;
+ }
+
+ key_datum.dptr = (char *) &entry.ipaddr;
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(indexdb, key_datum);
+
+ if (data_datum.dptr != NULL) {
+ memcpy(&num, data_datum.dptr, sizeof(int));
+
+ if (num > 0) {
+ num--;
+ data_datum.dptr = (char *) &num;
+ data_datum.dsize = sizeof(int);
+ rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
+
+ if (rcode < 0) {
+ printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
+ indexdbname, gdbm_strerror(gdbm_errno));
+ goto close;
+ }
+
+ if (num > 0 && entry.extra == 1) {
+ gdbm_delete(sessiondb, save_datum);
+ }
+ }
+ }
+ }
+ }
+ key_datum.dptr = NULL;
+
+ if (!key_datum.dptr) {
+ key_datum = gdbm_firstkey(sessiondb);
+
+ while (key_datum.dptr) {
+ data_datum = gdbm_fetch(sessiondb, key_datum);
+ if (data_datum.dptr != NULL) {
+ memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
+ free(data_datum.dptr);
+
+ if (entry.active == 0 && entry.ipaddr == ipaddr.s_addr) {
+ datum tmp;
+ tmp.dptr = (char *) &entry.ipaddr;
+ tmp.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(indexdb, tmp);
+ if (data_datum.dptr){
+ memcpy(&num, data_datum.dptr, sizeof(int));
+ free(data_datum.dptr);
+ if (num == 0){
+ delete = 1;
+ break;
+ }
+ } else {
+ delete = 1;
+ break;
+ }
+ }
+ }
+ nextkey = gdbm_nextkey(sessiondb, key_datum);
+ free(key_datum.dptr);
+ key_datum = nextkey;
+ }
+ }
+
+ if (key_datum.dptr){
+ if (found && ! mppp){
+ datum key_datum_tmp, data_datum_tmp;
+ old_ippool_key old_key_tmp;
+ ippool_key key_tmp;
+
+ if (old){
+ strlcpy(old_key_tmp.nas, NASname,
+ sizeof(old_key_tmp.nas));
+ old_key_tmp.port = port;
+ key_datum_tmp.dptr = (char *) &old_key_tmp;
+ key_datum_tmp.dsize = sizeof(old_ippool_key);
+ } else {
+ memcpy(key_tmp.key, key_str, 16);
+ key_datum_tmp.dptr = (char *) &key_tmp;
+ key_datum_tmp.dsize = sizeof(ippool_key);
+ }
+
+ data_datum_tmp = gdbm_fetch(sessiondb, key_datum_tmp);
+ if (data_datum_tmp.dptr != NULL) {
+ rcode = gdbm_store(sessiondb, key_datum, data_datum_tmp, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
+ sessiondbname, gdbm_strerror(gdbm_errno));
+ goto close;
+ }
+ free(data_datum_tmp.dptr);
+ }
+ } else {
+ if (delete) {
+ gdbm_delete(sessiondb, key_datum);
+ }
+ }
+
+ free(key_datum.dptr);
+ entry.active = 1;
+
+ data_datum.dptr = (char *) &entry;
+ data_datum.dsize = sizeof(ippool_info);
+
+ if (old){
+ strlcpy(old_key.nas, NASname, sizeof(old_key.nas));
+ old_key.port = port;
+ key_datum.dptr = (char *) &old_key;
+ key_datum.dsize = sizeof(old_ippool_key);
+ printf("rlm_ippool_tool: Allocating ip to nas/port: %s/%u\n", old_key.nas, old_key.port);
+ } else {
+ memcpy(key.key, key_str, 16);
+ key_datum.dptr = (char *) &key;
+ key_datum.dsize = sizeof(ippool_key);
+ printf("rlm_ippool_tool: Allocating ip to key: '%s'\n", hex_str);
+ }
+
+ rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
+ sessiondbname, gdbm_strerror(gdbm_errno));
+ goto close;
+ }
+
+ /* Increase the ip index count */
+ key_datum.dptr = (char *) &entry.ipaddr;
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(indexdb, key_datum);
+ if (data_datum.dptr) {
+ memcpy(&num, data_datum.dptr, sizeof(int));
+ } else {
+ num = 0;
+ }
+
+ num++;
+ printf("rlm_ippool_tool: num: %d\n", num);
+ data_datum.dptr = (char *) &num;
+ data_datum.dsize = sizeof(int);
+
+ rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("rlm_ippool_tool: Failed storing data to %s: %s\n",
+ indexdbname, gdbm_strerror(gdbm_errno));
+
+ goto close;
+ }
+
+ if (old) {
+ printf("rlm_ippool_tool: Allocated ip %s to client on nas %s, port %u\n",
+ ipaddress, old_key.nas, port);
+ } else {
+ printf("rlm_ippool_tool: Allocated ip %s to key '%s'\n", ipaddress, hex_str);
+ }
+ }
+
+ close:
+ gdbm_close(indexdb);
+ gdbm_close(sessiondb);
+}
+
+
+void tonewformat(char *sessiondbname, char *newsessiondbname) {
+ GDBM_FILE sessiondb;
+ GDBM_FILE newsessiondb;
+ datum key_datum, keynext_datum, data_datum, newkey_datum;
+ old_ippool_key old_key;
+ ippool_key key;
+ uint8_t key_str[17];
+ char hex_str[35];
+ int rcode;
+
+ sessiondb = gdbm_open(sessiondbname, 512, GDBM_READER, 0,NULL);
+ newsessiondb = gdbm_open(newsessiondbname, 512, GDBM_NEWDB, 0,NULL);
+
+ if (!sessiondb || !newsessiondb) return;
+
+ memset(key_str, 0, 17);
+
+ key_datum = gdbm_firstkey(sessiondb);
+ while (key_datum.dptr) {
+ keynext_datum = gdbm_nextkey(sessiondb, key_datum);
+
+ if (key_datum.dsize != sizeof(struct old_ippool_key)) {
+ goto next;
+ }
+
+ char md5_input_str[MAX_STRING_LEN];
+ FR_MD5_CTX md5_context;
+
+ memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key));
+
+ snprintf(md5_input_str, MAX_STRING_LEN, "%s %d", old_key.nas, old_key.port);
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, (uint8_t *) md5_input_str, strlen(md5_input_str));
+ fr_md5_final(key_str, &md5_context);
+
+ memcpy(key.key, key_str, 16);
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+
+ printf("rlm_ippool_tool: Transforming pair nas/port (%s/%d) to md5 '%s'\n",
+ old_key.nas, old_key.port, hex_str);
+
+ newkey_datum.dptr = (char *) &key;
+ newkey_datum.dsize = sizeof(ippool_key);
+ data_datum = gdbm_fetch(sessiondb, key_datum);
+
+ if (!data_datum.dptr) {
+ goto next;
+ }
+
+ rcode = gdbm_store(newsessiondb, newkey_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("Failed to update new file %s: %s\n", newsessiondbname, gdbm_strerror(gdbm_errno));
+ gdbm_close(newsessiondb);
+ gdbm_close(sessiondb);
+ return;
+ }
+
+ next:
+ key_datum = keynext_datum;
+ }
+
+ gdbm_close(newsessiondb);
+ gdbm_close(sessiondb);
+}
+
+void viewdb(char *sessiondbname, char *indexdbname, char *ipaddress, int old) {
+ GDBM_FILE sessiondb;
+ GDBM_FILE indexdb;
+ datum key_datum, keynext_datum, data_datum, save_datum;
+ old_ippool_key old_key;
+ ippool_key key;
+ ippool_info info;
+ struct in_addr ipaddr;
+ int num;
+ uint8_t key_str[17];
+ char hex_str[35];
+ char *ip;
+ int mode = GDBM_READER;
+ int rcode;
+
+ if (rflag) mode = GDBM_WRITER;
+ sessiondb = gdbm_open(sessiondbname, 512, mode, 0,NULL);
+ indexdb = gdbm_open(indexdbname, 512, mode, 0,NULL);
+
+ if ((!sessiondb) || (!indexdb)) {
+ return;
+ }
+
+ memset(&key, 0, sizeof(key)); /* -Winitialize */
+ memset(key_str, 0,17);
+
+ key_datum = gdbm_firstkey(sessiondb);
+ while (key_datum.dptr) {
+ keynext_datum = gdbm_nextkey(sessiondb, key_datum);
+
+ if ((key_datum.dsize != sizeof(struct ippool_key)) &&
+ (key_datum.dsize != sizeof(struct old_ippool_key))) {
+ goto next;
+ }
+
+ if (old) {
+ memcpy(&old_key, key_datum.dptr, sizeof(struct old_ippool_key));
+ } else {
+ memcpy(&key, key_datum.dptr, sizeof(struct ippool_key));
+ }
+
+ data_datum = gdbm_fetch(sessiondb, key_datum);
+ if (!data_datum.dptr) {
+ goto next;
+ }
+
+ memcpy(&info, data_datum.dptr, sizeof(struct ippool_info));
+ memcpy(&ipaddr, &info.ipaddr, 4);
+ ip = inet_ntoa(ipaddr);
+
+ if (info.active) active++;
+
+ if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
+ if (old) {
+ printf("NAS:%s port:0x%x - ", old_key.nas, old_key.port);
+ } else {
+ memcpy(key_str, key.key, 16);
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+ printf("KEY: '%s' - ", hex_str);
+ }
+ }
+
+ if (!vflag && aflag && info.active && MATCH_IP(ipaddress, ip)) {
+ printf("%s\n", ip);
+ } else if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
+ printf("ipaddr:%s active:%d cli:%s",
+ inet_ntoa(ipaddr), info.active, info.cli);
+ }
+
+ /*
+ * algorythm copied from rlm_ippool.c:
+ * - set active to zero
+ * - set number of sessions to zero
+ */
+ if (rflag && MATCH_IP(ipaddress, ip)) {
+ info.active = 0;
+ save_datum.dptr = key_datum.dptr;
+ save_datum.dsize = key_datum.dsize;
+ data_datum.dptr = (char *) &info;
+ data_datum.dsize = sizeof(ippool_info);
+
+ rcode = gdbm_store(sessiondb, key_datum, data_datum, GDBM_REPLACE);
+ if (rcode < 0) {
+ printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno));
+ gdbm_close(indexdb);
+ gdbm_close(sessiondb);
+ return;
+ }
+
+ key_datum.dptr = (char *)&info.ipaddr;
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(indexdb, key_datum);
+
+ if (data_datum.dptr != NULL) {
+ memcpy(&num, data_datum.dptr, sizeof(int));
+ if (num > 0) {
+ num--;
+ data_datum.dptr = (char *) &num;
+ data_datum.dsize = sizeof(int);
+ rcode = gdbm_store(indexdb, key_datum, data_datum, GDBM_REPLACE);
+
+ if (rcode < 0) {
+ printf("Failed to update %s: %s\n", ip, gdbm_strerror(gdbm_errno));
+ gdbm_close(indexdb);
+ gdbm_close(sessiondb);
+ return;
+ }
+
+ if (num > 0 && info.extra == 1) {
+ gdbm_delete(sessiondb, save_datum);
+ }
+ }
+ }
+ }
+
+ key_datum.dptr = (char *)&info.ipaddr;
+ key_datum.dsize = sizeof(uint32_t);
+ data_datum = gdbm_fetch(indexdb, key_datum);
+
+ if (data_datum.dptr!= NULL) {
+ memcpy(&num, data_datum.dptr, sizeof(int));
+
+ if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
+ printf(" num:%d", num);
+ }
+ }
+
+ if (vflag && MATCH_IP(ipaddress, ip) && MATCH_ACTIVE(info)) {
+ printf("\n");
+ } else if (vflag && !ipaddress){
+ if (old) {
+ printf("NAS:%s port:0x%x\n", old_key.nas, old_key.port);
+ } else {
+ memcpy(key_str, key.key, 16);
+ fr_bin2hex(hex_str, key_str, 16);
+ hex_str[32] = '\0';
+ printf("KEY: '%s' - ", hex_str);
+ }
+ }
+
+ next:
+ key_datum = keynext_datum;
+ }
+
+ gdbm_close(indexdb);
+ gdbm_close(sessiondb);
+}
+
+void NEVER_RETURNS usage(char *argv0) {
+ printf("Usage: %s [-a] [-c] [-o] [-v] <filename> <index-db> [ipaddress]\n", argv0);
+ printf(" -a: print all active entries\n");
+ printf(" -c: report number of active entries\n");
+ printf(" -r: remove active entries\n");
+ printf(" -v: verbose report of all entries\n");
+ printf(" -o: Assume old database format (nas/port pair, not md5 output)\n");
+ printf(" If an ipaddress is specified then that address is used to\n");
+ printf(" limit the actions or output.\n");
+ printf(" Usage: %s -n <filename> <index-db> <ipaddress> <nasIP> <nasPort>\n", argv0);
+ printf(" -n: Mark the entry nasIP/nasPort as having ipaddress\n");
+ printf(" Usage: %s -u <filename> <new-filename>\n", argv0);
+ printf(" -u: Update old format database to new.\n");
+ exit(0);
+}
+
+int main(int argc, char **argv) {
+ int ch;
+ char *argv0 = argv[0];
+
+ while ((ch = getopt(argc, argv, "acrvnou"))!= -1)
+ switch (ch) {
+ case 'a':
+ aflag++;
+ break;
+
+ case 'c':
+ cflag++;
+ break;
+
+ case 'r':
+ rflag++;
+ break;
+
+ case 'v':
+ vflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ case 'o':
+ oflag = 1;
+ break;
+
+ case 'u':
+ uflag = 1;
+ break;
+
+ default:
+ usage(argv0);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((argc == 2 || argc == 3) && !nflag && !uflag) {
+ viewdb(argv[0], argv[1], argv[2], oflag);
+ if (cflag) printf("%d\n", active);
+ } else {
+ if (argc == 5 && nflag) {
+ addip(argv[0], argv[1], argv[2], argv[3], argv[4], oflag);
+ } else if (argc == 2 && uflag) {
+ tonewformat(argv[0], argv[1]);
+ } else {
+ usage(argv0);
+ }
+ }
+
+ return 0;
+}
diff --git a/src/modules/rlm_ippool/rlm_ippool_tool.mk b/src/modules/rlm_ippool/rlm_ippool_tool.mk
new file mode 100644
index 0000000..4748ee8
--- /dev/null
+++ b/src/modules/rlm_ippool/rlm_ippool_tool.mk
@@ -0,0 +1,12 @@
+#
+# $Id$
+#
+
+SOURCES := rlm_ippool_tool.c
+TARGET := rlm_ippool_tool
+TGT_PREREQS := libfreeradius-radius.a
+
+SRC_CFLAGS := $(rlm_ippool_CFLAGS)
+TGT_LDLIBS := $(LIBS) $(rlm_ippool_LDLIBS)
+
+MAN := rlm_ippool_tool.8
diff --git a/src/modules/rlm_json/.gitignore b/src/modules/rlm_json/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_json/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_json/README.md b/src/modules/rlm_json/README.md
new file mode 100644
index 0000000..e7abfe1
--- /dev/null
+++ b/src/modules/rlm_json/README.md
@@ -0,0 +1,13 @@
+# rlm_json
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Parses JSON strings into an in memory format and permits creating
+JSON documents from RADIUS attributes, using the json-c library.
+
+Implements a very simple xpath-like query syntax, allowing values
+to be extracted and added to the request as attributes.
diff --git a/src/modules/rlm_json/all.mk.in b/src/modules/rlm_json/all.mk.in
new file mode 100644
index 0000000..6bba9b9
--- /dev/null
+++ b/src/modules/rlm_json/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c json.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_json/config.h.in b/src/modules/rlm_json/config.h.in
new file mode 100644
index 0000000..ad0bd4c
--- /dev/null
+++ b/src/modules/rlm_json/config.h.in
@@ -0,0 +1,34 @@
+/* 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_object_get_int64' function. */
+#undef HAVE_JSON_OBJECT_GET_INT64
+
+/* Define to 1 if you have the `json_object_get_string_len' function. */
+#undef HAVE_JSON_OBJECT_GET_STRING_LEN
+
+/* Define to 1 if you have the `json_object_new_int64' function. */
+#undef HAVE_JSON_OBJECT_NEW_INT64
+
+/* Define to 1 if you have the `json_object_object_add_ex' function. */
+#undef HAVE_JSON_OBJECT_OBJECT_ADD_EX
+
+/* Define to 1 if you have the `json_object_object_get_ex' function. */
+#undef HAVE_JSON_OBJECT_OBJECT_GET_EX
+
+/* Define to 1 if you have the `json_tokener_error_desc' function. */
+#undef HAVE_JSON_TOKENER_ERROR_DESC
+
+/* Define to 1 if you have the `json_tokener_get_error' function. */
+#undef HAVE_JSON_TOKENER_GET_ERROR
diff --git a/src/modules/rlm_json/configure b/src/modules/rlm_json/configure
new file mode 100755
index 0000000..3530a17
--- /dev/null
+++ b/src/modules/rlm_json/configure
@@ -0,0 +1,4904 @@
+#! /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_json.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_json
+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_json build without JSON support from json-c
+ --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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_json
+echo
+
+
+# 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_json was given.
+if test "${with_rlm_json+set}" = set; then :
+ withval=$with_rlm_json;
+fi
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_json" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+jsonc_include_dir=
+
+# Check whether --with-jsonc-include-dir was given.
+if test "${with_jsonc_include_dir+set}" = set; then :
+ withval=$with_jsonc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+jsonc_lib_dir=
+
+# Check whether --with-jsonc-lib-dir was given.
+if test "${with_jsonc_lib_dir+set}" = set; then :
+ withval=$with_jsonc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need jsonc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-jsonc-dir was given.
+if test "${with_jsonc_dir+set}" = set; then :
+ withval=$with_jsonc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need json-c-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ jsonc_lib_dir="$withval/lib"
+ jsonc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+
+have_json="yes"
+smart_try_dir="$jsonc_include_dir"
+
+
+
+ac_safe=`echo "json/json.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/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_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_object_add_ex \
+ json_object_new_int64 \
+ json_object_get_int64 \
+ json_tokener_error_desc \
+ json_tokener_get_error
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+else
+ { $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;}
+
+fail="$fail json-c"
+
+fi
+
+
+ targetname=rlm_json
+else
+ targetname=
+ echo \*\*\* module rlm_json is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_json to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_json." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_json." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_json requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_json requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+if test x"$fail" = x""; then :
+
+
+$as_echo "#define HAVE_JSON 1" >>confdefs.h
+
+
+fi
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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'
+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_json/configure.ac b/src/modules/rlm_json/configure.ac
new file mode 100644
index 0000000..97bd1df
--- /dev/null
+++ b/src/modules/rlm_json/configure.ac
@@ -0,0 +1,139 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_json.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_json], [JSON support from json-c])
+AC_CONFIG_HEADER(config.h)
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+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>.])
+ FR_MODULE_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 json of the checks
+ LDFLAGS="$SMART_LIBS"
+
+ dnl # Add any optional functions here
+ AC_CHECK_FUNCS(\
+ json_c_version \
+ json_object_get_string_len \
+ json_object_object_get_ex \
+ json_object_object_add_ex \
+ json_object_new_int64 \
+ json_object_get_int64 \
+ json_tokener_error_desc \
+ json_tokener_get_error
+ )
+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])
+ FR_MODULE_FAIL([json-c])
+fi
+
+FR_MODULE_END_TESTS
+
+FR_MODULE_TEST_PASS_DO([
+ AC_DEFINE([HAVE_JSON],[1],[Build with JSON support from json-c])
+])
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_json/json.c b/src/modules/rlm_json/json.c
new file mode 100644
index 0000000..83bcba5
--- /dev/null
+++ b/src/modules/rlm_json/json.c
@@ -0,0 +1,829 @@
+/*
+ * 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 json.c
+ * @brief Common functions for working with json-c
+ *
+ * @author Matthew Newton
+ * @author Arran Cudbard-Bell
+ *
+ * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2015,2021 Network RADIUS SARL (legal@networkradius.com)
+ * @copyright 2015 The FreeRADIUS Server Project
+ */
+
+#include <freeradius-devel/rad_assert.h>
+#include "json.h"
+
+#ifndef HAVE_JSON
+# error "rlm_json should not be built unless json-c is available"
+#endif
+
+
+const FR_NAME_NUMBER fr_json_format_table[] = {
+ { "array", JSON_MODE_ARRAY },
+ { "array_of_names", JSON_MODE_ARRAY_OF_NAMES },
+ { "array_of_values", JSON_MODE_ARRAY_OF_VALUES },
+ { "object", JSON_MODE_OBJECT },
+ { "object_simple", JSON_MODE_OBJECT_SIMPLE },
+
+ { NULL, -1 }
+};
+
+static inline CC_HINT(always_inline)
+void json_object_put_assert(json_object *obj)
+{
+ int ret;
+
+ ret = json_object_put(obj);
+ if (ret == 1) return;
+
+ rad_assert(0);
+}
+
+
+/** Given a VALUE_PAIR, create the correct JSON object based on the data type
+ *
+ * @param[in] ctx to allocate temporary buffers in
+ * @param[in] vp VALUE_PAIR to convert.
+ * @param[in] always_string create all values as strings
+ * @param[in] enum_as_int output enum attribute values as integers not strings
+ * @return Newly allocated JSON object, or NULL on error
+ */
+json_object *json_object_from_attr_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp, bool always_string, bool enum_as_int)
+{
+ char buf[2048];
+ ssize_t len;
+
+ /*
+ * We're converting to PRESENTATION format
+ * so any attributes with enumeration values
+ * should be converted to string types, unless
+ * enum_as_int is set.
+ */
+
+#define RETURN_ENUM_OR_STRING(_type) \
+ if (always_string) { \
+ len = snprintf(buf, sizeof(buf), "%d", vp->vp_ ## _type); \
+ return json_object_new_string_len(buf, len); \
+ } \
+ return json_object_new_int(vp->vp_ ## _type)
+
+ /*
+ * Handle enumeration values first
+ */
+ if (vp->da->flags.has_value) {
+ if (enum_as_int) {
+ switch (vp->da->type) {
+ default:
+ break;
+
+ case PW_TYPE_BYTE:
+ RETURN_ENUM_OR_STRING(byte);
+
+ case PW_TYPE_SHORT:
+ RETURN_ENUM_OR_STRING(short);
+
+ case PW_TYPE_INTEGER:
+ RETURN_ENUM_OR_STRING(integer);
+ }
+ } else {
+ always_string = true;
+ }
+ }
+
+
+ /*
+ * If always_string is set then we print everything to a string and
+ * return a JSON string object.
+ */
+ if (always_string) {
+ char *p;
+ char *quoted_string;
+ json_object *obj = NULL;
+
+ do_string:
+ p = vp_aprints_value(ctx, vp, '\0');
+ if (!p) return NULL;
+
+ quoted_string = fr_json_from_string(ctx, p, false);
+ if (!quoted_string) {
+ talloc_free(p);
+ return NULL;
+ }
+
+ obj = json_object_new_string(quoted_string);
+ talloc_free(p);
+
+ return obj;
+ }
+
+ /*
+ * Otherwise use the correct JSON object function depending on the
+ * attribute value type.
+ */
+ switch (vp->da->type) {
+ default:
+ goto do_string;
+
+ case PW_TYPE_BOOLEAN:
+ return json_object_new_boolean(vp->vp_byte);
+
+ case PW_TYPE_BYTE:
+ return json_object_new_int(vp->vp_byte);
+
+ case PW_TYPE_SHORT:
+ return json_object_new_int(vp->vp_short);
+
+#ifdef HAVE_JSON_OBJECT_GET_INT64
+ case PW_TYPE_INTEGER:
+ return json_object_new_int64((int64_t)vp->vp_integer64); /* uint32_t (max) > int32_t (max) */
+
+ case PW_TYPE_INTEGER64:
+ if (vp->vp_integer64 > INT64_MAX) goto do_string;
+ return json_object_new_int64(vp->vp_integer64);
+#else
+ case PW_TYPE_INTEGER:
+ if (vp->vp_integer > INT32_MAX) goto do_string;
+ return json_object_new_int(vp->vp_integer);
+#endif
+
+ case PW_TYPE_SIGNED:
+ return json_object_new_int(vp->vp_signed);
+ }
+}
+
+/** Escapes string for use as a JSON string
+ *
+ * @param ctx Talloc context to allocate this string
+ * @param s Input string
+ * @param include_quotes Include the surrounding quotes of JSON strings
+ * @return New allocated character string, or NULL if something failed.
+ */
+char *fr_json_from_string(TALLOC_CTX *ctx, char const *s, bool include_quotes)
+{
+ char const *p;
+ char *out = NULL;
+ struct json_object *json;
+ int len;
+
+ json = json_object_new_string(s);
+ if (!json) return NULL;
+
+ if ((p = json_object_to_json_string(json))) {
+ if (include_quotes) {
+ out = talloc_typed_strdup(ctx, p);
+ } else {
+ len = strlen(p);
+ out = talloc_bstrndup(ctx, p + 1, len - 2); /* to_json_string adds quotes (") */
+ }
+ }
+
+ /*
+ * Free the JSON structure, it's not needed any more
+ */
+ json_object_put_assert(json);
+
+ return out;
+}
+
+
+/** Convert VALUE_PAIR into a JSON object
+ *
+ * If inst.enum_as_int is set, and the given VP is an enum
+ * value, the integer value is returned as a json_object rather
+ * than the text representation.
+ *
+ * If inst.always_string is set then a numeric value pair
+ * will be returned as a JSON string object.
+ *
+ * @param[in] ctx Talloc context.
+ * @param[out] out returned json object.
+ * @param[in] vp to get the value of.
+ * @param[in] inst format definition, or NULL.
+ * @return
+ * - 1 if 'out' is the integer enum value, 0 otherwise
+ * - -1 on error.
+ */
+static int json_afrom_value_pair(TALLOC_CTX *ctx, json_object **out,
+ VALUE_PAIR *vp, rlm_json_t const *inst)
+{
+ struct json_object *obj;
+ int is_enum = 0;
+
+ fr_assert(vp);
+ fr_assert(inst);
+
+ MEM(obj = json_object_from_attr_value(ctx, vp, inst->always_string, inst->enum_as_int));
+
+ *out = obj;
+ return is_enum;
+}
+
+
+/** Add prefix to attribute name
+ *
+ * If the format "attr.prefix" string is set then prepend this
+ * to the given attribute name, otherwise return name unchanged.
+ *
+ * @param[out] buf where to write the new name, if set
+ * @param[in] buf_len length of buf
+ * @param[in] name original attribute name
+ * @param[in] inst json format structure
+ * @return pointer to name, or buf if the prefix was added
+ */
+static inline char const *attr_name_with_prefix(char *buf, size_t buf_len, const char *name, rlm_json_t const *inst)
+{
+ int len;
+
+ if (!inst->attr_prefix) return name;
+
+ len = snprintf(buf, buf_len, "%s:%s", inst->attr_prefix, name);
+
+ if (len == (int)strlen(buf)) {
+ return buf;
+ }
+
+ return name;
+}
+
+
+/** Verify that the options in rlm_json_t are valid
+ *
+ * Warnings are optional, will fatal error if the format is corrupt.
+ *
+ * @param[in] inst the format structure to check
+ * @param[in] verbose print out warnings if set
+ * @return true if format is good, otherwise false
+ */
+bool fr_json_format_verify(rlm_json_t const *inst, bool verbose)
+{
+ bool ret = true;
+
+ fr_assert(inst);
+
+ switch (inst->output_mode) {
+ case JSON_MODE_OBJECT:
+ case JSON_MODE_OBJECT_SIMPLE:
+ case JSON_MODE_ARRAY:
+ /* all options are valid */
+ return true;
+ case JSON_MODE_ARRAY_OF_VALUES:
+ if (inst->attr_prefix) {
+ if (verbose) WARN("attribute name prefix not valid in output_mode 'array_of_values' and will be ignored");
+ ret = false;
+ }
+ if (inst->value_as_array) {
+ if (verbose) WARN("'value_as_array' not valid in output_mode 'array_of_values' and will be ignored");
+ ret = false;
+ }
+ return ret;
+ case JSON_MODE_ARRAY_OF_NAMES:
+ if (inst->value_as_array) {
+ if (verbose) WARN("'value_as_array' not valid in output_mode 'array_of_names' and will be ignored");
+ ret = false;
+ }
+ if (inst->enum_as_int) {
+ if (verbose) WARN("'enum_as_int' not valid in output_mode 'array_of_names' and will be ignored");
+ ret = false;
+ }
+ if (inst->always_string) {
+ if (verbose) WARN("'always_string' not valid in output_mode 'array_of_names' and will be ignored");
+ ret = false;
+ }
+ return ret;
+ default:
+ ERROR("JSON format output mode is invalid");
+ }
+
+ /* If we get here, something has gone wrong */
+ fr_assert(0);
+
+ return false;
+}
+
+
+/** Returns a JSON object representation of a list of value pairs
+ *
+ * The result is a struct json_object, which should be free'd with
+ * json_object_put() by the caller. Intended to only be called by
+ * fr_json_afrom_pair_list().
+ *
+ * This function generates the "object" format, JSON_MODE_OBJECT.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, must be set.
+ * @return JSON object with the generated representation.
+ */
+static json_object *json_object_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ VALUE_PAIR *vp;
+ struct json_object *obj;
+ char buf[DICT_ATTR_MAX_NAME_LEN + 32];
+
+ /* Check format and type */
+ fr_assert(inst);
+ fr_assert(inst->output_mode == JSON_MODE_OBJECT);
+
+ MEM(obj = json_object_new_object());
+
+ for (vp = vps;
+ vp;
+ vp = vp->next) {
+ char const *attr_name;
+ struct json_object *vp_object, *values, *value, *type_name;
+
+ /*
+ * Get attribute name and value.
+ */
+ attr_name = attr_name_with_prefix(buf, sizeof(buf), vp->da->name, inst);
+
+ if (json_afrom_value_pair(ctx, &value, vp, inst) < 0) {
+ fr_strerror_printf("Failed to convert attribute value to JSON object");
+ error:
+ json_object_put_assert(obj);
+
+ return NULL;
+ }
+
+ /*
+ * Look in the table to see if we already have
+ * a key for the attribute we're working on.
+ */
+ if (!json_object_object_get_ex(obj, attr_name, &vp_object)) {
+ /*
+ * Wasn't there, so create a new object for this attribute.
+ */
+ MEM(vp_object = json_object_new_object());
+ json_object_object_add(obj, attr_name, vp_object);
+
+ /*
+ * Add "type" to newly created keys.
+ */
+ MEM(type_name = json_object_new_string(fr_int2str(dict_attr_types, vp->da->type, "<INVALID>")));
+ json_object_object_add_ex(vp_object, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
+
+ /*
+ * Create a "value" array to hold any attribute values for this attribute...
+ */
+ if (inst->value_as_array) {
+ MEM(values = json_object_new_array());
+ json_object_object_add_ex(vp_object, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
+ } else {
+ /*
+ * ...unless this is the first time we've seen the attribute and
+ * value_as_array is false, in which case just add the value directly
+ * and move on to the next attribute.
+ */
+ json_object_object_add_ex(vp_object, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
+ continue;
+ }
+ } else {
+ /*
+ * Find the 'values' array to add the current value to.
+ */
+ if (!json_object_object_get_ex(vp_object, "value", &values)) {
+ fr_strerror_printf("Inconsistent JSON tree");
+ goto error;
+ }
+
+ /*
+ * If value_as_array is no set then "values" may not be an array, so it will
+ * need converting to an array to add this extra attribute.
+ */
+ if (!inst->value_as_array) {
+ json_type type;
+ struct json_object *convert_value = values;
+
+ /* Check "values" type */
+ type = json_object_get_type(values);
+
+ /* It wasn't an array, so turn it into one with the old value as the first entry */
+ if (type != json_type_array) {
+ MEM(values = json_object_new_array());
+ json_object_array_add(values, json_object_get(convert_value));
+ json_object_object_del(vp_object, "value");
+ json_object_object_add_ex(vp_object, "value", values,
+ JSON_C_OBJECT_KEY_IS_CONSTANT);
+ }
+ }
+ }
+
+ /*
+ * Append to the JSON array.
+ */
+ json_object_array_add(values, value);
+ }
+
+ return obj;
+}
+
+
+/** Returns a JSON object representation of a list of value pairs
+ *
+ * The result is a struct json_object, which should be free'd with
+ * json_object_put() by the caller. Intended to only be called by
+ * fr_json_afrom_pair_list().
+ *
+ * This function generates the "simple object" format, JSON_MODE_OBJECT_SIMPLE.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, must be set.
+ * @return JSON object with the generated representation.
+ */
+static json_object *json_smplobj_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ VALUE_PAIR *vp;
+ struct json_object *obj;
+ char buf[DICT_ATTR_MAX_NAME_LEN + 32];
+ json_type type;
+
+ /* Check format and type */
+ fr_assert(inst);
+ fr_assert(inst->output_mode == JSON_MODE_OBJECT_SIMPLE);
+
+ MEM(obj = json_object_new_object());
+
+ for (vp = vps;
+ vp;
+ vp = vp->next) {
+ char const *attr_name;
+ struct json_object *vp_object, *value;
+ struct json_object *values = NULL;
+ bool add_single = false;
+
+ /*
+ * Get attribute name and value.
+ */
+ attr_name = attr_name_with_prefix(buf, sizeof(buf), vp->da->name, inst);
+
+ if (json_afrom_value_pair(ctx, &value, vp, inst) < 0) {
+ fr_strerror_printf("Failed to convert attribute value to JSON object");
+
+ json_object_put_assert(obj);
+ return NULL;
+ }
+
+ /*
+ * See if we already have a key in the table we're working on,
+ * if not then create a new one.
+ */
+ if (!json_object_object_get_ex(obj, attr_name, &vp_object)) {
+ if (inst->value_as_array) {
+ /*
+ * We have been asked to ensure /all/ values are lists,
+ * even if there's only one attribute.
+ */
+ MEM(values = json_object_new_array());
+ json_object_object_add(obj, attr_name, values);
+ } else {
+ /*
+ * Deal with it later on.
+ */
+ add_single = true;
+ }
+ /*
+ * If we do have the key already, get its value array.
+ */
+ } else {
+ type = json_object_get_type(vp_object);
+
+ if (type == json_type_array) {
+ values = vp_object;
+ } else {
+ /*
+ * We've seen one of these before, but didn't add
+ * it as an array the first time. Sort that out.
+ */
+ MEM(values = json_object_new_array());
+ json_object_array_add(values, json_object_get(vp_object));
+
+ /*
+ * Existing key will have refcount decremented
+ * and will be freed if thise drops to zero.
+ */
+ json_object_object_add(obj, attr_name, values);
+ }
+ }
+
+ if (add_single) {
+ /*
+ * Only ever used the first time adding a new
+ * attribute when "value_as_array" is not set.
+ */
+ json_object_object_add(obj, attr_name, value);
+ } else {
+ /*
+ * Otherwise we're always appending to a JSON array.
+ */
+ json_object_array_add(values, value);
+ }
+ }
+
+ return obj;
+}
+
+
+/** Returns a JSON array representation of a list of value pairs
+ *
+ * The result is a struct json_object, which should be free'd with
+ * json_object_put() by the caller. Intended to only be called by
+ * fr_json_afrom_pair_list().
+ *
+ * This function generates the "array" format, JSON_MODE_ARRAY.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, must be set.
+ * @return JSON object with the generated representation.
+ */
+static struct json_object *json_array_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ VALUE_PAIR *vp;
+ struct json_object *obj;
+ struct json_object *seen_attributes = NULL;
+ char buf[DICT_ATTR_MAX_NAME_LEN + 32];
+
+ /* Check format and type */
+ fr_assert(inst);
+ fr_assert(inst->output_mode == JSON_MODE_ARRAY);
+
+ MEM(obj = json_object_new_array());
+
+ /*
+ * If attribute values should be in a list format, then keep track
+ * of the attributes we've previously seen in a JSON object.
+ */
+ if (inst->value_as_array) {
+ seen_attributes = json_object_new_object();
+ }
+
+ for (vp = vps;
+ vp;
+ vp = vp->next) {
+ char const *attr_name;
+ struct json_object *name, *value, *type_name;
+ struct json_object *values = NULL;
+ struct json_object *attrobj = NULL;
+ bool already_seen = false;
+
+ /*
+ * Get attribute name and value.
+ */
+ attr_name = attr_name_with_prefix(buf, sizeof(buf), vp->da->name, inst);
+
+ if (json_afrom_value_pair(ctx, &value, vp, inst) < 0) {
+ fr_strerror_printf("Failed to convert attribute value to JSON object");
+ json_object_put_assert(obj);
+ return NULL;
+ }
+
+ if (inst->value_as_array) {
+ /*
+ * Try and find this attribute in the "seen_attributes" object. If it is
+ * there then get the "values" array to add this attribute value to.
+ */
+ already_seen = json_object_object_get_ex(seen_attributes, attr_name, &values);
+ }
+
+ /*
+ * If we're adding all attributes to the toplevel array, or we're adding values
+ * to an array of an existing attribute but haven't seen it before, then we need
+ * to create a new JSON object for this attribute.
+ */
+ if (!inst->value_as_array || !already_seen) {
+ /*
+ * Create object and add it to top-level array
+ */
+ MEM(attrobj = json_object_new_object());
+ json_object_array_add(obj, attrobj);
+
+ /*
+ * Add the attribute name in the "name" key and the type in the "type" key
+ */
+ MEM(name = json_object_new_string(attr_name));
+ json_object_object_add_ex(attrobj, "name", name, JSON_C_OBJECT_KEY_IS_CONSTANT);
+
+ MEM(type_name = json_object_new_string(fr_int2str(dict_attr_types, vp->da->type, "<INVALID>")));
+ json_object_object_add_ex(attrobj, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
+ }
+
+ if (inst->value_as_array) {
+ /*
+ * We're adding values to an array for the first copy of this attribute
+ * that we saw. First time around we need to create an array.
+ */
+ if (!already_seen) {
+ MEM(values = json_object_new_array());
+ /*
+ * Add "value":[] key to the attribute object
+ */
+ json_object_object_add_ex(attrobj, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
+
+ /*
+ * Also add to "seen_attributes" to check later
+ */
+ json_object_object_add(seen_attributes, attr_name, json_object_get(values));
+ }
+
+ /*
+ * Always add the value to the respective "values" array.
+ */
+ json_object_array_add(values, value);
+ } else {
+ /*
+ * This is simpler; just add a "value": key to the attribute object.
+ */
+ json_object_object_add_ex(attrobj, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
+ }
+
+ }
+
+ /*
+ * No longer need the "seen_attributes" object, it was just used for tracking.
+ */
+ if (inst->value_as_array) {
+ json_object_put_assert(seen_attributes);
+ }
+
+ return obj;
+}
+
+
+/** Returns a JSON array of a list of value pairs
+ *
+ * The result is a struct json_object, which should be free'd with
+ * json_object_put() by the caller. Intended to only be called by
+ * fr_json_afrom_pair_list().
+ *
+ * This function generates the "array_of_values" format,
+ * JSON_MODE_ARRAY_OF_VALUES, listing just the attribute values.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, must be set.
+ * @return JSON object with the generated representation.
+ */
+static struct json_object *json_value_array_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ VALUE_PAIR *vp;
+ struct json_object *obj;
+
+ /* Check format and type */
+ fr_assert(inst);
+ fr_assert(inst->output_mode == JSON_MODE_ARRAY_OF_VALUES);
+
+ MEM(obj = json_object_new_array());
+
+ /*
+ * This array format is very simple - just add all the
+ * attribute values to the array in order.
+ */
+ for (vp = vps;
+ vp;
+ vp = vp->next) {
+ struct json_object *value;
+
+ if (json_afrom_value_pair(ctx, &value, vp, inst) < 0) {
+ fr_strerror_printf("Failed to convert attribute value to JSON object");
+ json_object_put_assert(obj);
+ return NULL;
+ }
+
+ json_object_array_add(obj, value);
+ }
+
+ return obj;
+}
+
+
+/** Returns a JSON array of a list of value pairs
+ *
+ * The result is a struct json_object, which should be free'd with
+ * json_object_put() by the caller. Intended to only be called by
+ * fr_json_afrom_pair_list().
+ *
+ * This function generates the "array_of_names" format,
+ * JSON_MODE_ARRAY_OF_NAMES, listing just the attribute names.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, must be set.
+ * @return JSON object with the generated representation.
+ */
+static struct json_object *json_attr_array_afrom_pair_list(UNUSED TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ VALUE_PAIR *vp;
+ struct json_object *obj;
+ char buf[DICT_ATTR_MAX_NAME_LEN + 32];
+
+ /* Check format and type */
+ fr_assert(inst);
+ fr_assert(inst->output_mode == JSON_MODE_ARRAY_OF_NAMES);
+
+ MEM(obj = json_object_new_array());
+
+ /*
+ * Add all the attribute names to the array in order.
+ */
+ for (vp = vps;
+ vp;
+ vp = vp->next) {
+ char const *attr_name;
+ struct json_object *value;
+
+ attr_name = attr_name_with_prefix(buf, sizeof(buf), vp->da->name, inst);
+ value = json_object_new_string(attr_name);
+
+ json_object_array_add(obj, value);
+ }
+
+ return obj;
+}
+
+
+/** Returns a JSON string of a list of value pairs
+ *
+ * The result is a talloc-ed string, freeing the string is
+ * the responsibility of the caller.
+ *
+ * The 'inst' format struct contains settings to configure the output
+ * JSON document format.
+ * @see fr_json_format_s
+ *
+ * @param[in] ctx Talloc context.
+ * @param[in] vps a list of value pairs.
+ * @param[in] inst Formatting control, can be NULL to use default format.
+ * @return JSON string representation of the value pairs
+ */
+char *fr_json_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *inst)
+{
+ struct json_object *obj = NULL;
+ const char *p;
+ char *out;
+
+ rad_assert(inst);
+
+ switch (inst->output_mode) {
+ case JSON_MODE_OBJECT:
+ MEM(obj = json_object_afrom_pair_list(ctx, vps, inst));
+ break;
+ case JSON_MODE_OBJECT_SIMPLE:
+ MEM(obj = json_smplobj_afrom_pair_list(ctx, vps, inst));
+ break;
+ case JSON_MODE_ARRAY:
+ MEM(obj = json_array_afrom_pair_list(ctx, vps, inst));
+ break;
+ case JSON_MODE_ARRAY_OF_VALUES:
+ MEM(obj = json_value_array_afrom_pair_list(ctx, vps, inst));
+ break;
+ case JSON_MODE_ARRAY_OF_NAMES:
+ MEM(obj = json_attr_array_afrom_pair_list(ctx, vps, inst));
+ break;
+ default:
+ /* This should never happen */
+ rad_assert(0);
+ }
+
+ /*
+ * p is a buff inside obj, and will be freed
+ * when it is freed.
+ */
+ MEM(p = json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN));
+ MEM(out = talloc_typed_strdup(ctx, p));
+
+ /*
+ * Free the JSON structure, it's not needed any more
+ */
+ json_object_put_assert(obj);
+
+ return out;
+}
diff --git a/src/modules/rlm_json/json.h b/src/modules/rlm_json/json.h
new file mode 100644
index 0000000..d05ae12
--- /dev/null
+++ b/src/modules/rlm_json/json.h
@@ -0,0 +1,99 @@
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file lib/json/base.h
+ * @brief Implements the evaluation and parsing functions for the FreeRADIUS version of jpath.
+ *
+ * @author Arran Cudbard-Bell
+ * @author Matthew Newton
+ *
+ * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2015,2021 Network RADIUS SARL (legal@networkradius.com)
+ * @copyright 2015 The FreeRADIUS Server Project
+ */
+RCSIDH(json_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include "config.h"
+
+#ifdef HAVE_JSON
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+
+# if defined(HAVE_JSONMC_JSON_H)
+# include <json-c/json.h>
+# elif defined(HAVE_JSON_JSON_H)
+# include <json/json.h>
+# else
+# error "Need json-c headers"
+# endif
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+/* for json-c < 0.13 */
+#ifndef HAVE_JSON_OBJECT_OBJECT_ADD_EX
+# define json_object_object_add_ex(_obj, _key, _val, _opt) json_object_object_add(_obj, _key, _val)
+#endif
+
+# include <freeradius-devel/radiusd.h>
+
+extern const FR_NAME_NUMBER fr_json_format_table[];
+
+/** List of possible JSON format output modes.
+ *
+ */
+typedef enum {
+ JSON_MODE_UNSET = 0,
+ JSON_MODE_OBJECT,
+ JSON_MODE_OBJECT_SIMPLE,
+ JSON_MODE_ARRAY,
+ JSON_MODE_ARRAY_OF_VALUES,
+ JSON_MODE_ARRAY_OF_NAMES
+} json_mode_type_t;
+
+/** rlm_json module instance
+ *
+ */
+typedef struct {
+ char const *attr_prefix; //!< Prefix to add to all attribute names
+ bool value_as_array; //!< Use JSON array for multiple attribute values.
+ bool enum_as_int; //!< Output enums as value, not their string representation.
+ bool always_string; //!< Output all data types as strings.
+
+
+ char const *output_mode_str; //!< For CONF_PARSER only.
+ json_mode_type_t output_mode; //!< Determine the format of JSON document to generate.
+
+ bool include_type; //!< Include attribute type where possible.
+
+ char const *name;
+} rlm_json_t;
+
+
+json_object *json_object_from_attr_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp, bool always_string, bool enum_as_int);
+void fr_json_version_print(void);
+char *fr_json_afrom_pair_list(TALLOC_CTX *ctx, VALUE_PAIR *vps,
+ rlm_json_t const *format);
+bool fr_json_format_verify(rlm_json_t const *inst, bool verbose);
+char *fr_json_from_string(TALLOC_CTX *ctx, char const *s, bool include_quotes);
+#endif
diff --git a/src/modules/rlm_json/rlm_json.c b/src/modules/rlm_json/rlm_json.c
new file mode 100644
index 0000000..9cf99d8
--- /dev/null
+++ b/src/modules/rlm_json/rlm_json.c
@@ -0,0 +1,237 @@
+/*
+ * 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_json.c
+ * @brief Parses JSON responses
+ *
+ * @author Matthew Newton
+ * @author Arran Cudbard-Bell
+ *
+ * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2015,2021 Network RADIUS SARL (legal@networkradius.com)
+ * @copyright 2015 The FreeRADIUS Server Project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "json.h"
+#include <ctype.h>
+
+#ifndef HAVE_JSON
+# error "rlm_json should not be built unless json-c is available"
+#endif
+
+
+static CONF_PARSER const json_format_attr_config[] = {
+ { "prefix", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_json_t, attr_prefix), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER const json_format_value_config[] = {
+ { "single_value_as_array", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_json_t, value_as_array), "no" },
+ { "enum_as_integer", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_json_t, enum_as_int), "no" },
+ { "always_string", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_json_t, always_string), "no" },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER const fr_json_format_config[] = {
+ { "output_mode", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_json_t, output_mode_str), "object" },
+ { "attribute", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) json_format_attr_config },
+ { "value", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) json_format_value_config },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER const module_config[] = {
+ { "encode", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) fr_json_format_config },
+
+ CONF_PARSER_TERMINATOR
+};
+
+
+/** Convert given attributes to a JSON document
+ *
+ * Usage is `%{json_encode:attr tmpl list}`
+ *
+ * @ingroup xlat_functions
+ *
+ * @param instance module instance
+ * @param request the current request
+ * @param fmt input to the xlat
+ * @param out where to write the output
+ * @param outlen space available for the output
+ * @return length of output generated
+ */
+static ssize_t json_encode_xlat(UNUSED void * instance, REQUEST *request, char const *fmt,
+ char *out, size_t outlen)
+{
+ rlm_json_t const *inst = instance;
+ ssize_t slen;
+ vp_tmpl_t *vpt = NULL;
+ VALUE_PAIR *json_vps = NULL, *vps;
+ bool negate;
+ char const *p = fmt;
+ char *json_str = NULL;
+ char *buf;
+
+
+ /*
+ * Iterate through the list of attribute templates in the xlat. For each
+ * one we either add it to the list of attributes for the JSON document
+ * or, if prefixed with '!', remove from the JSON list.
+ */
+
+ p = fmt;
+
+ while (isspace((uint8_t) *p)) p++;
+ if (*p == '\0') return -1;
+
+ while (*p) {
+ while (isspace((uint8_t) *p)) p++;
+
+ if (*p == '\0') break;
+
+ negate = false;
+
+ /* Check if we should be removing attributes */
+ if (*p == '!') {
+ p++;
+ negate = true;
+ }
+
+ if (*p == '\0') {
+ /* May happen e.g. with '!' on its own at the end */
+ REMARKER(fmt, (p - fmt), "Missing attribute name");
+ error:
+ fr_pair_list_free(&json_vps);
+ talloc_free(vpt);
+ return -1;
+ }
+
+
+ /* Decode next attr template */
+ slen = tmpl_afrom_attr_substr(request, &vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+
+ if (slen <= 0) {
+ REMARKER(fmt, (p - fmt) -slen, fr_strerror());
+ goto error;
+ }
+
+ /*
+ * Get attributes from the template.
+ * Missing attribute isn't an error (so -1, not 0).
+ */
+ if (tmpl_copy_vps(request, &vps, request, vpt) < -1) {
+ REDEBUG("Error copying attributes");
+ goto error;
+ }
+
+ if (negate) {
+ /* Remove all template attributes from JSON list */
+ for (VALUE_PAIR *vp = vps;
+ vp;
+ vp = vp->next) {
+ fr_pair_delete_by_da(&json_vps, vp->da);
+ }
+
+ fr_pair_list_free(&vps);
+ } else {
+ /* Add template VPs to JSON list */
+ fr_pair_add(&json_vps, vps);
+ }
+
+ TALLOC_FREE(vpt);
+
+ /* Jump forward to next attr */
+ p += slen;
+
+ if (*p != '\0' && !isspace((uint8_t)*p)) {
+ REMARKER(fmt, (p - fmt), "Missing whitespace");
+ goto error;
+ }
+ }
+
+ /*
+ * Given the list of attributes we now have in json_vps,
+ * convert them into a JSON document and append it to the
+ * return cursor.
+ */
+ MEM(buf = talloc_zero_array(request, char, 8192));
+
+ json_str = fr_json_afrom_pair_list(request, json_vps, inst);
+ if (!json_str) {
+ REDEBUG("Failed to generate JSON string");
+ goto error;
+ }
+
+ slen = snprintf(out, outlen, "%s", json_str);
+
+ fr_pair_list_free(&json_vps);
+
+ return slen;
+}
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_json_t *inst = talloc_get_type_abort(instance, rlm_json_t);
+ char *name;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+ name = talloc_asprintf(inst, "%s_encode", inst->name);
+ xlat_register(name, json_encode_xlat, NULL, inst);
+ talloc_free(name);
+
+ /*
+ * Check the output format type and warn on unused
+ * format options
+ */
+ inst->output_mode = fr_str2int(fr_json_format_table, inst->output_mode_str, JSON_MODE_UNSET);
+ if (inst->output_mode == JSON_MODE_UNSET) {
+ cf_log_err_cs(conf, "output_mode value \"%s\" is invalid", inst->output_mode_str);
+ return -1;
+ }
+ fr_json_format_verify(inst, true);
+
+ 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_json;
+module_t rlm_json = {
+ .magic = RLM_MODULE_INIT,
+ .name = "json",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_json_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+};
diff --git a/src/modules/rlm_krb5/.gitignore b/src/modules/rlm_krb5/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_krb5/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_krb5/README.md b/src/modules/rlm_krb5/README.md
new file mode 100644
index 0000000..35cc285
--- /dev/null
+++ b/src/modules/rlm_krb5/README.md
@@ -0,0 +1,12 @@
+# rlm_krb5
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Implements Kerberos authentication, using the result of decrypting
+the TGT as an indication that the provided password was correct.
+
+Supports both MIT and Heimdal libraries.
diff --git a/src/modules/rlm_krb5/all.mk.in b/src/modules/rlm_krb5/all.mk.in
new file mode 100644
index 0000000..4d79778
--- /dev/null
+++ b/src/modules/rlm_krb5/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c krb5.c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -DKRB5_DEPRECATED
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_krb5/configure b/src/modules/rlm_krb5/configure
new file mode 100755
index 0000000..c7df335
--- /dev/null
+++ b/src/modules/rlm_krb5/configure
@@ -0,0 +1,5603 @@
+#! /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_krb5.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+krb5_config
+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_krb5
+with_rlm_krb5_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_krb5 build without Kerberos support
+ --with-rlm-krb5-dir=DIR Directory for krb5 files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_krb5
+echo
+
+
+# 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
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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; } && { ac_try='./conftest$ac_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 :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ 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_run
+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_krb5 was given.
+if test "${with_rlm_krb5+set}" = set; then :
+ withval=$with_rlm_krb5;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_krb5" != 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
+
+
+rlm_krb5_dir=
+
+# Check whether --with-rlm-krb5-dir was given.
+if test "${with_rlm_krb5_dir+set}" = set; then :
+ withval=$with_rlm_krb5_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-krb5-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_krb5_dir="$withval"
+ ;;
+ esac
+fi
+
+
+# Extract the first word of "krb5-config", so it can be a program name with args.
+set dummy krb5-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_krb5_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $krb5_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_krb5_config="$krb5_config" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${rlm_krb5_dir}/bin:${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_krb5_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
+
+ test -z "$ac_cv_path_krb5_config" && ac_cv_path_krb5_config="not-found"
+ ;;
+esac
+fi
+krb5_config=$ac_cv_path_krb5_config
+if test -n "$krb5_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $krb5_config" >&5
+$as_echo "$krb5_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+if test "$krb5_config" != 'not-found'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking krb5-config CFLAGS" >&5
+$as_echo_n "checking krb5-config CFLAGS... " >&6; }
+ SMART_CPPFLAGS=$($krb5_config --cflags)
+ SMART_CPPFLAGS=$(echo "$SMART_CPPFLAGS" | sed 's/-I[ ]*/-isystem /g')
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: \"$SMART_CPPFLAGS\"" >&5
+$as_echo "\"$SMART_CPPFLAGS\"" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking krb5-config LDFLAGS" >&5
+$as_echo_n "checking krb5-config LDFLAGS... " >&6; }
+ SMART_LIBS=$($krb5_config --libs)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${SMART_LIBS}" >&5
+$as_echo "${SMART_LIBS}" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking krb5-config reported version" >&5
+$as_echo_n "checking krb5-config reported version... " >&6; }
+ krb5_version_raw=$($krb5_config --version)
+
+ krb5_version=$(echo "$krb5_version_raw" | head -n 1 | \
+ awk '{split($(4),v,"."); if (v["3"] = "") v["3"] = "0"; print v["1"]v["2"]v["3"] }')
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${krb5_version_raw} ($krb5_version)" >&5
+$as_echo "${krb5_version_raw} ($krb5_version)" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking krb5-config reported vendor" >&5
+$as_echo_n "checking krb5-config reported vendor... " >&6; }
+ krb5_vendor=$($krb5_config --vendor)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${krb5_vendor}" >&5
+$as_echo "${krb5_vendor}" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking canonical API type" >&5
+$as_echo_n "checking canonical API type... " >&6; }
+ if test "$krb5_vendor" = "Massachusetts Institute of Technology" || \
+ echo "$krb5_vendor" | grep -i 'MIT' > /dev/null 2>&1 || \
+ echo "$krb5_version_raw" | grep -i 'MIT' > /dev/null 2>&1 ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: MIT" >&5
+$as_echo "MIT" >&6; }
+ krb5_api_type='mit'
+
+if echo "$fr_features" | grep -q "+using MIT kerberos+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""" >> config.report.tmp
+ fr_features="$fr_features +using MIT kerberos+"
+fi
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: HEIMDAL" >&5
+$as_echo "HEIMDAL" >&6; }
+ krb5_api_type='heimdal'
+
+if echo "$fr_features" | grep -q "+using Heimdal kerberos+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""" >> config.report.tmp
+ fr_features="$fr_features +using Heimdal kerberos+"
+fi
+
+ fi
+else
+ smart_try_dir="$rlm_krb5_dir/include"
+
+
+
+ac_safe=`echo "krb5.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 krb5.h in $try" >&5
+$as_echo_n "checking for krb5.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <krb5.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}/krb5.h" >&5
+$as_echo_n "checking for ${_prefix}/krb5.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <krb5.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 krb5.h" >&5
+$as_echo_n "checking for krb5.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <krb5.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 krb5.h in $try" >&5
+$as_echo_n "checking for krb5.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <krb5.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+ if test "$ac_cv_header_krb5_h" != "yes"; then
+
+fail="$fail krb5.h"
+
+ fi
+
+ krb5libcrypto=
+ smart_try_dir="$rlm_krb5_dir/lib"
+
+
+sm_lib_safe=`echo "k5crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "krb5_encrypt_data" | 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 krb5_encrypt_data in -lk5crypto in $try" >&5
+$as_echo_n "checking for krb5_encrypt_data in -lk5crypto in $try... " >&6; }
+ LIBS="-lk5crypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_encrypt_data();
+int
+main ()
+{
+krb5_encrypt_data()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lk5crypto"
+ 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 krb5_encrypt_data in -lk5crypto" >&5
+$as_echo_n "checking for krb5_encrypt_data in -lk5crypto... " >&6; }
+ LIBS="-lk5crypto $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_encrypt_data();
+int
+main ()
+{
+krb5_encrypt_data()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lk5crypto"
+ { $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 krb5_encrypt_data in -lk5crypto in $try" >&5
+$as_echo_n "checking for krb5_encrypt_data in -lk5crypto in $try... " >&6; }
+ LIBS="-lk5crypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_encrypt_data();
+int
+main ()
+{
+krb5_encrypt_data()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lk5crypto"
+ 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_k5crypto_krb5_encrypt_data" = xyes; then
+ krb5libcrypto="-lk5crypto"
+ fi
+
+ if test "x$krb5libcrypto" = x; then
+
+
+sm_lib_safe=`echo "crypto" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "DH_new" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto" >&5
+$as_echo_n "checking for DH_new in -lcrypto... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DH_new in -lcrypto in $try" >&5
+$as_echo_n "checking for DH_new in -lcrypto in $try... " >&6; }
+ LIBS="-lcrypto $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char DH_new();
+int
+main ()
+{
+DH_new()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcrypto"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS="$old_LIBS"
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_lib" != "x"; then
+ eval "ac_cv_lib_${sm_lib_safe}_${sm_func_safe}=yes"
+ LIBS="$smart_ldflags $smart_lib $old_LIBS"
+ SMART_LIBS="$smart_ldflags $smart_lib $SMART_LIBS"
+fi
+
+ if test "x$ac_cv_lib_crypto_DH_new" = xyes; then
+ krb5libcrypto="-lcrypto"
+ fi
+ fi
+
+ if test "x$krb5libcrypto" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: neither krb5 'k5crypto' nor 'crypto' libraries are found!" >&5
+$as_echo "$as_me: WARNING: neither krb5 'k5crypto' nor 'crypto' libraries are found!" >&2;}
+ fi
+
+
+
+sm_lib_safe=`echo "com_err" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "set_com_err_hook" | 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 set_com_err_hook in -lcom_err in $try" >&5
+$as_echo_n "checking for set_com_err_hook in -lcom_err in $try... " >&6; }
+ LIBS="-lcom_err $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char set_com_err_hook();
+int
+main ()
+{
+set_com_err_hook()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcom_err"
+ 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 set_com_err_hook in -lcom_err" >&5
+$as_echo_n "checking for set_com_err_hook in -lcom_err... " >&6; }
+ LIBS="-lcom_err $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char set_com_err_hook();
+int
+main ()
+{
+set_com_err_hook()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcom_err"
+ { $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 set_com_err_hook in -lcom_err in $try" >&5
+$as_echo_n "checking for set_com_err_hook in -lcom_err in $try... " >&6; }
+ LIBS="-lcom_err $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char set_com_err_hook();
+int
+main ()
+{
+set_com_err_hook()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lcom_err"
+ 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_com_err_set_com_err_hook" != xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: the comm_err library isn't found!" >&5
+$as_echo "$as_me: WARNING: the comm_err library isn't found!" >&2;}
+ fi
+
+
+
+sm_lib_safe=`echo "krb5" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "krb5_verify_user_opt" | 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 krb5_verify_user_opt in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_verify_user_opt in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_verify_user_opt();
+int
+main ()
+{
+krb5_verify_user_opt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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 krb5_verify_user_opt in -lkrb5" >&5
+$as_echo_n "checking for krb5_verify_user_opt in -lkrb5... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_verify_user_opt();
+int
+main ()
+{
+krb5_verify_user_opt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ { $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 krb5_verify_user_opt in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_verify_user_opt in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_verify_user_opt();
+int
+main ()
+{
+krb5_verify_user_opt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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_krb5_krb5_verify_user_opt" = xyes; then
+ krb5_api_type='heimdal'
+
+if echo "$fr_features" | grep -q "+using Heimdal kerberos+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""" >> config.report.tmp
+ fr_features="$fr_features +using Heimdal kerberos+"
+fi
+
+ else
+ krb5_api_type='mit'
+
+if echo "$fr_features" | grep -q "+using MIT kerberos+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""" >> config.report.tmp
+ fr_features="$fr_features +using MIT kerberos+"
+fi
+
+
+
+
+sm_lib_safe=`echo "krb5" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "krb5_get_init_creds_password" | 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 krb5_get_init_creds_password in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_get_init_creds_password in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_get_init_creds_password();
+int
+main ()
+{
+krb5_get_init_creds_password()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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 krb5_get_init_creds_password in -lkrb5" >&5
+$as_echo_n "checking for krb5_get_init_creds_password in -lkrb5... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_get_init_creds_password();
+int
+main ()
+{
+krb5_get_init_creds_password()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ { $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 krb5_get_init_creds_password in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_get_init_creds_password in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_get_init_creds_password();
+int
+main ()
+{
+krb5_get_init_creds_password()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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_krb5_krb5_get_init_creds_password" != xyes; then
+
+fail="$fail krb5"
+
+ fi
+ fi
+
+fi
+
+LDFLAGS="${LDFLAGS} ${SMART_LIBS}"
+CFLAGS="${CFLAGS} ${SMART_CPPFLAGS}"
+
+for ac_func in krb5_get_error_message krb5_free_error_string krb5_free_error_message
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+if test "x$ac_cv_func_krb5_get_error_message" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_GET_ERROR_MESSAGE"
+fi
+if test "x$ac_cv_func_krb5_free_error_message" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_FREE_ERROR_MESSAGE"
+fi
+if test "x$ac_cv_func_krb5_free_error_string" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_FREE_ERROR_STRING"
+fi
+
+if test "$krb5threadsafe" != "no"; then
+ krb5threadsafe=
+
+
+
+sm_lib_safe=`echo "krb5" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "krb5_is_thread_safe" | 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 krb5_is_thread_safe in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_is_thread_safe in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_is_thread_safe();
+int
+main ()
+{
+krb5_is_thread_safe()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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 krb5_is_thread_safe in -lkrb5" >&5
+$as_echo_n "checking for krb5_is_thread_safe in -lkrb5... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_is_thread_safe();
+int
+main ()
+{
+krb5_is_thread_safe()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ { $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 krb5_is_thread_safe in -lkrb5 in $try" >&5
+$as_echo_n "checking for krb5_is_thread_safe in -lkrb5 in $try... " >&6; }
+ LIBS="-lkrb5 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char krb5_is_thread_safe();
+int
+main ()
+{
+krb5_is_thread_safe()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lkrb5"
+ 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_krb5_krb5_is_thread_safe" = xyes; then
+ if test "$cross_compiling" = yes; then :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <krb5.h>
+int
+main ()
+{
+return krb5_is_thread_safe() ? 0 : 1
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ krb5threadsafe="-DKRB5_IS_THREAD_SAFE"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libkrb5 is not threadsafe" >&5
+$as_echo "$as_me: WARNING: libkrb5 is not threadsafe" >&2;}
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+else
+ krb5threadsafe=""
+fi
+
+if test "$krb5_api_type" = "mit"; then
+
+
+ac_safe=`echo "com_err.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 com_err.h in $try" >&5
+$as_echo_n "checking for com_err.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <com_err.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}/com_err.h" >&5
+$as_echo_n "checking for ${_prefix}/com_err.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <com_err.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 com_err.h" >&5
+$as_echo_n "checking for com_err.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <com_err.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 com_err.h in $try" >&5
+$as_echo_n "checking for com_err.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <com_err.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+ if test "$ac_cv_header_com_err_h" != "yes"; then
+
+
+ac_safe=`echo "et/com_err.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 et/com_err.h in $try" >&5
+$as_echo_n "checking for et/com_err.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <et/com_err.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}/et/com_err.h" >&5
+$as_echo_n "checking for ${_prefix}/et/com_err.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <et/com_err.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 et/com_err.h" >&5
+$as_echo_n "checking for et/com_err.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <et/com_err.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 et/com_err.h in $try" >&5
+$as_echo_n "checking for et/com_err.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <et/com_err.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+ if test "$ac_cv_header_et_com_err_h" != "yes"; then
+
+fail="$fail com_err.h"
+
+ else
+ krb5mod_cflags="$krb5mod_cflags -DET_COMM_ERR "
+ fi
+ fi
+else
+ krb5mod_cflags="$krb5mod_cflags -DHEIMDAL_KRB5"
+fi
+
+
+ targetname=rlm_krb5
+else
+ targetname=
+ echo \*\*\* module rlm_krb5 is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_krb5 to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_krb5." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_krb5." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_krb5 requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_krb5 requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$krb5mod_ldflags $krb5libcrypto $SMART_LIBS"
+mod_cflags="$krb5mod_cflags $krb5threadsafe $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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_krb5/configure.ac b/src/modules/rlm_krb5/configure.ac
new file mode 100644
index 0000000..9ee6379
--- /dev/null
+++ b/src/modules/rlm_krb5/configure.ac
@@ -0,0 +1,178 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_krb5.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_krb5], [Kerberos support])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl extra argument: --with-rlm-krb5-dir
+rlm_krb5_dir=
+AC_ARG_WITH(rlm-krb5-dir,
+ [AS_HELP_STRING([--with-rlm-krb5-dir=DIR],
+ [Directory for krb5 files])],
+ [ case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-krb5-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_krb5_dir="$withval"
+ ;;
+ esac])
+
+AC_PATH_PROG(krb5_config, krb5-config, not-found, [${rlm_krb5_dir}/bin:${PATH}:/usr/bin:/usr/local/bin])
+
+dnl #
+dnl # If we can find krb5-config we can get the version of the library and determine
+dnl # whether it's safe to enable threading.
+dnl #
+if test "$krb5_config" != 'not-found'; then
+ AC_MSG_CHECKING([krb5-config CFLAGS])
+ SMART_CPPFLAGS=$($krb5_config --cflags)
+ SMART_CPPFLAGS=[$(echo "$SMART_CPPFLAGS" | sed 's/-I[ ]*/-isystem /g')]
+ AC_MSG_RESULT("$SMART_CPPFLAGS")
+
+ AC_MSG_CHECKING([krb5-config LDFLAGS])
+ SMART_LIBS=$($krb5_config --libs)
+ AC_MSG_RESULT(${SMART_LIBS})
+
+ AC_MSG_CHECKING([krb5-config reported version])
+ krb5_version_raw=$($krb5_config --version)
+
+ dnl # AWK originally from from https://github.com/hpc/lustre
+ krb5_version=$(echo "$krb5_version_raw" | head -n 1 | \
+ awk '{split($(4),v,"."); if (v@<:@"3"@:>@ = "") v@<:@"3"@:>@ = "0"; print v@<:@"1"@:>@v@<:@"2"@:>@v@<:@"3"@:>@ }')
+ AC_MSG_RESULT([${krb5_version_raw} ($krb5_version)])
+
+ AC_MSG_CHECKING([krb5-config reported vendor])
+ krb5_vendor=$($krb5_config --vendor)
+ AC_MSG_RESULT([${krb5_vendor}])
+
+ AC_MSG_CHECKING([canonical API type])
+ if test "$krb5_vendor" = "Massachusetts Institute of Technology" || \
+ echo "$krb5_vendor" | grep -i 'MIT' > /dev/null 2>&1 || \
+ echo "$krb5_version_raw" | grep -i 'MIT' > /dev/null 2>&1 ; then
+ AC_MSG_RESULT([MIT])
+ krb5_api_type='mit'
+ FR_MODULE_FEATURE([using MIT kerberos])
+ else
+ AC_MSG_RESULT([HEIMDAL])
+ krb5_api_type='heimdal'
+ FR_MODULE_FEATURE([using Heimdal kerberos])
+ fi
+else
+ smart_try_dir="$rlm_krb5_dir/include"
+ FR_SMART_CHECK_INCLUDE(krb5.h)
+ if test "$ac_cv_header_krb5_h" != "yes"; then
+ FR_MODULE_FAIL([krb5.h])
+ fi
+
+ krb5libcrypto=
+ smart_try_dir="$rlm_krb5_dir/lib"
+ FR_SMART_CHECK_LIB(k5crypto, krb5_encrypt_data)
+ if test "x$ac_cv_lib_k5crypto_krb5_encrypt_data" = xyes; then
+ krb5libcrypto="-lk5crypto"
+ fi
+
+ if test "x$krb5libcrypto" = x; then
+ FR_SMART_CHECK_LIB(crypto, DH_new)
+ if test "x$ac_cv_lib_crypto_DH_new" = xyes; then
+ krb5libcrypto="-lcrypto"
+ fi
+ fi
+
+ if test "x$krb5libcrypto" = x; then
+ AC_MSG_WARN([neither krb5 'k5crypto' nor 'crypto' libraries are found!])
+ fi
+
+ FR_SMART_CHECK_LIB(com_err, set_com_err_hook)
+ if test "x$ac_cv_lib_com_err_set_com_err_hook" != xyes; then
+ AC_MSG_WARN([the comm_err library isn't found!])
+ fi
+
+ dnl #
+ dnl # Only the heimdal version of the library has this function
+ dnl #
+ FR_SMART_CHECK_LIB(krb5, krb5_verify_user_opt)
+ if test "x$ac_cv_lib_krb5_krb5_verify_user_opt" = xyes; then
+ krb5_api_type='heimdal'
+ FR_MODULE_FEATURE([using Heimdal kerberos])
+ else
+ krb5_api_type='mit'
+ FR_MODULE_FEATURE([using MIT kerberos])
+
+ FR_SMART_CHECK_LIB(krb5, krb5_get_init_creds_password)
+ if test "x$ac_cv_lib_krb5_krb5_get_init_creds_password" != xyes; then
+ FR_MODULE_FAIL([krb5])
+ fi
+ fi
+
+fi
+
+dnl #
+dnl # Need to ensure the test program(s) link against the right library
+dnl #
+LDFLAGS="${LDFLAGS} ${SMART_LIBS}"
+CFLAGS="${CFLAGS} ${SMART_CPPFLAGS}"
+
+dnl #
+dnl # Check how to free things returned by krb5_get_error_message
+dnl #
+AC_CHECK_FUNCS([krb5_get_error_message krb5_free_error_string krb5_free_error_message])
+if test "x$ac_cv_func_krb5_get_error_message" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_GET_ERROR_MESSAGE"
+fi
+if test "x$ac_cv_func_krb5_free_error_message" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_FREE_ERROR_MESSAGE"
+fi
+if test "x$ac_cv_func_krb5_free_error_string" = xyes; then
+ krb5mod_cflags="${krb5mod_cflags} -DHAVE_KRB5_FREE_ERROR_STRING"
+fi
+
+dnl #
+dnl # Only check if version checks have not found kerberos to be thread unsafe
+dnl #
+if test "$krb5threadsafe" != "no"; then
+ krb5threadsafe=
+
+ FR_SMART_CHECK_LIB(krb5, krb5_is_thread_safe)
+ if test "x$ac_cv_lib_krb5_krb5_is_thread_safe" = xyes; then
+ AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <krb5.h>]], [[return krb5_is_thread_safe() ? 0 : 1]])],
+ [krb5threadsafe="-DKRB5_IS_THREAD_SAFE"], [AC_MSG_WARN([[libkrb5 is not threadsafe]])])
+ fi
+else
+ krb5threadsafe=""
+fi
+
+if test "$krb5_api_type" = "mit"; then
+ dnl #
+ dnl # This lives in different places depending on the distro
+ dnl #
+ FR_SMART_CHECK_INCLUDE([com_err.h])
+ if test "$ac_cv_header_com_err_h" != "yes"; then
+ FR_SMART_CHECK_INCLUDE([et/com_err.h])
+ if test "$ac_cv_header_et_com_err_h" != "yes"; then
+ FR_MODULE_FAIL([com_err.h])
+ else
+ krb5mod_cflags="$krb5mod_cflags -DET_COMM_ERR "
+ fi
+ fi
+else
+ krb5mod_cflags="$krb5mod_cflags -DHEIMDAL_KRB5"
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$krb5mod_ldflags $krb5libcrypto $SMART_LIBS"
+mod_cflags="$krb5mod_cflags $krb5threadsafe $SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_krb5/krb5.c b/src/modules/rlm_krb5/krb5.c
new file mode 100644
index 0000000..153a10c
--- /dev/null
+++ b/src/modules/rlm_krb5/krb5.c
@@ -0,0 +1,166 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file krb5.h
+ * @brief Context management functions for rlm_krb5
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include "krb5.h"
+
+#ifdef HAVE_KRB5_GET_ERROR_MESSAGE
+# define KRB5_STRERROR_BUFSIZE (2048)
+
+fr_thread_local_setup(char *, krb5_error_buffer) /* macro */
+
+/*
+ * Explicitly cleanup the memory allocated to the error buffer.
+ */
+static void _krb5_logging_free(void *arg)
+{
+ free(arg);
+}
+
+char const *rlm_krb5_error(krb5_context context, krb5_error_code code)
+{
+ char const *msg;
+ char *buffer;
+
+ buffer = fr_thread_local_init(krb5_error_buffer, _krb5_logging_free);
+ if (!buffer) {
+ int ret;
+
+ /*
+ * malloc is thread safe, talloc is not
+ */
+ buffer = malloc(sizeof(char) * KRB5_STRERROR_BUFSIZE);
+ if (!buffer) {
+ ERROR("Failed allocating memory for krb5 error buffer");
+ return NULL;
+ }
+
+ ret = fr_thread_local_set(krb5_error_buffer, buffer);
+ if (ret != 0) {
+ ERROR("Failed setting up TLS for krb5 error buffer: %s", fr_syserror(ret));
+ free(buffer);
+ return NULL;
+ }
+ }
+
+ msg = krb5_get_error_message(context, code);
+ if (msg) {
+ strlcpy(buffer, msg, KRB5_STRERROR_BUFSIZE);
+# ifdef HAVE_KRB5_FREE_ERROR_MESSAGE
+ krb5_free_error_message(context, msg);
+# elif defined(HAVE_KRB5_FREE_ERROR_STRING)
+ {
+ char *free;
+
+ memcpy(&free, &msg, sizeof(free));
+ krb5_free_error_string(context, free);
+ }
+# else
+# error "No way to free error strings, missing krb5_free_error_message() and krb5_free_error_string()"
+# endif
+ } else {
+ strlcpy(buffer, "Unknown error", KRB5_STRERROR_BUFSIZE);
+ }
+
+ return buffer;
+}
+#endif
+
+/** Frees libkrb5 resources associated with the handle
+ *
+ * Must not be called directly.
+ *
+ * @param conn to free.
+ * @return 0 (always indicates success).
+ */
+static int _mod_conn_free(rlm_krb5_handle_t *conn) {
+ krb5_free_context(conn->context);
+
+ if (conn->keytab) krb5_kt_close(conn->context, conn->keytab);
+
+#ifdef HEIMDAL_KRB5
+ if (conn->ccache) krb5_cc_destroy(conn->context, conn->ccache);
+#endif
+
+ return 0;
+}
+
+/** Create and return a new connection
+ *
+ * libkrb5(s) can talk to the KDC over TCP. Were assuming something sane is implemented
+ * by libkrb5 and that it does connection caching associated with contexts, so it's
+ * worth using a connection pool to preserve connections when workers die.
+ */
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_krb5_t *inst = instance;
+ rlm_krb5_handle_t *conn;
+ krb5_error_code ret;
+
+ MEM(conn = talloc_zero(ctx, rlm_krb5_handle_t));
+ ret = krb5_init_context(&conn->context);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Context initialisation failed: %s", inst->xlat_name,
+ rlm_krb5_error(NULL, ret));
+
+ return NULL;
+ }
+ talloc_set_destructor(conn, _mod_conn_free);
+
+ ret = inst->keytabname ?
+ krb5_kt_resolve(conn->context, inst->keytabname, &conn->keytab) :
+ krb5_kt_default(conn->context, &conn->keytab);
+ if (ret) {
+ ERROR("Resolving keytab failed: %s", rlm_krb5_error(conn->context, ret));
+
+ goto cleanup;
+ }
+
+#ifdef HEIMDAL_KRB5
+ ret = krb5_cc_new_unique(conn->context, "MEMORY", NULL, &conn->ccache);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Credential cache creation failed: %s", inst->xlat_name,
+ rlm_krb5_error(conn->context, ret));
+
+ return NULL;
+ }
+
+ krb5_verify_opt_init(&conn->options);
+ krb5_verify_opt_set_ccache(&conn->options, conn->ccache);
+
+ krb5_verify_opt_set_keytab(&conn->options, conn->keytab);
+ krb5_verify_opt_set_secure(&conn->options, true);
+
+ if (inst->service) krb5_verify_opt_set_service(&conn->options, inst->service);
+#else
+ krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, true);
+#endif
+ return conn;
+
+cleanup:
+ talloc_free(conn);
+ return NULL;
+}
diff --git a/src/modules/rlm_krb5/krb5.h b/src/modules/rlm_krb5/krb5.h
new file mode 100644
index 0000000..0d2d584
--- /dev/null
+++ b/src/modules/rlm_krb5/krb5.h
@@ -0,0 +1,93 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file krb5.h
+ * @brief types and function signatures for rlm_krb5.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSIDH(krb5_h, "$Id$")
+
+#if defined(KRB5_IS_THREAD_SAFE) && !defined(HAVE_PTHREAD_H)
+# undef KRB5_IS_THREAD_SAFE
+#endif
+
+/* krb5 includes */
+USES_APPLE_DEPRECATED_API
+#include <krb5.h>
+
+typedef struct rlm_krb5_handle {
+ krb5_context context;
+ krb5_keytab keytab;
+
+#ifdef HEIMDAL_KRB5
+ krb5_ccache ccache;
+ krb5_verify_opt options;
+#endif
+} rlm_krb5_handle_t;
+
+/** Instance configuration for rlm_krb5
+ *
+ * Holds the configuration and preparsed data for a instance of rlm_krb5.
+ */
+typedef struct rlm_krb5_t {
+#ifdef KRB5_IS_THREAD_SAFE
+ fr_connection_pool_t *pool; //!< Connection pool instance.
+#else
+ rlm_krb5_handle_t *conn;
+#endif
+
+ char const *xlat_name; //!< This module's instance name.
+ char const *keytabname; //!< The keytab to resolve the service in.
+ char const *service_princ; //!< The service name provided by the
+ //!< config parser.
+
+ char *hostname; //!< The hostname component of
+ //!< service_princ, or NULL.
+ char *service; //!< The service component of service_princ, or NULL.
+
+ krb5_context context; //!< The kerberos context (cloned once per request).
+
+#ifndef HEIMDAL_KRB5
+ krb5_get_init_creds_opt *gic_options; //!< Options to pass to the get_initial_credentials
+ //!< function.
+ krb5_verify_init_creds_opt *vic_options; //!< Options to pass to the validate_initial_creds
+ //!< function.
+
+ krb5_principal server; //!< A structure representing the parsed
+ //!< service_princ.
+#endif
+} rlm_krb5_t;
+
+/*
+ * MIT Kerberos uses comm_err, so the macro just expands to a call
+ * to error_message.
+ */
+#ifndef HAVE_KRB5_GET_ERROR_MESSAGE
+# ifdef ET_COMM_ERR
+# include <et/com_err.h>
+# else
+# include <com_err.h>
+# endif
+# define rlm_krb5_error(_x, _y) error_message(_y)
+#else
+char const *rlm_krb5_error(krb5_context context, krb5_error_code code);
+#endif
+
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
diff --git a/src/modules/rlm_krb5/rlm_krb5.c b/src/modules/rlm_krb5/rlm_krb5.c
new file mode 100644
index 0000000..152e78b
--- /dev/null
+++ b/src/modules/rlm_krb5/rlm_krb5.c
@@ -0,0 +1,470 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_krb5.c
+ * @brief Authenticate users, retrieving their TGT from a Kerberos V5 TDC.
+ *
+ * @copyright 2000,2006,2012-2013 The FreeRADIUS server project
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000 Nathan Neulinger <nneul@umr.edu>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include "krb5.h"
+
+static const CONF_PARSER module_config[] = {
+ { "keytab", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_krb5_t, keytabname), NULL },
+ { "service_principal", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_krb5_t, service_princ), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_detach(void *instance)
+{
+ rlm_krb5_t *inst = instance;
+
+#ifndef HEIMDAL_KRB5
+ talloc_free(inst->vic_options);
+
+ if (inst->gic_options) krb5_get_init_creds_opt_free(inst->context, inst->gic_options);
+ if (inst->server) krb5_free_principal(inst->context, inst->server);
+#endif
+
+ /* Don't free hostname, it's just a pointer into service_princ */
+ talloc_free(inst->service);
+
+ if (inst->context) krb5_free_context(inst->context);
+#ifdef KRB5_IS_THREAD_SAFE
+ fr_connection_pool_free(inst->pool);
+#endif
+
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_krb5_t *inst = instance;
+ krb5_error_code ret;
+#ifndef HEIMDAL_KRB5
+ krb5_keytab keytab;
+ char keytab_name[200];
+ char *princ_name;
+#endif
+
+#ifdef HEIMDAL_KRB5
+ DEBUG("Using Heimdal Kerberos library");
+#else
+ DEBUG("Using MIT Kerberos library");
+#endif
+
+ if (!krb5_is_thread_safe()) {
+/*
+ * rlm_krb5 was built as threadsafe
+ */
+#ifdef KRB5_IS_THREAD_SAFE
+ ERROR("Build time libkrb5 was threadsafe, but run time library claims not to be");
+ ERROR("Modify runtime linker path (LD_LIBRARY_PATH on most systems), to prefer threadsafe libkrb5");
+ return -1;
+/*
+ * rlm_krb5 was not built as threadsafe
+ */
+#else
+ radlog(L_WARN, "libkrb5 is not threadsafe, recompile it with thread support enabled ("
+# ifdef HEIMDAL_KRB5
+ "--enable-pthread-support"
+# else
+ "--disable-thread-support=no"
+# endif
+ ")");
+ WARN("rlm_krb5 will run in single threaded mode, performance may be degraded");
+ } else {
+ WARN("Build time libkrb5 was not threadsafe, but run time library claims to be");
+ WARN("Reconfigure and recompile rlm_krb5 to enable thread support");
+#endif
+ }
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
+
+ ret = krb5_init_context(&inst->context);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): context initialisation failed: %s", inst->xlat_name,
+ rlm_krb5_error(NULL, ret));
+
+ return -1;
+ }
+
+ /*
+ * Split service principal into service and host components
+ * they're needed to build the server principal in MIT,
+ * and to set the validation service in Heimdal.
+ */
+ if (inst->service_princ) {
+ size_t len;
+ /* Service principal appears to contain a host component */
+ inst->hostname = strchr(inst->service_princ, '/');
+ if (inst->hostname) {
+ len = (inst->hostname - inst->service_princ);
+ inst->hostname++;
+ } else {
+ len = strlen(inst->service_princ);
+ }
+
+ if (len) {
+ inst->service = talloc_array(inst, char, (len + 1));
+ strlcpy(inst->service, inst->service_princ, len + 1);
+ }
+ }
+
+#ifdef HEIMDAL_KRB5
+ if (inst->hostname) DEBUG("rlm_krb5 (%s): Ignoring hostname component of service principal \"%s\", not "
+ "needed/supported by Heimdal", inst->xlat_name, inst->hostname);
+#else
+
+ /*
+ * Convert the service principal string to a krb5 principal.
+ */
+ ret = krb5_sname_to_principal(inst->context, inst->hostname, inst->service, KRB5_NT_SRV_HST, &(inst->server));
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Failed parsing service principal: %s", inst->xlat_name,
+ rlm_krb5_error(inst->context, ret));
+
+ return -1;
+ }
+
+ ret = krb5_unparse_name(inst->context, inst->server, &princ_name);
+ if (ret) {
+ /* Uh? */
+ ERROR("rlm_krb5 (%s): Failed constructing service principal string: %s", inst->xlat_name,
+ rlm_krb5_error(inst->context, ret));
+
+ return -1;
+ }
+
+ /*
+ * Not necessarily the same as the config item
+ */
+ DEBUG("rlm_krb5 (%s): Using service principal \"%s\"", inst->xlat_name, princ_name);
+ krb5_free_unparsed_name(inst->context, princ_name);
+
+ /*
+ * Setup options for getting credentials and verifying them
+ */
+ ret = krb5_get_init_creds_opt_alloc(inst->context, &(inst->gic_options)); /* For some reason the 'init' version
+ of this function is deprecated */
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Couldn't allocated initial credential options: %s", inst->xlat_name,
+ rlm_krb5_error(inst->context, ret));
+
+ return -1;
+ }
+
+ /*
+ * Perform basic checks on the keytab
+ */
+ ret = inst->keytabname ?
+ krb5_kt_resolve(inst->context, inst->keytabname, &keytab) :
+ krb5_kt_default(inst->context, &keytab);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Resolving keytab failed: %s", inst->xlat_name,
+ rlm_krb5_error(inst->context, ret));
+
+ return -1;
+ }
+
+ ret = krb5_kt_get_name(inst->context, keytab, keytab_name, sizeof(keytab_name));
+ krb5_kt_close(inst->context, keytab);
+ if (ret) {
+ ERROR("rlm_krb5 (%s): Can't retrieve keytab name: %s", inst->xlat_name,
+ rlm_krb5_error(inst->context, ret));
+
+ return -1;
+ }
+
+ DEBUG("rlm_krb5 (%s): Using keytab \"%s\"", inst->xlat_name, keytab_name);
+
+ MEM(inst->vic_options = talloc_zero(inst, krb5_verify_init_creds_opt));
+ krb5_verify_init_creds_opt_init(inst->vic_options);
+#endif
+
+#ifdef KRB5_IS_THREAD_SAFE
+ /*
+ * Initialize the socket pool.
+ */
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, NULL);
+ if (!inst->pool) return -1;
+#else
+ inst->conn = mod_conn_create(inst, inst);
+ if (!inst->conn) return -1;
+#endif
+ return 0;
+}
+
+/** Common function for transforming a User-Name string into a principal.
+ *
+ * @param[out] client Where to write the client principal.
+ * @param[in] request Current request.
+ * @param[in] context Kerberos context.
+ */
+static rlm_rcode_t krb5_parse_user(krb5_principal *client, REQUEST *request, krb5_context context)
+{
+ krb5_error_code ret;
+ char *princ_name;
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
+ */
+ if (!request->username) {
+ REDEBUG("Attribute \"User-Name\" is required for authentication");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Password attribute.
+ */
+ if (!request->password) {
+ REDEBUG("Attribute \"User-Password\" is required for authentication");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Ensure that we're being passed a plain-text password,
+ * and not anything else.
+ */
+ if (request->password->da->attr != PW_USER_PASSWORD) {
+ REDEBUG("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".",
+ request->password->da->name);
+
+ return RLM_MODULE_INVALID;
+ }
+
+ ret = krb5_parse_name(context, request->username->vp_strvalue, client);
+ if (ret) {
+ REDEBUG("Failed parsing username as principal: %s", rlm_krb5_error(context, ret));
+
+ return RLM_MODULE_FAIL;
+ }
+
+ krb5_unparse_name(context, *client, &princ_name);
+ RDEBUG("Using client principal \"%s\"", princ_name);
+#ifdef HEIMDAL_KRB5
+ free(princ_name);
+#else
+ krb5_free_unparsed_name(context, princ_name);
+#endif
+ return RLM_MODULE_OK;
+}
+
+/** Log error message and return appropriate rcode
+ *
+ * Translate kerberos error codes into return codes.
+ * @param request Current request.
+ * @param ret code from kerberos.
+ * @param conn used in the last operation.
+ */
+static rlm_rcode_t krb5_process_error(REQUEST *request, rlm_krb5_handle_t *conn, int ret)
+{
+ rad_assert(ret != 0);
+ rad_assert(conn); /* Silences warnings */
+
+ switch (ret) {
+ case KRB5_LIBOS_BADPWDMATCH:
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ REDEBUG("Provided password was incorrect (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_REJECT;
+
+ case KRB5KDC_ERR_KEY_EXP:
+ case KRB5KDC_ERR_CLIENT_REVOKED:
+ case KRB5KDC_ERR_SERVICE_REVOKED:
+ REDEBUG("Account has been locked out (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_USERLOCK;
+
+ case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
+ RDEBUG("User not found (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_NOTFOUND;
+
+ default:
+ REDEBUG("Error verifying credentials (%i): %s", ret, rlm_krb5_error(conn->context, ret));
+ return RLM_MODULE_FAIL;
+ }
+}
+
+#ifdef HEIMDAL_KRB5
+
+/*
+ * Validate user/pass (Heimdal)
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_krb5_t *inst = instance;
+ rlm_rcode_t rcode;
+ krb5_error_code ret;
+
+ rlm_krb5_handle_t *conn;
+
+ krb5_principal client;
+
+# ifdef KRB5_IS_THREAD_SAFE
+ conn = fr_connection_get(inst->pool);
+ if (!conn) return RLM_MODULE_FAIL;
+# else
+ conn = inst->conn;
+# endif
+
+ /*
+ * Zero out local storage
+ */
+ memset(&client, 0, sizeof(client));
+
+ rcode = krb5_parse_user(&client, request, conn->context);
+ if (rcode != RLM_MODULE_OK) goto release;
+
+ /*
+ * Verify the user, using the options we set in instantiate
+ */
+ ret = krb5_verify_user_opt(conn->context, client, request->password->vp_strvalue, &conn->options);
+ if (ret) {
+ rcode = krb5_process_error(request, conn, ret);
+ goto cleanup;
+ }
+
+ /*
+ * krb5_verify_user_opt adds the credentials to the ccache
+ * we specified with krb5_verify_opt_set_ccache.
+ *
+ * To make sure we don't accumulate thousands of sets of
+ * credentials, remove them again here.
+ *
+ * @todo This should definitely be optional, which means writing code for the MIT
+ * variant as well.
+ */
+ {
+ krb5_cc_cursor cursor;
+ krb5_creds cred;
+
+ krb5_cc_start_seq_get(conn->context, conn->ccache, &cursor);
+ for (ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred);
+ ret == 0;
+ ret = krb5_cc_next_cred(conn->context, conn->ccache, &cursor, &cred)) {
+ krb5_cc_remove_cred(conn->context, conn->ccache, 0, &cred);
+ }
+ krb5_cc_end_seq_get(conn->context, conn->ccache, &cursor);
+ }
+
+cleanup:
+ krb5_free_principal(conn->context, client);
+
+release:
+# ifdef KRB5_IS_THREAD_SAFE
+ fr_connection_release(inst->pool, conn);
+# endif
+ return rcode;
+}
+
+#else /* HEIMDAL_KRB5 */
+
+/*
+ * Validate userid/passwd (MIT)
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_krb5_t *inst = instance;
+ rlm_rcode_t rcode;
+ krb5_error_code ret;
+
+ rlm_krb5_handle_t *conn;
+
+ krb5_principal client;
+ krb5_creds init_creds;
+ char *password; /* compiler warnings */
+
+ rad_assert(inst->context);
+
+# ifdef KRB5_IS_THREAD_SAFE
+ conn = fr_connection_get(inst->pool);
+ if (!conn) return RLM_MODULE_FAIL;
+# else
+ conn = inst->conn;
+# endif
+
+ /*
+ * Zero out local storage
+ */
+ memset(&client, 0, sizeof(client));
+ memset(&init_creds, 0, sizeof(init_creds));
+
+ /*
+ * Check we have all the required VPs, and convert the username
+ * into a principal.
+ */
+ rcode = krb5_parse_user(&client, request, conn->context);
+ if (rcode != RLM_MODULE_OK) goto release;
+
+ /*
+ * Retrieve the TGT from the TGS/KDC and check we can decrypt it.
+ */
+ memcpy(&password, &request->password->vp_strvalue, sizeof(password));
+ RDEBUG("Retrieving and decrypting TGT");
+ ret = krb5_get_init_creds_password(conn->context, &init_creds, client, password,
+ NULL, NULL, 0, NULL, inst->gic_options);
+ if (ret) {
+ rcode = krb5_process_error(request, conn, ret);
+ goto cleanup;
+ }
+
+ RDEBUG("Attempting to authenticate against service principal");
+ ret = krb5_verify_init_creds(conn->context, &init_creds, inst->server, conn->keytab, NULL, inst->vic_options);
+ if (ret) rcode = krb5_process_error(request, conn, ret);
+
+cleanup:
+ krb5_free_principal(conn->context, client);
+ krb5_free_cred_contents(conn->context, &init_creds);
+
+release:
+# ifdef KRB5_IS_THREAD_SAFE
+ fr_connection_release(inst->pool, conn);
+# endif
+ return rcode;
+}
+
+#endif /* MIT_KRB5 */
+
+extern module_t rlm_krb5;
+module_t rlm_krb5 = {
+ .magic = RLM_MODULE_INIT,
+ .name = "krb5",
+ .type = RLM_TYPE_HUP_SAFE
+#ifdef KRB5_IS_THREAD_SAFE
+ | RLM_TYPE_THREAD_SAFE
+#endif
+ ,
+ .inst_size = sizeof(rlm_krb5_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate
+ },
+};
diff --git a/src/modules/rlm_ldap/.gitignore b/src/modules/rlm_ldap/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_ldap/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_ldap/README.md b/src/modules/rlm_ldap/README.md
new file mode 100644
index 0000000..757c57c
--- /dev/null
+++ b/src/modules/rlm_ldap/README.md
@@ -0,0 +1,14 @@
+# rlm_ldap
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Allows LDAP directory entries to be retrieved, modified, inserted and deleted.
+
+May also perform user authentication using LDAP binds, or by
+retrieving the contents of a password attribute for later
+comparison by a module such as rlm_pap, or an rlm_eap method.
diff --git a/src/modules/rlm_ldap/all.mk.in b/src/modules/rlm_ldap/all.mk.in
new file mode 100644
index 0000000..daa64ec
--- /dev/null
+++ b/src/modules/rlm_ldap/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c attrmap.c ldap.c clients.c groups.c edir.c @SASL@
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_ldap/attrmap.c b/src/modules/rlm_ldap/attrmap.c
new file mode 100644
index 0000000..0589697
--- /dev/null
+++ b/src/modules/rlm_ldap/attrmap.c
@@ -0,0 +1,389 @@
+/*
+ * 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 ldap.c
+ * @brief Functions for mapping between LDAP and FreeRADIUS attributes.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Network RADIUS SARL <info@networkradius.com>
+ * @copyright 2013 The FreeRADIUS Server Project.
+ */
+
+#include <freeradius-devel/rad_assert.h>
+#include "ldap.h"
+
+/** Callback for map_to_request
+ *
+ * Performs exactly the same job as map_to_vp, but pulls attribute values from LDAP entries
+ *
+ * @see map_to_vp
+ */
+int rlm_ldap_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
+{
+ rlm_ldap_result_t *self = uctx;
+ VALUE_PAIR *head = NULL, *vp;
+ vp_cursor_t cursor;
+ int i;
+
+ fr_cursor_init(&cursor, &head);
+
+ switch (map->lhs->type) {
+ /*
+ * This is a mapping in the form of:
+ * <list>: += <ldap attr>
+ *
+ * Where <ldap attr> is:
+ * <list>:<attr> <op> <value>
+ *
+ * It is to allow for legacy installations which stored
+ * RADIUS control and reply attributes in separate LDAP
+ * attributes.
+ */
+ case TMPL_TYPE_LIST:
+ for (i = 0; i < self->count; i++) {
+ vp_map_t *attr = NULL;
+
+ RDEBUG3("Parsing valuepair string \"%s\"", self->values[i]->bv_val);
+ if (map_afrom_attr_str(ctx, &attr, self->values[i]->bv_val,
+ map->lhs->tmpl_request, map->lhs->tmpl_list,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ RWDEBUG("Failed parsing \"%s\" as valuepair (%s), skipping...", fr_strerror(),
+ self->values[i]->bv_val);
+ continue;
+ }
+
+ if (attr->lhs->tmpl_request != map->lhs->tmpl_request) {
+ RWDEBUG("valuepair \"%s\" has conflicting request qualifier (%s vs %s), skipping...",
+ self->values[i]->bv_val,
+ fr_int2str(request_refs, attr->lhs->tmpl_request, "<INVALID>"),
+ fr_int2str(request_refs, map->lhs->tmpl_request, "<INVALID>"));
+ next_pair:
+ talloc_free(attr);
+ continue;
+ }
+
+ if ((attr->lhs->tmpl_list != map->lhs->tmpl_list)) {
+ RWDEBUG("valuepair \"%s\" has conflicting list qualifier (%s vs %s), skipping...",
+ self->values[i]->bv_val,
+ fr_int2str(pair_lists, attr->lhs->tmpl_list, "<INVALID>"),
+ fr_int2str(pair_lists, map->lhs->tmpl_list, "<INVALID>"));
+ goto next_pair;
+ }
+
+ if (map_to_vp(request, &vp, request, attr, NULL) < 0) {
+ RWDEBUG("Failed creating attribute for valuepair \"%s\", skipping...",
+ self->values[i]->bv_val);
+ goto next_pair;
+ }
+
+ fr_cursor_merge(&cursor, vp);
+ talloc_free(attr);
+
+ /*
+ * Only process the first value, unless the operator is +=
+ */
+ if (map->op != T_OP_ADD) break;
+ }
+ break;
+
+ /*
+ * Iterate over all the retrieved values,
+ * don't try and be clever about changing operators
+ * just use whatever was set in the attribute map.
+ */
+ case TMPL_TYPE_ATTR:
+ for (i = 0; i < self->count; i++) {
+ if (!self->values[i]->bv_len) continue;
+
+ RDEBUG3("Parsing %s = %s", map->lhs->name, self->values[i]->bv_val);
+
+ vp = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ rad_assert(vp);
+
+ if (fr_pair_value_from_str(vp, self->values[i]->bv_val, self->values[i]->bv_len) < 0) {
+ char *escaped;
+
+ escaped = fr_aprints(vp, self->values[i]->bv_val, self->values[i]->bv_len, '"');
+ RWDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped,
+ map->lhs->tmpl_da->name, fr_strerror());
+
+ talloc_free(vp); /* also frees escaped */
+ continue;
+ }
+
+ vp->op = map->op;
+ fr_cursor_insert(&cursor, vp);
+
+ /*
+ * Only process the first value, unless the operator is +=
+ */
+ if (map->op != T_OP_ADD) break;
+ }
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ *out = head;
+
+ return 0;
+}
+
+int rlm_ldap_map_verify(vp_map_t *map, void *instance)
+{
+ rlm_ldap_t *inst = instance;
+
+ /*
+ * Destinations where we can put the VALUE_PAIRs we
+ * create using LDAP values.
+ */
+ switch (map->lhs->type) {
+ case TMPL_TYPE_LIST:
+ case TMPL_TYPE_ATTR:
+ break;
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ cf_log_err(map->ci, "Unknown attribute %s", map->lhs->tmpl_unknown_name);
+ return -1;
+
+ default:
+ cf_log_err(map->ci, "Left hand side of map must be an attribute or list, not a %s",
+ fr_int2str(tmpl_names, map->lhs->type, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * Sources we can use to get the name of the attribute
+ * we're retrieving from LDAP.
+ */
+ switch (map->rhs->type) {
+ case TMPL_TYPE_XLAT:
+ case TMPL_TYPE_ATTR:
+ case TMPL_TYPE_EXEC:
+ case TMPL_TYPE_LITERAL:
+ break;
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ cf_log_err(map->ci, "Unknown attribute %s", map->rhs->tmpl_unknown_name);
+ return -1;
+
+ default:
+ cf_log_err(map->ci, "Right hand side of map must be an xlat, attribute, exec, or literal, not a %s",
+ fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * Only =, :=, and += aoperators are supported for LDAP mappings.
+ */
+ switch (map->op) {
+ case T_OP_SET:
+ case T_OP_EQ:
+ case T_OP_ADD:
+ break;
+
+ default:
+ cf_log_err(map->ci, "Operator \"%s\" not allowed for LDAP mappings",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * Be smart about whether we warn the user about missing passwords.
+ * If there are no password attributes in the mapping, then the user's either an idiot
+ * and has no idea what they're doing, or they're authenticating the user using a different
+ * method.
+ */
+ if (!inst->expect_password && (map->lhs->type == TMPL_TYPE_ATTR) && map->lhs->tmpl_da) {
+ switch (map->lhs->tmpl_da->attr) {
+ case PW_CLEARTEXT_PASSWORD:
+ case PW_NT_PASSWORD:
+ case PW_USER_PASSWORD:
+ case PW_PASSWORD_WITH_HEADER:
+ case PW_CRYPT_PASSWORD:
+ /*
+ * Because you just know someone is going to map NT-Password to the
+ * request list, and then complain it's not working...
+ */
+ if (map->lhs->tmpl_list != PAIR_LIST_CONTROL) {
+ LDAP_DBGW("Mapping LDAP (%s) attribute to \"known good\" password attribute "
+ "(%s) in %s list. This is probably *NOT* the correct list, "
+ "you should prepend \"control:\" to password attribute "
+ "(control:%s)",
+ map->rhs->name, map->lhs->tmpl_da->name,
+ fr_int2str(pair_lists, map->lhs->tmpl_list, "<invalid>"),
+ map->lhs->tmpl_da->name);
+ }
+
+ inst->expect_password = true;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/** Expand values in an attribute map where needed
+ *
+ * @param[out] expanded array of attributes. Need not be initialised (we'll initialise).
+ * @param[in] request The current request.
+ * @param[in] maps to expand.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int rlm_ldap_map_expand(rlm_ldap_map_exp_t *expanded, REQUEST *request, vp_map_t const *maps)
+{
+ vp_map_t const *map;
+ unsigned int total = 0;
+
+ TALLOC_CTX *ctx = NULL;
+ char const *attr;
+ char attr_buff[1024 + 1]; /* X.501 says we need to support at least 1024 chars for attr names */
+
+ for (map = maps; map != NULL; map = map->next) {
+ if (tmpl_expand(&attr, attr_buff, sizeof(attr_buff), request, map->rhs, NULL, NULL) < 0) {
+ RDEBUG("Expansion of LDAP attribute \"%s\" failed", map->rhs->name);
+ TALLOC_FREE(ctx);
+ return -1;
+ }
+
+ /*
+ * Dynamic value
+ */
+ if (attr == attr_buff) {
+ if (!ctx) ctx = talloc_new(NULL);
+ expanded->attrs[total++] = talloc_strdup(ctx, attr_buff);
+ continue;
+ }
+ expanded->attrs[total++] = attr;
+ }
+ expanded->attrs[total] = NULL;
+ expanded->ctx = ctx; /* Freeing this frees any dynamic values */
+ expanded->count = total;
+ expanded->maps = maps;
+
+ return 0;
+}
+
+
+/** Convert attribute map into valuepairs
+ *
+ * Use the attribute map built earlier to convert LDAP values into valuepairs and insert them into whichever
+ * list they need to go into.
+ *
+ * This is *NOT* atomic, but there's no condition for which we should error out...
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in] handle associated with entry.
+ * @param[in] expanded attributes (rhs of map).
+ * @param[in] entry to retrieve attributes from.
+ * @return
+ * - Number of maps successfully applied.
+ * - -1 on failure.
+ */
+int rlm_ldap_map_do(const rlm_ldap_t *inst, REQUEST *request, LDAP *handle,
+ rlm_ldap_map_exp_t const *expanded, LDAPMessage *entry)
+{
+ vp_map_t const *map;
+ unsigned int total = 0;
+ int applied = 0; /* How many maps have been applied to the current request */
+
+ rlm_ldap_result_t result;
+ char const *name;
+
+ for (map = expanded->maps; map != NULL; map = map->next) {
+ int ret;
+
+ name = expanded->attrs[total++];
+
+ /*
+ * Binary safe
+ */
+ result.values = ldap_get_values_len(handle, entry, name);
+ if (!result.values) {
+ RDEBUG3("Attribute \"%s\" not found in LDAP object", name);
+
+ goto next;
+ }
+
+ /*
+ * Find out how many values there are for the
+ * attribute and extract all of them.
+ */
+ result.count = ldap_count_values_len(result.values);
+
+ /*
+ * If something bad happened, just skip, this is probably
+ * a case of the dst being incorrect for the current
+ * request context
+ */
+ ret = map_to_request(request, map, rlm_ldap_map_getvalue, &result);
+ if (ret == -1) return -1; /* Fail */
+
+ /*
+ * How many maps we've processed
+ */
+ applied++;
+
+ next:
+ ldap_value_free_len(result.values);
+ }
+
+
+ /*
+ * Retrieve any valuepair attributes from the result, these are generic values specifying
+ * a radius list, operator and value.
+ */
+ if (inst->valuepair_attr) {
+ struct berval **values;
+ int count, i;
+
+ values = ldap_get_values_len(handle, entry, inst->valuepair_attr);
+ count = ldap_count_values_len(values);
+
+ for (i = 0; i < count; i++) {
+ vp_map_t *attr;
+ char *value;
+
+ value = rlm_ldap_berval_to_string(request, values[i]);
+ RDEBUG3("Parsing attribute string '%s'", value);
+ if (map_afrom_attr_str(request, &attr, value,
+ REQUEST_CURRENT, PAIR_LIST_REPLY,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ RWDEBUG("Failed parsing '%s' value \"%s\" as valuepair (%s), skipping...",
+ fr_strerror(), inst->valuepair_attr, value);
+ talloc_free(value);
+ continue;
+ }
+ if (map_to_request(request, attr, map_to_vp, NULL) < 0) {
+ RWDEBUG("Failed adding \"%s\" to request, skipping...", value);
+ } else {
+ applied++;
+ }
+ talloc_free(attr);
+ talloc_free(value);
+ }
+ ldap_value_free_len(values);
+ }
+
+ return applied;
+}
diff --git a/src/modules/rlm_ldap/clients.c b/src/modules/rlm_ldap/clients.c
new file mode 100644
index 0000000..8654475
--- /dev/null
+++ b/src/modules/rlm_ldap/clients.c
@@ -0,0 +1,263 @@
+/*
+ * 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 clients.c
+ * @brief LDAP module dynamic clients.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013,2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013-2015 The FreeRADIUS Server Project.
+ */
+#include <freeradius-devel/rad_assert.h>
+#include <ctype.h>
+
+#include "ldap.h"
+
+/** Iterate over pairs in mapping section recording their values in an array
+ *
+ * This array is the list of attributes we retrieve from LDAP, and is NULL
+ * terminated.
+ *
+ * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
+ *
+ * @param[out] values array of char pointers.
+ * @param[in,out] idx records current array offset.
+ * @param[in] cs to iterate over.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+static int rlm_ldap_client_get_attrs(char const **values, int *idx, CONF_SECTION const *cs)
+{
+ CONF_ITEM const *ci;
+
+ for (ci = cf_item_find_next(cs, NULL);
+ ci != NULL;
+ ci = cf_item_find_next(cs, ci)) {
+ char const *value;
+
+ if (cf_item_is_section(ci)) {
+ if (rlm_ldap_client_get_attrs(values, idx, cf_item_to_section(ci)) < 0) return -1;
+ continue;
+ }
+
+ value = cf_pair_value(cf_item_to_pair(ci));
+ if (!value) return -1;
+
+ values[(*idx)++] = value;
+ }
+
+ values[*idx] = NULL;
+
+ return 0;
+}
+
+typedef struct ldap_client_data {
+ ldap_handle_t *conn;
+ LDAPMessage *entry;
+} ldap_client_data_t;
+
+static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
+{
+ struct berval **values;
+ ldap_client_data_t *this = data;
+
+ values = ldap_get_values_len(this->conn->handle, this->entry, cf_pair_value(cp));
+ if (!values) {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = rlm_ldap_berval_to_string(NULL, values[0]);
+ ldap_value_free_len(values);
+
+ if (!*out) return -1;
+ return 0;
+}
+
+/** Load clients from LDAP on server start
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] tmpl to use as the base for the new client.
+ * @param[in] map to load client attribute/LDAP attribute mappings from.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
+{
+ int ret = 0;
+ ldap_rcode_t status;
+ ldap_handle_t *conn = NULL;
+
+ char const **attrs = NULL;
+
+ CONF_PAIR *cp;
+ int count = 0, idx = 0;
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+ char *dn = NULL;
+
+ RADCLIENT *c;
+
+ LDAP_DBG("Loading dynamic clients");
+
+ rad_assert(inst->clientobj_base_dn);
+
+ count = cf_pair_count(map);
+ count++;
+
+ /*
+ * Create an array of LDAP attributes to feed to rlm_ldap_search.
+ */
+ attrs = talloc_array(inst, char const *, count);
+ if (rlm_ldap_client_get_attrs(attrs, &idx, map) < 0) {
+ talloc_free(attrs);
+ return -1;
+ }
+
+ conn = mod_conn_get(inst, NULL);
+ if (!conn) {
+ talloc_free(attrs);
+ return -1;
+ }
+
+ /*
+ * Perform all searches as the admin user.
+ */
+ if (conn->rebound) {
+ status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
+ &(conn->inst->admin_sasl), true);
+ if (status != LDAP_PROC_SUCCESS) {
+ ret = -1;
+ goto finish;
+ }
+
+ rad_assert(conn);
+
+ conn->rebound = false;
+ }
+
+ status = rlm_ldap_search(&result, inst, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope,
+ inst->clientobj_filter, attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ LDAP_INFO("No clients were found in the directory");
+ ret = 0;
+ goto finish;
+
+ default:
+ ret = -1;
+ goto finish;
+ }
+
+ rad_assert(conn);
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
+ int ldap_errno;
+
+ ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ ret = -1;
+ goto finish;
+ }
+
+ do {
+ ldap_client_data_t data;
+
+ CONF_SECTION *client;
+ char *id;
+
+ struct berval **values;
+
+ id = dn = ldap_get_dn(conn->handle, entry);
+ if (!dn) {
+ int ldap_errno;
+
+ ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ LDAP_ERR("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+ rlm_ldap_normalise_dn(dn, dn);
+
+ cp = cf_pair_find(map, "identifier");
+ if (cp) {
+ values = ldap_get_values_len(conn->handle, entry, cf_pair_value(cp));
+ if (values) id = rlm_ldap_berval_to_string(NULL, values[0]);
+ ldap_value_free_len(values);
+ }
+
+ /*
+ * Iterate over mapping sections
+ */
+ client = tmpl ? cf_section_dup(NULL, tmpl, "client", id, true) :
+ cf_section_alloc(NULL, "client", id);
+
+ data.conn = conn;
+ data.entry = entry;
+
+ if (client_map_section(client, map, _get_client_value, &data) < 0) {
+ talloc_free(client);
+ ret = -1;
+ goto finish;
+ }
+
+ /*
+ *@todo these should be parented from something
+ */
+ c = client_afrom_cs(NULL, client, false, false);
+ if (!c) {
+ talloc_free(client);
+ ret = -1;
+ goto finish;
+ }
+
+ /*
+ * Client parents the CONF_SECTION which defined it
+ */
+ talloc_steal(c, client);
+
+ if (!client_add(NULL, c)) {
+ LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn);
+ ret = -1;
+ client_free(c);
+ goto finish;
+ }
+
+ LDAP_DBG("Client \"%s\" added", dn);
+
+ ldap_memfree(dn);
+ dn = NULL;
+ } while ((entry = ldap_next_entry(conn->handle, entry)));
+
+finish:
+ talloc_free(attrs);
+ if (dn) ldap_memfree(dn);
+ if (result) ldap_msgfree(result);
+
+ mod_conn_release(inst, conn);
+
+ return ret;
+}
+
diff --git a/src/modules/rlm_ldap/config.h.in b/src/modules/rlm_ldap/config.h.in
new file mode 100644
index 0000000..8ef08da
--- /dev/null
+++ b/src/modules/rlm_ldap/config.h.in
@@ -0,0 +1,43 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `ldap_create_sort_control' function. */
+#undef HAVE_LDAP_CREATE_SORT_CONTROL
+
+/* Define to 1 if you have the `ldap_create_sort_keylist' function. */
+#undef HAVE_LDAP_CREATE_SORT_KEYLIST
+
+/* Define to 1 if you have the `ldap_free_sort_keylist' function. */
+#undef HAVE_LDAP_FREE_SORT_KEYLIST
+
+/* Define to 1 if you have the `ldap_initialize' function. */
+#undef HAVE_LDAP_INITIALIZE
+
+/* Define to 1 if you have the `ldap_is_ldap_url' function. */
+#undef HAVE_LDAP_IS_LDAP_URL
+
+/* Define to 1 if you have the `ldap_sasl_interactive_bind' function. */
+#undef HAVE_LDAP_SASL_INTERACTIVE_BIND
+
+/* Define to 1 if you have the `ldap_set_rebind_proc' function. */
+#undef HAVE_LDAP_SET_REBIND_PROC
+
+/* Define to 1 if you have the `ldap_start_tls_s' function. */
+#undef HAVE_LDAP_START_TLS_S
+
+/* Define to 1 if you have the `ldap_unbind_ext_s' function. */
+#undef HAVE_LDAP_UNBIND_EXT_S
+
+/* Define to 1 if you have the `ldap_url_desc2str' function. */
+#undef HAVE_LDAP_URL_DESC2STR
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#undef HAVE_LDAP_URL_PARSE
+
+/* Number of arguments the rebind procedure takes */
+#undef LDAP_SET_REBIND_PROC_ARGS
+
+/* Build the server with support for Novell eDir Universal Password */
+#undef WITH_EDIR
+
+/* Build the server with support for SASL binds */
+#undef WITH_SASL
diff --git a/src/modules/rlm_ldap/configure b/src/modules/rlm_ldap/configure
new file mode 100755
index 0000000..685c29f
--- /dev/null
+++ b/src/modules/rlm_ldap/configure
@@ -0,0 +1,4636 @@
+#! /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_ldap.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+SASL
+mod_cflags
+mod_ldflags
+targetname
+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_ldap
+with_rlm_ldap_lib_dir
+with_rlm_ldap_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_ldap build without LDAP support
+ --with-rlm-ldap-lib-dir=DIR
+ directory for LDAP library files
+ --with-rlm-ldap-include-dir=DIR
+ directory for LDAP include files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_ldap
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_ldap was given.
+if test "${with_rlm_ldap+set}" = set; then :
+ withval=$with_rlm_ldap;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+SASL=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_ldap" != 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
+
+
+
+rlm_ldap_lib_dir=
+
+# Check whether --with-rlm-ldap-lib-dir was given.
+if test "${with_rlm_ldap_lib_dir+set}" = set; then :
+ withval=$with_rlm_ldap_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-ldap-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_ldap_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+rlm_ldap_include_dir=
+
+# Check whether --with-rlm-ldap-include-dir was given.
+if test "${with_rlm_ldap_include_dir+set}" = set; then :
+ withval=$with_rlm_ldap_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-ldap-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_ldap_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir=$rlm_ldap_lib_dir
+
+
+
+sm_lib_safe=`echo "ldap" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ldap_init" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_init in -lldap in $try" >&5
+$as_echo_n "checking for ldap_init in -lldap in $try... " >&6; }
+ LIBS="-lldap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ldap_init();
+int
+main ()
+{
+ldap_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lldap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+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 ldap_init in -lldap" >&5
+$as_echo_n "checking for ldap_init in -lldap... " >&6; }
+ LIBS="-lldap $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ldap_init();
+int
+main ()
+{
+ldap_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lldap"
+ { $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 ldap_init in -lldap in $try" >&5
+$as_echo_n "checking for ldap_init in -lldap in $try... " >&6; }
+ LIBS="-lldap $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ldap_init();
+int
+main ()
+{
+ldap_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lldap"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+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_ldap_ldap_init" != "xyes"; then
+
+fail="$fail libldap"
+
+fi
+
+
+smart_try_dir=$rlm_ldap_include_dir
+
+
+ac_safe=`echo "ldap.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 ldap.h in $try" >&5
+$as_echo_n "checking for ldap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ldap.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}/ldap.h" >&5
+$as_echo_n "checking for ${_prefix}/ldap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ldap.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 ldap.h" >&5
+$as_echo_n "checking for ldap.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ldap.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 ldap.h in $try" >&5
+$as_echo_n "checking for ldap.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ldap.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_ldap_h" != "yes"; then
+
+fail="$fail ldap.h"
+
+fi
+
+
+
+if test x"$fail" = x""; then :
+
+ for ac_func in ldap_sasl_interactive_bind \
+ ldap_unbind_ext_s \
+ ldap_start_tls_s \
+ ldap_initialize \
+ ldap_set_rebind_proc \
+ ldap_create_sort_control \
+ ldap_create_sort_keylist \
+ ldap_free_sort_keylist \
+ ldap_url_parse \
+ ldap_is_ldap_url \
+ ldap_url_desc2str
+
+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 "$as_me:${as_lineno-$LINENO}: checking whether ldap_set_rebind_proc takes 3 arguments" >&5
+$as_echo_n "checking whether ldap_set_rebind_proc takes 3 arguments... " >&6; }
+if ${ac_cv_ldap_set_rebind_proc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <lber.h>
+ #include <ldap.h>
+int
+main ()
+{
+ldap_set_rebind_proc(0, 0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_ldap_set_rebind_proc=3
+else
+ ac_cv_ldap_set_rebind_proc=2
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_ldap_set_rebind_proc" >&5
+$as_echo "$ac_cv_ldap_set_rebind_proc" >&6; }
+
+fi
+
+
+
+
+ac_safe=`echo "sasl/sasl.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 sasl/sasl.h in $try" >&5
+$as_echo_n "checking for sasl/sasl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sasl/sasl.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}/sasl/sasl.h" >&5
+$as_echo_n "checking for ${_prefix}/sasl/sasl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sasl/sasl.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 sasl/sasl.h" >&5
+$as_echo_n "checking for sasl/sasl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sasl/sasl.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 sasl/sasl.h in $try" >&5
+$as_echo_n "checking for sasl/sasl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sasl/sasl.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_sasl_sasl_h" = "xyes"; then
+ if test x"$ac_cv_func_ldap_sasl_interactive_bind" = "xyes"; then
+
+$as_echo "#define WITH_SASL 1" >>confdefs.h
+
+ SASL=sasl.c
+
+if echo "$fr_features" | grep -q "+sasl+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with SASL support" >> config.report.tmp
+ fr_features="$fr_features +sasl+"
+fi
+
+ fi
+else
+
+if echo "$fr_features" | grep -q "+sasl+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without SASL support" >> config.report.tmp
+ fr_features="$fr_features +sasl+"
+fi
+
+fi
+
+
+ targetname=rlm_ldap
+else
+ targetname=
+ echo \*\*\* module rlm_ldap is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_ldap to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_ldap." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_ldap." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_ldap requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_ldap requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+$as_echo "#define WITH_EDIR 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define LDAP_SET_REBIND_PROC_ARGS ${ac_cv_ldap_set_rebind_proc}
+_ACEOF
+
+
+mod_ldflags=$SMART_LIBS
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_ldap/configure.ac b/src/modules/rlm_ldap/configure.ac
new file mode 100644
index 0000000..f8991d9
--- /dev/null
+++ b/src/modules/rlm_ldap/configure.ac
@@ -0,0 +1,140 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_ldap.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_ldap], [LDAP support])
+
+SMART_LIBS=
+SMART_CLFAGS=
+SASL=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for compiler
+dnl ############################################################
+
+AC_PROG_CC
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl # extra argument: --with-rlm-ldap-lib-dir
+rlm_ldap_lib_dir=
+AC_ARG_WITH(rlm-ldap-lib-dir,
+ [AS_HELP_STRING([--with-rlm-ldap-lib-dir=DIR],
+ [directory for LDAP library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-ldap-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_ldap_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl # extra argument: --with-rlm-ldap-include-dir
+rlm_ldap_include_dir=
+AC_ARG_WITH(rlm-ldap-include-dir,
+ [AS_HELP_STRING([--with-rlm-ldap-include-dir=DIR],
+ [directory for LDAP include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-ldap-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_ldap_include_dir="$withval"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+dnl #
+dnl # Official word from those who represent OpenLDAP say
+dnl # libldap_r is unsupported for use outside the OpenLDAP
+dnl # server. But libldap *may* work with the FreeRADIUS
+dnl # as we use a threadpool to prevent concurrent access to
+dnl # the same libldap handle.
+dnl #
+dnl # In FreeRADIUS <= 3.0.6 we used libldap_r in preference
+dnl # to libldap, however, in order to support certain distros
+dnl # or packagers that only ship libldap in their OpenLDAP
+dnl # client packages, we're forced to switch to just libldap.
+dnl #
+smart_try_dir=$rlm_ldap_lib_dir
+FR_SMART_CHECK_LIB(ldap, ldap_init)
+if test "x$ac_cv_lib_ldap_ldap_init" != "xyes"; then
+ FR_MODULE_FAIL([libldap])
+fi
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir=$rlm_ldap_include_dir
+FR_SMART_CHECK_INCLUDE(ldap.h)
+if test "$ac_cv_header_ldap_h" != "yes"; then
+ FR_MODULE_FAIL([ldap.h])
+fi
+
+dnl ############################################################
+dnl # Check for library functions
+dnl ############################################################
+
+FR_MODULE_TEST_PASS_DO([
+ AC_CHECK_FUNCS(
+ ldap_sasl_interactive_bind \
+ ldap_unbind_ext_s \
+ ldap_start_tls_s \
+ ldap_initialize \
+ ldap_set_rebind_proc \
+ ldap_create_sort_control \
+ ldap_create_sort_keylist \
+ ldap_free_sort_keylist \
+ ldap_url_parse \
+ ldap_is_ldap_url \
+ ldap_url_desc2str
+ )
+ AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, ac_cv_ldap_set_rebind_proc, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <lber.h>
+ #include <ldap.h>]], [[ldap_set_rebind_proc(0, 0, 0);]])],[ac_cv_ldap_set_rebind_proc=3],[ac_cv_ldap_set_rebind_proc=2])
+ ])
+])
+
+dnl ############################################################
+dnl # Check for SASL support
+dnl ############################################################
+FR_SMART_CHECK_INCLUDE([sasl/sasl.h])
+if test "x$ac_cv_header_sasl_sasl_h" = "xyes"; then
+ if test x"$ac_cv_func_ldap_sasl_interactive_bind" = "xyes"; then
+ AC_DEFINE(WITH_SASL, 1, [Build the server with support for SASL binds])
+ SASL=sasl.c
+ FR_MODULE_FEATURE([sasl], [with SASL support])
+ fi
+else
+ FR_MODULE_FEATURE([sasl], [without SASL support])
+fi
+
+FR_MODULE_END_TESTS
+
+AC_DEFINE(WITH_EDIR, 1, [Build the server with support for Novell eDir Universal Password])
+AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, ${ac_cv_ldap_set_rebind_proc}, [Number of arguments the rebind procedure takes])
+
+mod_ldflags=$SMART_LIBS
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+AC_SUBST(SASL)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_ldap/edir.c b/src/modules/rlm_ldap/edir.c
new file mode 100644
index 0000000..ddac7e2
--- /dev/null
+++ b/src/modules/rlm_ldap/edir.c
@@ -0,0 +1,275 @@
+/*
+ * 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 edir.c
+ * @brief LDAP extension for reading eDirectory universal password.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ *
+ * @copyright 2012 Olivier Beytrison <olivier@heliosnet.org>
+ * @copyright 2012 Alan DeKok <aland@freeradius.org>
+ * @copyright 2002-2004 Novell, Inc.
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "ldap.h"
+
+/* NMAS error codes */
+#define NMAS_E_BASE (-1600)
+
+#define NMAS_E_FRAG_FAILURE (NMAS_E_BASE-31) /* -1631 0xFFFFF9A1 */
+#define NMAS_E_BUFFER_OVERFLOW (NMAS_E_BASE-33) /* -1633 0xFFFFF99F */
+#define NMAS_E_SYSTEM_RESOURCES (NMAS_E_BASE-34) /* -1634 0xFFFFF99E */
+#define NMAS_E_INSUFFICIENT_MEMORY (NMAS_E_BASE-35) /* -1635 0xFFFFF99D */
+#define NMAS_E_NOT_SUPPORTED (NMAS_E_BASE-36) /* -1636 0xFFFFF99C */
+#define NMAS_E_INVALID_PARAMETER (NMAS_E_BASE-43) /* -1643 0xFFFFF995 */
+#define NMAS_E_INVALID_VERSION (NMAS_E_BASE-52) /* -1652 0xFFFFF98C */
+#define NMAS_E_ACCESS_NOT_ALLOWED (NMAS_E_BASE-59) /* -1659 0xFFFFF985 */
+#define NMAS_E_INVALID_SPM_REQUEST (NMAS_E_BASE-97) /* -1697 0xFFFFF95F */
+
+/* OID of LDAP extenstion calls to read Universal Password */
+#define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
+#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
+
+#define NMAS_LDAP_EXT_VERSION 1
+
+/** Takes the object DN and BER encodes the data into the BER value which is used as part of the request
+ *
+ @verbatim
+ RequestBer contents:
+ clientVersion INTEGER
+ targetObjectDN OCTET STRING
+ @endverbatim
+ *
+ * @param[out] request_bv where to write the request BER value (must be freed with ber_bvfree).
+ * @param[in] dn to query for.
+ * @return
+ * - 0 on success.
+ * - < 0 on error.
+ */
+static int ber_encode_request_data(char const *dn, struct berval **request_bv)
+{
+ int err = 0;
+ int rc = 0;
+ BerElement *request_ber = NULL;
+
+ if (!dn || !*dn) {
+ err = NMAS_E_INVALID_PARAMETER;
+ goto finish;
+ }
+
+ /* Allocate a BerElement for the request parameters.*/
+ if ((request_ber = ber_alloc()) == NULL) {
+ err = NMAS_E_FRAG_FAILURE;
+ goto finish;
+ }
+
+ rc = ber_printf(request_ber, "{io}", NMAS_LDAP_EXT_VERSION, dn, strlen(dn) + 1);
+ if (rc < 0) {
+ err = NMAS_E_FRAG_FAILURE;
+ goto finish;
+ }
+
+ /*
+ * Convert the BER we just built to a berval that we'll
+ * send with the extended request.
+ */
+ if (ber_flatten(request_ber, request_bv) < 0) {
+ err = NMAS_E_FRAG_FAILURE;
+ goto finish;
+ }
+
+finish:
+ if (request_ber) ber_free(request_ber, 1);
+
+ return err;
+}
+
+/** Converts the reply into server version and a return code
+ *
+ * This function takes the reply BER Value and decodes the NMAS server version and return code and if a non
+ * null retData buffer was supplied, tries to decode the the return data and length.
+ *
+ @verbatim
+ ResponseBer contents:
+ server_version INTEGER
+ error INTEGER
+ data OCTET STRING
+ @endverbatim
+ *
+ * @param[in] reply_bv reply data from extended request.
+ * @param[out] server_version that responded.
+ * @param[out] out data.
+ * @param[out] outlen Length of data written to out.
+ * @return
+ * - 0 on success.
+ * - < 0 on error.
+ */
+static int ber_decode_login_data(struct berval *reply_bv, int *server_version, void *out, size_t *outlen)
+{
+ int rc = 0;
+ int err = 0;
+ BerElement *reply_ber = NULL;
+
+ rad_assert(out != NULL);
+ rad_assert(outlen != NULL);
+
+ if ((reply_ber = ber_init(reply_bv)) == NULL) {
+ err = NMAS_E_SYSTEM_RESOURCES;
+ goto finish;
+ }
+
+ rc = ber_scanf(reply_ber, "{iis}", server_version, &err, out, outlen);
+ if (rc == -1) {
+ err = NMAS_E_FRAG_FAILURE;
+ goto finish;
+ }
+
+finish:
+
+ if (reply_ber) ber_free(reply_ber, 1);
+
+ return err;
+}
+
+/** Attempt to retrieve the universal password from Novell eDirectory
+ *
+ * @param[in] ld LDAP handle.
+ * @param[in] dn of user we want to retrieve the password for.
+ * @param[out] password Where to write the retrieved password.
+ * @param[out] passlen Length of data written to the password buffer.
+ * @return
+ * - 0 on success.
+ * - < 0 on failure.
+ */
+int nmasldap_get_password(LDAP *ld, char const *dn, char *password, size_t *passlen)
+{
+ int err = 0;
+ struct berval *request_bv = NULL;
+ char *reply_oid = NULL;
+ struct berval *reply_bv = NULL;
+ int server_version;
+ size_t bufsize;
+ char buffer[256];
+
+ /* Validate parameters. */
+ if (!dn || !*dn || !passlen || !ld) {
+ return NMAS_E_INVALID_PARAMETER;
+ }
+
+ err = ber_encode_request_data(dn, &request_bv);
+ if (err) goto finish;
+
+ /* Call the ldap_extended_operation (synchronously) */
+ err = ldap_extended_operation_s(ld, NMASLDAP_GET_PASSWORD_REQUEST, request_bv, NULL, NULL, &reply_oid, &reply_bv);
+ if (err) goto finish;
+
+ /* Make sure there is a return OID */
+ if (!reply_oid) {
+ err = NMAS_E_NOT_SUPPORTED;
+ goto finish;
+ }
+
+ /* Is this what we were expecting to get back. */
+ if (strcmp(reply_oid, NMASLDAP_GET_PASSWORD_RESPONSE) != 0) {
+ err = NMAS_E_NOT_SUPPORTED;
+ goto finish;
+ }
+
+ /* Do we have a good returned berval? */
+ if (!reply_bv) {
+ /*
+ * No; returned berval means we experienced a rather
+ * drastic error. Return operations error.
+ */
+ err = NMAS_E_SYSTEM_RESOURCES;
+ goto finish;
+ }
+
+ bufsize = sizeof(buffer);
+ err = ber_decode_login_data(reply_bv, &server_version, buffer, &bufsize);
+ if (err) goto finish;
+
+ if (server_version != NMAS_LDAP_EXT_VERSION) {
+ err = NMAS_E_INVALID_VERSION;
+ goto finish;
+ }
+
+ if (bufsize > *passlen) {
+ err = NMAS_E_BUFFER_OVERFLOW;
+ goto finish;
+ }
+
+ memcpy(password, buffer, bufsize);
+ password[bufsize] = '\0';
+ *passlen = bufsize;
+
+finish:
+ if (reply_bv) {
+ ber_bvfree(reply_bv);
+ }
+
+ /* Free the return OID string if one was returned. */
+ if (reply_oid) {
+ ldap_memfree(reply_oid);
+ }
+
+ /* Free memory allocated while building the request ber and berval. */
+ if (request_bv) {
+ ber_bvfree(request_bv);
+ }
+
+ return err;
+}
+
+char const *edir_errstr(int code) {
+ switch (code) {
+ case NMAS_E_FRAG_FAILURE:
+ return "BER manipulation failed";
+
+ case NMAS_E_BUFFER_OVERFLOW:
+ return "Insufficient buffer space to write retrieved password";
+
+ case NMAS_E_SYSTEM_RESOURCES:
+ case NMAS_E_INSUFFICIENT_MEMORY:
+ return "Insufficient memory or system resources";
+
+ case NMAS_E_NOT_SUPPORTED:
+ return "Server response indicated Universal Password is not supported (missing password response OID)";
+
+ case NMAS_E_INVALID_PARAMETER:
+ return "Bad arguments passed to eDir functions";
+
+ case NMAS_E_INVALID_VERSION:
+ return "LDAP EXT version does not match expected version" STRINGIFY(NMAS_LDAP_EXT_VERSION);
+
+ case NMAS_E_ACCESS_NOT_ALLOWED:
+ return "Bound user does not have sufficient rights to read the Universal Password of users";
+
+ case NMAS_E_INVALID_SPM_REQUEST:
+ return "Universal password is not enabled for the container of this user object";
+
+ default:
+ return ldap_err2string(code);
+ }
+}
diff --git a/src/modules/rlm_ldap/groups.c b/src/modules/rlm_ldap/groups.c
new file mode 100644
index 0000000..21fe232
--- /dev/null
+++ b/src/modules/rlm_ldap/groups.c
@@ -0,0 +1,863 @@
+/*
+ * 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 groups.c
+ * @brief LDAP module group functions.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ *
+ * @copyright 2013 Network RADIUS SARL <info@networkradius.com>
+ * @copyright 2013-2015 The FreeRADIUS Server Project.
+ */
+#include <freeradius-devel/rad_assert.h>
+#include <ctype.h>
+
+#include "ldap.h"
+
+/** Convert multiple group names into a DNs
+ *
+ * Given an array of group names, builds a filter matching all names, then retrieves all group objects
+ * and stores the DN associated with each group object.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] names to covert to DNs (NULL terminated).
+ * @param[out] out Where to write the DNs. DNs must be freed with ldap_memfree(). Will be NULL terminated.
+ * @param[in] outlen Size of out.
+ * @return One of the RLM_MODULE_* values.
+ */
+static rlm_rcode_t rlm_ldap_group_name2dn(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char **names, char **out, size_t outlen)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+ int ldap_errno;
+
+ unsigned int name_cnt = 0;
+ unsigned int entry_cnt;
+ char const *attrs[] = { NULL };
+
+ LDAPMessage *result = NULL, *entry;
+
+ char **name = names;
+ char **dn = out;
+ char const *base_dn = NULL;
+ char base_dn_buff[LDAP_MAX_DN_STR_LEN];
+ char buffer[LDAP_MAX_GROUP_NAME_LEN + 1];
+
+ char *filter;
+
+ *dn = NULL;
+
+ if (!*names) {
+ return RLM_MODULE_OK;
+ }
+
+ if (!inst->groupobj_name_attr) {
+ REDEBUG("Told to convert group names to DNs but missing 'group.name_attribute' directive");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ RDEBUG("Converting group name(s) to group DN(s)");
+
+ /*
+ * It'll probably only save a few ms in network latency, but it means we can send a query
+ * for the entire group list at once.
+ */
+ filter = talloc_typed_asprintf(request, "%s%s%s",
+ inst->groupobj_filter ? "(&" : "",
+ inst->groupobj_filter ? inst->groupobj_filter : "",
+ names[0] && names[1] ? "(|" : "");
+ while (*name) {
+ rlm_ldap_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
+ filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);
+
+ name_cnt++;
+ }
+ filter = talloc_asprintf_append_buffer(filter, "%s%s",
+ inst->groupobj_filter ? ")" : "",
+ names[0] && names[1] ? ")" : "");
+
+ if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
+ inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
+ REDEBUG("Failed creating base_dn");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ status = rlm_ldap_search(&result, inst, request, pconn, base_dn, inst->groupobj_scope,
+ filter, attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ RDEBUG("Tried to resolve group name(s) to DNs but got no results");
+ goto finish;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ entry_cnt = ldap_count_entries((*pconn)->handle, result);
+ if (entry_cnt > name_cnt) {
+ REDEBUG("Number of DNs exceeds number of names, group and/or dn should be more restrictive");
+ rcode = RLM_MODULE_INVALID;
+
+ goto finish;
+ }
+
+ if (entry_cnt > (outlen - 1)) {
+ REDEBUG("Number of DNs exceeds limit (%zu)", outlen - 1);
+ rcode = RLM_MODULE_INVALID;
+
+ goto finish;
+ }
+
+ if (entry_cnt < name_cnt) {
+ RWDEBUG("Got partial mapping of group names (%i) to DNs (%i), membership information may be incomplete",
+ name_cnt, entry_cnt);
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (!entry) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ do {
+ *dn = ldap_get_dn((*pconn)->handle, entry);
+ if (!*dn) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ rlm_ldap_normalise_dn(*dn, *dn);
+
+ RDEBUG("Got group DN \"%s\"", *dn);
+ dn++;
+ } while((entry = ldap_next_entry((*pconn)->handle, entry)));
+
+ *dn = NULL;
+
+finish:
+ talloc_free(filter);
+ if (result) {
+ ldap_msgfree(result);
+ }
+
+ /*
+ * Be nice and cleanup the output array if we error out.
+ */
+ if (rcode != RLM_MODULE_OK) {
+ dn = out;
+ while(*dn) ldap_memfree(*dn++);
+ *dn = NULL;
+ }
+
+ return rcode;
+}
+
+/** Convert a single group name into a DN
+ *
+ * Unlike the inverse conversion of a name to a DN, most LDAP directories don't allow filtering by DN,
+ * so we need to search for each DN individually.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn to resolve.
+ * @param[out] out Where to write group name (must be freed with talloc_free).
+ * @return One of the RLM_MODULE_* values.
+ */
+static rlm_rcode_t rlm_ldap_group_dn2name(rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t **pconn, char const *dn, char **out)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+ int ldap_errno;
+
+ struct berval **values = NULL;
+ char const *attrs[] = { inst->groupobj_name_attr, NULL };
+ LDAPMessage *result = NULL, *entry;
+
+ *out = NULL;
+
+ if (!inst->groupobj_name_attr) {
+ REDEBUG("Told to resolve group DN to name but missing 'group.name_attribute' directive");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ RDEBUG("Resolving group DN \"%s\" to group name", dn);
+
+ status = rlm_ldap_search(&result, inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ REDEBUG("Group DN \"%s\" did not resolve to an object", dn);
+ return inst->allow_dangling_group_refs ? RLM_MODULE_NOOP : RLM_MODULE_INVALID;
+
+ default:
+ return RLM_MODULE_FAIL;
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (!entry) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ rcode = RLM_MODULE_INVALID;
+ goto finish;
+ }
+
+ values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
+ if (!values) {
+ REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);
+
+ rcode = RLM_MODULE_INVALID;
+
+ goto finish;
+ }
+
+ *out = rlm_ldap_berval_to_string(request, values[0]);
+ RDEBUG("Group DN \"%s\" resolves to name \"%s\"", dn, *out);
+
+finish:
+ if (result) ldap_msgfree(result);
+ if (values) ldap_value_free_len(values);
+
+ return rcode;
+}
+
+/** Convert group membership information into attributes
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
+ * @param[in] attr membership attribute to look for in the entry.
+ * @return One of the RLM_MODULE_* values.
+ */
+rlm_rcode_t rlm_ldap_cacheable_userobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ LDAPMessage *entry, char const *attr)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+
+ struct berval **values;
+
+ char *group_name[LDAP_MAX_CACHEABLE + 1];
+ char **name_p = group_name;
+
+ char *group_dn[LDAP_MAX_CACHEABLE + 1];
+ char **dn_p;
+
+ char *name;
+
+ VALUE_PAIR *vp, **list, *groups = NULL;
+ TALLOC_CTX *list_ctx, *value_ctx;
+ vp_cursor_t list_cursor, groups_cursor;
+
+ int is_dn, i, count, to_resolve = 0;
+
+ rad_assert(entry);
+ rad_assert(attr);
+
+ /*
+ * Parse the membership information we got in the initial user query.
+ */
+ values = ldap_get_values_len((*pconn)->handle, entry, attr);
+ if (!values) {
+ RDEBUG2("No cacheable group memberships found in user object");
+
+ return RLM_MODULE_OK;
+ }
+ count = ldap_count_values_len(values);
+
+ list = radius_list(request, PAIR_LIST_CONTROL);
+ list_ctx = radius_list_ctx(request, PAIR_LIST_CONTROL);
+
+ /*
+ * Simplifies freeing temporary values
+ */
+ value_ctx = talloc_new(request);
+
+ /*
+ * Temporary list to hold new group VPs, will be merged
+ * once all group info has been gathered/resolved
+ * successfully.
+ */
+ fr_cursor_init(&groups_cursor, &groups);
+
+ for (i = 0; (to_resolve < LDAP_MAX_CACHEABLE) && (i < count); i++) {
+ is_dn = rlm_ldap_is_dn(values[i]->bv_val, values[i]->bv_len);
+
+ if (inst->cacheable_group_dn) {
+ /*
+ * The easy case, we're caching DNs and we got a DN.
+ */
+ if (is_dn) {
+ MEM(vp = fr_pair_afrom_da(list_ctx, inst->cache_da));
+ fr_pair_value_bstrncpy(vp, values[i]->bv_val, values[i]->bv_len);
+ fr_cursor_insert(&groups_cursor, vp);
+ /*
+ * We were told to cache DNs but we got a name, we now need to resolve
+ * this to a DN. Store all the group names in an array so we can do one query.
+ */
+ } else {
+ *name_p++ = rlm_ldap_berval_to_string(value_ctx, values[i]);
+ to_resolve++;
+ }
+ }
+
+ if (inst->cacheable_group_name) {
+ /*
+ * The easy case, we're caching names and we got a name.
+ */
+ if (!is_dn) {
+ MEM(vp = fr_pair_afrom_da(list_ctx, inst->cache_da));
+ fr_pair_value_bstrncpy(vp, values[i]->bv_val, values[i]->bv_len);
+ fr_cursor_insert(&groups_cursor, vp);
+ /*
+ * We were told to cache names but we got a DN, we now need to resolve
+ * this to a name.
+ * Only Active Directory supports filtering on DN, so we have to search
+ * for each individual group.
+ */
+ } else {
+ char *dn;
+
+ dn = rlm_ldap_berval_to_string(value_ctx, values[i]);
+ rcode = rlm_ldap_group_dn2name(inst, request, pconn, dn, &name);
+ talloc_free(dn);
+
+ if (rcode == RLM_MODULE_NOOP) continue;
+
+ if (rcode != RLM_MODULE_OK) {
+ ldap_value_free_len(values);
+ talloc_free(value_ctx);
+ fr_pair_list_free(&groups);
+
+ return rcode;
+ }
+
+ MEM(vp = fr_pair_afrom_da(list_ctx, inst->cache_da));
+ fr_pair_value_bstrncpy(vp, name, talloc_array_length(name) - 1);
+ fr_cursor_insert(&groups_cursor, vp);
+ talloc_free(name);
+ }
+ }
+ }
+ *name_p = NULL;
+
+ rcode = rlm_ldap_group_name2dn(inst, request, pconn, group_name, group_dn, sizeof(group_dn));
+
+ ldap_value_free_len(values);
+ talloc_free(value_ctx);
+
+ if (rcode != RLM_MODULE_OK) return rcode;
+
+ fr_cursor_init(&list_cursor, list);
+
+ RDEBUG("Adding cacheable user object memberships");
+ RINDENT();
+ if (RDEBUG_ENABLED) {
+ for (vp = fr_cursor_first(&groups_cursor);
+ vp;
+ vp = fr_cursor_next(&groups_cursor)) {
+ RDEBUG("&control:%s += \"%s\"", inst->cache_da->name, vp->vp_strvalue);
+ }
+ }
+
+ fr_cursor_merge(&list_cursor, groups);
+
+ for (dn_p = group_dn; *dn_p; dn_p++) {
+ MEM(vp = fr_pair_afrom_da(list_ctx, inst->cache_da));
+ fr_pair_value_strcpy(vp, *dn_p);
+ fr_cursor_insert(&list_cursor, vp);
+
+ RDEBUG("&control:%s += \"%s\"", inst->cache_da->name, vp->vp_strvalue);
+ ldap_memfree(*dn_p);
+ }
+ REXDENT();
+
+ return rcode;
+}
+
+/** Convert group membership information into attributes
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @return One of the RLM_MODULE_* values.
+ */
+rlm_rcode_t rlm_ldap_cacheable_groupobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+ int ldap_errno;
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry;
+
+ char const *base_dn;
+ char base_dn_buff[LDAP_MAX_DN_STR_LEN];
+
+ char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
+ char filter[LDAP_MAX_FILTER_STR_LEN + 1];
+
+ char const *attrs[] = { inst->groupobj_name_attr, NULL };
+
+ VALUE_PAIR *vp;
+ char *dn;
+
+ rad_assert(inst->groupobj_base_dn);
+
+ if (!inst->groupobj_membership_filter) {
+ RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set");
+
+ return RLM_MODULE_OK;
+ }
+
+ if (rlm_ldap_xlat_filter(request,
+ filters, sizeof(filters) / sizeof(*filters),
+ filter, sizeof(filter)) < 0) {
+ return RLM_MODULE_INVALID;
+ }
+
+ if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
+ inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
+ REDEBUG("Failed creating base_dn");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ status = rlm_ldap_search(&result, inst, request, pconn, base_dn,
+ inst->groupobj_scope, filter, attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ RDEBUG2("No cacheable group memberships found in group objects");
+ goto finish;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (!entry) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+
+ RDEBUG("Adding cacheable group object memberships");
+ do {
+ if (inst->cacheable_group_dn) {
+ dn = ldap_get_dn((*pconn)->handle, entry);
+ if (!dn) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+ rlm_ldap_normalise_dn(dn, dn);
+
+ MEM(vp = pair_make_config(inst->cache_da->name, NULL, T_OP_ADD));
+ fr_pair_value_strcpy(vp, dn);
+
+ RINDENT();
+ RDEBUG("&control:%s += \"%s\"", inst->cache_da->name, dn);
+ REXDENT();
+ ldap_memfree(dn);
+ }
+
+ if (inst->cacheable_group_name) {
+ struct berval **values;
+
+ values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr);
+ if (!values) continue;
+
+ MEM(vp = pair_make_config(inst->cache_da->name, NULL, T_OP_ADD));
+ fr_pair_value_bstrncpy(vp, values[0]->bv_val, values[0]->bv_len);
+
+ RINDENT();
+ RDEBUG("&control:%s += \"%.*s\"", inst->cache_da->name,
+ (int)values[0]->bv_len, values[0]->bv_val);
+ REXDENT();
+
+ ldap_value_free_len(values);
+ }
+ } while ((entry = ldap_next_entry((*pconn)->handle, entry)));
+
+finish:
+ if (result) ldap_msgfree(result);
+
+ return rcode;
+}
+
+/** Query the LDAP directory to check if a group object includes a user object as a member
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] check vp containing the group value (name or dn).
+ * @return One of the RLM_MODULE_* values.
+ */
+rlm_rcode_t rlm_ldap_check_groupobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ VALUE_PAIR *check)
+
+{
+ ldap_rcode_t status;
+ LDAPMessage *result = NULL;
+
+ char const *base_dn;
+ char base_dn_buff[LDAP_MAX_DN_STR_LEN + 1];
+ char filter[LDAP_MAX_FILTER_STR_LEN + 1];
+ int ret;
+
+ rad_assert(inst->groupobj_base_dn);
+
+ switch (check->op) {
+ case T_OP_CMP_EQ:
+ case T_OP_CMP_FALSE:
+ case T_OP_CMP_TRUE:
+ case T_OP_REG_EQ:
+ case T_OP_REG_NE:
+ break;
+
+ default:
+ REDEBUG("Operator \"%s\" not allowed for LDAP group comparisons",
+ fr_int2str(fr_tokens, check->op, "<INVALID>"));
+ return 1;
+ }
+
+ RDEBUG2("Checking for user in group objects");
+
+ if (rlm_ldap_is_dn(check->vp_strvalue, check->vp_length)) {
+ char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
+
+ RINDENT();
+ ret = rlm_ldap_xlat_filter(request,
+ filters, sizeof(filters) / sizeof(*filters),
+ filter, sizeof(filter));
+ REXDENT();
+
+ if (ret < 0) return RLM_MODULE_INVALID;
+
+ base_dn = check->vp_strvalue;
+ } else {
+ char name_filter[LDAP_MAX_FILTER_STR_LEN];
+ char const *filters[] = { name_filter, inst->groupobj_filter, inst->groupobj_membership_filter };
+
+ if (!inst->groupobj_name_attr) {
+ REDEBUG("Told to search for group by name, but missing 'group.name_attribute' "
+ "directive");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ snprintf(name_filter, sizeof(name_filter), "(%s=%s)", inst->groupobj_name_attr, check->vp_strvalue);
+ RINDENT();
+ ret = rlm_ldap_xlat_filter(request,
+ filters, sizeof(filters) / sizeof(*filters),
+ filter, sizeof(filter));
+ REXDENT();
+ if (ret < 0) return RLM_MODULE_INVALID;
+
+
+ /*
+ * rlm_ldap_find_user does this, too. Oh well.
+ */
+ RINDENT();
+ ret = tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request, inst->groupobj_base_dn,
+ rlm_ldap_escape_func, NULL);
+ REXDENT();
+ if (ret < 0) {
+ REDEBUG("Failed creating base_dn");
+
+ return RLM_MODULE_INVALID;
+ }
+ }
+
+ RINDENT();
+ status = rlm_ldap_search(&result, inst, request, pconn, base_dn, inst->groupobj_scope, filter, NULL, NULL, NULL);
+ REXDENT();
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ {
+ LDAPMessage *entry = NULL;
+ char *dn = NULL;
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (entry) dn = ldap_get_dn((*pconn)->handle, entry);
+ RDEBUG("User found in group object \"%s\"", dn);
+ ldap_memfree(dn);
+ ldap_msgfree(result);
+ }
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ return RLM_MODULE_NOTFOUND;
+
+ default:
+ return RLM_MODULE_FAIL;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+/** Query the LDAP directory to check if a user object is a member of a group
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn of user object.
+ * @param[in] check vp containing the group value (name or dn).
+ * @return One of the RLM_MODULE_* values.
+ */
+rlm_rcode_t rlm_ldap_check_userobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *dn, VALUE_PAIR *check)
+{
+ rlm_rcode_t rcode = RLM_MODULE_NOTFOUND, ret;
+ ldap_rcode_t status;
+ bool name_is_dn = false, value_is_dn = false;
+
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+ struct berval **values = NULL;
+
+ char const *attrs[] = { inst->userobj_membership_attr, NULL };
+ int i, count, ldap_errno;
+
+ RDEBUG2("Checking user object's %s attributes", inst->userobj_membership_attr);
+ RINDENT();
+ status = rlm_ldap_search(&result, inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
+ REXDENT();
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ RDEBUG("Can't check membership attributes, user object not found");
+
+ rcode = RLM_MODULE_NOTFOUND;
+
+ /* FALL-THROUGH */
+ default:
+ goto finish;
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, result);
+ if (!entry) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ values = ldap_get_values_len((*pconn)->handle, entry, inst->userobj_membership_attr);
+ if (!values) {
+ RDEBUG("No group membership attribute(s) found in user object");
+
+ goto finish;
+ }
+
+ /*
+ * Loop over the list of groups the user is a member of,
+ * looking for a match.
+ */
+ name_is_dn = rlm_ldap_is_dn(check->vp_strvalue, check->vp_length);
+ count = ldap_count_values_len(values);
+ for (i = 0; i < count; i++) {
+ value_is_dn = rlm_ldap_is_dn(values[i]->bv_val, values[i]->bv_len);
+
+ RDEBUG2("Processing %s value \"%.*s\" as a %s", inst->userobj_membership_attr,
+ (int)values[i]->bv_len, values[i]->bv_val, value_is_dn ? "DN" : "group name");
+
+ /*
+ * Both literal group names, do case sensitive comparison
+ */
+ if (!name_is_dn && !value_is_dn) {
+ if ((check->vp_length == values[i]->bv_len) &&
+ (memcmp(values[i]->bv_val, check->vp_strvalue, values[i]->bv_len) == 0)) {
+ RDEBUG("User found in group \"%s\". Comparison between membership: name, check: name",
+ check->vp_strvalue);
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+
+ continue;
+ }
+
+ /*
+ * Both DNs, do case insensitive, binary safe comparison
+ */
+ if (name_is_dn && value_is_dn) {
+ if (check->vp_length == values[i]->bv_len) {
+ int j;
+
+ for (j = 0; j < (int)values[i]->bv_len; j++) {
+ if (tolower(values[i]->bv_val[j]) != tolower(check->vp_strvalue[j])) break;
+ }
+ if (j == (int)values[i]->bv_len) {
+ RDEBUG("User found in group DN \"%s\". "
+ "Comparison between membership: dn, check: dn", check->vp_strvalue);
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+ }
+
+ continue;
+ }
+
+ /*
+ * If the value is not a DN, and the name we were given is a dn
+ * convert the value to a DN and do a comparison.
+ */
+ if (!value_is_dn && name_is_dn) {
+ char *resolved;
+ bool eq = false;
+
+ RINDENT();
+ ret = rlm_ldap_group_dn2name(inst, request, pconn, check->vp_strvalue, &resolved);
+ REXDENT();
+
+ if (ret == RLM_MODULE_NOOP) continue;
+
+ if (ret != RLM_MODULE_OK) {
+ rcode = ret;
+ goto finish;
+ }
+
+ if (((talloc_array_length(resolved) - 1) == values[i]->bv_len) &&
+ (memcmp(values[i]->bv_val, resolved, values[i]->bv_len) == 0)) eq = true;
+ talloc_free(resolved);
+ if (eq) {
+ RDEBUG("User found in group \"%.*s\". Comparison between membership: name, check: name "
+ "(resolved from DN \"%s\")", (int)values[i]->bv_len,
+ values[i]->bv_val, check->vp_strvalue);
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+
+ continue;
+ }
+
+ /*
+ * We have a value which is a DN, and a check item which specifies the name of a group,
+ * convert the value to a name so we can do a comparison.
+ */
+ if (value_is_dn && !name_is_dn) {
+ char *resolved;
+ char *value;
+ bool eq = false;
+
+ value = rlm_ldap_berval_to_string(request, values[i]);
+ RINDENT();
+ ret = rlm_ldap_group_dn2name(inst, request, pconn, value, &resolved);
+ REXDENT();
+ talloc_free(value);
+
+ if (ret == RLM_MODULE_NOOP) continue;
+
+ if (ret != RLM_MODULE_OK) {
+ rcode = ret;
+ goto finish;
+ }
+
+ if (((talloc_array_length(resolved) - 1) == check->vp_length) &&
+ (memcmp(check->vp_strvalue, resolved, check->vp_length) == 0)) eq = true;
+ talloc_free(resolved);
+ if (eq) {
+ RDEBUG("User found in group \"%s\". Comparison between membership: name "
+ "(resolved from DN \"%s\"), check: name", check->vp_strvalue, value);
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+
+ continue;
+ }
+ rad_assert(0);
+ }
+
+finish:
+ if (values) ldap_value_free_len(values);
+ if (result) ldap_msgfree(result);
+
+ return rcode;
+}
+
+/** Check group membership attributes to see if a user is a member.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in] check vp containing the group value (name or dn).
+ *
+ * @return One of the RLM_MODULE_* values.
+ */
+rlm_rcode_t rlm_ldap_check_cached(rlm_ldap_t const *inst, REQUEST *request, VALUE_PAIR *check)
+{
+ VALUE_PAIR *vp;
+ int ret;
+ vp_cursor_t cursor;
+
+ fr_cursor_init(&cursor, &request->config);
+
+ /*
+ * We return RLM_MODULE_INVALID here as an indication
+ * the caller should try a dynamic group lookup instead.
+ */
+ vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY);
+ if (!vp) return RLM_MODULE_INVALID;
+ fr_cursor_first(&cursor);
+
+ while ((vp = fr_cursor_next_by_num(&cursor, inst->cache_da->attr, inst->cache_da->vendor, TAG_ANY))) {
+ ret = fr_pair_cmp_op(T_OP_CMP_EQ, vp, check);
+ if (ret == 1) {
+ RDEBUG2("User found. Matched cached membership");
+ return RLM_MODULE_OK;
+ }
+
+ if (ret < -1) {
+ return RLM_MODULE_FAIL;
+ }
+ }
+
+ RDEBUG2("Cached membership not found");
+ return RLM_MODULE_NOTFOUND;
+}
diff --git a/src/modules/rlm_ldap/ldap.c b/src/modules/rlm_ldap/ldap.c
new file mode 100644
index 0000000..c356921
--- /dev/null
+++ b/src/modules/rlm_ldap/ldap.c
@@ -0,0 +1,1661 @@
+/*
+ * 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 ldap.c
+ * @brief LDAP module library functions.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013-2015 Network RADIUS SARL <info@networkradius.com>
+ * @copyright 2013-2015 The FreeRADIUS Server Project.
+ */
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_OPENSSL_SSL_H
+# include <openssl/ssl.h>
+#endif
+
+#include "ldap.h"
+
+/** Converts "bad" strings into ones which are safe for LDAP
+ *
+ * @note RFC 4515 says filter strings can only use the @verbatim \<hex><hex> @endverbatim
+ * format, whereas RFC 4514 indicates that some chars in DNs, may be escaped simply
+ * with a backslash. For simplicity, we always use the hex escape sequences.
+ * In other areas where we're doing DN comparison, the DNs need to be normalised first
+ * so that they both use only hex escape sequences.
+ *
+ * @note This is a callback for xlat operations.
+ *
+ * Will escape any characters in input strings that would cause the string to be interpreted
+ * as part of a DN and or filter. Escape sequence is @verbatim \<hex><hex> @endverbatim.
+ *
+ * @param request The current request.
+ * @param out Pointer to output buffer.
+ * @param outlen Size of the output buffer.
+ * @param in Raw unescaped string.
+ * @param arg Any additional arguments (unused).
+ */
+size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ static char const encode[] = ",+\"\\<>;*=()";
+ static char const hextab[] = "0123456789abcdef";
+ size_t left = outlen;
+
+ if (*in && ((*in == ' ') || (*in == '#'))) goto encode;
+
+ while (*in) {
+ /*
+ * Encode unsafe characters.
+ */
+ if (memchr(encode, *in, sizeof(encode) - 1)) {
+ encode:
+ /*
+ * Only 3 or less bytes available.
+ */
+ if (left <= 3) break;
+
+ *out++ = '\\';
+ *out++ = hextab[(*in >> 4) & 0x0f];
+ *out++ = hextab[*in & 0x0f];
+ in++;
+ left -= 3;
+
+ continue;
+ }
+
+ if (left <= 1) break;
+
+ /*
+ * Doesn't need encoding
+ */
+ *out++ = *in++;
+ left--;
+ }
+
+ *out = '\0';
+
+ return outlen - left;
+}
+
+/** Check whether a string looks like a DN
+ *
+ * @param[in] in Str to check.
+ * @param[in] inlen Length of string to check.
+ * @return
+ * - true if string looks like a DN.
+ * - false if string does not look like DN.
+ */
+bool rlm_ldap_is_dn(char const *in, size_t inlen)
+{
+ char const *p;
+
+ char want = '=';
+ bool too_soon = true;
+ int comp = 1;
+
+ for (p = in; inlen > 0; p++, inlen--) {
+ if (p[0] == '\\') {
+ char c;
+
+ too_soon = false;
+
+ /*
+ * Invalid escape sequence, not a DN
+ */
+ if (inlen < 2) return false;
+
+ /*
+ * Double backslash, consume two chars
+ */
+ if (p[1] == '\\') {
+ inlen--;
+ p++;
+ continue;
+ }
+
+ /*
+ * Special, consume two chars
+ */
+ switch (p[1]) {
+ case ' ':
+ case '#':
+ case '=':
+ case '"':
+ case '+':
+ case ',':
+ case ';':
+ case '<':
+ case '>':
+ case '\'':
+ inlen -= 1;
+ p += 1;
+ continue;
+
+ default:
+ break;
+ }
+
+ /*
+ * Invalid escape sequence, not a DN
+ */
+ if (inlen < 3) return false;
+
+ /*
+ * Hex encoding, consume three chars
+ */
+ if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
+ inlen -= 2;
+ p += 2;
+ continue;
+ }
+
+ /*
+ * Invalid escape sequence, not a DN
+ */
+ return false;
+ }
+
+ switch (*p) {
+ case '=':
+ if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
+ want = ',';
+ too_soon = true;
+ break;
+
+ case ',':
+ if (too_soon || (*p != want)) return false; /* Too soon after last , or = */
+ want = '=';
+ too_soon = true;
+ comp++;
+ break;
+
+ default:
+ too_soon = false;
+ break;
+ }
+ }
+
+ /*
+ * If the string ended with , or =, or the number
+ * of components was less than 2
+ *
+ * i.e. we don't have <attr>=<val>,<attr>=<val>
+ */
+ if (too_soon || (comp < 2)) return false;
+
+ return true;
+}
+
+/** Convert a berval to a talloced string
+ *
+ * The ldap_get_values function is deprecated, and ldap_get_values_len
+ * does not guarantee the berval buffers it returns are \0 terminated.
+ *
+ * For some cases this is fine, for others we require a \0 terminated
+ * buffer (feeding DNs back into libldap for example).
+ *
+ * @param ctx to allocate in.
+ * @param in Berval to copy.
+ * @return \0 terminated buffer containing in->bv_val.
+ */
+char *rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
+{
+ char *out;
+
+ out = talloc_array(ctx, char, in->bv_len + 1);
+ if (!out) return NULL;
+
+ memcpy(out, in->bv_val, in->bv_len);
+ out[in->bv_len] = '\0';
+
+ return out;
+}
+
+/** Normalise escape sequences in a DN
+ *
+ * Characters in a DN can either be escaped as
+ * @verbatim \<hex><hex> @endverbatim or @verbatim \<special> @endverbatim
+ *
+ * The LDAP directory chooses how characters are escaped, which can make
+ * local comparisons of DNs difficult.
+ *
+ * Here we search for hex sequences that match special chars, and convert
+ * them to the @verbatim \<special> @endverbatim form.
+ *
+ * @note the resulting output string will only ever be shorter than the
+ * input, so it's fine to use the same buffer for both out and in.
+ *
+ * @param out Where to write the normalised DN.
+ * @param in The input DN.
+ * @return The number of bytes written to out.
+ */
+size_t rlm_ldap_normalise_dn(char *out, char const *in)
+{
+ char const *p;
+ char *o = out;
+
+ for (p = in; *p != '\0'; p++) {
+ if (p[0] == '\\') {
+ char c;
+
+ /*
+ * Double backslashes get processed specially
+ */
+ if (p[1] == '\\') {
+ p += 1;
+ *o++ = p[0];
+ *o++ = p[1];
+ continue;
+ }
+
+ /*
+ * Hex encodings that have an alternative
+ * special encoding, get rewritten to the
+ * special encoding.
+ */
+ if (fr_hex2bin((uint8_t *) &c, 1, p + 1, 2) == 1) {
+ switch (c) {
+ case ' ':
+ case '#':
+ case '=':
+ case '"':
+ case '+':
+ case ',':
+ case ';':
+ case '<':
+ case '>':
+ case '\'':
+ *o++ = '\\';
+ *o++ = c;
+ p += 2;
+ continue;
+
+ default:
+ break;
+ }
+ }
+ }
+ *o++ = *p;
+ }
+ *o = '\0';
+
+ return o - out;
+}
+
+/** Find the place at which the two DN strings diverge
+ *
+ * Returns the length of the non matching string in full.
+ *
+ * @param full DN.
+ * @param part Partial DN as returned by ldap_parse_result.
+ * @return
+ * - Length of the portion of full which wasn't matched
+ * - -1 on failure.
+ */
+static size_t rlm_ldap_common_dn(char const *full, char const *part)
+{
+ size_t f_len, p_len, i;
+
+ if (!full) {
+ return -1;
+ }
+
+ f_len = strlen(full);
+
+ if (!part) {
+ return -1;
+ }
+
+ p_len = strlen(part);
+ if (!p_len) {
+ return f_len;
+ }
+
+ if ((f_len < p_len) || !f_len) {
+ return -1;
+ }
+
+ for (i = 0; i < p_len; i++) {
+ if (part[p_len - i] != full[f_len - i]) {
+ return -1;
+ }
+ }
+
+ return f_len - p_len;
+}
+
+/** Combine and expand filters
+ *
+ * @param request Current request.
+ * @param out Where to write the expanded string.
+ * @param outlen Length of output buffer.
+ * @param sub Array of subfilters (may contain NULLs).
+ * @param sublen Number of potential subfilters in array.
+ * @return length of expanded data.
+ */
+ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen)
+{
+ char buffer[LDAP_MAX_FILTER_STR_LEN + 1];
+ char const *in = NULL;
+ char *p = buffer;
+
+ ssize_t len = 0;
+
+ unsigned int i;
+ int cnt = 0;
+
+ /*
+ * Figure out how many filter elements we need to integrate
+ */
+ for (i = 0; i < sublen; i++) {
+ if (sub[i] && *sub[i]) {
+ in = sub[i];
+ cnt++;
+ }
+ }
+
+ if (!cnt) {
+ out[0] = '\0';
+ return 0;
+ }
+
+ if (cnt > 1) {
+ if (outlen < 3) {
+ goto oob;
+ }
+
+ p[len++] = '(';
+ p[len++] = '&';
+
+ for (i = 0; i < sublen; i++) {
+ if (sub[i] && (*sub[i] != '\0')) {
+ len += strlcpy(p + len, sub[i], outlen - len);
+
+ if ((size_t) len >= outlen) {
+ oob:
+ REDEBUG("Out of buffer space creating filter");
+
+ return -1;
+ }
+ }
+ }
+
+ if ((outlen - len) < 2) {
+ goto oob;
+ }
+
+ p[len++] = ')';
+ p[len] = '\0';
+
+ in = buffer;
+ }
+
+ len = radius_xlat(out, outlen, request, in, rlm_ldap_escape_func, NULL);
+ if (len < 0) {
+ REDEBUG("Failed creating filter");
+
+ return -1;
+ }
+
+ return len;
+}
+
+/** Return the error string associated with a handle
+ *
+ * @param conn to retrieve error from.
+ * @return error string.
+ */
+char const *rlm_ldap_error_str(ldap_handle_t const *conn)
+{
+ int lib_errno;
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
+ if (lib_errno == LDAP_SUCCESS) {
+ return "unknown";
+ }
+
+ return ldap_err2string(lib_errno);
+}
+
+/** Parse response from LDAP server dealing with any errors
+ *
+ * Should be called after an LDAP operation. Will check result of operation and if it was successful, then attempt
+ * to retrieve and parse the result.
+ *
+ * Will also produce extended error output including any messages the server sent, and information about partial
+ * DN matches.
+ *
+ * @param[in] inst of LDAP module.
+ * @param[in] conn Current connection.
+ * @param[in] msgid returned from last operation. May be -1 if no result processing is required.
+ * @param[in] dn Last search or bind DN.
+ * @param[out] result Where to write result, if NULL result will be freed.
+ * @param[out] error Where to write the error string, may be NULL, must not be freed.
+ * @param[out] extra Where to write additional error string to, may be NULL (faster) or must be freed
+ * (with talloc_free).
+ * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
+ */
+ldap_rcode_t rlm_ldap_result(rlm_ldap_t const *inst, ldap_handle_t const *conn, int msgid, char const *dn,
+ LDAPMessage **result, char const **error, char **extra)
+{
+ ldap_rcode_t status = LDAP_PROC_SUCCESS;
+
+ int lib_errno = LDAP_SUCCESS; // errno returned by the library.
+ int srv_errno = LDAP_SUCCESS; // errno in the result message.
+
+ char *part_dn = NULL; // Partial DN match.
+ char *our_err = NULL; // Our extended error message.
+ char *srv_err = NULL; // Server's extended error message.
+ char *p, *a;
+
+ bool freeit = false; // Whether the message should be freed after being processed.
+ int len;
+
+ struct timeval tv; // Holds timeout values.
+
+ LDAPMessage *tmp_msg = NULL; // Temporary message pointer storage if we weren't provided with one.
+
+ char const *tmp_err; // Temporary error pointer storage if we weren't provided with one.
+
+ if (!error) error = &tmp_err;
+ *error = NULL;
+
+ if (extra) *extra = NULL;
+ if (result) *result = NULL;
+
+ /*
+ * We always need the result, but our caller may not
+ */
+ if (!result) {
+ result = &tmp_msg;
+ freeit = true;
+ }
+
+ /*
+ * Check if there was an error sending the request
+ */
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
+ if (lib_errno != LDAP_SUCCESS) goto process_error;
+ if (msgid < 0) return LDAP_SUCCESS; /* No msgid and no error, return now */
+
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = inst->res_timeout;
+
+ /*
+ * Now retrieve the result and check for errors
+ * ldap_result returns -1 on failure, and 0 on timeout
+ */
+ lib_errno = ldap_result(conn->handle, msgid, 1, &tv, result);
+ if (lib_errno == 0) {
+ lib_errno = LDAP_TIMEOUT;
+
+ goto process_error;
+ }
+
+ if (lib_errno == -1) {
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
+
+ goto process_error;
+ }
+
+ /*
+ * Parse the result and check for errors sent by the server
+ */
+ lib_errno = ldap_parse_result(conn->handle, *result,
+ &srv_errno,
+ extra ? &part_dn : NULL,
+ extra ? &srv_err : NULL,
+ NULL, NULL, freeit);
+ if (freeit) *result = NULL;
+
+ if (lib_errno != LDAP_SUCCESS) {
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &lib_errno);
+ goto process_error;
+ }
+
+process_error:
+ if ((lib_errno == LDAP_SUCCESS) && (srv_errno != LDAP_SUCCESS)) {
+ lib_errno = srv_errno;
+ } else if ((lib_errno != LDAP_SUCCESS) && (srv_errno == LDAP_SUCCESS)) {
+ srv_errno = lib_errno;
+ }
+
+ switch (lib_errno) {
+ case LDAP_SUCCESS:
+ *error = "Success";
+ break;
+
+ case LDAP_SASL_BIND_IN_PROGRESS:
+ *error = "Continuing";
+ status = LDAP_PROC_CONTINUE;
+ break;
+
+ case LDAP_NO_SUCH_OBJECT:
+ *error = "The specified DN wasn't found";
+ status = LDAP_PROC_BAD_DN;
+
+ if (!extra) break;
+
+ /*
+ * Build our own internal diagnostic string
+ */
+ len = rlm_ldap_common_dn(dn, part_dn);
+ if (len < 0) break;
+
+ our_err = talloc_typed_asprintf(conn, "Match stopped here: [%.*s]%s", len, dn, part_dn ? part_dn : "");
+ goto error_string;
+
+ case LDAP_INSUFFICIENT_ACCESS:
+ *error = "Insufficient access. Check the identity and password configuration directives";
+ status = LDAP_PROC_NOT_PERMITTED;
+ break;
+
+ case LDAP_UNWILLING_TO_PERFORM:
+ *error = "Server was unwilling to perform";
+ status = LDAP_PROC_NOT_PERMITTED;
+ break;
+
+ case LDAP_FILTER_ERROR:
+ *error = "Bad search filter";
+ status = LDAP_PROC_ERROR;
+ break;
+
+ case LDAP_TIMEOUT:
+ *error = "Timed out while waiting for server to respond";
+ goto timeout;
+
+ case LDAP_TIMELIMIT_EXCEEDED:
+ *error = "Time limit exceeded";
+ timeout:
+ exec_trigger(NULL, inst->cs, "modules.ldap.timeout", true);
+ /* FALL-THROUGH */
+
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ case LDAP_SERVER_DOWN:
+ status = LDAP_PROC_RETRY;
+ goto error_string;
+
+ case LDAP_INVALID_CREDENTIALS:
+ case LDAP_CONSTRAINT_VIOLATION:
+ status = LDAP_PROC_REJECT;
+ goto error_string;
+
+ case LDAP_OPERATIONS_ERROR:
+ if (inst->chase_referrals) {
+ *error = "Operations error with LDAP database. Please see the LDAP server configuration / documentation for more information.";
+ } else {
+ *error = "Please set 'chase_referrals=yes' and 'rebind=yes'. See the ldap module configuration "
+ "for details.";
+ }
+
+ /* FALL-THROUGH */
+ default:
+ status = LDAP_PROC_ERROR;
+
+ error_string:
+ if (!*error) *error = ldap_err2string(lib_errno);
+
+ if (!extra || ((lib_errno == srv_errno) && !our_err && !srv_err)) break;
+
+ /*
+ * Output the error codes from the library and server
+ */
+ p = talloc_zero_array(conn, char, 1);
+ if (!p) break;
+
+ if (lib_errno != srv_errno) {
+ a = talloc_asprintf_append(p, "LDAP lib error: %s (%u), srv error: %s (%u). ",
+ ldap_err2string(lib_errno), lib_errno,
+ ldap_err2string(srv_errno), srv_errno);
+ if (!a) {
+ talloc_free(p);
+ break;
+ }
+
+ p = a;
+ }
+
+ if (our_err) {
+ a = talloc_asprintf_append_buffer(p, "%s. ", our_err);
+ if (!a) {
+ talloc_free(p);
+ break;
+ }
+
+ p = a;
+ }
+
+ if (srv_err) {
+ a = talloc_asprintf_append_buffer(p, "Server said: %s. ", srv_err);
+ if (!a) {
+ talloc_free(p);
+ break;
+ }
+
+ p = a;
+ }
+
+ *extra = p;
+
+ break;
+ }
+
+ /*
+ * Cleanup memory
+ */
+ if (srv_err) ldap_memfree(srv_err);
+ if (part_dn) ldap_memfree(part_dn);
+
+ talloc_free(our_err);
+
+ if ((status < 0) && *result) {
+ ldap_msgfree(*result);
+ *result = NULL;
+ }
+
+ return status;
+}
+
+/** Bind to the LDAP directory as a user
+ *
+ * Performs a simple bind to the LDAP directory, and handles any errors that occur.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request, this may be NULL, in which case all debug logging is done with radlog.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn of the user, may be NULL to bind anonymously.
+ * @param[in] password of the user, may be NULL if no password is specified.
+ * @param[in] sasl mechanism to use for bind, and additional parameters.
+ * @param[in] retry if the server is down.
+ * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
+ */
+ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
+ char const *password, ldap_sasl *sasl, bool retry)
+{
+ ldap_rcode_t status = LDAP_PROC_ERROR;
+
+ int msgid = -1;
+
+ char const *error = NULL;
+ char *extra = NULL;
+
+ int i, num;
+
+ rad_assert(*pconn && (*pconn)->handle);
+ rad_assert(!retry || inst->pool);
+
+#ifndef WITH_SASL
+ if (sasl && sasl->mech) {
+ REDEBUG("Server is built without SASL, but is being asked to do SASL.");
+ return status;
+ }
+#endif
+
+ /*
+ * Bind as anonymous user
+ */
+ if (!dn) dn = "";
+
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ num = retry ? fr_connection_pool_get_retries(inst->pool) : 0;
+ for (i = num; i >= 0; i--) {
+#ifdef WITH_SASL
+ if (sasl && sasl->mech) {
+ status = rlm_ldap_sasl_interactive(inst, request, *pconn, dn, password, sasl,
+ &error, &extra);
+ } else
+#endif
+ {
+ msgid = ldap_bind((*pconn)->handle, dn, password, LDAP_AUTH_SIMPLE);
+
+ /* We got a valid message ID */
+ if (msgid >= 0) {
+ if (request) {
+ RDEBUG2("Waiting for bind result...");
+ } else {
+ DEBUG2("rlm_ldap (%s): Waiting for bind result...", inst->name);
+ }
+ }
+
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
+ }
+
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ LDAP_DBG_REQ("Bind successful");
+ break;
+
+ case LDAP_PROC_NOT_PERMITTED:
+ LDAP_ERR_REQ("Bind was not permitted: %s", error);
+ LDAP_EXT_REQ();
+
+ break;
+
+ case LDAP_PROC_REJECT:
+ LDAP_ERR_REQ("Bind credentials incorrect: %s", error);
+ LDAP_EXT_REQ();
+
+ break;
+
+ case LDAP_PROC_RETRY:
+ if (retry) {
+ *pconn = fr_connection_reconnect(inst->pool, *pconn);
+ if (*pconn) {
+ LDAP_DBGW_REQ("Bind with %s to %s failed: %s. Got new socket, retrying...",
+ *dn ? dn : "(anonymous)", inst->server, error);
+
+ talloc_free(extra); /* don't leak debug info */
+
+ continue;
+ }
+ };
+ status = LDAP_PROC_ERROR;
+
+ /*
+ * Were not allowed to retry, or there are no more
+ * sockets, treat this as a hard failure.
+ */
+ /* FALL-THROUGH */
+ default:
+ LDAP_ERR_REQ("Bind with %s to %s failed: %s", *dn ? dn : "(anonymous)",
+ inst->server, error);
+ LDAP_EXT_REQ();
+
+ break;
+ }
+
+ break;
+ }
+
+ if (retry && (i < 0)) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
+ }
+
+ talloc_free(extra);
+
+ return status; /* caller closes the connection */
+}
+
+/** Search for something in the LDAP directory
+ *
+ * Binds as the administrative user and performs a search, dealing with any errors.
+ *
+ * @param[out] result Where to store the result. Must be freed with ldap_msgfree if LDAP_PROC_SUCCESS is returned.
+ * May be NULL in which case result will be automatically freed after use.
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn to use as base for the search.
+ * @param[in] scope to use (LDAP_SCOPE_BASE, LDAP_SCOPE_ONE, LDAP_SCOPE_SUB).
+ * @param[in] filter to use, should be pre-escaped.
+ * @param[in] attrs to retrieve.
+ * @param[in] serverctrls Search controls to pass to the server. May be NULL.
+ * @param[in] clientctrls Search controls for ldap_search. May be NULL.
+ * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
+ */
+ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t **pconn,
+ char const *dn, int scope, char const *filter, char const * const *attrs,
+ LDAPControl **serverctrls, LDAPControl **clientctrls)
+{
+ ldap_rcode_t status = LDAP_PROC_ERROR;
+ LDAPMessage *our_result = NULL;
+
+ int msgid; // Message id returned by
+ // ldap_search_ext.
+
+ int count = 0; // Number of results we got.
+
+ struct timeval tv; // Holds timeout values.
+
+ char const *error = NULL;
+ char *extra = NULL;
+
+ int i;
+
+ rad_assert(*pconn && (*pconn)->handle);
+
+ /*
+ * OpenLDAP library doesn't declare attrs array as const, but
+ * it really should be *sigh*.
+ */
+ char **search_attrs;
+ memcpy(&search_attrs, &attrs, sizeof(attrs));
+
+ /*
+ * Do all searches as the admin user.
+ */
+ if ((*pconn)->rebound) {
+ status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
+ (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true);
+ if (status != LDAP_PROC_SUCCESS) {
+ return LDAP_PROC_ERROR;
+ }
+
+ rad_assert(*pconn);
+
+ (*pconn)->rebound = false;
+ }
+
+ if (filter) {
+ LDAP_DBG_REQ("Performing search in \"%s\" with filter \"%s\", scope \"%s\"", dn, filter,
+ fr_int2str(ldap_scope, scope, "<INVALID>"));
+ } else {
+ LDAP_DBG_REQ("Performing unfiltered search in \"%s\", scope \"%s\"", dn,
+ fr_int2str(ldap_scope, scope, "<INVALID>"));
+ }
+ /*
+ * If LDAP search produced an error it should also be logged
+ * to the ld. result should pick it up without us
+ * having to pass it explicitly.
+ */
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = inst->res_timeout;
+
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ for (i = fr_connection_pool_get_retries(inst->pool); i >= 0; i--) {
+ (void) ldap_search_ext((*pconn)->handle, dn, scope, filter, search_attrs,
+ 0, serverctrls, clientctrls, &tv, 0, &msgid);
+
+ LDAP_DBG_REQ("Waiting for search result...");
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, &our_result, &error, &extra);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ /*
+ * Invalid DN isn't a failure when searching.
+ * The DN may be xlat expanded so may point directly
+ * to an LDAP object. If that can't be located, it's
+ * the same as notfound.
+ */
+ case LDAP_PROC_BAD_DN:
+ LDAP_DBG_REQ("%s", error);
+ if (extra) LDAP_DBG_REQ("%s", extra);
+ break;
+
+ case LDAP_PROC_RETRY:
+ *pconn = fr_connection_reconnect(inst->pool, *pconn);
+ if (*pconn) {
+ LDAP_DBGW_REQ("Search failed: %s. Got new socket, retrying...", error);
+
+ talloc_free(extra); /* don't leak debug info */
+
+ continue;
+ }
+
+ status = LDAP_PROC_ERROR;
+
+ /* FALL-THROUGH */
+ default:
+ LDAP_ERR_REQ("Failed performing search: %s", error);
+ if (extra) LDAP_ERR_REQ("%s", extra);
+
+ goto finish;
+ }
+
+ break;
+ }
+
+ if (i < 0) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
+
+ goto finish;
+ }
+
+ count = ldap_count_entries((*pconn)->handle, our_result);
+ if (count < 0) {
+ LDAP_ERR_REQ("Error counting results: %s", rlm_ldap_error_str(*pconn));
+ status = LDAP_PROC_ERROR;
+
+ ldap_msgfree(our_result);
+ our_result = NULL;
+ } else if (count == 0) {
+ LDAP_DBG_REQ("Search returned no results");
+ status = LDAP_PROC_NO_RESULT;
+
+ ldap_msgfree(our_result);
+ our_result = NULL;
+ }
+
+finish:
+ talloc_free(extra);
+
+ /*
+ * We always need to get the result to count entries, but the caller
+ * may not of requested one. If that's the case, free it, else write
+ * it to where our caller said.
+ */
+ if (!result) {
+ if (our_result) ldap_msgfree(our_result);
+ } else {
+ *result = our_result;
+ }
+
+ return status;
+}
+
+/** Modify something in the LDAP directory
+ *
+ * Binds as the administrative user and attempts to modify an LDAP object.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn of the object to modify.
+ * @param[in] mods to make, see 'man ldap_modify' for more information.
+ * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
+ */
+ldap_rcode_t rlm_ldap_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *dn, LDAPMod *mods[])
+{
+ ldap_rcode_t status = LDAP_PROC_ERROR;
+
+ int msgid; // Message id returned by ldap_search_ext.
+
+ char const *error = NULL;
+ char *extra = NULL;
+
+ int i;
+
+ rad_assert(*pconn && (*pconn)->handle);
+
+ /*
+ * Perform all modifications as the admin user.
+ */
+ if ((*pconn)->rebound) {
+ status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
+ (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true);
+ if (status != LDAP_PROC_SUCCESS) {
+ return LDAP_PROC_ERROR;
+ }
+
+ rad_assert(*pconn);
+
+ (*pconn)->rebound = false;
+ }
+
+ /*
+ * For sanity, for when no connections are viable,
+ * and we can't make a new one.
+ */
+ for (i = fr_connection_pool_get_retries(inst->pool); i >= 0; i--) {
+ RDEBUG2("Modifying object with DN \"%s\"", dn);
+ (void) ldap_modify_ext((*pconn)->handle, dn, mods, NULL, NULL, &msgid);
+
+ RDEBUG2("Waiting for modify result...");
+ status = rlm_ldap_result(inst, *pconn, msgid, dn, NULL, &error, &extra);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_RETRY:
+ *pconn = fr_connection_reconnect(inst->pool, *pconn);
+ if (*pconn) {
+ RWDEBUG("Modify failed: %s. Got new socket, retrying...", error);
+
+ talloc_free(extra); /* don't leak debug info */
+ continue;
+ }
+
+ status = LDAP_PROC_ERROR;
+
+ /* FALL-THROUGH */
+ default:
+ REDEBUG("Failed modifying object: %s", error);
+ REDEBUG("%s", extra);
+
+ goto finish;
+ }
+
+ break;
+ }
+
+ if (i < 0) {
+ LDAP_ERR_REQ("Hit reconnection limit");
+ status = LDAP_PROC_ERROR;
+ }
+
+finish:
+ talloc_free(extra);
+
+ return status;
+}
+
+/** Retrieve the DN of a user object
+ *
+ * Retrieves the DN of a user and adds it to the control list as LDAP-UserDN. Will also retrieve any
+ * attributes passed and return the result in *result.
+ *
+ * This potentially allows for all authorization and authentication checks to be performed in one
+ * ldap search operation, which is a big bonus given the number of crappy, slow *cough*AD*cough*
+ * LDAP directory servers out there.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] attrs Additional attributes to retrieve, may be NULL.
+ * @param[in] force Query even if the User-DN already exists.
+ * @param[out] result Where to write the result, may be NULL in which case result is discarded.
+ * @param[out] rcode The status of the operation, one of the RLM_MODULE_* codes.
+ * @return The user's DN or NULL on error.
+ */
+char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode)
+{
+ static char const *tmp_attrs[] = { NULL };
+
+ ldap_rcode_t status;
+ VALUE_PAIR *vp = NULL;
+ LDAPMessage *tmp_msg = NULL, *entry = NULL;
+ int ldap_errno;
+ int cnt;
+ char *dn = NULL;
+ char const *filter = NULL;
+ char filter_buff[LDAP_MAX_FILTER_STR_LEN];
+ char const *base_dn;
+ char base_dn_buff[LDAP_MAX_DN_STR_LEN];
+ LDAPControl *serverctrls[] = { inst->userobj_sort_ctrl, NULL };
+
+ bool freeit = false; //!< Whether the message should
+ //!< be freed after being processed.
+
+ *rcode = RLM_MODULE_FAIL;
+
+ if (!result) {
+ result = &tmp_msg;
+ freeit = true;
+ }
+ *result = NULL;
+
+ if (!attrs) {
+ memset(&attrs, 0, sizeof(tmp_attrs));
+ }
+
+ /*
+ * If the caller isn't looking for the result we can just return the current userdn value.
+ */
+ if (!force) {
+ vp = fr_pair_find_by_da(request->config, inst->user_dn_da, TAG_ANY);
+ if (vp) {
+ RDEBUG("Using user DN from request \"%s\"", vp->vp_strvalue);
+ *rcode = RLM_MODULE_OK;
+ return vp->vp_strvalue;
+ }
+ }
+
+ /*
+ * Perform all searches as the admin user.
+ */
+ if ((*pconn)->rebound) {
+ status = rlm_ldap_bind(inst, request, pconn, (*pconn)->inst->admin_identity,
+ (*pconn)->inst->admin_password, &(*pconn)->inst->admin_sasl, true);
+ if (status != LDAP_PROC_SUCCESS) {
+ *rcode = RLM_MODULE_FAIL;
+ return NULL;
+ }
+
+ rad_assert(*pconn);
+
+ (*pconn)->rebound = false;
+ }
+
+ if (inst->userobj_filter) {
+ if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request, inst->userobj_filter,
+ rlm_ldap_escape_func, NULL) < 0) {
+ REDEBUG("Unable to create filter");
+ *rcode = RLM_MODULE_INVALID;
+
+ return NULL;
+ }
+ }
+
+ if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request,
+ inst->userobj_base_dn, rlm_ldap_escape_func, NULL) < 0) {
+ REDEBUG("Unable to create base_dn");
+ *rcode = RLM_MODULE_INVALID;
+
+ return NULL;
+ }
+
+ status = rlm_ldap_search(result, inst, request, pconn, base_dn,
+ inst->userobj_scope, filter, attrs, serverctrls, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_BAD_DN:
+ case LDAP_PROC_NO_RESULT:
+ *rcode = RLM_MODULE_NOTFOUND;
+ return NULL;
+
+ default:
+ *rcode = RLM_MODULE_FAIL;
+ return NULL;
+ }
+
+ rad_assert(*pconn);
+
+ /*
+ * Forbid the use of unsorted search results that
+ * contain multiple entries, as it's a potential
+ * security issue, and likely non deterministic.
+ */
+ if (!inst->userobj_sort_ctrl) {
+ cnt = ldap_count_entries((*pconn)->handle, *result);
+ if (cnt > 1) {
+ REDEBUG("Ambiguous search result, returned %i unsorted entries (should return 1 or 0). "
+ "Enable sorting, or specify a more restrictive base_dn, filter or scope", cnt);
+ REDEBUG("The following entries were returned:");
+ RINDENT();
+ for (entry = ldap_first_entry((*pconn)->handle, *result);
+ entry;
+ entry = ldap_next_entry((*pconn)->handle, entry)) {
+ dn = ldap_get_dn((*pconn)->handle, entry);
+ REDEBUG("%s", dn);
+ ldap_memfree(dn);
+ }
+ REXDENT();
+ *rcode = RLM_MODULE_INVALID;
+ goto finish;
+ }
+ }
+
+ entry = ldap_first_entry((*pconn)->handle, *result);
+ if (!entry) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s",
+ ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+
+ dn = ldap_get_dn((*pconn)->handle, entry);
+ if (!dn) {
+ ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+ rlm_ldap_normalise_dn(dn, dn);
+
+ /*
+ * We can't use fr_pair_make here to copy the value into the
+ * attribute, as the dn must be copied into the attribute
+ * verbatim (without de-escaping).
+ *
+ * Special chars are pre-escaped by libldap, and because
+ * we pass the string back to libldap we must not alter it.
+ */
+ RDEBUG("User object found at DN \"%s\"", dn);
+ vp = fr_pair_afrom_da(request, inst->user_dn_da);
+ if (vp) {
+ fr_pair_add(&request->config, vp);
+ fr_pair_value_strcpy(vp, dn);
+ *rcode = RLM_MODULE_OK;
+ }
+ ldap_memfree(dn);
+
+finish:
+ if ((freeit || (*rcode != RLM_MODULE_OK)) && *result) {
+ ldap_msgfree(*result);
+ *result = NULL;
+ }
+
+ return vp ? vp->vp_strvalue : NULL;
+}
+
+/** Check for presence of access attribute in result
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in] conn used to retrieve access attributes.
+ * @param[in] entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
+ * @return
+ * - #RLM_MODULE_USERLOCK if the user was denied access.
+ * - #RLM_MODULE_OK otherwise.
+ */
+rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t const *conn, LDAPMessage *entry)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ struct berval **values = NULL;
+
+ values = ldap_get_values_len(conn->handle, entry, inst->userobj_access_attr);
+ if (values) {
+ if (inst->access_positive) {
+ if ((values[0]->bv_len >= 5) && (strncasecmp(values[0]->bv_val, "false", 5) == 0)) {
+ RDEBUG("\"%s\" attribute exists but is set to 'false' - user locked out",
+ inst->userobj_access_attr);
+ rcode = RLM_MODULE_USERLOCK;
+ }
+ /* RLM_MODULE_OK set above... */
+ } else if ((values[0]->bv_len < 5) || (strncasecmp(values[0]->bv_val, "false", 5) != 0)) {
+ RDEBUG("\"%s\" attribute exists - user locked out", inst->userobj_access_attr);
+ rcode = RLM_MODULE_USERLOCK;
+ }
+ ldap_value_free_len(values);
+ } else if (inst->access_positive) {
+ RDEBUG("No \"%s\" attribute - user locked out", inst->userobj_access_attr);
+ rcode = RLM_MODULE_USERLOCK;
+ }
+
+ return rcode;
+}
+
+/** Verify we got a password from the search
+ *
+ * Checks to see if after the LDAP to RADIUS mapping has been completed that a reference password.
+ *
+ * @param inst rlm_ldap configuration.
+ * @param request Current request.
+ */
+void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request)
+{
+ /*
+ * More warning messages for people who can't be bothered to read the documentation.
+ *
+ * Expect_password is set when we process the mapping, and is only true if there was a mapping between
+ * an LDAP attribute and a password reference attribute in the control list.
+ */
+ if (inst->expect_password && (rad_debug_lvl > 1)) {
+ if (!fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) &&
+ !fr_pair_find_by_num(request->config, PW_NT_PASSWORD, 0, TAG_ANY) &&
+ !fr_pair_find_by_num(request->config, PW_USER_PASSWORD, 0, TAG_ANY) &&
+ !fr_pair_find_by_num(request->config, PW_PASSWORD_WITH_HEADER, 0, TAG_ANY) &&
+ !fr_pair_find_by_num(request->config, PW_CRYPT_PASSWORD, 0, TAG_ANY)) {
+ RWDEBUG("No \"known good\" password added. Ensure the admin user has permission to "
+ "read the password attribute");
+ RWDEBUG("PAP authentication will *NOT* work with Active Directory (if that is what you "
+ "were trying to configure)");
+ }
+ }
+}
+
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+/** Callback for OpenLDAP to rebind and chase referrals
+ *
+ * Called by OpenLDAP when it receives a referral and has to rebind.
+ *
+ * @param handle to rebind.
+ * @param url to bind to.
+ * @param request that triggered the rebind.
+ * @param msgid that triggered the rebind.
+ * @param ctx rlm_ldap configuration.
+ */
+static int rlm_ldap_rebind(LDAP *handle, LDAP_CONST char *url, UNUSED ber_tag_t request, UNUSED ber_int_t msgid,
+ void *ctx)
+{
+ ldap_rcode_t status;
+ ldap_handle_t *conn = talloc_get_type_abort(ctx, ldap_handle_t);
+
+ int ldap_errno;
+
+ rad_assert(handle == conn->handle);
+
+ DEBUG("rlm_ldap (%s): Rebinding to URL %s", conn->inst->name, url);
+
+ status = rlm_ldap_bind(conn->inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
+ &(conn->inst->admin_sasl), false);
+ if (status != LDAP_PROC_SUCCESS) {
+ ldap_get_option(handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+
+ return ldap_errno;
+ }
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+int rlm_ldap_global_init(rlm_ldap_t *inst)
+{
+ int ldap_errno;
+#if defined(LDAP_OPT_X_TLS_PACKAGE) && defined(LDAP_OPT_X_TLS_CTX) && defined(HAVE_OPENSSL_SSL_H)
+ bool use_openssl = false;
+#endif
+
+#define do_ldap_global_option(_option, _name, _value) \
+ if (ldap_set_option(NULL, _option, _value) != LDAP_OPT_SUCCESS) { \
+ ldap_get_option(NULL, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
+ ERROR("Failed setting global option %s: %s", _name, \
+ (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
+ return -1;\
+ }
+
+#define maybe_ldap_global_option(_option, _name, _value) \
+ if (_value) do_ldap_global_option(_option, _name, _value)
+
+#ifdef LDAP_OPT_DEBUG_LEVEL
+ /*
+ * Can't use do_ldap_global_option
+ */
+ if (inst->ldap_debug) do_ldap_global_option(LDAP_OPT_DEBUG_LEVEL, "ldap_debug", &(inst->ldap_debug));
+#endif
+
+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
+ /*
+ * OpenLDAP will error out if we attempt to set
+ * this on a handle. Presumably it's global in
+ * OpenSSL too.
+ */
+ maybe_ldap_global_option(LDAP_OPT_X_TLS_RANDOM_FILE, "random_file", inst->tls_random_file);
+#endif
+
+#ifdef LDAP_OPT_X_TLS_PACKAGE
+ {
+ char *name = NULL;
+
+ if (ldap_get_option(NULL, LDAP_OPT_X_TLS_PACKAGE, (void *) &name) == LDAP_OPT_SUCCESS) {
+ if (strcmp(name, "OpenSSL") != 0) {
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ WARN("!! libldap is using %s, while FreeRADIUS is using OpenSSL", name);
+ WARN("!! There may be random issues with TLS connections due to this conflict.");
+ WARN("!! The server may also crash.");
+ WARN("!! See https://wiki.freeradius.org/modules/Rlm_ldap for more information.");
+ WARN("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ }
+#if defined(LDAP_OPT_X_TLS_CTX) && defined(HAVE_OPENSSL_SSL_H)
+ else {
+ use_openssl = true;
+ }
+#endif
+
+ ldap_memfree(name);
+ }
+ }
+#endif
+
+#ifdef LDAP_OPT_X_TLS_CTX
+#ifdef HAVE_OPENSSL_SSL_H
+ {
+ X509_STORE *store;
+ SSL_CTX *ssl_ctx;
+
+ if (inst->tls_check_crl &&
+#ifdef LDAP_OPT_X_TLS_PACKAGE
+ use_openssl &&
+#endif
+
+ (ldap_get_option(NULL, LDAP_OPT_X_TLS_CTX, (void *) &ssl_ctx) == LDAP_OPT_SUCCESS)) {
+ store = SSL_CTX_get_cert_store(ssl_ctx);
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
+ }
+ }
+#endif
+#endif
+
+ return 0;
+}
+
+/** Close and delete a connection
+ *
+ * Unbinds the LDAP connection, informing the server and freeing any memory, then releases the memory used by the
+ * connection handle.
+ *
+ * @param conn to destroy.
+ * @return always indicates success.
+ */
+static int _mod_conn_free(ldap_handle_t *conn)
+{
+ if (conn->handle) {
+ DEBUG3("rlm_ldap: Closing libldap handle %p", conn->handle);
+#ifdef HAVE_LDAP_UNBIND_EXT_S
+ ldap_unbind_ext_s(conn->handle, NULL, NULL);
+#else
+ ldap_unbind_s(conn->handle);
+#endif
+ }
+
+ return 0;
+}
+
+/** Create and return a new connection
+ *
+ * Create a new ldap connection and allocate memory for a new rlm_handle_t
+ */
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ ldap_rcode_t status;
+
+ int ldap_errno, ldap_version;
+ struct timeval tv;
+
+ rlm_ldap_t *inst = instance;
+ ldap_handle_t *conn;
+
+ /*
+ * Allocate memory for the handle.
+ */
+ conn = talloc_zero(ctx, ldap_handle_t);
+ if (!conn) return NULL;
+ talloc_set_destructor(conn, _mod_conn_free);
+
+ conn->inst = inst;
+ conn->rebound = false;
+
+ DEBUG("rlm_ldap (%s): Connecting to %s", inst->name, inst->server);
+#ifdef HAVE_LDAP_INITIALIZE
+ ldap_errno = ldap_initialize(&conn->handle, inst->server);
+ if (ldap_errno != LDAP_SUCCESS) {
+ LDAP_ERR("ldap_initialize failed: %s", ldap_err2string(ldap_errno));
+ goto error;
+ }
+#else
+ conn->handle = ldap_init(inst->server, inst->port);
+ if (!conn->handle) {
+ LDAP_ERR("ldap_init failed");
+ goto error;
+ }
+#endif
+ DEBUG3("rlm_ldap (%s): New libldap handle %p", inst->name, conn->handle);
+
+ /*
+ * We now have a connection structure, but no actual connection.
+ *
+ * Set a bunch of LDAP options, using common code.
+ */
+#define do_ldap_option(_option, _name, _value) \
+ if (ldap_set_option(conn->handle, _option, _value) != LDAP_OPT_SUCCESS) { \
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno); \
+ LDAP_ERR("Failed setting connection option %s: %s", _name, \
+ (ldap_errno != LDAP_SUCCESS) ? ldap_err2string(ldap_errno) : "Unknown error"); \
+ goto error;\
+ }
+
+#define maybe_ldap_option(_option, _name, _value) \
+ if (_value) do_ldap_option(_option, _name, _value)
+
+ /*
+ * Leave "dereference" unset to use the OpenLDAP default.
+ */
+ if (inst->dereference_str) {
+ do_ldap_option(LDAP_OPT_DEREF, "dereference", &(inst->dereference));
+ }
+
+ /*
+ * Leave "chase_referrals" unset to use the OpenLDAP default.
+ */
+ if (!inst->chase_referrals_unset) {
+ if (inst->chase_referrals) {
+ do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_ON);
+
+ if (inst->rebind == true) {
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc(conn->handle, rlm_ldap_rebind, conn);
+#endif
+ }
+ } else {
+ do_ldap_option(LDAP_OPT_REFERRALS, "chase_referrals", LDAP_OPT_OFF);
+ }
+ }
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ if (inst->net_timeout) {
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = inst->net_timeout;
+
+ do_ldap_option(LDAP_OPT_NETWORK_TIMEOUT, "net_timeout", &tv);
+ }
+#endif
+
+ do_ldap_option(LDAP_OPT_TIMELIMIT, "srv_timelimit", &(inst->srv_timelimit));
+
+ ldap_version = LDAP_VERSION3;
+ do_ldap_option(LDAP_OPT_PROTOCOL_VERSION, "ldap_version", &ldap_version);
+
+#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
+ do_ldap_option(LDAP_OPT_X_KEEPALIVE_IDLE, "keepalive idle", &(inst->keepalive_idle));
+#endif
+
+#ifdef LDAP_OPT_X_KEEPALIVE_PROBES
+ do_ldap_option(LDAP_OPT_X_KEEPALIVE_PROBES, "keepalive probes", &(inst->keepalive_probes));
+#endif
+
+#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
+ do_ldap_option(LDAP_OPT_X_KEEPALIVE_INTERVAL, "keepalive interval", &(inst->keepalive_interval));
+#endif
+
+#ifdef HAVE_LDAP_START_TLS_S
+ /*
+ * Set all of the TLS options
+ */
+ if (inst->tls_mode) {
+ do_ldap_option(LDAP_OPT_X_TLS, "tls_mode", &(inst->tls_mode));
+ }
+
+ maybe_ldap_option(LDAP_OPT_X_TLS_CACERTFILE, "ca_file", inst->tls_ca_file);
+ maybe_ldap_option(LDAP_OPT_X_TLS_CACERTDIR, "ca_path", inst->tls_ca_path);
+
+
+ /*
+ * Set certificate options
+ */
+ maybe_ldap_option(LDAP_OPT_X_TLS_CERTFILE, "certificate_file", inst->tls_certificate_file);
+ maybe_ldap_option(LDAP_OPT_X_TLS_KEYFILE, "private_key_file", inst->tls_private_key_file);
+
+# ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
+ if (inst->tls_require_cert_str) {
+ do_ldap_option(LDAP_OPT_X_TLS_REQUIRE_CERT, "require_cert", &inst->tls_require_cert);
+ }
+# endif
+
+# ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
+ if (inst->tls_min_version_str) {
+ do_ldap_option(LDAP_OPT_X_TLS_PROTOCOL_MIN, "tls_min_version", &inst->tls_min_version);
+ }
+# endif
+
+ /*
+ * Counter intuitively the TLS context appears to need to be initialised
+ * after all the TLS options are set on the handle.
+ */
+# ifdef LDAP_OPT_X_TLS_NEWCTX
+ {
+ /* Always use the new TLS configuration context */
+ int is_server = 0;
+ do_ldap_option(LDAP_OPT_X_TLS_NEWCTX, "new TLS context", &is_server);
+
+ }
+# endif
+
+# ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
+ if (inst->tls_cipher_list) {
+ do_ldap_option(LDAP_OPT_X_TLS_CIPHER_SUITE, "cipher_list", inst->tls_cipher_list);
+ }
+# endif
+
+ /*
+ * And finally start the TLS code.
+ */
+ if (inst->start_tls) {
+ if (inst->port == 636) {
+ WARN("Told to Start TLS on LDAPS port this will probably fail, please correct the "
+ "configuration");
+ }
+
+ if (ldap_start_tls_s(conn->handle, NULL, NULL) != LDAP_SUCCESS) {
+ ldap_get_option(conn->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
+
+ LDAP_ERR("Could not start TLS: %s", ldap_err2string(ldap_errno));
+ goto error;
+ }
+ }
+#endif /* HAVE_LDAP_START_TLS_S */
+
+ if (inst->sasl_secprops) {
+ do_ldap_option(LDAP_OPT_X_SASL_SECPROPS, "SASL_SECPROPS", inst->sasl_secprops);
+ }
+
+ status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
+ &(conn->inst->admin_sasl), false);
+ if (status != LDAP_PROC_SUCCESS) {
+ goto error;
+ }
+
+ return conn;
+
+error:
+ talloc_free(conn);
+
+ return NULL;
+}
+
+/** Gets an LDAP socket from the connection pool
+ *
+ * Retrieve a socket from the connection pool, or NULL on error (of if no sockets are available).
+ *
+ * @param inst rlm_ldap configuration.
+ * @param request Current request (may be NULL).
+ */
+ldap_handle_t *mod_conn_get(rlm_ldap_t const *inst, UNUSED REQUEST *request)
+{
+ return fr_connection_get(inst->pool);
+}
+
+/** Frees an LDAP socket back to the connection pool
+ *
+ * If the socket was rebound chasing a referral onto another server then we destroy it.
+ * If the socket was rebound to another user on the same server, we let the next caller rebind it.
+ *
+ * @param inst rlm_ldap configuration.
+ * @param conn to release.
+ */
+void mod_conn_release(rlm_ldap_t const *inst, ldap_handle_t *conn)
+{
+ /*
+ * Could have already been free'd due to a previous error.
+ */
+ if (!conn) return;
+
+ fr_connection_release(inst->pool, conn);
+ return;
+}
diff --git a/src/modules/rlm_ldap/ldap.h b/src/modules/rlm_ldap/ldap.h
new file mode 100644
index 0000000..e2e628d
--- /dev/null
+++ b/src/modules/rlm_ldap/ldap.h
@@ -0,0 +1,489 @@
+/**
+ * $Id$
+ * @file ldap.h
+ * @brief LDAP authorization and authentication module headers.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013 Network RADIUS SARL<info@networkradius.com>
+ * @copyright 2013-2015 The FreeRADIUS Server Project.
+ */
+#ifndef _RLM_LDAP_H
+#define _RLM_LDAP_H
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+/*
+ * We're mostly using the new API now, but ldap_bind
+ * is in the list of deprecated functions, at we may
+ * always need to support that.
+ */
+#define LDAP_DEPRECATED 1
+USES_APPLE_DEPRECATED_API /* Apple wants us to use OpenDirectory Framework, we don't want that */
+#include <lber.h>
+#include <ldap.h>
+#include "config.h"
+
+/*
+ * Ensure the have the ldap_create_sort_keylist()
+ * function too, else we can't use ldap_create_sort_control()
+ */
+#if !defined(LDAP_CREATE_SORT_KEYLIST) || !defined(LDAP_FREE_SORT_KEYLIST)
+# undef HAVE_LDAP_CREATE_SORT_CONTROL
+#endif
+
+/*
+ * Because the LTB people define LDAP_VENDOR_VERSION_PATCH
+ * as X, which precludes its use in printf statements *sigh*
+ *
+ * Identifiers that are not macros, all evaluate to 0,
+ * which is why this works.
+ */
+#if !defined(LDAP_VENDOR_VERSION_PATCH) || LDAP_VENDOR_VERSION_PATCH == 0
+# undef LDAP_VENDOR_VERSION_PATCH
+# define LDAP_VENDOR_VERSION_PATCH 0
+#endif
+
+/*
+ * For compatibility with other LDAP libraries
+ */
+#if !defined(LDAP_SCOPE_BASE) && defined(LDAP_SCOPE_BASEOBJECT)
+# define LDAP_SCOPE_BASE LDAP_SCOPE_BASEOBJECT
+#endif
+
+#if !defined(LDAP_SCOPE_ONE) && defined(LDAP_SCOPE_ONELEVEL)
+# define LDAP_SCOPE_ONE LDAP_SCOPE_ONELEVEL
+#endif
+
+#if !defined(LDAP_SCOPE_SUB) && defined(LDAP_SCOPE_SUBTREE)
+# define LDAP_SCOPE_SUB LDAP_SCOPE_SUBTREE
+#endif
+
+#if !defined(LDAP_OPT_RESULT_CODE) && defined(LDAP_OPT_ERROR_NUMBER)
+# define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER
+#endif
+
+#ifndef LDAP_CONST
+# define LDAP_CONST
+#endif
+
+#if defined(HAVE_LDAP_URL_PARSE) && defined(HAVE_LDAP_IS_LDAP_URL) && defined(HAVE_LDAP_URL_DESC2STR)
+# define LDAP_CAN_PARSE_URLS
+#endif
+
+#define MOD_PREFIX "rlm_ldap" //!< The name of the module.
+
+#define LDAP_MAX_ATTRMAP 128 //!< Maximum number of mappings between LDAP and
+ //!< FreeRADIUS attributes.
+#define LDAP_MAP_RESERVED 4 //!< Number of additional items to allocate in expanded
+ //!< attribute name arrays. Currently for enable attribute,
+ //!< group membership attribute, valuepair attribute,
+ //!< and profile attribute.
+
+#define LDAP_MAX_CACHEABLE 64 //!< Maximum number of groups we retrieve from the server for
+ //!< a given user which need resolving from name to DN.
+
+#define LDAP_MAX_GROUP_NAME_LEN 128 //!< Maximum name of a group name.
+#define LDAP_MAX_ATTR_STR_LEN 256 //!< Maximum length of an xlat expanded LDAP attribute.
+#define LDAP_MAX_FILTER_STR_LEN 1024 //!< Maximum length of an xlat expanded filter.
+#define LDAP_MAX_DN_STR_LEN 1024 //!< Maximum length of an xlat expanded DN.
+
+#define LDAP_VIRTUAL_DN_ATTR "dn" //!< 'Virtual' attribute which maps to the DN of the object.
+
+typedef struct ldap_acct_section {
+ CONF_SECTION *cs; //!< Section configuration.
+
+ char const *reference; //!< Configuration reference string.
+} ldap_acct_section_t;
+
+typedef struct ldap_sasl {
+ char const *mech; //!< SASL mech(s) to try.
+ char const *proxy; //!< Identity to proxy.
+ char const *realm; //!< Kerberos realm.
+} ldap_sasl;
+
+typedef struct ldap_sasl_dynamic {
+ vp_tmpl_t *mech; //!< SASL mech(s) to try.
+ vp_tmpl_t *proxy; //!< Identity to proxy.
+ vp_tmpl_t *realm; //!< Kerberos realm.
+} ldap_sasl_dynamic;
+
+typedef struct ldap_instance {
+ CONF_SECTION *cs; //!< Main configuration section for this instance.
+ fr_connection_pool_t *pool; //!< Connection pool instance.
+
+ char const *config_server; //!< Server set in the config.
+ char *server; //!< Initial server to bind to.
+ uint16_t port; //!< Port to use when binding to the server.
+
+ char const *admin_identity; //!< Identity we bind as when we need to query the LDAP
+ //!< directory.
+ char const *admin_password; //!< Password used in administrative bind.
+
+ ldap_sasl admin_sasl; //!< SASL parameters used when binding as the admin.
+
+ const char *sasl_secprops; //!< SASL Security Properties to set.
+
+ char const *dereference_str; //!< When to dereference (never, searching, finding, always)
+ int dereference; //!< libldap value specifying dereferencing behaviour.
+
+ bool chase_referrals; //!< If the LDAP server returns a referral to another server
+ //!< or point in the tree, follow it, establishing new
+ //!< connections and binding where necessary.
+ bool chase_referrals_unset; //!< If true, use the OpenLDAP defaults for chase_referrals.
+
+ bool rebind; //!< Controls whether we set an ldad_rebind_proc function
+ //!< and so determines if we can bind to other servers whilst
+ //!< chasing referrals. If this is false, we will still chase
+ //!< referrals on the same server, but won't bind to other
+ //!< servers.
+
+ uint32_t ldap_debug; //!< Debug flag for the SDK.
+
+ char const *name; //!< Instance name.
+
+ bool expect_password; //!< True if the user_map included a mapping between an LDAP
+ //!< attribute and one of our password reference attributes.
+
+ /*
+ * RADIUS attribute to LDAP attribute maps
+ */
+ vp_map_t *user_map; //!< Attribute map applied to users and profiles.
+
+ /*
+ * User object attributes and filters
+ */
+ vp_tmpl_t *userobj_filter; //!< Filter to retrieve only user objects.
+ vp_tmpl_t *userobj_base_dn; //!< DN to search for users under.
+ char const *userobj_scope_str; //!< Scope (sub, one, base).
+ char const *userobj_sort_by; //!< List of attributes to sort by.
+ LDAPControl *userobj_sort_ctrl; //!< Server side sort control.
+
+ int userobj_scope; //!< Search scope.
+
+ char const *user_dn; //!< for multiple LDAP modules
+ DICT_ATTR const *user_dn_da; //!< cached user DN
+
+ char const *userobj_membership_attr; //!< Attribute that describes groups the user is a member of.
+ char const *userobj_access_attr; //!< Attribute to check to see if the user should be locked out.
+ bool access_positive; //!< If true the presence of the attribute will allow access,
+ //!< else it will deny access.
+
+ char const *valuepair_attr; //!< Generic dynamic mapping attribute, contains a RADIUS
+ //!< attribute and value.
+
+ ldap_sasl_dynamic user_sasl; //!< SASL parameters used when binding as the user.
+
+ /*
+ * Group object attributes and filters
+ */
+ char const *groupobj_filter; //!< Filter to retrieve only group objects.
+ vp_tmpl_t *groupobj_base_dn; //!< DN to search for users under.
+ char const *groupobj_scope_str; //!< Scope (sub, one, base).
+ int groupobj_scope; //!< Search scope.
+
+ char const *groupobj_name_attr; //!< The name of the group.
+ char const *groupobj_membership_filter; //!< Filter to only retrieve groups which contain
+ //!< the user as a member.
+
+ bool cacheable_group_name; //!< If true the server will determine complete set of group
+ //!< memberships for the current user object, and perform any
+ //!< resolution necessary to determine the names of those
+ //!< groups, then right them to the control list (LDAP-Group).
+
+ bool cacheable_group_dn; //!< If true the server will determine complete set of group
+ //!< memberships for the current user object, and perform any
+ //!< resolution necessary to determine the DNs of those groups,
+ //!< then right them to the control list (LDAP-GroupDN).
+
+ char const *cache_attribute; //!< Sets the attribute we use when creating and retrieving
+ //!< cached group memberships.
+
+ DICT_ATTR const *cache_da; //!< The DA associated with this specific instance of the
+ //!< rlm_ldap module.
+
+ DICT_ATTR const *group_da; //!< The DA associated with this specific instance of the
+ //!< rlm_ldap module.
+
+ bool allow_dangling_group_refs; //!< Don't error if we fail to resolve a group DN referenced
+ ///< from a user object.
+
+
+ /*
+ * Dynamic clients
+ */
+ char const *clientobj_filter; //!< Filter to retrieve only client objects.
+ char const *clientobj_base_dn; //!< DN to search for clients under.
+ char const *clientobj_scope_str; //!< Scope (sub, one, base).
+ int clientobj_scope; //!< Search scope.
+
+ bool do_clients; //!< If true, attempt to load clients on instantiation.
+
+ /*
+ * Profiles
+ */
+ vp_tmpl_t *default_profile; //!< If this is set, we will search for a profile object
+ //!< with this name, and map any attributes it contains.
+ //!< No value should be set if profiles are not being used
+ //!< as there is an associated performance penalty.
+ char const *profile_attr; //!< Attribute that identifies profiles to apply. May appear
+ //!< in userobj or groupobj.
+ vp_tmpl_t *profile_filter; //!< Filter to retrieve only retrieve group objects.
+
+ /*
+ * Accounting
+ */
+ ldap_acct_section_t *postauth; //!< Modify mappings for post-auth.
+ ldap_acct_section_t *accounting; //!< Modify mappings for accounting.
+
+ /*
+ * TLS items. We should really normalize these with the
+ * TLS code in 3.0.
+ */
+ int tls_mode;
+ bool start_tls; //!< Send the Start TLS message to the LDAP directory
+ //!< to start encrypted communications using the standard
+ //!< LDAP port.
+
+ char const *tls_ca_file; //!< Sets the full path to a CA certificate (used to validate
+ //!< the certificate the server presents).
+
+ char const *tls_ca_path; //!< Sets the path to a directory containing CA certificates.
+
+ char const *tls_certificate_file; //!< Sets the path to the public certificate file we present
+ //!< to the servers.
+
+ char const *tls_private_key_file; //!< Sets the path to the private key for our public
+ //!< certificate.
+
+ char const *tls_random_file; //!< Path to the random file if /dev/random and /dev/urandom
+ //!< are unavailable.
+
+ char const *tls_require_cert_str; //!< Sets requirements for validating the certificate the
+ //!< server presents.
+
+ int tls_require_cert; //!< OpenLDAP constant representing the require cert string.
+
+ bool tls_check_crl; //!< whether we do CRL checks or not
+
+ char const *tls_min_version_str; //!< Minimum TLS version
+ int tls_min_version;
+
+ char const *tls_cipher_list; //!< cipher suites
+
+ /*
+ * Options
+ */
+ uint32_t net_timeout; //!< How long we wait for new connections to the LDAP server
+ //!< to be established.
+ uint32_t res_timeout; //!< How long we wait for a result from the server.
+ uint32_t srv_timelimit; //!< How long the server should spent on a single request
+ //!< (also bounded by value on the server).
+
+#ifdef WITH_EDIR
+ /*
+ * eDir support
+ */
+ bool edir; //!< If true attempt to retrieve the user's cleartext password
+ //!< using the Universal Password feature of Novell eDirectory.
+ bool edir_autz; //!< If true, and we have the Universal Password, bind with it
+ //!< to perform additional authorisation checks.
+#endif
+ /*
+ * For keep-alives.
+ */
+#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
+ uint32_t keepalive_idle; //!< Number of seconds a connections needs to remain idle
+ //!< before TCP starts sending keepalive probes.
+#endif
+#ifdef LDAP_OPT_X_KEEPALIVE_PROBES
+ uint32_t keepalive_probes; //!< Number of missed timeouts before the connection is
+ //!< dropped.
+#endif
+#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
+ uint32_t keepalive_interval; //!< Interval between keepalive probes.
+#endif
+
+ LDAP *handle; //!< Hack for OpenLDAP libldap global initialisation.
+} rlm_ldap_t;
+
+/** Tracks the state of a libldap connection handle
+ *
+ */
+typedef struct ldap_handle {
+ LDAP *handle; //!< libldap handle.
+ bool rebound; //!< Whether the connection has been rebound to something
+ //!< other than the admin user.
+ rlm_ldap_t *inst; //!< rlm_ldap configuration.
+} ldap_handle_t;
+
+/** Result of expanding the RHS of a set of maps
+ *
+ * Used to store the array of attributes we'll be querying for.
+ */
+typedef struct rlm_ldap_map_exp {
+ vp_map_t const *maps; //!< Head of list of maps we expanded the RHS of.
+ char const *attrs[LDAP_MAX_ATTRMAP + LDAP_MAP_RESERVED + 1]; //!< Reserve some space for access attributes
+ //!< and NULL termination.
+ TALLOC_CTX *ctx; //!< Context to allocate new attributes in.
+ int count; //!< Index on next free element.
+} rlm_ldap_map_exp_t;
+
+/** Contains a collection of values
+ *
+ */
+typedef struct rlm_ldap_result {
+ struct berval **values; //!< libldap struct containing bv_val (char *)
+ //!< and length bv_len.
+ int count; //!< Number of values.
+} rlm_ldap_result_t;
+
+/** Codes returned by rlm_ldap internal functions
+ *
+ */
+typedef enum {
+ LDAP_PROC_CONTINUE = 1, //!< Operation is in progress.
+ LDAP_PROC_SUCCESS = 0, //!< Operation was successfull.
+
+ LDAP_PROC_ERROR = -1, //!< Unrecoverable library/server error.
+
+ LDAP_PROC_RETRY = -2, //!< Transitory error, caller should retry the operation
+ //!< with a new connection.
+
+ LDAP_PROC_NOT_PERMITTED = -3, //!< Operation was not permitted, either current user was
+ //!< locked out in the case of binds, or has insufficient
+ //!< access.
+
+ LDAP_PROC_REJECT = -4, //!< Bind failed, user was rejected.
+
+ LDAP_PROC_BAD_DN = -5, //!< Specified an invalid object in a bind or search DN.
+
+ LDAP_PROC_NO_RESULT = -6 //!< Got no results.
+} ldap_rcode_t;
+
+/*
+ * Some functions may be called with a NULL request structure, this
+ * simplifies switching certain messages from the request log to
+ * the main log.
+ */
+#define LDAP_INFO(fmt, ...) INFO("rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_WARN(fmt, ...) WARN("rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+
+#define LDAP_DBGW(fmt, ...) radlog(L_DBG_WARN, "rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_DBGW_REQ(fmt, ...) do { if (request) {RWDEBUG(fmt, ##__VA_ARGS__);} else {LDAP_DBGW(fmt, ##__VA_ARGS__);}} while (0)
+
+#define LDAP_DBG(fmt, ...) radlog(L_DBG, "rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_DBG_REQ(fmt, ...) do { if (request) {RDEBUG(fmt, ##__VA_ARGS__);} else {LDAP_DBG(fmt, ##__VA_ARGS__);}} while (0)
+
+#define LDAP_DBG2(fmt, ...) if (rad_debug_lvl >= L_DBG_LVL_2) radlog(L_DBG, "rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_DBG_REQ2(fmt, ...) do { if (request) {RDEBUG2(fmt, ##__VA_ARGS__);} else if (rad_debug_lvl >= L_DBG_LVL_2) {LDAP_DBG(fmt, ##__VA_ARGS__);}} while (0)
+
+#define LDAP_DBG3(fmt, ...) if (rad_debug_lvl >= L_DBG_LVL_3) radlog(L_DBG, "rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_DBG_REQ3(fmt, ...) do { if (request) {RDEBUG3(fmt, ##__VA_ARGS__);} else if (rad_debug_lvl >= L_DBG_LVL_3) {LDAP_DBG(fmt, ##__VA_ARGS__);}} while (0)
+
+#define LDAP_ERR(fmt, ...) ERROR("rlm_ldap (%s): " fmt, inst->name, ##__VA_ARGS__)
+#define LDAP_ERR_REQ(fmt, ...) do { if (request) {REDEBUG(fmt, ##__VA_ARGS__);} else {LDAP_ERR(fmt, ##__VA_ARGS__);}} while (0)
+
+#define LDAP_EXT() if (extra) LDAP_ERR(extra)
+#define LDAP_EXT_REQ() do { if (extra) { if (request) REDEBUG("%s", extra); else LDAP_ERR("%s", extra); }} while (0)
+
+extern FR_NAME_NUMBER const ldap_scope[];
+extern FR_NAME_NUMBER const ldap_tls_require_cert[];
+
+/*
+ * ldap.c - Wrappers arounds OpenLDAP functions.
+ */
+size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg);
+
+bool rlm_ldap_is_dn(char const *in, size_t inlen);
+
+size_t rlm_ldap_normalise_dn(char *out, char const *in);
+
+ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen);
+
+ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn,
+ char const *password, ldap_sasl *sasl, bool retry);
+
+char const *rlm_ldap_error_str(ldap_handle_t const *conn);
+
+ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t **pconn,
+ char const *dn, int scope, char const *filter, char const * const *attrs,
+ LDAPControl **serverctrls, LDAPControl **clientctrls);
+
+ldap_rcode_t rlm_ldap_modify(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *dn, LDAPMod *mods[]);
+
+char const *rlm_ldap_find_user(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *attrs[], bool force, LDAPMessage **result, rlm_rcode_t *rcode);
+
+rlm_rcode_t rlm_ldap_check_access(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t const *conn,
+ LDAPMessage *entry);
+
+void rlm_ldap_check_reply(rlm_ldap_t const *inst, REQUEST *request);
+
+/*
+ * ldap.c - Callbacks for the connection pool API.
+ */
+ldap_rcode_t rlm_ldap_result(rlm_ldap_t const *inst, ldap_handle_t const *conn, int msgid, char const *dn,
+ LDAPMessage **result, char const **error, char **extra);
+
+char *rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in);
+
+int rlm_ldap_global_init(rlm_ldap_t *inst) CC_HINT(nonnull);
+
+void *mod_conn_create(TALLOC_CTX *ctx, void *instance);
+
+ldap_handle_t *mod_conn_get(rlm_ldap_t const *inst, REQUEST *request);
+
+void mod_conn_release(rlm_ldap_t const *inst, ldap_handle_t *conn);
+
+/*
+ * groups.c - Group membership functions.
+ */
+rlm_rcode_t rlm_ldap_cacheable_userobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ LDAPMessage *entry, char const *attr);
+
+rlm_rcode_t rlm_ldap_cacheable_groupobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn);
+
+rlm_rcode_t rlm_ldap_check_groupobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ VALUE_PAIR *check);
+
+rlm_rcode_t rlm_ldap_check_userobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *dn, VALUE_PAIR *check);
+
+rlm_rcode_t rlm_ldap_check_cached(rlm_ldap_t const *inst, REQUEST *request, VALUE_PAIR *check);
+
+/*
+ * attrmap.c - Attribute mapping code.
+ */
+int rlm_ldap_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx);
+
+int rlm_ldap_map_verify(vp_map_t *map, void *instance);
+
+int rlm_ldap_map_expand(rlm_ldap_map_exp_t *expanded, REQUEST *request, vp_map_t const *maps);
+
+int rlm_ldap_map_do(rlm_ldap_t const *inst, REQUEST *request, LDAP *handle,
+ rlm_ldap_map_exp_t const *expanded, LDAPMessage *entry);
+
+/*
+ * clients.c - Dynamic clients (bulk load).
+ */
+int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTION *cs);
+
+/*
+ * edir.c - Magic extensions for Novell
+ */
+int nmasldap_get_password(LDAP *ld, char const *dn, char *password, size_t *len);
+
+char const *edir_errstr(int code);
+
+/*
+ * sasl.s - SASL bind functions
+ */
+ldap_rcode_t rlm_ldap_sasl_interactive(rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t *pconn, char const *dn,
+ char const *password, ldap_sasl *sasl,
+ char const **error, char **error_extra);
+#endif
diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c
new file mode 100644
index 0000000..a8df048
--- /dev/null
+++ b/src/modules/rlm_ldap/rlm_ldap.c
@@ -0,0 +1,1985 @@
+/*
+ * 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_ldap.c
+ * @brief LDAP authorization and authentication module.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @author Alan DeKok <aland@freeradius.org>
+ *
+ * @copyright 2012,2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2013,2015 Network RADIUS SARL <info@networkradius.com>
+ * @copyright 2012 Alan DeKok <aland@freeradius.org>
+ * @copyright 1999-2013 The FreeRADIUS Server Project.
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/rad_assert.h>
+
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "ldap.h"
+
+/*
+ * Scopes
+ */
+FR_NAME_NUMBER const ldap_scope[] = {
+ { "sub", LDAP_SCOPE_SUB },
+ { "one", LDAP_SCOPE_ONE },
+ { "base", LDAP_SCOPE_BASE },
+#ifdef LDAP_SCOPE_CHILDREN
+ { "children", LDAP_SCOPE_CHILDREN },
+#endif
+ { NULL , -1 }
+};
+
+#ifdef LDAP_OPT_X_TLS_NEVER
+FR_NAME_NUMBER const ldap_tls_require_cert[] = {
+ { "never", LDAP_OPT_X_TLS_NEVER },
+ { "demand", LDAP_OPT_X_TLS_DEMAND },
+ { "allow", LDAP_OPT_X_TLS_ALLOW },
+ { "try", LDAP_OPT_X_TLS_TRY },
+ { "hard", LDAP_OPT_X_TLS_HARD }, /* oh yes, just like that */
+
+ { NULL , -1 }
+};
+#endif
+
+static FR_NAME_NUMBER const ldap_dereference[] = {
+ { "never", LDAP_DEREF_NEVER },
+ { "searching", LDAP_DEREF_SEARCHING },
+ { "finding", LDAP_DEREF_FINDING },
+ { "always", LDAP_DEREF_ALWAYS },
+
+ { NULL , -1 }
+};
+
+static CONF_PARSER sasl_mech_dynamic[] = {
+ { "mech", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL | PW_TYPE_NOT_EMPTY, ldap_sasl_dynamic, mech), NULL },
+ { "proxy", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, ldap_sasl_dynamic, proxy), NULL },
+ { "realm", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, ldap_sasl_dynamic, realm), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER sasl_mech_static[] = {
+ { "mech", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, ldap_sasl, mech), NULL },
+ { "proxy", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_sasl, proxy), NULL },
+ { "realm", FR_CONF_OFFSET(PW_TYPE_STRING, ldap_sasl, realm), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * TLS Configuration
+ */
+static CONF_PARSER tls_config[] = {
+ /*
+ * Deprecated attributes
+ */
+ { "cacertfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_ca_file), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_file), NULL },
+
+ { "cacertdir", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_ca_path), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_ca_path), NULL },
+
+ { "certfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_certificate_file), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_certificate_file), NULL },
+
+ { "keyfile", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_private_key_file), NULL }, // OK if it changes on HUP
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_ldap_t, tls_private_key_file), NULL }, // OK if it changes on HUP
+
+ { "randfile", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS | PW_TYPE_DEPRECATED, rlm_ldap_t, tls_random_file), NULL },
+ { "random_file", FR_CONF_OFFSET(PW_TYPE_FILE_EXISTS, rlm_ldap_t, tls_random_file), NULL },
+
+#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
+ { "tls_min_version", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, tls_min_version_str), NULL },
+#endif
+
+#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
+ { "cipher_list", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, tls_cipher_list), NULL },
+#endif
+
+#ifdef LDAP_OPT_X_TLS_CTX
+ { "check_crl", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, tls_check_crl), "no" },
+#endif
+
+ /*
+ * LDAP Specific TLS attributes
+ */
+ { "start_tls", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, start_tls), "no" },
+ { "require_cert", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, tls_require_cert_str), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static CONF_PARSER profile_config[] = {
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_ldap_t, profile_filter), "(&)" }, //!< Correct filter for when the DN is known.
+ { "attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, profile_attr), NULL },
+ { "default", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_ldap_t, default_profile), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * User configuration
+ */
+static CONF_PARSER user_config[] = {
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_ldap_t, userobj_filter), NULL },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, userobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_ldap_t, userobj_base_dn), "" },
+ { "sort_by", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, userobj_sort_by), NULL },
+
+ { "access_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, userobj_access_attr), NULL },
+ { "access_positive", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, access_positive), "yes" },
+
+ /* Should be deprecated */
+ { "sasl", FR_CONF_OFFSET(PW_TYPE_SUBSECTION, rlm_ldap_t, user_sasl), (void const *) sasl_mech_dynamic },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Group configuration
+ */
+static CONF_PARSER group_config[] = {
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, groupobj_filter), NULL },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, groupobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_ldap_t, groupobj_base_dn), "" },
+
+ { "name_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, groupobj_name_attr), "cn" },
+ { "membership_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, userobj_membership_attr), NULL },
+ { "membership_filter", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_ldap_t, groupobj_membership_filter), NULL },
+ { "cacheable_name", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, cacheable_group_name), "no" },
+ { "cacheable_dn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, cacheable_group_dn), "no" },
+ { "cache_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, cache_attribute), NULL },
+ { "allow_dangling_group_ref", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, allow_dangling_group_refs), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER client_config[] = {
+ { "filter", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, clientobj_filter), NULL },
+ { "scope", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, clientobj_scope_str), "sub" },
+ { "base_dn", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, clientobj_base_dn), "" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Reference for accounting updates
+ */
+static const CONF_PARSER acct_section_config[] = {
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, ldap_acct_section_t, reference), "." },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Various options that don't belong in the main configuration.
+ *
+ * Note that these overlap a bit with the connection pool code!
+ */
+static CONF_PARSER option_config[] = {
+ /*
+ * Debugging flags to the server
+ */
+ { "ldap_debug", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, ldap_debug), "0x0000" },
+
+ { "dereference", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, dereference_str), NULL },
+
+ { "chase_referrals", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, chase_referrals), NULL },
+
+ { "rebind", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, rebind), NULL },
+
+ { "sasl_secprops", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, sasl_secprops), NULL },
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ /* timeout on network activity */
+ { "net_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, net_timeout), "10" },
+#endif
+
+ /* timeout for search results */
+ { "res_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, res_timeout), "20" },
+
+ /* allow server unlimited time for search (server-side limit) */
+ { "srv_timelimit", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, srv_timelimit), "20" },
+
+#ifdef LDAP_OPT_X_KEEPALIVE_IDLE
+ { "idle", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, keepalive_idle), "60" },
+#endif
+#ifdef LDAP_OPT_X_KEEPALIVE_PROBES
+ { "probes", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, keepalive_probes), "3" },
+#endif
+#ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
+ { "interval", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_ldap_t, keepalive_interval), "30" },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+
+static const CONF_PARSER module_config[] = {
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_MULTI, rlm_ldap_t, config_server), NULL }, /* Do not set to required */
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, rlm_ldap_t, port), NULL },
+
+ { "identity", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, admin_identity), NULL },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_ldap_t, admin_password), NULL },
+
+ { "sasl", FR_CONF_OFFSET(PW_TYPE_SUBSECTION, rlm_ldap_t, admin_sasl), (void const *) sasl_mech_static },
+
+ { "valuepair_attribute", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, valuepair_attr), NULL },
+
+ { "user_dn", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_ldap_t, user_dn), NULL },
+
+#ifdef WITH_EDIR
+ /* support for eDirectory Universal Password */
+ { "edir", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, edir), NULL }, /* NULL defaults to "no" */
+
+ /*
+ * Attempt to bind with the cleartext password we got from eDirectory
+ * Universal password for additional authorization checks.
+ */
+ { "edir_autz", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, edir_autz), NULL }, /* NULL defaults to "no" */
+#endif
+
+ { "read_clients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_ldap_t, do_clients), NULL }, /* NULL defaults to "no" */
+
+ { "user", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) user_config },
+
+ { "group", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) group_config },
+
+ { "client", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) client_config },
+
+ { "profile", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) profile_config },
+
+ { "options", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) option_config },
+
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
+ CONF_PARSER_TERMINATOR
+};
+
+static ssize_t ldapquote_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ return rlm_ldap_escape_func(request, out, freespace, fmt, NULL);
+}
+
+/** Expand an LDAP URL into a query, and return a string result from that query.
+ *
+ */
+static ssize_t ldap_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ ldap_rcode_t status;
+ size_t len = 0;
+ rlm_ldap_t *inst = instance;
+
+ LDAPURLDesc *ldap_url;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entry = NULL;
+
+ struct berval **values;
+
+ ldap_handle_t *conn;
+ int ldap_errno;
+
+ char const *url;
+ char const **attrs;
+
+ url = fmt;
+
+ if (!ldap_is_ldap_url(url)) {
+ REDEBUG("String passed does not look like an LDAP URL");
+ return -1;
+ }
+
+ if (ldap_url_parse(url, &ldap_url)){
+ REDEBUG("Parsing LDAP URL failed");
+ return -1;
+ }
+
+ /*
+ * Nothing, empty string, "*" string, or got 2 things, die.
+ */
+ if (!ldap_url->lud_attrs || !ldap_url->lud_attrs[0] ||
+ !*ldap_url->lud_attrs[0] ||
+ (strcmp(ldap_url->lud_attrs[0], "*") == 0) ||
+ ldap_url->lud_attrs[1]) {
+ REDEBUG("Bad attributes list in LDAP URL. URL must specify exactly one attribute to retrieve");
+
+ goto free_urldesc;
+ }
+
+ conn = mod_conn_get(inst, request);
+ if (!conn) goto free_urldesc;
+
+ memcpy(&attrs, &ldap_url->lud_attrs, sizeof(attrs));
+
+ status = rlm_ldap_search(&result, inst, request, &conn, ldap_url->lud_dn, ldap_url->lud_scope,
+ ldap_url->lud_filter, attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ default:
+ goto free_socket;
+ }
+
+ rad_assert(conn);
+ rad_assert(result);
+
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
+ ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+ len = -1;
+ goto free_result;
+ }
+
+ values = ldap_get_values_len(conn->handle, entry, ldap_url->lud_attrs[0]);
+ if (!values) {
+ RDEBUG("No \"%s\" attributes found in specified object", ldap_url->lud_attrs[0]);
+ goto free_result;
+ }
+
+ if (values[0]->bv_len >= freespace) goto free_values;
+
+ memcpy(out, values[0]->bv_val, values[0]->bv_len + 1); /* +1 as strlcpy expects buffer size */
+ len = values[0]->bv_len;
+
+free_values:
+ ldap_value_free_len(values);
+free_result:
+ ldap_msgfree(result);
+free_socket:
+ mod_conn_release(inst, conn);
+free_urldesc:
+ ldap_free_urldesc(ldap_url);
+
+ return len;
+}
+
+/** Perform LDAP-Group comparison checking
+ *
+ * Attempts to match users to groups using a variety of methods.
+ *
+ * @param instance of the rlm_ldap module.
+ * @param request Current request.
+ * @param thing Unknown.
+ * @param check Which group to check for user membership.
+ * @param check_pairs Unknown.
+ * @param reply_pairs Unknown.
+ * @return
+ * - 1 on failure (or if the user is not a member).
+ * - 0 on success.
+ */
+static int rlm_ldap_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ rlm_ldap_t *inst = instance;
+ rlm_rcode_t rcode;
+
+ bool found = false;
+ bool check_is_dn;
+
+ ldap_handle_t *conn = NULL;
+ char const *user_dn;
+
+ rad_assert(inst->groupobj_base_dn);
+
+ RDEBUG("Searching for user in group \"%s\"", check->vp_strvalue);
+
+ if (check->vp_length == 0) {
+ REDEBUG("Cannot do comparison (group name is empty)");
+ return 1;
+ }
+
+ /*
+ * Check if we can do cached membership verification
+ */
+ check_is_dn = rlm_ldap_is_dn(check->vp_strvalue, check->vp_length);
+ if (check_is_dn) {
+ char *norm;
+
+ MEM(norm = talloc_memdup(check, check->vp_strvalue, talloc_array_length(check->vp_strvalue)));
+ rlm_ldap_normalise_dn(norm, check->vp_strvalue);
+ fr_pair_value_strsteal(check, norm);
+ }
+ if ((check_is_dn && inst->cacheable_group_dn) || (!check_is_dn && inst->cacheable_group_name)) {
+ switch (rlm_ldap_check_cached(inst, request, check)) {
+ case RLM_MODULE_NOTFOUND:
+ found = false;
+ goto finish;
+
+ case RLM_MODULE_OK:
+ found = true;
+ goto finish;
+ /*
+ * Fallback to dynamic search on failure
+ */
+ case RLM_MODULE_FAIL:
+ case RLM_MODULE_INVALID:
+ default:
+ break;
+ }
+ }
+
+ conn = mod_conn_get(inst, request);
+ if (!conn) return 1;
+
+ /*
+ * This is used in the default membership filter.
+ */
+ user_dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
+ if (!user_dn) {
+ mod_conn_release(inst, conn);
+ return 1;
+ }
+
+ rad_assert(conn);
+
+ /*
+ * Check groupobj user membership
+ */
+ if (inst->groupobj_membership_filter) {
+ switch (rlm_ldap_check_groupobj_dynamic(inst, request, &conn, check)) {
+ case RLM_MODULE_NOTFOUND:
+ break;
+
+ case RLM_MODULE_OK:
+ found = true;
+
+ default:
+ goto finish;
+ }
+ }
+
+ rad_assert(conn);
+
+ /*
+ * Check userobj group membership
+ */
+ if (inst->userobj_membership_attr) {
+ switch (rlm_ldap_check_userobj_dynamic(inst, request, &conn, user_dn, check)) {
+ case RLM_MODULE_NOTFOUND:
+ break;
+
+ case RLM_MODULE_OK:
+ found = true;
+
+ default:
+ goto finish;
+ }
+ }
+
+ rad_assert(conn);
+
+finish:
+ if (conn) mod_conn_release(inst, conn);
+
+ if (!found) {
+ RDEBUG("User is not a member of \"%s\"", check->vp_strvalue);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Detach from the LDAP server and cleanup internal state.
+ *
+ */
+static int mod_detach(void *instance)
+{
+ rlm_ldap_t *inst = instance;
+
+ fr_connection_pool_free(inst->pool);
+
+ if (inst->user_map) {
+ talloc_free(inst->user_map);
+ }
+
+ /*
+ * Keeping the dummy ld around for the lifetime
+ * of the module should always work,
+ * irrespective of what changes happen in libldap.
+ */
+ if (inst->handle) {
+#ifdef HAVE_LDAP_UNBIND_EXT_S
+ ldap_unbind_ext_s(inst->handle, NULL, NULL);
+#else
+ ldap_unbind_s(inst->handle);
+#endif
+ }
+
+#ifdef HAVE_LDAP_CREATE_SORT_CONTROL
+ if (inst->userobj_sort_ctrl) ldap_control_free(inst->userobj_sort_ctrl);
+#endif
+
+ return 0;
+}
+
+/** Parse an accounting sub section.
+ *
+ * Allocate a new ldap_acct_section_t and write the config data into it.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] parent of the config section.
+ * @param[out] config to write the sub section parameters to.
+ * @param[in] comp The section name were parsing the config for.
+ * @return
+ * - 0 on success.
+ * - < 0 on failure.
+ */
+static int parse_sub_section(rlm_ldap_t *inst, CONF_SECTION *parent, ldap_acct_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) {
+ DEBUG2("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls "
+ "from this section", inst->name, name);
+
+ return 0;
+ }
+
+ *config = talloc_zero(inst, ldap_acct_section_t);
+ if (cf_section_parse(cs, *config, acct_section_config) < 0) {
+ LDAP_ERR("Failed parsing configuration for section %s", name);
+
+ return -1;
+ }
+
+ (*config)->cs = cs;
+
+ return 0;
+}
+
+/** Bootstrap the module
+ *
+ * Define attributes.
+ *
+ * @param conf to parse.
+ * @param instance configuration data.
+ * @return
+ * - 0 on success.
+ * - < 0 on failure.
+ */
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_ldap_t *inst = instance;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ /*
+ * Group comparison checks.
+ */
+ if (cf_section_name2(conf)) {
+ char buffer[256];
+
+ snprintf(buffer, sizeof(buffer), "%s-LDAP-Group", inst->name);
+
+ if (paircompare_register_byname(buffer, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst) < 0) {
+ LDAP_ERR("Error registering group comparison: %s", fr_strerror());
+ goto error;
+ }
+
+ inst->group_da = dict_attrbyname(buffer);
+
+ /*
+ * We're the default instance
+ */
+ } else {
+ if (paircompare_register_byname("LDAP-Group", dict_attrbyvalue(PW_USER_NAME, 0),
+ false, rlm_ldap_groupcmp, inst) < 0) {
+ LDAP_ERR("Error registering group comparison: %s", fr_strerror());
+ goto error;
+ }
+
+ inst->group_da = dict_attrbyname("LDAP-Group");
+ }
+
+ /*
+ * Setup the cache attribute
+ */
+ if (inst->cache_attribute) {
+ ATTR_FLAGS flags;
+
+ memset(&flags, 0, sizeof(flags));
+ if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) {
+ LDAP_ERR("Error creating cache attribute: %s", fr_strerror());
+ error:
+ return -1;
+
+ }
+ inst->cache_da = dict_attrbyname(inst->cache_attribute);
+ } else {
+ inst->cache_da = inst->group_da; /* Default to the group_da */
+ }
+
+ if (!inst->user_dn || !*inst->user_dn) {
+ inst->user_dn = talloc_strdup(inst, "LDAP-UserDn");
+ }
+
+ /*
+ * Check or create the LDAP-UserDn attribute.
+ */
+ if (inst->user_dn) {
+ ATTR_FLAGS flags;
+
+ memset(&flags, 0, sizeof(flags));
+ if (dict_addattr(inst->user_dn, -1, 0, PW_TYPE_STRING, flags) < 0) {
+ LDAP_ERR("Error creating %s attribute: %s", inst->user_dn, fr_strerror());
+ return -1;
+ }
+ inst->user_dn_da = dict_attrbyname(inst->user_dn);
+ }
+
+ xlat_register(inst->name, ldap_xlat, rlm_ldap_escape_func, inst);
+ xlat_register("ldapquote", ldapquote_xlat, NULL, inst);
+
+ return 0;
+}
+
+
+/** Instantiate the module
+ *
+ * Creates a new instance of the module reading parameters from a configuration section.
+ *
+ * @param conf to parse.
+ * @param instance configuration data.
+ * @return
+ * - 0 on success.
+ * - < 0 on failure.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ static bool version_done;
+
+ CONF_PAIR *cp;
+ CONF_ITEM *ci;
+
+ CONF_SECTION *options, *update;
+ rlm_ldap_t *inst = instance;
+
+ inst->cs = conf;
+
+ options = cf_section_sub_find(conf, "options");
+ if (!options || !cf_pair_find(options, "chase_referrals")) {
+ inst->chase_referrals_unset = true; /* use OpenLDAP defaults */
+ }
+
+ /*
+ * Only needs to be done once, prevents races in environment
+ * initialisation within libldap.
+ *
+ * See: https://github.com/arr2036/ldapperf/issues/2
+ */
+#ifdef HAVE_LDAP_INITIALIZE
+ ldap_initialize(&inst->handle, "");
+#else
+ inst->handle = ldap_init("", 0);
+#endif
+
+ /*
+ * Get version info from the LDAP API.
+ */
+ if (!version_done) {
+ static LDAPAPIInfo info = { .ldapai_info_version = LDAP_API_INFO_VERSION }; /* static to quiet valgrind about this being uninitialised */
+ int ldap_errno;
+
+ version_done = true;
+
+ ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info);
+ if (ldap_errno == LDAP_OPT_SUCCESS) {
+ int i;
+
+ /*
+ * Don't generate warnings if the compile type vendor name
+ * is found within the link time vendor name.
+ *
+ * This allows the server to be built against OpenLDAP but
+ * run with Symas OpenLDAP.
+ */
+ if (strcasestr(info.ldapai_vendor_name, LDAP_VENDOR_NAME) == NULL) {
+ WARN("rlm_ldap: libldap vendor changed since the server was built");
+ WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME);
+ }
+
+ if (info.ldapai_vendor_version < LDAP_VENDOR_VERSION) {
+ WARN("rlm_ldap: libldap older than the version the server was built against");
+ WARN("rlm_ldap: linked: %i, built: %i",
+ info.ldapai_vendor_version, LDAP_VENDOR_VERSION);
+ }
+
+ INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name,
+ info.ldapai_vendor_version);
+
+ if (info.ldapai_extensions != NULL ) {
+ for ( i = 0; info.ldapai_extensions[i] != NULL; i++) {
+ ldap_memfree(info.ldapai_extensions[i]);
+ }
+ ldap_memfree(info.ldapai_extensions);
+ }
+ ldap_memfree(info.ldapai_vendor_name);
+ } else {
+ DEBUG("rlm_ldap: Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO "
+ "returned: %i", ldap_errno);
+ INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME,
+ LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH);
+ }
+ }
+
+ /*
+ * If the configuration parameters can't be parsed, then fail.
+ */
+ if ((parse_sub_section(inst, conf, &inst->accounting, MOD_ACCOUNTING) < 0) ||
+ (parse_sub_section(inst, conf, &inst->postauth, MOD_POST_AUTH) < 0)) {
+ cf_log_err_cs(conf, "Failed parsing configuration");
+
+ goto error;
+ }
+
+ /*
+ * Sanity checks for cacheable groups code.
+ */
+ if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
+ if (!inst->groupobj_name_attr) {
+ cf_log_err_cs(conf, "Configuration item 'group.name_attribute' must be set if cacheable "
+ "group names are enabled");
+
+ goto error;
+ }
+ }
+
+ /*
+ * If we have a *pair* as opposed to a *section*
+ * then the module is referencing another ldap module's
+ * connection pool.
+ */
+ if (!cf_pair_find(conf, "pool")) {
+ if (!inst->config_server) {
+ cf_log_err_cs(conf, "Configuration item 'server' must have a value");
+ goto error;
+ }
+ }
+
+#ifndef WITH_SASL
+ if (inst->user_sasl.mech) {
+ cf_log_err_cs(conf, "Configuration item 'user.sasl.mech' not supported. "
+ "Linked libldap does not provide ldap_sasl_bind function");
+ goto error;
+ }
+
+ if (inst->admin_sasl.mech) {
+ cf_log_err_cs(conf, "Configuration item 'sasl.mech' not supported. "
+ "Linked libldap does not provide ldap_sasl_interactive_bind function");
+ goto error;
+ }
+#endif
+
+#ifndef HAVE_LDAP_CREATE_SORT_CONTROL
+ if (inst->userobj_sort_by) {
+ cf_log_err_cs(conf, "Configuration item 'sort_by' not supported. "
+ "Linked libldap does not provide ldap_create_sort_control function");
+ goto error;
+ }
+#endif
+
+ /*
+ * For backwards compatibility hack up the first 'server'
+ * CONF_ITEM into chunks, and add them back into the config.
+ *
+ * @fixme this should be removed at some point.
+ */
+ if (inst->config_server) {
+ char const *value;
+ char const *p;
+ char const *q;
+ char *buff;
+
+ bool done = false;
+ bool first = true;
+
+ cp = cf_pair_find(conf, "server");
+ if (!cp) {
+ cf_log_err_cs(conf, "Configuration item 'server' must have a value");
+ return -1;
+ }
+
+ value = cf_pair_value(cp);
+
+ p = value;
+ q = p;
+ while (!done) {
+ switch (*q) {
+ case '\0':
+ done = true;
+ if (p == value) break; /* string contained no separators */
+
+ /* FALL-THROUGH */
+
+ case ',':
+ case ';':
+ case ' ':
+ while (isspace((uint8_t) *p)) p++;
+ if (p == q) continue;
+
+ buff = talloc_array(inst, char, (q - p) + 1);
+ strlcpy(buff, p, talloc_array_length(buff));
+ p = ++q;
+
+ if (first) {
+ WARN("Listing multiple LDAP servers in the 'server' configuration item "
+ "is deprecated and will be removed in a future release. "
+ "Use multiple 'server' configuration items instead");
+ WARN("- server = '%s'", value);
+ }
+ WARN("+ server = '%s'", buff);
+
+ /*
+ * For the first instance of server we find, just replace
+ * the existing "server" config item.
+ */
+ if (first) {
+ cf_pair_replace(conf, cp, buff);
+ first = false;
+ continue;
+ }
+
+ /*
+ * For subsequent instances we need to add new conf pairs.
+ */
+ cp = cf_pair_alloc(conf, "server", buff, T_OP_EQ, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
+ if (!cp) return -1;
+
+ ci = cf_pair_to_item(cp);
+ cf_item_add(conf, ci);
+
+ break;
+
+ default:
+ q++;
+ continue;
+ }
+ }
+ }
+
+ /*
+ * Now iterate over all the 'server' config items
+ */
+ if (!inst->server) inst->server = talloc_strdup(inst, "");
+ for (cp = cf_pair_find(conf, "server");
+ cp;
+ cp = cf_pair_find_next(conf, cp, "server")) {
+ char const *value;
+
+ value = cf_pair_value(cp);
+
+#ifdef LDAP_CAN_PARSE_URLS
+ /*
+ * Split original server value out into URI, server and port
+ * so whatever initialization function we use later will have
+ * the server information in the format it needs.
+ */
+ if (ldap_is_ldap_url(value)) {
+ LDAPURLDesc *ldap_url;
+ bool set_port_maybe = true;
+ int default_port = LDAP_PORT;
+ char *p;
+
+ if (ldap_url_parse(value, &ldap_url)){
+ cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", value);
+ ldap_url_error:
+ ldap_free_urldesc(ldap_url);
+ return -1;
+ }
+
+ if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != '\0')) {
+ cf_log_err_cs(conf, "Base DN cannot be specified via server URL");
+ goto ldap_url_error;
+ }
+
+ if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
+ cf_log_err_cs(conf, "Attribute list cannot be specified via server URL");
+ goto ldap_url_error;
+ }
+
+ /*
+ * ldap_url_parse sets this to base by default.
+ */
+ if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
+ cf_log_err_cs(conf, "Scope cannot be specified via server URL");
+ goto ldap_url_error;
+ }
+ ldap_url->lud_scope = -1; /* Otherwise LDAP adds ?base */
+
+ /*
+ * The public ldap_url_parse function sets the default
+ * port, so we have to discover whether a port was
+ * included ourselves.
+ */
+ if ((p = strchr(value, ']')) && (p[1] == ':')) { /* IPv6 */
+ set_port_maybe = false;
+ } else if ((p = strchr(value, ':')) && (strchr(p + 1, ':') != NULL)) { /* IPv4 */
+ set_port_maybe = false;
+ }
+
+ /* We allow extensions */
+
+# ifdef HAVE_LDAP_INITIALIZE
+ {
+ char *url;
+
+ /*
+ * Figure out the default port from the URL
+ */
+ if (ldap_url->lud_scheme) {
+ if (strcmp(ldap_url->lud_scheme, "ldaps") == 0) {
+ if (inst->start_tls == true) {
+ cf_log_err_cs(conf, "ldaps:// scheme is not compatible "
+ "with 'start_tls'");
+ goto ldap_url_error;
+ }
+ default_port = LDAPS_PORT;
+
+ } else if (strcmp(ldap_url->lud_scheme, "ldapi") == 0) {
+ set_port_maybe = false; /* Unix socket, no port */
+ }
+ }
+
+ if (set_port_maybe) {
+ /*
+ * URL port overrides configured port.
+ */
+ ldap_url->lud_port = inst->port;
+
+ /*
+ * If there's no URL port, then set it to the default
+ * this is so debugging messages show explicitly
+ * the port we're connecting to.
+ */
+ if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
+ }
+
+ url = ldap_url_desc2str(ldap_url);
+ if (!url) {
+ cf_log_err_cs(conf, "Failed recombining URL components");
+ goto ldap_url_error;
+ }
+ inst->server = talloc_asprintf_append(inst->server, "%s ", url);
+ free(url);
+ }
+# else
+ /*
+ * No LDAP initialize function. Can't specify a scheme.
+ */
+ if (ldap_url->lud_scheme &&
+ ((strcmp(ldap_url->lud_scheme, "ldaps") == 0) ||
+ (strcmp(ldap_url->lud_scheme, "ldapi") == 0) ||
+ (strcmp(ldap_url->lud_scheme, "cldap") == 0))) {
+ cf_log_err_cs(conf, "%s is not supported by linked libldap",
+ ldap_url->lud_scheme);
+ return -1;
+ }
+
+ /*
+ * URL port over-rides the configured
+ * port. But if there's no configured
+ * port, we use the hard-coded default.
+ */
+ if (set_port_maybe) {
+ ldap_url->lud_port = inst->port;
+ if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
+ }
+
+ inst->server = talloc_asprintf_append(inst->server, "%s:%i ",
+ ldap_url->lud_host ? ldap_url->lud_host : "localhost",
+ ldap_url->lud_port);
+# endif
+ /*
+ * @todo We could set a few other top level
+ * directives using the URL, like base_dn
+ * and scope.
+ */
+ ldap_free_urldesc(ldap_url);
+ /*
+ * We need to construct an LDAP URI
+ */
+ } else
+#endif /* HAVE_LDAP_URL_PARSE && HAVE_LDAP_IS_LDAP_URL && LDAP_URL_DESC2STR */
+ /*
+ * If it's not an URL, or we don't have the functions necessary
+ * to break apart the URL and recombine it, then just treat
+ * server as a hostname.
+ */
+ {
+#ifdef HAVE_LDAP_INITIALIZE
+ char const *p;
+ char *q;
+ int port = 0;
+ size_t len;
+
+ port = inst->port;
+
+ /*
+ * We don't support URLs if the library didn't provide
+ * URL parsing functions.
+ */
+ if (strchr(value, '/')) {
+ bad_server_fmt:
+#ifdef LDAP_CAN_PARSE_URLS
+ cf_log_err_cp(cp, "Invalid server value, must be in format <server>[:<port>] or "
+ "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
+#else
+ cf_log_err_cp(cp, "Invalid server value, must be in format <server>[:<port>]");
+#endif
+ return -1;
+ }
+
+ p = strrchr(value, ':');
+ if (p) {
+ port = (int)strtol((p + 1), &q, 10);
+ if ((p == value) || ((p + 1) == q) || (*q != '\0')) goto bad_server_fmt;
+ len = p - value;
+ } else {
+ len = strlen(value);
+ }
+ if (port == 0) port = LDAP_PORT;
+
+ inst->server = talloc_asprintf_append(inst->server, "ldap://%.*s:%i ", (int) len, value, port);
+#else
+ /*
+ * ldap_init takes port, which can be overridden by :port so
+ * we don't need to do any parsing here.
+ */
+ inst->server = talloc_asprintf_append(inst->server, "%s ", value);
+#endif
+ }
+ }
+ if (inst->server) inst->server[talloc_array_length(inst->server) - 2] = '\0';
+
+ DEBUG4("LDAP server string: %s", inst->server);
+
+#ifdef LDAP_OPT_X_TLS_NEVER
+ /*
+ * Workaround for servers which support LDAPS but not START TLS
+ */
+ if (inst->port == LDAPS_PORT || inst->tls_mode) {
+ inst->tls_mode = LDAP_OPT_X_TLS_HARD;
+ } else {
+ inst->tls_mode = 0;
+ }
+#endif
+
+ /*
+ * Convert dereference strings to enumerated constants
+ */
+ if (inst->dereference_str) {
+ inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1);
+ if (inst->dereference < 0) {
+ cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', "
+ "'finding' or 'always'", inst->dereference_str);
+ goto error;
+ }
+ }
+
+#if LDAP_SET_REBIND_PROC_ARGS != 3
+ /*
+ * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance
+ * variable for the username, password, etc.
+ */
+ if (inst->rebind == true) {
+ cf_log_err_cs(conf, "Cannot use 'rebind' configuration item as this version of libldap "
+ "does not support the API that we need");
+
+ goto error;
+ }
+#endif
+
+ /*
+ * Convert scope strings to enumerated constants
+ */
+ inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1);
+ if (inst->userobj_scope < 0) {
+ cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'"
+#ifdef LDAP_SCOPE_CHILDREN
+ ", 'base' or 'children'"
+#else
+ " or 'base'"
+#endif
+ , inst->userobj_scope_str);
+ goto error;
+ }
+
+ inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1);
+ if (inst->groupobj_scope < 0) {
+ cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'"
+#ifdef LDAP_SCOPE_CHILDREN
+ ", 'base' or 'children'"
+#else
+ " or 'base'"
+#endif
+ , inst->groupobj_scope_str);
+ goto error;
+ }
+
+ inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1);
+ if (inst->clientobj_scope < 0) {
+ cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'"
+#ifdef LDAP_SCOPE_CHILDREN
+ ", 'base' or 'children'"
+#else
+ " or 'base'"
+#endif
+ , inst->clientobj_scope_str);
+ goto error;
+ }
+
+#ifdef HAVE_LDAP_CREATE_SORT_CONTROL
+ /*
+ * Build the server side sort control for user objects
+ */
+ if (inst->userobj_sort_by) {
+ LDAPSortKey **keys;
+ int ret;
+ char *p;
+
+ memcpy(&p, &inst->userobj_sort_by, sizeof(p));
+
+ ret = ldap_create_sort_keylist(&keys, p);
+ if (ret != LDAP_SUCCESS) {
+ cf_log_err_cs(conf, "Invalid user.sort_by value \"%s\": %s",
+ inst->userobj_sort_by, ldap_err2string(ret));
+ goto error;
+ }
+
+ /*
+ * Always set the control as critical, if it's not needed
+ * the user can comment it out...
+ */
+ ret = ldap_create_sort_control(inst->handle, keys, 1, &inst->userobj_sort_ctrl);
+ ldap_free_sort_keylist(keys);
+ if (ret != LDAP_SUCCESS) {
+ LDAP_ERR("Failed creating server sort control: %s", ldap_err2string(ret));
+ goto error;
+ }
+ }
+#endif
+
+ if (inst->tls_require_cert_str) {
+#ifdef LDAP_OPT_X_TLS_NEVER
+ /*
+ * Convert cert strictness to enumerated constants
+ */
+ inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1);
+ if (inst->tls_require_cert < 0) {
+ cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', "
+ "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str);
+ goto error;
+ }
+#else
+ cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current "
+ "version of libldap. Please upgrade or substitute current libldap and "
+ "rebuild this module");
+
+ goto error;
+#endif
+ }
+
+ if (inst->tls_min_version_str) {
+#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
+ if (strcmp(inst->tls_min_version_str, "1.2") == 0) {
+ inst->tls_min_version = LDAP_OPT_X_TLS_PROTOCOL_TLS1_2;
+
+ } else if (strcmp(inst->tls_min_version_str, "1.1") == 0) {
+ inst->tls_min_version = LDAP_OPT_X_TLS_PROTOCOL_TLS1_1;
+
+ } else if (strcmp(inst->tls_min_version_str, "1.0") == 0) {
+ inst->tls_min_version = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0;
+
+ } else {
+ cf_log_err_cs(conf, "Invalid 'tls.tls_min_version' value \"%s\"", inst->tls_min_version_str);
+ goto error;
+ }
+#else
+ cf_log_err_cs(conf, "This version of libldap does not support tls.tls_min_version."
+ " Please upgrade or substitute current libldap and "
+ "rebuild this module");
+ goto error;
+
+#endif
+ }
+
+ /*
+ * Build the attribute map
+ */
+ update = cf_section_sub_find(inst->cs, "update");
+ if (update && (map_afrom_cs(&inst->user_map, update,
+ PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst,
+ LDAP_MAX_ATTRMAP) < 0)) {
+ return -1;
+ }
+
+ /*
+ * Set global options
+ */
+ if (rlm_ldap_global_init(inst) < 0) goto error;
+
+ /*
+ * Initialize the socket pool.
+ */
+ inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
+ if (!inst->pool) goto error;
+
+ /*
+ * Bulk load dynamic clients.
+ */
+ if (inst->do_clients) {
+ CONF_SECTION *cs, *map, *tmpl;
+
+ cs = cf_section_sub_find(inst->cs, "client");
+ if (!cs) {
+ cf_log_err_cs(conf, "Told to load clients but no client section found");
+ goto error;
+ }
+
+ map = cf_section_sub_find(cs, "attribute");
+ if (!map) {
+ cf_log_err_cs(cs, "Told to load clients but no attribute section found");
+ goto error;
+ }
+
+ tmpl = cf_section_sub_find(cs, "template");
+
+ if (rlm_ldap_client_load(inst, tmpl, map) < 0) {
+ cf_log_err_cs(cs, "Error loading clients");
+
+ return -1;
+ }
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode;
+ ldap_rcode_t status;
+ char const *dn;
+ rlm_ldap_t *inst = instance;
+ ldap_handle_t *conn;
+
+ char sasl_mech_buff[LDAP_MAX_DN_STR_LEN];
+ char sasl_proxy_buff[LDAP_MAX_DN_STR_LEN];
+ char sasl_realm_buff[LDAP_MAX_DN_STR_LEN];
+ ldap_sasl sasl;
+
+ /*
+ * Ensure that we're being passed a plain-text password, and not
+ * anything else.
+ */
+
+ if (!request->username) {
+ REDEBUG("Attribute \"User-Name\" is required for authentication");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ if (!request->password ||
+ (request->password->da->attr != PW_USER_PASSWORD)) {
+ RWDEBUG("You have set \"Auth-Type := LDAP\" somewhere");
+ RWDEBUG("*********************************************");
+ RWDEBUG("* THAT CONFIGURATION IS WRONG. DELETE IT. ");
+ RWDEBUG("* YOU ARE PREVENTING THE SERVER FROM WORKING");
+ RWDEBUG("*********************************************");
+
+ REDEBUG("Attribute \"User-Password\" is required for authentication");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ if (request->password->vp_length == 0) {
+ REDEBUG("Empty password supplied");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ conn = mod_conn_get(inst, request);
+ if (!conn) return RLM_MODULE_FAIL;
+
+ /*
+ * Expand dynamic SASL fields
+ */
+ if (conn->inst->user_sasl.mech) {
+ memset(&sasl, 0, sizeof(sasl));
+
+ if (tmpl_expand(&sasl.mech, sasl_mech_buff, sizeof(sasl_mech_buff), request,
+ conn->inst->user_sasl.mech, rlm_ldap_escape_func, inst) < 0) {
+ REDEBUG("Failed expanding user.sasl.mech: %s", fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ if (conn->inst->user_sasl.proxy) {
+ if (tmpl_expand(&sasl.proxy, sasl_proxy_buff, sizeof(sasl_proxy_buff), request,
+ conn->inst->user_sasl.proxy, rlm_ldap_escape_func, inst) < 0) {
+ REDEBUG("Failed expanding user.sasl.proxy: %s", fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+
+ if (conn->inst->user_sasl.realm) {
+ if (tmpl_expand(&sasl.realm, sasl_realm_buff, sizeof(sasl_realm_buff), request,
+ conn->inst->user_sasl.realm, rlm_ldap_escape_func, inst) < 0) {
+ REDEBUG("Failed expanding user.sasl.realm: %s", fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+ }
+
+ RDEBUG("Login attempt by \"%s\"", request->username->vp_strvalue);
+
+ /*
+ * Get the DN by doing a search.
+ */
+ dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
+ if (!dn) {
+ mod_conn_release(inst, conn);
+
+ return rcode;
+ }
+ conn->rebound = true;
+ status = rlm_ldap_bind(inst, request, &conn, dn, request->password->vp_strvalue,
+ conn->inst->user_sasl.mech ? &sasl : NULL, true);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ rcode = RLM_MODULE_OK;
+ RDEBUG("Bind as user \"%s\" was successful", dn);
+ break;
+
+ case LDAP_PROC_NOT_PERMITTED:
+ rcode = RLM_MODULE_USERLOCK;
+ break;
+
+ case LDAP_PROC_REJECT:
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case LDAP_PROC_BAD_DN:
+ rcode = RLM_MODULE_INVALID;
+ break;
+
+ case LDAP_PROC_NO_RESULT:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ break;
+ };
+
+finish:
+ mod_conn_release(inst, conn);
+
+ return rcode;
+}
+
+/** Search for and apply an LDAP profile
+ *
+ * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common sets of attributes
+ * to the request.
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request.
+ * @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] dn of profile object to apply.
+ * @param[in] expanded Structure containing a list of xlat expanded attribute names and mapping information.
+ * @return One of the RLM_MODULE_* values.
+ */
+static rlm_rcode_t rlm_ldap_map_profile(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn,
+ char const *dn, rlm_ldap_map_exp_t const *expanded)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+ LDAPMessage *result = NULL, *entry = NULL;
+ int ldap_errno;
+ LDAP *handle = (*pconn)->handle;
+ char const *filter;
+ char filter_buff[LDAP_MAX_FILTER_STR_LEN];
+
+ rad_assert(inst->profile_filter); /* We always have a default filter set */
+
+ if (!dn || !*dn) return RLM_MODULE_OK;
+
+ if (tmpl_expand(&filter, filter_buff, sizeof(filter_buff), request,
+ inst->profile_filter, rlm_ldap_escape_func, NULL) < 0) {
+ REDEBUG("Failed creating profile filter");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ status = rlm_ldap_search(&result, inst, request, pconn, dn,
+ LDAP_SCOPE_BASE, filter, expanded->attrs, NULL, NULL);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_BAD_DN:
+ case LDAP_PROC_NO_RESULT:
+ RDEBUG("Profile object \"%s\" not found", dn);
+ return RLM_MODULE_NOTFOUND;
+
+ default:
+ return RLM_MODULE_FAIL;
+ }
+
+ rad_assert(*pconn);
+ rad_assert(result);
+
+ entry = ldap_first_entry(handle, result);
+ if (!entry) {
+ ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ rcode = RLM_MODULE_NOTFOUND;
+
+ goto free_result;
+ }
+
+ RDEBUG("Processing profile attributes");
+ if (rlm_ldap_map_do(inst, request, handle, expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
+
+free_result:
+ ldap_msgfree(result);
+
+ return rcode;
+}
+
+static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+ int ldap_errno;
+ int i;
+ rlm_ldap_t *inst = instance;
+ struct berval **values;
+ VALUE_PAIR *vp;
+ ldap_handle_t *conn;
+ LDAPMessage *result, *entry;
+ char const *dn = NULL;
+ rlm_ldap_map_exp_t expanded; /* faster than mallocing every time */
+
+ /*
+ * Don't be tempted to add a check for request->username
+ * or request->password here. rlm_ldap.authorize can be used for
+ * many things besides searching for users.
+ */
+
+ if (rlm_ldap_map_expand(&expanded, request, inst->user_map) < 0) return RLM_MODULE_FAIL;
+
+ conn = mod_conn_get(inst, request);
+ if (!conn) return RLM_MODULE_FAIL;
+
+ /*
+ * Add any additional attributes we need for checking access, memberships, and profiles
+ */
+ if (inst->userobj_access_attr) {
+ expanded.attrs[expanded.count++] = inst->userobj_access_attr;
+ }
+
+ if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
+ expanded.attrs[expanded.count++] = inst->userobj_membership_attr;
+ }
+
+ if (inst->profile_attr) {
+ expanded.attrs[expanded.count++] = inst->profile_attr;
+ }
+
+ if (inst->valuepair_attr) {
+ expanded.attrs[expanded.count++] = inst->valuepair_attr;
+ }
+
+ expanded.attrs[expanded.count] = NULL;
+
+ dn = rlm_ldap_find_user(inst, request, &conn, expanded.attrs, true, &result, &rcode);
+ if (!dn) {
+ goto finish;
+ }
+
+ entry = ldap_first_entry(conn->handle, result);
+ if (!entry) {
+ ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
+ REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
+
+ goto finish;
+ }
+
+ /*
+ * Check for access.
+ */
+ if (inst->userobj_access_attr) {
+ rcode = rlm_ldap_check_access(inst, request, conn, entry);
+ if (rcode != RLM_MODULE_OK) {
+ goto finish;
+ }
+ }
+
+ /*
+ * Check if we need to cache group memberships
+ */
+ if (inst->cacheable_group_dn || inst->cacheable_group_name) {
+ if (inst->userobj_membership_attr) {
+ rcode = rlm_ldap_cacheable_userobj(inst, request, &conn, entry, inst->userobj_membership_attr);
+ if (rcode != RLM_MODULE_OK) {
+ goto finish;
+ }
+ }
+
+ rcode = rlm_ldap_cacheable_groupobj(inst, request, &conn);
+ if (rcode != RLM_MODULE_OK) {
+ goto finish;
+ }
+ }
+
+#ifdef WITH_EDIR
+ /*
+ * We already have a Cleartext-Password. Skip edir.
+ */
+ if (fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
+ goto skip_edir;
+ }
+
+ /*
+ * Retrieve Universal Password if we use eDirectory
+ */
+ if (inst->edir) {
+ int res = 0;
+ char password[256];
+ size_t pass_size = sizeof(password);
+
+ /*
+ * Retrive universal password
+ */
+ res = nmasldap_get_password(conn->handle, dn, password, &pass_size);
+ if (res != 0) {
+ REDEBUG("Failed to retrieve eDirectory password: (%i) %s", res, edir_errstr(res));
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ /*
+ * Add Cleartext-Password attribute to the request
+ */
+ vp = radius_pair_create(request, &request->config, PW_CLEARTEXT_PASSWORD, 0);
+ fr_pair_value_strcpy(vp, password);
+ vp->vp_length = pass_size;
+
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Added eDirectory password. control:%s += '%s'", vp->da->name, vp->vp_strvalue);
+ } else {
+ RDEBUG2("Added eDirectory password");
+ }
+
+ if (inst->edir_autz) {
+ RDEBUG2("Binding as user for eDirectory authorization checks");
+ /*
+ * Bind as the user
+ */
+ conn->rebound = true;
+ status = rlm_ldap_bind(inst, request, &conn, dn, vp->vp_strvalue, NULL, true);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ rcode = RLM_MODULE_OK;
+ RDEBUG("Bind as user '%s' was successful", dn);
+ break;
+
+ case LDAP_PROC_NOT_PERMITTED:
+ rcode = RLM_MODULE_USERLOCK;
+ goto finish;
+
+ case LDAP_PROC_REJECT:
+ rcode = RLM_MODULE_REJECT;
+ goto finish;
+
+ case LDAP_PROC_BAD_DN:
+ rcode = RLM_MODULE_INVALID;
+ goto finish;
+
+ case LDAP_PROC_NO_RESULT:
+ rcode = RLM_MODULE_NOTFOUND;
+ goto finish;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ };
+ }
+ }
+
+skip_edir:
+#endif
+
+ /*
+ * Apply ONE user profile, or a default user profile.
+ */
+ if (inst->default_profile) {
+ char const *profile;
+ char profile_buff[1024];
+
+ if (tmpl_expand(&profile, profile_buff, sizeof(profile_buff),
+ request, inst->default_profile, NULL, NULL) < 0) {
+ REDEBUG("Failed creating default profile string");
+
+ rcode = RLM_MODULE_INVALID;
+ goto finish;
+ }
+
+ switch (rlm_ldap_map_profile(inst, request, &conn, profile, &expanded)) {
+ case RLM_MODULE_INVALID:
+ rcode = RLM_MODULE_INVALID;
+ goto finish;
+
+ case RLM_MODULE_FAIL:
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+
+ case RLM_MODULE_UPDATED:
+ rcode = RLM_MODULE_UPDATED;
+ /* FALL-THROUGH */
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Apply a SET of user profiles.
+ */
+ if (inst->profile_attr) {
+ values = ldap_get_values_len(conn->handle, entry, inst->profile_attr);
+ if (values != NULL) {
+ for (i = 0; values[i] != NULL; i++) {
+ rlm_rcode_t ret;
+ char *value;
+
+ value = rlm_ldap_berval_to_string(request, values[i]);
+ ret = rlm_ldap_map_profile(inst, request, &conn, value, &expanded);
+ talloc_free(value);
+ if (ret == RLM_MODULE_FAIL) {
+ ldap_value_free_len(values);
+ rcode = ret;
+ goto finish;
+ }
+
+ }
+ ldap_value_free_len(values);
+ }
+ }
+
+ if (inst->user_map || inst->valuepair_attr) {
+ RDEBUG("Processing user attributes");
+ if (rlm_ldap_map_do(inst, request, conn->handle, &expanded, entry) > 0) rcode = RLM_MODULE_UPDATED;
+ rlm_ldap_check_reply(inst, request);
+ }
+
+finish:
+ talloc_free(expanded.ctx);
+ if (result) ldap_msgfree(result);
+ mod_conn_release(inst, conn);
+
+ return rcode;
+}
+
+/** Modify user's object in LDAP
+ *
+ * Process a modifcation map to update a user object in the LDAP directory.
+ *
+ * @param inst rlm_ldap instance.
+ * @param request Current request.
+ * @param section that holds the map to process.
+ * @return one of the RLM_MODULE_* values.
+ */
+static rlm_rcode_t user_modify(rlm_ldap_t *inst, REQUEST *request, ldap_acct_section_t *section)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ldap_rcode_t status;
+
+ ldap_handle_t *conn = NULL;
+
+ LDAPMod *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP];
+ LDAPMod **modify = mod_p;
+
+ char *passed[LDAP_MAX_ATTRMAP * 2];
+ int i, total = 0, last_pass = 0;
+
+ char *expanded[LDAP_MAX_ATTRMAP];
+ int last_exp = 0;
+
+ char const *attr;
+ char const *value;
+
+ char const *dn;
+ /*
+ * Build our set of modifications using the update sections in
+ * the config.
+ */
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+ CONF_SECTION *cs;
+ FR_TOKEN op;
+ char path[MAX_STRING_LEN];
+
+ char *p = path;
+
+ rad_assert(section);
+
+ /*
+ * Locate the update section were going to be using
+ */
+ if (section->reference[0] != '.') {
+ *p++ = '.';
+ }
+
+ if (radius_xlat(p, (sizeof(path) - (p - path)) - 1, request, section->reference, NULL, NULL) < 0) {
+ goto error;
+ }
+
+ ci = cf_reference_item(NULL, section->cs, path);
+ if (!ci) {
+ goto error;
+ }
+
+ if (!cf_item_is_section(ci)){
+ REDEBUG("Reference must resolve to a section");
+
+ goto error;
+ }
+
+ cs = cf_section_sub_find(cf_item_to_section(ci), "update");
+ if (!cs) {
+ REDEBUG("Section must contain 'update' subsection");
+
+ goto error;
+ }
+
+ /*
+ * Iterate over all the pairs, building our mods array
+ */
+ for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) {
+ bool do_xlat = false;
+
+ if (total == LDAP_MAX_ATTRMAP) {
+ REDEBUG("Modify map size exceeded");
+
+ goto error;
+ }
+
+ if (!cf_item_is_pair(ci)) {
+ REDEBUG("Entry is not in \"ldap-attribute = value\" format");
+
+ goto error;
+ }
+
+ /*
+ * Retrieve all the information we need about the pair
+ */
+ cp = cf_item_to_pair(ci);
+ value = cf_pair_value(cp);
+ attr = cf_pair_attr(cp);
+ op = cf_pair_operator(cp);
+
+ if (!value || (*value == '\0')) {
+ RDEBUG("Empty value string, skipping attribute \"%s\"", attr);
+
+ continue;
+ }
+
+ switch (cf_pair_value_type(cp)) {
+ case T_BARE_WORD:
+ case T_SINGLE_QUOTED_STRING:
+ break;
+
+ case T_BACK_QUOTED_STRING:
+ case T_DOUBLE_QUOTED_STRING:
+ do_xlat = true;
+ break;
+
+ default:
+ rad_assert(0);
+ goto error;
+ }
+
+ if (op == T_OP_CMP_FALSE) {
+ passed[last_pass] = NULL;
+ } else if (do_xlat) {
+ char *exp = NULL;
+
+ if (radius_axlat(&exp, request, value, NULL, NULL) <= 0) {
+ RDEBUG("Skipping attribute \"%s\"", attr);
+
+ talloc_free(exp);
+
+ continue;
+ }
+
+ expanded[last_exp++] = exp;
+ passed[last_pass] = exp;
+ /*
+ * Static strings
+ */
+ } else {
+ memcpy(&(passed[last_pass]), &value, sizeof(passed[last_pass]));
+ }
+
+ passed[last_pass + 1] = NULL;
+
+ mod_s[total].mod_values = &(passed[last_pass]);
+
+ last_pass += 2;
+
+ switch (op) {
+ /*
+ * T_OP_EQ is *NOT* supported, it is impossible to
+ * support because of the lack of transactions in LDAP
+ */
+ case T_OP_ADD:
+ mod_s[total].mod_op = LDAP_MOD_ADD;
+ break;
+
+ case T_OP_SET:
+ mod_s[total].mod_op = LDAP_MOD_REPLACE;
+ break;
+
+ case T_OP_SUB:
+ case T_OP_CMP_FALSE:
+ mod_s[total].mod_op = LDAP_MOD_DELETE;
+ break;
+
+#ifdef LDAP_MOD_INCREMENT
+ case T_OP_INCRM:
+ mod_s[total].mod_op = LDAP_MOD_INCREMENT;
+ break;
+#endif
+ default:
+ REDEBUG("Operator '%s' is not supported for LDAP modify operations",
+ fr_int2str(fr_tokens, op, "<INVALID>"));
+
+ goto error;
+ }
+
+ /*
+ * Now we know the value is ok, copy the pointers into
+ * the ldapmod struct.
+ */
+ memcpy(&(mod_s[total].mod_type), &attr, sizeof(mod_s[total].mod_type));
+
+ mod_p[total] = &(mod_s[total]);
+ total++;
+ }
+
+ if (total == 0) {
+ rcode = RLM_MODULE_NOOP;
+ goto release;
+ }
+
+ mod_p[total] = NULL;
+
+ conn = mod_conn_get(inst, request);
+ if (!conn) return RLM_MODULE_FAIL;
+
+
+ dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode);
+ if (!dn || (rcode != RLM_MODULE_OK)) {
+ goto error;
+ }
+
+ status = rlm_ldap_modify(inst, request, &conn, dn, modify);
+ switch (status) {
+ case LDAP_PROC_SUCCESS:
+ break;
+
+ case LDAP_PROC_REJECT:
+ case LDAP_PROC_BAD_DN:
+ rcode = RLM_MODULE_INVALID;
+ break;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ break;
+ };
+
+ release:
+ error:
+ /*
+ * Free up any buffers we allocated for xlat expansion
+ */
+ for (i = 0; i < last_exp; i++) {
+ talloc_free(expanded[i]);
+ }
+
+ mod_conn_release(inst, conn);
+
+ return rcode;
+}
+
+static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_ldap_t *inst = instance;
+
+ if (inst->accounting) return user_modify(inst, request, inst->accounting);
+
+ return RLM_MODULE_NOOP;
+}
+
+static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_ldap_t *inst = instance;
+
+ if (inst->postauth) {
+ return user_modify(inst, request, inst->postauth);
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+
+/* globally exported name */
+extern module_t rlm_ldap;
+module_t rlm_ldap = {
+ .magic = RLM_MODULE_INIT,
+ .name = "ldap",
+ .inst_size = sizeof(rlm_ldap_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_ldap/sasl.c b/src/modules/rlm_ldap/sasl.c
new file mode 100644
index 0000000..17a6356
--- /dev/null
+++ b/src/modules/rlm_ldap/sasl.c
@@ -0,0 +1,194 @@
+/*
+ * 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
+ */
+
+#include "ldap.h"
+
+/**
+ * $Id$
+ * @file sasl.c
+ * @brief Functions to perform SASL binds against an LDAP directory.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2015 The FreeRADIUS Server Project.
+ */
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sasl/sasl.h>
+
+/** Data passed to the _sasl interact callback.
+ *
+ */
+typedef struct rlm_ldap_sasl_ctx {
+ rlm_ldap_t const *inst; //!< LDAP instance
+ REQUEST *request; //!< The current request.
+
+ char const *identity; //!< User's DN or identity.
+ char const *password; //!< Bind password.
+
+ ldap_sasl *extra; //!< Extra fields (realm and proxy id).
+} rlm_ldap_sasl_ctx_t;
+
+/** Callback for ldap_sasl_interactive_bind
+ *
+ * @param handle used for the SASL bind.
+ * @param flags data as provided to ldap_sasl_interactive_bind.
+ * @param ctx Our context data, containing the identity, password, realm and various other things.
+ * @param sasl_callbacks Array of challenges to provide responses for.
+ * @return SASL_OK.
+ */
+static int _sasl_interact(UNUSED LDAP *handle, UNUSED unsigned flags, void *ctx, void *sasl_callbacks)
+{
+ rlm_ldap_sasl_ctx_t *this = ctx;
+ REQUEST *request = this->request;
+ rlm_ldap_t const *inst = this->inst;
+ sasl_interact_t *cb = sasl_callbacks;
+ sasl_interact_t *cb_p;
+
+ for (cb_p = cb; cb_p->id != SASL_CB_LIST_END; cb_p++) {
+ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "SASL challenge : %s", cb_p->challenge);
+ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "SASL prompt : %s", cb_p->prompt);
+
+ switch (cb_p->id) {
+ case SASL_CB_AUTHNAME:
+ cb_p->result = this->identity;
+ cb_p->len = strlen(this->identity);
+ break;
+
+ case SASL_CB_PASS:
+ cb_p->result = this->password;
+ cb_p->len = strlen(this->password);
+ break;
+
+ case SASL_CB_USER:
+ cb_p->result = this->extra->proxy ? this->extra->proxy : this->identity;
+ cb_p->len = this->extra->proxy ? strlen(this->extra->proxy) : strlen(this->identity);
+ break;
+
+ case SASL_CB_GETREALM:
+ if (this->extra->realm) {
+ cb_p->result = this->extra->realm;
+ cb_p->len = strlen(this->extra->realm);
+ }
+ break;
+
+ default:
+ break;
+ }
+ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "SASL result : %s", cb_p->result ? (char const *)cb_p->result : "");
+ }
+ return SASL_OK;
+}
+
+/** Initiate an LDAP interactive bind
+ *
+ * @param[in] inst rlm_ldap configuration.
+ * @param[in] request Current request, this may be NULL, in which case all debug logging is done with radlog.
+ * @param[in] conn to use. May change as this function calls functions which auto re-connect.
+ * @param[in] identity of the user.
+ * @param[in] password of the user.
+ * @param[in] sasl mechanism to use for bind, and additional parameters.
+ * @param[out] error message resulting from bind.
+ * @param[out] extra information about the error.
+ * @return One of the LDAP_PROC_* (#ldap_rcode_t) values.
+ */
+ldap_rcode_t rlm_ldap_sasl_interactive(rlm_ldap_t const *inst, REQUEST *request,
+ ldap_handle_t *conn, char const *identity,
+ char const *password, ldap_sasl *sasl,
+ char const **error, char **extra)
+{
+ ldap_rcode_t status;
+ int ret = 0;
+ int msgid;
+ char const *mech;
+ LDAPMessage *result = NULL;
+ rlm_ldap_sasl_ctx_t sasl_ctx; /* SASL defaults */
+
+ /* rlm_ldap_result may not be called */
+ if (error) *error = NULL;
+ if (extra) *extra = NULL;
+
+ sasl_ctx.inst = inst;
+ sasl_ctx.request = request;
+ sasl_ctx.identity = identity;
+ sasl_ctx.password = password;
+ sasl_ctx.extra = sasl;
+
+ MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Starting SASL mech(s): %s", sasl->mech);
+ for (;;) {
+ ret = ldap_sasl_interactive_bind(conn->handle, NULL, sasl->mech,
+ NULL, NULL, LDAP_SASL_AUTOMATIC,
+ _sasl_interact, &sasl_ctx, result,
+ &mech, &msgid);
+
+ /*
+ * If ldap_sasl_interactive_bind indicates it didn't want
+ * to continue, then we're done.
+ *
+ * Calling ldap_result here, results in a timeout in some
+ * cases, so we need to figure out whether the bind was
+ * successful without the help of ldap_result.
+ */
+ if (ret != LDAP_SASL_BIND_IN_PROGRESS) {
+ status = rlm_ldap_result(inst, conn, -1, identity, NULL, error, extra);
+ break; /* Old result gets freed on after exit */
+ }
+
+ ldap_msgfree(result); /* We always need to free the old message */
+
+ /*
+ * If LDAP parse result indicates there was an error
+ * then we're done.
+ */
+ status = rlm_ldap_result(inst, conn, msgid, identity, &result, error, extra);
+ switch (status) {
+ case LDAP_PROC_SUCCESS: /* ldap_sasl_interactive_bind should have indicated success */
+ case LDAP_PROC_CONTINUE:
+ break;
+
+ default:
+ goto done;
+ }
+
+ /*
+ * ...otherwise, the bind is still in progress.
+ */
+ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "Continuing SASL mech %s...", mech);
+
+ /*
+ * Write the servers response to the debug log
+ */
+ if (((request && RDEBUG_ENABLED3) || DEBUG_ENABLED3) && result) {
+ struct berval *srv_cred;
+
+ if ((ldap_parse_sasl_bind_result(conn->handle, result, &srv_cred, 0) == LDAP_SUCCESS) &&
+ (srv_cred != NULL)) {
+ char *escaped;
+
+ escaped = fr_aprints(request, srv_cred->bv_val, srv_cred->bv_len, '\0');
+ MOD_ROPTIONAL(RDEBUG3, DEBUG3, "SASL response : %s", escaped);
+
+ talloc_free(escaped);
+ ber_bvfree(srv_cred);
+ }
+ }
+ }
+done:
+ ldap_msgfree(result);
+
+ return status;
+}
diff --git a/src/modules/rlm_linelog/README.md b/src/modules/rlm_linelog/README.md
new file mode 100644
index 0000000..b9604a4
--- /dev/null
+++ b/src/modules/rlm_linelog/README.md
@@ -0,0 +1,11 @@
+# rlm_linelog
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Creates log entries from attributes, string expansions, or static
+strings, and writes them to a variety of backends, including
+syslog, flat files, and raw UDP/TCP sockets.
diff --git a/src/modules/rlm_linelog/all.mk b/src/modules/rlm_linelog/all.mk
new file mode 100644
index 0000000..8564c9c
--- /dev/null
+++ b/src/modules/rlm_linelog/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_linelog.a
+SOURCES := rlm_linelog.c
diff --git a/src/modules/rlm_linelog/rlm_linelog.c b/src/modules/rlm_linelog/rlm_linelog.c
new file mode 100644
index 0000000..8f381fc
--- /dev/null
+++ b/src/modules/rlm_linelog/rlm_linelog.c
@@ -0,0 +1,328 @@
+/*
+ * rlm_linelog.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2004,2006 The FreeRADIUS server project
+ * Copyright 2004 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/exfile.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+
+#ifndef LOG_INFO
+#define LOG_INFO (0)
+#endif
+#endif
+
+/*
+ * Define a structure for our module configuration.
+ */
+typedef struct rlm_linelog_t {
+ CONF_SECTION *cs;
+ char const *filename;
+
+ bool escape; //!< do filename escaping, yes / no
+
+ xlat_escape_t escape_func; //!< escape function
+
+ char const *syslog_facility; //!< Syslog facility string.
+ char const *syslog_severity; //!< Syslog severity string.
+ int syslog_priority; //!< Bitwise | of severity and facility.
+
+ uint32_t permissions;
+ char const *group;
+ char const *line;
+ char const *reference;
+ char const *header;
+ exfile_t *ef;
+} rlm_linelog_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_linelog_t, filename), NULL },
+ { "escape_filenames", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_linelog_t, escape), "no" },
+ { "syslog_facility", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, syslog_facility), NULL },
+ { "syslog_severity", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, syslog_severity), "info" },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_linelog_t, permissions), "0600" },
+ { "group", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_linelog_t, group), NULL },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_linelog_t, line), NULL },
+ { "header", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_linelog_t, header), NULL },
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_linelog_t, reference), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Instantiate the module.
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_linelog_t *inst = instance;
+ int num;
+
+ if (!inst->filename) {
+ cf_log_err_cs(conf, "No value provided for 'filename'");
+ return -1;
+ }
+
+ /*
+ * Escape filenames only if asked.
+ */
+ if (inst->escape) {
+ inst->escape_func = rad_filename_escape;
+ } else {
+ inst->escape_func = rad_filename_make_safe;
+ }
+
+#ifndef HAVE_SYSLOG_H
+ if (strcmp(inst->filename, "syslog") == 0) {
+ cf_log_err_cs(conf, "Syslog output is not supported on this system");
+ return -1;
+ }
+#else
+
+ if (inst->syslog_facility) {
+ num = fr_str2int(syslog_facility_table, inst->syslog_facility, -1);
+ if (num < 0) {
+ cf_log_err_cs(conf, "Invalid syslog facility \"%s\"", inst->syslog_facility);
+ return -1;
+ }
+
+ inst->syslog_priority |= num;
+ }
+
+ num = fr_str2int(syslog_severity_table, inst->syslog_severity, -1);
+ if (num < 0) {
+ cf_log_err_cs(conf, "Invalid syslog severity \"%s\"", inst->syslog_severity);
+ return -1;
+ }
+ inst->syslog_priority |= num;
+#endif
+
+ if (!inst->line && !inst->reference) {
+ cf_log_err_cs(conf, "Must specify a log format, or reference");
+ return -1;
+ }
+
+ /*
+ * If the admin wants the logs to go to stdout or stderr,
+ * then skip locking / seeking on those files. Since
+ * everything in /dev/ isn't a real file, we can't seek
+ * or lock it.
+ */
+ inst->ef = exfile_init(inst, 256, 30, (strncmp(inst->filename, "/dev/", 5) != 0));
+ if (!inst->ef) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
+ inst->cs = conf;
+ return 0;
+}
+
+
+/*
+ * Escape unprintable characters.
+ */
+static size_t linelog_escape_func(UNUSED REQUEST *request,
+ char *out, size_t outlen, char const *in,
+ UNUSED void *arg)
+{
+ if (outlen == 0) return 0;
+
+ if (outlen == 1) {
+ *out = '\0';
+ return 0;
+ }
+
+ return fr_prints(out, outlen, in, -1, 0);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_do_linelog(void *instance, REQUEST *request)
+{
+ int fd = -1;
+ rlm_linelog_t *inst = (rlm_linelog_t*) instance;
+ char const *value = inst->line;
+ off_t offset;
+
+#ifdef HAVE_GRP_H
+ gid_t gid;
+ char *endptr;
+#endif
+ char path[2048];
+ char line[4096];
+
+ line[0] = '\0';
+
+ if (inst->reference) {
+ CONF_ITEM *ci;
+ CONF_PAIR *cp;
+
+ if (radius_xlat(line + 1, sizeof(line) - 1, request, inst->reference, linelog_escape_func, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ line[0] = '.'; /* force to be in current section */
+
+ /*
+ * Don't allow it to go back up
+ */
+ if (line[1] == '.') goto do_log;
+
+ ci = cf_reference_item(NULL, inst->cs, line);
+ if (!ci) {
+ RDEBUG2("No such entry \"%s\"", line);
+ return RLM_MODULE_NOOP;
+ }
+
+ if (!cf_item_is_pair(ci)) {
+ RDEBUG2("Entry \"%s\" is not a variable assignment ", line);
+ goto do_log;
+ }
+
+ cp = cf_item_to_pair(ci);
+ value = cf_pair_value(cp);
+ if (!value) {
+ RWDEBUG2("Entry \"%s\" has no value", line);
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Value exists, but is empty. Don't log anything.
+ */
+ if (!*value) return RLM_MODULE_OK;
+ }
+
+ do_log:
+ /*
+ * FIXME: Check length.
+ */
+ if (radius_xlat(line, sizeof(line) - 1, request, value, linelog_escape_func, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+#ifdef HAVE_SYSLOG_H
+ if (strcmp(inst->filename, "syslog") == 0) {
+ syslog(inst->syslog_priority, "%s", line);
+ return RLM_MODULE_OK;
+ }
+#endif
+
+ /*
+ * We're using a real filename now.
+ */
+ if (radius_xlat(path, sizeof(path), request, inst->filename, inst->escape_func, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ fd = exfile_open(inst->ef, path, inst->permissions, &offset);
+ if (fd < 0) {
+ ERROR("rlm_linelog: Failed to open %s: %s", path, fr_syserror(errno));
+ return RLM_MODULE_FAIL;
+ }
+
+ if (inst->group != NULL) {
+ gid = strtol(inst->group, &endptr, 10);
+ if (*endptr != '\0') {
+ if (rad_getgid(request, &gid, inst->group) < 0) {
+ RDEBUG2("Unable to find system group \"%s\"", inst->group);
+ goto skip_group;
+ }
+ }
+
+ if (chown(path, -1, gid) == -1) {
+ RDEBUG2("Unable to change system group of \"%s\"", path);
+ }
+ }
+
+ skip_group:
+ if (inst->header && (offset == 0)) {
+ char header[4096];
+ if (radius_xlat(header, sizeof(header) - 1, request, inst->header, linelog_escape_func, NULL) < 0) {
+ error:
+ exfile_close(inst->ef, fd);
+ return RLM_MODULE_FAIL;
+ }
+ strcat(header, "\n");
+ if (write(fd, header, strlen(header)) < 0) {
+ ERROR("rlm_linelog: Failed writing: %s", fr_syserror(errno));
+ goto error;
+ }
+ }
+
+ strcat(line, "\n");
+
+ if (write(fd, line, strlen(line)) < 0) goto error;
+
+ exfile_close(inst->ef, fd);
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * Externally visible module definition.
+ */
+extern module_t rlm_linelog;
+module_t rlm_linelog = {
+ .magic = RLM_MODULE_INIT,
+ .name = "linelog",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_linelog_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_do_linelog,
+ [MOD_AUTHORIZE] = mod_do_linelog,
+ [MOD_PREACCT] = mod_do_linelog,
+ [MOD_ACCOUNTING] = mod_do_linelog,
+ [MOD_PRE_PROXY] = mod_do_linelog,
+ [MOD_POST_PROXY] = mod_do_linelog,
+ [MOD_POST_AUTH] = mod_do_linelog,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_do_linelog,
+ [MOD_SEND_COA] = mod_do_linelog
+#endif
+ },
+};
diff --git a/src/modules/rlm_logintime/README.md b/src/modules/rlm_logintime/README.md
new file mode 100644
index 0000000..a8e1cba
--- /dev/null
+++ b/src/modules/rlm_logintime/README.md
@@ -0,0 +1,14 @@
+# rlm_logintime
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Enforces the time span during which a user may login to the system.
+
+Time spans are defined with timestrings, which are similar in
+format to those used by UUCP. A timestring may be a simple
+timestring, or it may be a list of simple timestrings separated
+by "|" or ",".
diff --git a/src/modules/rlm_logintime/all.mk b/src/modules/rlm_logintime/all.mk
new file mode 100644
index 0000000..ef0b18a
--- /dev/null
+++ b/src/modules/rlm_logintime/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_logintime.a
+SOURCES := rlm_logintime.c timestr.c
diff --git a/src/modules/rlm_logintime/rlm_logintime.c b/src/modules/rlm_logintime/rlm_logintime.c
new file mode 100644
index 0000000..ca8249d
--- /dev/null
+++ b/src/modules/rlm_logintime/rlm_logintime.c
@@ -0,0 +1,260 @@
+/*
+ * 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_logintime.c
+ * @brief Allow login only during a given timeslot.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2004 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include <ctype.h>
+
+/* timestr.c */
+int timestr_match(char const *, time_t);
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_logintime_t {
+ uint32_t min_time;
+} rlm_logintime_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "minimum-timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_logintime_t, min_time), NULL },
+ { "minimum_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_logintime_t, min_time), "60" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * Compare the current time to a range.
+ */
+static int timecmp(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ /*
+ * If there's a request, use that timestamp.
+ */
+ if (timestr_match(check->vp_strvalue,
+ req ? req->timestamp : time(NULL)) >= 0)
+ return 0;
+
+ return -1;
+}
+
+
+/*
+ * Time-Of-Day support
+ */
+static int time_of_day(UNUSED void *instance, REQUEST *req, UNUSED VALUE_PAIR *request, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ int scan;
+ int hhmmss, when;
+ char const *p;
+ struct tm *tm, s_tm;
+
+ /*
+ * Must be called with a request pointer.
+ */
+ if (!req) return -1;
+
+ if (strspn(check->vp_strvalue, "0123456789: ") != strlen(check->vp_strvalue)) {
+ DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
+ check->vp_strvalue);
+ return -1;
+ }
+
+ tm = localtime_r(&req->timestamp, &s_tm);
+ hhmmss = (tm->tm_hour * 3600) + (tm->tm_min * 60) + tm->tm_sec;
+
+ /*
+ * Time of day is a 24-hour clock
+ */
+ p = check->vp_strvalue;
+ scan = atoi(p);
+ p = strchr(p, ':');
+ if ((scan > 23) || !p) {
+ DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
+ check->vp_strvalue);
+ return -1;
+ }
+ when = scan * 3600;
+ p++;
+
+ scan = atoi(p);
+ if (scan > 59) {
+ DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
+ check->vp_strvalue);
+ return -1;
+ }
+ when += scan * 60;
+
+ p = strchr(p, ':');
+ if (p) {
+ scan = atoi(p + 1);
+ if (scan > 59) {
+ DEBUG("rlm_logintime: Bad Time-Of-Day value \"%s\"",
+ check->vp_strvalue);
+ return -1;
+ }
+ when += scan;
+ }
+
+ fprintf(stderr, "returning %d - %d\n",
+ hhmmss, when);
+
+ return hhmmss - when;
+}
+
+/*
+ * Check if account has expired, and if user may login now.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_logintime_t *inst = instance;
+ VALUE_PAIR *ends, *timeout;
+ int left;
+
+ ends = fr_pair_find_by_num(request->config, PW_LOGIN_TIME, 0, TAG_ANY);
+ if (!ends) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Authentication is OK. Now see if this user may login at this time of the day.
+ */
+ RDEBUG("Checking Login-Time");
+
+ /*
+ * Compare the time the request was received with the current Login-Time value
+ */
+ left = timestr_match(ends->vp_strvalue, request->timestamp);
+ if (left < 0) return RLM_MODULE_USERLOCK; /* outside of the allowed time */
+
+ /*
+ * Do nothing, login time is not controlled (unendsed).
+ */
+ if (left == 0) {
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * The min_time setting is to deal with NAS that won't allow Session-Timeout values below a certain value
+ * For example some Alcatel Lucent products won't allow a Session-Timeout < 300 (5 minutes).
+ *
+ * We don't know were going to get another chance to lock out the user, so we need to do it now.
+ */
+ if (left < (int) inst->min_time) {
+ REDEBUG("Login outside of allowed time-slot (session end %s, with lockout %i seconds before)",
+ ends->vp_strvalue, inst->min_time);
+
+ return RLM_MODULE_USERLOCK;
+ }
+
+ /* else left > inst->min_time */
+
+ /*
+ * There's time left in the users session, inform the NAS by including a Session-Timeout
+ * attribute in the reply, or modifying the existing one.
+ */
+ RDEBUG("Login within allowed time-slot, %d seconds left in this session", left);
+
+ timeout = fr_pair_find_by_num(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY);
+ if (timeout) { /* just update... */
+ if (timeout->vp_integer > (unsigned int) left) {
+ timeout->vp_integer = left;
+ }
+ } else {
+ timeout = radius_pair_create(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0);
+ timeout->vp_integer = left;
+ }
+
+ RDEBUG("reply:Session-Timeout set to %d", left);
+
+ return RLM_MODULE_UPDATED;
+}
+
+
+/*
+ * 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_logintime_t *inst = instance;
+
+ if (inst->min_time == 0) {
+ cf_log_err_cs(conf, "Invalid value '0' for minimum_timeout");
+ return -1;
+ }
+
+ /*
+ * Register a Current-Time comparison function
+ */
+ paircompare_register(dict_attrbyvalue(PW_CURRENT_TIME, 0), NULL, true, timecmp, inst);
+ paircompare_register(dict_attrbyvalue(PW_TIME_OF_DAY, 0), NULL, true, time_of_day, inst);
+
+ 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_logintime;
+module_t rlm_logintime = {
+ .magic = RLM_MODULE_INIT,
+ .name = "logintime",
+ .inst_size = sizeof(rlm_logintime_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_POST_AUTH] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_logintime/timestr.c b/src/modules/rlm_logintime/timestr.c
new file mode 100644
index 0000000..1cd827a
--- /dev/null
+++ b/src/modules/rlm_logintime/timestr.c
@@ -0,0 +1,269 @@
+/*
+ * timestr.c See if a string like 'Su2300-0700' matches (UUCP style).
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include <ctype.h>
+
+int timestr_match(char const *, time_t);
+
+static char const *days[] =
+ { "su", "mo", "tu", "we", "th", "fr", "sa", "wk", "any", "al" };
+
+#define DAYMIN (24*60)
+#define WEEKMIN (24*60*7)
+#define val(x) (( (x) < 48 || (x) > 57) ? 0 : ((x) - 48))
+
+#if 0 /* Set to 1 if you're a developer and want to debug this code */
+# define timestr_debug DEBUG2
+# define do_timestr_debug 1
+#else
+# define timestr_debug if (0) printf
+#endif
+
+/*
+ * String code.
+ */
+static int strcode (char const **str)
+{
+ int i;
+ size_t l;
+
+ timestr_debug("strcode %s called\n", *str);
+
+ for (i = 0; i < 10; i++) {
+ l = strlen(days[i]);
+ if (l > strlen(*str))
+ continue;
+ if (strncmp(*str, days[i], l) == 0) {
+ *str += l;
+ break;
+ }
+ }
+ timestr_debug("strcode result %d\n", i);
+
+ return (i >= 10) ? -1 : i;
+
+}
+
+/*
+ * Fill bitmap with hours/mins.
+ */
+static int hour_fill(char *bitmap, char const *tm)
+{
+ char *p;
+ int start, end;
+ int i, bit, byte;
+
+ timestr_debug("hour_fill called for %s\n", tm);
+
+ /*
+ * Get timerange in start and end.
+ */
+ end = -1;
+ if ((p = strchr(tm, '-')) != NULL) {
+ p++;
+ if (p - tm != 5 || strlen(p) < 4 || !isdigit((uint8_t) *p))
+ return 0;
+ end = 600 * val(p[0]) + 60 * val(p[1]) + atoi(p + 2);
+ }
+ if (*tm == 0) {
+ start = 0;
+ end = DAYMIN - 1;
+ } else {
+ if (strlen(tm) < 4 || !isdigit((uint8_t) *tm))
+ return 0;
+ start = 600 * val(tm[0]) + 60 * val(tm[1]) + atoi(tm + 2);
+ if (end < 0) end = start;
+ }
+ /* Treat 2400 as 0000, and do some more silent error checks. */
+ if (end < 0) end = 0;
+ if (start < 0) start = 0;
+ if (end >= DAYMIN) end = DAYMIN - 1;
+ if (start >= DAYMIN) start = DAYMIN - 1;
+
+ timestr_debug("hour_fill: range from %d to %d\n", start, end);
+
+ /*
+ * Fill bitmap.
+ */
+ i = start;
+ while (1) {
+ byte = (i / 8);
+ bit = i % 8;
+ timestr_debug("setting byte %d, bit %d\n", byte, bit);
+ bitmap[byte] |= (1 << bit);
+ if (i == end) break;
+ i++;
+ i %= DAYMIN;
+ }
+ return 1;
+}
+
+/*
+ * Call the fill bitmap function for every day listed.
+ */
+static int day_fill(char *bitmap, char const *tm)
+{
+ char const *hr;
+ int n;
+ int start, end;
+
+ for (hr = tm; *hr; hr++)
+ if (isdigit((uint8_t) *hr))
+ break;
+ if (hr == tm)
+ tm = "Al";
+
+ timestr_debug("dayfill: hr %s tm %s\n", hr, tm);
+
+ while ((start = strcode(&tm)) >= 0) {
+ /*
+ * Find start and end weekdays and
+ * build a valid range 0 - 6.
+ */
+ if (*tm == '-') {
+ tm++;
+ if ((end = strcode(&tm)) < 0)
+ break;
+ } else
+ end = start;
+ if (start == 7) {
+ start = 1;
+ end = 5;
+ }
+ if (start > 7) {
+ start = 0;
+ end = 6;
+ }
+ n = start;
+ timestr_debug("day_fill: range from %d to %d\n", start, end);
+ while (1) {
+ hour_fill(bitmap + 180 * n, hr);
+ if (n == end) break;
+ n++;
+ n %= 7;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Fill the week bitmap with allowed times.
+ */
+static int week_fill(char *bitmap, char const *tm)
+{
+ char *s;
+ char tmp[256];
+
+ strlcpy(tmp, tm, sizeof(tmp));
+ for (s = tmp; *s; s++)
+ if (isupper((uint8_t) *s)) *s = tolower((uint8_t) *s);
+
+ s = strtok(tmp, ",|");
+ while (s) {
+ day_fill(bitmap, s);
+ s = strtok(NULL, ",|");
+ }
+
+ return 0;
+}
+
+/*
+ * Match a timestring and return seconds left.
+ * -1 for no match, 0 for unlimited.
+ */
+int timestr_match(char const *tmstr, time_t t)
+{
+ struct tm *tm, s_tm;
+ char bitmap[WEEKMIN / 8];
+ int now, tot, i;
+ int byte, bit;
+#ifdef do_timestr_debug
+ int y;
+ char *s;
+ char null[8];
+#endif
+
+ tm = localtime_r(&t, &s_tm);
+ now = tm->tm_wday * DAYMIN + tm->tm_hour * 60 + tm->tm_min;
+ tot = 0;
+ memset(bitmap, 0, sizeof(bitmap));
+ week_fill(bitmap, tmstr);
+
+#ifdef do_timestr_debug
+ memset(null, 0, 8);
+ for (i = 0; i < 7; i++) {
+ timestr_debug("%d: ", i);
+ s = bitmap + 180 * i;
+ for (y = 0; y < 23; y++) {
+ s = bitmap + 180 * i + (75 * y) / 10;
+ timestr_debug("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
+ }
+ timestr_debug("\n");
+ }
+#endif
+
+ /*
+ * See how many minutes we have.
+ */
+ i = now;
+ while (1) {
+ byte = i / 8;
+ bit = i % 8;
+ timestr_debug("READ: checking byte %d bit %d\n", byte, bit);
+ if (!(bitmap[byte] & (1 << bit)))
+ break;
+ tot += 60;
+ i++;
+ i %= WEEKMIN;
+ if (i == now)
+ break;
+ }
+
+ if (tot == 0)
+ return -1;
+
+ return (i == now) ? 0 : tot;
+}
+
+#ifdef STANDALONE
+
+int main(int argc, char **argv)
+{
+ int l;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: test timestring\n");
+ exit(1);
+ }
+ l = timestr_match(argv[1], time(NULL));
+ printf ("%s: %d seconds left\n", argv[1], l);
+ return 0;
+}
+
+#endif
+
diff --git a/src/modules/rlm_mschap/.gitignore b/src/modules/rlm_mschap/.gitignore
new file mode 100644
index 0000000..0dd46d5
--- /dev/null
+++ b/src/modules/rlm_mschap/.gitignore
@@ -0,0 +1,3 @@
+config.h
+rlm_mschap.mk
+smbencrypt
diff --git a/src/modules/rlm_mschap/README.md b/src/modules/rlm_mschap/README.md
new file mode 100644
index 0000000..a05ab8d
--- /dev/null
+++ b/src/modules/rlm_mschap/README.md
@@ -0,0 +1,10 @@
+# rlm_mschap
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Supports MS-CHAP and MS-CHAPv2 authentication. It also enforces
+the SMB-Account-Ctrl attribute.
diff --git a/src/modules/rlm_mschap/all.mk b/src/modules/rlm_mschap/all.mk
new file mode 100644
index 0000000..533d19a
--- /dev/null
+++ b/src/modules/rlm_mschap/all.mk
@@ -0,0 +1,5 @@
+SUBMAKEFILES := rlm_mschap.mk smbencrypt.mk
+
+src/modules/rlm_mschap/rlm_mschap.mk: src/modules/rlm_mschap/rlm_mschap.mk.in src/modules/rlm_mschap/configure
+ @echo CONFIGURE $(dir $<)
+ @cd $(dir $<) && ./configure $(CONFIGURE_ARGS) && touch $(notdir $@)
diff --git a/src/modules/rlm_mschap/auth_wbclient.c b/src/modules/rlm_mschap/auth_wbclient.c
new file mode 100644
index 0000000..8b4a3ee
--- /dev/null
+++ b/src/modules/rlm_mschap/auth_wbclient.c
@@ -0,0 +1,270 @@
+/*
+ * 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 auth_wbclient.c
+ * @brief NTLM authentication against the wbclient library
+ *
+ * @copyright 2015 Matthew Newton
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <core/ntstatus.h>
+
+#include "rlm_mschap.h"
+#include "mschap.h"
+#include "auth_wbclient.h"
+
+#define NT_LENGTH 24
+
+/** Use Winbind to normalise a username
+ *
+ * @param[in] tctx The talloc context where the result is parented from
+ * @param[in] ctx The winbind context
+ * @param[in] dom_name The domain of the user
+ * @param[in] name The username (without the domain) to be normalised
+ * @return The username with the casing according to the Winbind remote server,
+ * or NULL if the username could not be found.
+ */
+static char *wbclient_normalise_username(TALLOC_CTX *tctx, struct wbcContext *ctx, char const *dom_name, char const *name)
+{
+ struct wbcDomainSid sid;
+ enum wbcSidType name_type;
+ wbcErr err;
+ char *res_domain = NULL;
+ char *res_name = NULL;
+ char *res = NULL;
+
+ /* Step 1: Convert a name to a sid */
+ err = wbcCtxLookupName(ctx, dom_name, name, &sid, &name_type);
+ if (!WBC_ERROR_IS_OK(err))
+ return NULL;
+
+ /* Step 2: Convert the sid back to a name */
+ err = wbcCtxLookupSid(ctx, &sid, &res_domain, &res_name, &name_type);
+ if (!WBC_ERROR_IS_OK(err))
+ return NULL;
+
+ MEM(res = talloc_strdup(tctx, res_name));
+
+ wbcFreeMemory(res_domain);
+ wbcFreeMemory(res_name);
+
+ return res;
+}
+
+/*
+ * Check NTLM authentication direct to winbind via
+ * Samba's libwbclient library
+ *
+ * Returns:
+ * 0 success
+ * -1 auth failure
+ * -2 failed connecting to AD
+ * -648 password expired
+ */
+int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
+ uint8_t const *challenge, uint8_t const *response,
+ uint8_t nthashhash[NT_DIGEST_LENGTH])
+{
+ int rcode = -1;
+ struct wbcContext *wb_ctx = NULL;
+ struct wbcAuthUserParams authparams;
+ wbcErr err;
+ int len;
+ struct wbcAuthUserInfo *info = NULL;
+ struct wbcAuthErrorInfo *error = NULL;
+ char user_name_buf[500];
+ char domain_name_buf[500];
+ uint8_t resp[NT_LENGTH];
+
+ /*
+ * Clear the auth parameters - this is important, as
+ * there are options that will cause wbcAuthenticateUserEx
+ * to bomb out if not zero.
+ */
+ memset(&authparams, 0, sizeof(authparams));
+
+ /*
+ * wb_username must be set for this function to be called
+ */
+ rad_assert(inst->wb_username);
+
+ /*
+ * Get the username and domain from the configuration
+ */
+ len = tmpl_expand(&authparams.account_name, user_name_buf, sizeof(user_name_buf),
+ request, inst->wb_username, NULL, NULL);
+ if (len < 0) {
+ REDEBUG2("Unable to expand winbind_username");
+ goto done;
+ }
+
+ if (inst->wb_domain) {
+ len = tmpl_expand(&authparams.domain_name, domain_name_buf, sizeof(domain_name_buf),
+ request, inst->wb_domain, NULL, NULL);
+ if (len < 0) {
+ REDEBUG2("Unable to expand winbind_domain");
+ goto done;
+ }
+ } else {
+ RWDEBUG2("No domain specified; authentication may fail because of this");
+ }
+
+
+ /*
+ * Build the wbcAuthUserParams structure with what we know
+ */
+ authparams.level = WBC_AUTH_USER_LEVEL_RESPONSE;
+ authparams.password.response.nt_length = NT_LENGTH;
+
+ memcpy(resp, response, NT_LENGTH);
+ authparams.password.response.nt_data = resp;
+
+ memcpy(authparams.password.response.challenge, challenge,
+ sizeof(authparams.password.response.challenge));
+
+ authparams.parameter_control |= WBC_MSV1_0_ALLOW_MSVCHAPV2 |
+ WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
+ WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;
+
+
+ /*
+ * Send auth request across to winbind
+ */
+ wb_ctx = fr_connection_get(inst->wb_pool);
+ if (wb_ctx == NULL) {
+ RERROR("Unable to get winbind connection from pool");
+ goto done;
+ }
+
+ RDEBUG2("sending authentication request user='%s' domain='%s'", authparams.account_name,
+ authparams.domain_name);
+
+ err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
+
+ if (err == WBC_ERR_AUTH_ERROR && inst->wb_retry_with_normalised_username) {
+ VALUE_PAIR *vp_response, *vp_challenge;
+ char *normalised_username = wbclient_normalise_username(request, wb_ctx, authparams.domain_name, authparams.account_name);
+ if (normalised_username) {
+ RDEBUG2("Starting retry, normalised username %s to %s", authparams.account_name, normalised_username);
+ if (strcmp(authparams.account_name, normalised_username) != 0) {
+ authparams.account_name = normalised_username;
+
+ /* Set PW_MS_CHAP_USER_NAME */
+ if (!fr_pair_make(request->packet, &request->packet->vps, "MS-CHAP-User-Name", normalised_username, T_OP_SET)) {
+ RERROR("Failed creating MS-CHAP-User-Name");
+ goto normalised_username_retry_failure;
+ }
+
+ RDEBUG2("retrying authentication request user='%s' domain='%s'", authparams.account_name,
+ authparams.domain_name);
+
+ /* Recalculate hash */
+ if (!(vp_challenge = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY))) {
+ RERROR("Unable to get MS-CHAP-Challenge");
+ goto normalised_username_retry_failure;
+ }
+ if (!(vp_response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY))) {
+ RERROR("Unable to get MS-CHAP2-Response");
+ goto normalised_username_retry_failure;
+ }
+ mschap_challenge_hash(vp_response->vp_octets + 2,
+ vp_challenge->vp_octets,
+ normalised_username,
+ authparams.password.response.challenge);
+
+ err = wbcCtxAuthenticateUserEx(wb_ctx, &authparams, &info, &error);
+ }
+normalised_username_retry_failure:
+ talloc_free(normalised_username);
+ }
+ }
+
+ fr_connection_release(inst->wb_pool, wb_ctx);
+
+ /*
+ * Try and give some useful feedback on what happened. There are only
+ * a few errors that can actually be returned from wbcCtxAuthenticateUserEx.
+ */
+ switch (err) {
+ case WBC_ERR_SUCCESS:
+ rcode = 0;
+ RDEBUG2("Authenticated successfully");
+ /* Grab the nthashhash from the result */
+ memcpy(nthashhash, info->user_session_key, NT_DIGEST_LENGTH);
+ break;
+ case WBC_ERR_WINBIND_NOT_AVAILABLE:
+ rcode = -2;
+ RERROR("Unable to contact winbind!");
+ RDEBUG2("Check that winbind is running and that FreeRADIUS has");
+ RDEBUG2("permission to connect to the winbind privileged socket.");
+ break;
+ case WBC_ERR_DOMAIN_NOT_FOUND:
+ REDEBUG2("Domain not found");
+ break;
+ case WBC_ERR_AUTH_ERROR:
+ if (!error) {
+ REDEBUG2("Authentication failed");
+ break;
+ }
+
+ /*
+ * The password needs to be changed, so set rcode appropriately.
+ */
+ if (error->nt_status == NT_STATUS_PASSWORD_EXPIRED ||
+ error->nt_status == NT_STATUS_PASSWORD_MUST_CHANGE) {
+ rcode = -648;
+ }
+
+ /*
+ * Return the NT_STATUS human readable error string, if there is one.
+ */
+ if (error->display_string) {
+ REDEBUG2("%s [0x%X]", error->display_string, error->nt_status);
+ } else {
+ REDEBUG2("Authentication failed [0x%X]", error->nt_status);
+ }
+ break;
+ default:
+ /*
+ * Only errors left are
+ * WBC_ERR_INVALID_PARAM
+ * WBC_ERR_NO_MEMORY
+ * neither of which are particularly likely.
+ */
+ rcode = -2;
+ if (error && error->display_string) {
+ REDEBUG2("libwbclient error: wbcErr %d (%s)", err, error->display_string);
+ } else {
+ REDEBUG2("libwbclient error: wbcErr %d", err);
+ }
+ break;
+ }
+
+
+done:
+ if (info) wbcFreeMemory(info);
+ if (error) wbcFreeMemory(error);
+
+ return rcode;
+}
+
diff --git a/src/modules/rlm_mschap/auth_wbclient.h b/src/modules/rlm_mschap/auth_wbclient.h
new file mode 100644
index 0000000..e54591c
--- /dev/null
+++ b/src/modules/rlm_mschap/auth_wbclient.h
@@ -0,0 +1,19 @@
+/* Copyright 2015 The FreeRADIUS server project */
+
+#ifndef _AUTH_WBCLIENT_H
+#define _AUTH_WBCLIENT_H
+
+RCSIDH(auth_wbclient_h, "$Id$")
+
+#include <wbclient.h>
+
+/* Samba does not export this constant yet */
+#ifndef WBC_MSV1_0_ALLOW_MSVCHAPV2
+#define WBC_MSV1_0_ALLOW_MSVCHAPV2 0x00010000
+#endif
+
+int do_auth_wbclient(rlm_mschap_t *inst, REQUEST *request,
+ uint8_t const *challenge, uint8_t const *response,
+ uint8_t nthashhash[NT_DIGEST_LENGTH]);
+
+#endif /*_AUTH_WBCLIENT_H*/
diff --git a/src/modules/rlm_mschap/config.h.in b/src/modules/rlm_mschap/config.h.in
new file mode 100644
index 0000000..ccd7fc8
--- /dev/null
+++ b/src/modules/rlm_mschap/config.h.in
@@ -0,0 +1,7 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Build with Apple Open Directory support */
+#undef HAVE_MEMBERSHIP_H
+
+/* Build with direct winbind auth support */
+#undef WITH_AUTH_WINBIND
diff --git a/src/modules/rlm_mschap/configure b/src/modules/rlm_mschap/configure
new file mode 100755
index 0000000..fe001f1
--- /dev/null
+++ b/src/modules/rlm_mschap/configure
@@ -0,0 +1,4931 @@
+#! /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_mschap.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+mschap_sources
+targetname
+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_mschap
+with_winbind_include_dir
+with_winbind_lib_dir
+with_winbind_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_mschap build without MS-CHAP and MS-CHAPv2 authentication
+ --with-winbind-include-dir=DIR
+ Directory where the winbind includes may be found
+ --with-winbind-lib-dir=DIR
+ Directory where the winbind libraries may be found
+ --with-winbind-dir=DIR Base directory where winbind 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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_mschap
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_mschap was given.
+if test "${with_rlm_mschap+set}" = set; then :
+ withval=$with_rlm_mschap;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_mschap" != 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
+
+
+
+winbind_include_dir=
+
+# Check whether --with-winbind-include-dir was given.
+if test "${with_winbind_include_dir+set}" = set; then :
+ withval=$with_winbind_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need winbind-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+winbind_lib_dir=
+
+# Check whether --with-winbind-lib-dir was given.
+if test "${with_winbind_lib_dir+set}" = set; then :
+ withval=$with_winbind_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need winbind-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-winbind-dir was given.
+if test "${with_winbind_dir+set}" = set; then :
+ withval=$with_winbind_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need winbind-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_lib_dir="$withval/lib"
+ winbind_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+
+mschap_sources=
+
+
+
+ac_safe=`echo "membership.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 membership.h in $try" >&5
+$as_echo_n "checking for membership.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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}/membership.h" >&5
+$as_echo_n "checking for ${_prefix}/membership.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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 membership.h" >&5
+$as_echo_n "checking for membership.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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 membership.h in $try" >&5
+$as_echo_n "checking for membership.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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_membership_h" = "xyes"; then
+
+$as_echo "#define HAVE_MEMBERSHIP_H 1" >>confdefs.h
+
+ mschap_sources="$mschap_sources opendir.c"
+ mod_ldflags="-F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks -framework DirectoryService"
+
+if echo "$fr_features" | grep -q "+opendirectory+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with opendirectory support" >> config.report.tmp
+ fr_features="$fr_features +opendirectory+"
+fi
+
+else
+
+if echo "$fr_features" | grep -q "+opendirectory+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without opendirectory support" >> config.report.tmp
+ fr_features="$fr_features +opendirectory+"
+fi
+
+fi
+
+smart_try_dir="$winbind_include_dir /usr/include/samba-4.0"
+
+
+ac_safe=`echo "wbclient.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 wbclient.h in $try" >&5
+$as_echo_n "checking for wbclient.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <wbclient.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}/wbclient.h" >&5
+$as_echo_n "checking for ${_prefix}/wbclient.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <wbclient.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 wbclient.h" >&5
+$as_echo_n "checking for wbclient.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <wbclient.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 wbclient.h in $try" >&5
+$as_echo_n "checking for wbclient.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <wbclient.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_wbclient_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: wbclient.h not found. Use --with-winbind-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: wbclient.h not found. Use --with-winbind-include-dir=<path>." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&5
+$as_echo "$as_me: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&2;}
+
+if echo "$fr_features" | grep -q "+wbclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without direct winbind support" >> config.report.tmp
+ fr_features="$fr_features +wbclient+"
+fi
+
+fi
+
+
+
+ac_safe=`echo "core/ntstatus.h" | sed 'y%./+-%__pm%'`
+old_CPPFLAGS="$CPPFLAGS"
+smart_include=
+smart_include_dir="/usr/local/include /opt/include"
+
+_smart_try_dir=
+_smart_include_dir=
+
+for _prefix in $smart_prefix ""; do
+ for _dir in $smart_try_dir; do
+ _smart_try_dir="${_smart_try_dir} ${_dir}/${_prefix}"
+ done
+
+ for _dir in $smart_include_dir; do
+ _smart_include_dir="${_smart_include_dir} ${_dir}/${_prefix}"
+ done
+done
+
+if test "x$_smart_try_dir" != "x"; then
+ for try in $_smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h in $try" >&5
+$as_echo_n "checking for core/ntstatus.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" = "x"; then
+ for _prefix in $smart_prefix; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${_prefix}/core/ntstatus.h" >&5
+$as_echo_n "checking for ${_prefix}/core/ntstatus.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem ${_prefix}/"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+fi
+
+if test "x$smart_include" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h" >&5
+$as_echo_n "checking for core/ntstatus.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for core/ntstatus.h in $try" >&5
+$as_echo_n "checking for core/ntstatus.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdint.h>
+ #include <stdbool.h>
+ #include <core/ntstatus.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "x$ac_cv_header_core_ntstatus_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: core/ntstatus.h not found. Use --with-winbind-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: core/ntstatus.h not found. Use --with-winbind-include-dir=<path>." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&5
+$as_echo "$as_me: WARNING: silently building without support for direct authentication via winbind. requires: libwbclient" >&2;}
+
+if echo "$fr_features" | grep -q "+wbclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without direct winbind support" >> config.report.tmp
+ fr_features="$fr_features +wbclient+"
+fi
+
+fi
+
+
+if test "x$ac_cv_header_wbclient_h" = "xyes" && \
+ test "x$ac_cv_header_core_ntstatus_h" = "xyes"; then
+
+ smart_try_dir="$winbind_lib_dir"
+
+
+sm_lib_safe=`echo "wbclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "wbcCtxAuthenticateUserEx" | 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 wbcCtxAuthenticateUserEx in -lwbclient in $try" >&5
+$as_echo_n "checking for wbcCtxAuthenticateUserEx in -lwbclient in $try... " >&6; }
+ LIBS="-lwbclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char wbcCtxAuthenticateUserEx();
+int
+main ()
+{
+wbcCtxAuthenticateUserEx()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lwbclient"
+ 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 wbcCtxAuthenticateUserEx in -lwbclient" >&5
+$as_echo_n "checking for wbcCtxAuthenticateUserEx in -lwbclient... " >&6; }
+ LIBS="-lwbclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char wbcCtxAuthenticateUserEx();
+int
+main ()
+{
+wbcCtxAuthenticateUserEx()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lwbclient"
+ { $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 wbcCtxAuthenticateUserEx in -lwbclient in $try" >&5
+$as_echo_n "checking for wbcCtxAuthenticateUserEx in -lwbclient in $try... " >&6; }
+ LIBS="-lwbclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char wbcCtxAuthenticateUserEx();
+int
+main ()
+{
+wbcCtxAuthenticateUserEx()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lwbclient"
+ 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_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: winbind libraries not found. Use --with-winbind-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: winbind libraries not found. Use --with-winbind-lib-dir=<path>." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Samba must be version 4.2.1 or higher to use this feature." >&5
+$as_echo "$as_me: WARNING: Samba must be version 4.2.1 or higher to use this feature." >&2;}
+
+if echo "$fr_features" | grep -q "+wbclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without direct winbind support" >> config.report.tmp
+ fr_features="$fr_features +wbclient+"
+fi
+
+ else
+ mschap_sources="$mschap_sources auth_wbclient.c"
+
+$as_echo "#define WITH_AUTH_WINBIND 1" >>confdefs.h
+
+
+if echo "$fr_features" | grep -q "+wbclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with direct winbind support" >> config.report.tmp
+ fr_features="$fr_features +wbclient+"
+fi
+
+ fi
+fi
+
+
+ targetname=rlm_mschap
+else
+ targetname=
+ echo \*\*\* module rlm_mschap is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_mschap to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_mschap." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_mschap." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_mschap requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_mschap requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$mod_ldflags $SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files rlm_mschap.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "rlm_mschap.mk") CONFIG_FILES="$CONFIG_FILES rlm_mschap.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_mschap/configure.ac b/src/modules/rlm_mschap/configure.ac
new file mode 100644
index 0000000..953336f
--- /dev/null
+++ b/src/modules/rlm_mschap/configure.ac
@@ -0,0 +1,128 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_mschap.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_mschap], [MS-CHAP and MS-CHAPv2 authentication])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-winbind-include-dir=DIR
+winbind_include_dir=
+AC_ARG_WITH(winbind-include-dir,
+ [AS_HELP_STRING([--with-winbind-include-dir=DIR],
+ [Directory where the winbind includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need winbind-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-winbind-lib-dir=DIR
+winbind_lib_dir=
+AC_ARG_WITH(winbind-lib-dir,
+ [AS_HELP_STRING([--with-winbind-lib-dir=DIR],
+ [Directory where the winbind libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need winbind-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-winbind-dir=DIR
+AC_ARG_WITH(winbind-dir,
+ [AS_HELP_STRING([--with-winbind-dir=DIR],
+ [Base directory where winbind is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need winbind-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ winbind_lib_dir="$withval/lib"
+ winbind_include_dir="$withval/include"
+ ;;
+ esac])
+
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+mschap_sources=
+FR_SMART_CHECK_INCLUDE(membership.h)
+if test "x$ac_cv_header_membership_h" = "xyes"; then
+ AC_DEFINE([HAVE_MEMBERSHIP_H],[1],[Build with Apple Open Directory support])
+ mschap_sources="$mschap_sources opendir.c"
+ mod_ldflags="-F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks -framework DirectoryService"
+ FR_MODULE_FEATURE([opendirectory], [with opendirectory support])
+else
+ FR_MODULE_FEATURE([opendirectory], [without opendirectory support])
+fi
+
+smart_try_dir="$winbind_include_dir /usr/include/samba-4.0"
+FR_SMART_CHECK_INCLUDE(wbclient.h, [#include <stdint.h>
+ #include <stdbool.h>])
+if test "x$ac_cv_header_wbclient_h" != "xyes"; then
+ AC_MSG_WARN([wbclient.h not found. Use --with-winbind-include-dir=<path>.])
+ AC_MSG_WARN([silently building without support for direct authentication via winbind. requires: libwbclient])
+ FR_MODULE_FEATURE([wbclient], [without direct winbind support])
+fi
+
+FR_SMART_CHECK_INCLUDE(core/ntstatus.h, [#include <stdint.h>
+ #include <stdbool.h>])
+if test "x$ac_cv_header_core_ntstatus_h" != "xyes"; then
+ AC_MSG_WARN([core/ntstatus.h not found. Use --with-winbind-include-dir=<path>.])
+ AC_MSG_WARN([silently building without support for direct authentication via winbind. requires: libwbclient])
+ FR_MODULE_FEATURE([wbclient], [without direct winbind support])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+if test "x$ac_cv_header_wbclient_h" = "xyes" && \
+ test "x$ac_cv_header_core_ntstatus_h" = "xyes"; then
+
+ smart_try_dir="$winbind_lib_dir"
+ FR_SMART_CHECK_LIB(wbclient, wbcCtxAuthenticateUserEx)
+ if test "x$ac_cv_lib_wbclient_wbcCtxAuthenticateUserEx" != "xyes"; then
+ AC_MSG_WARN([winbind libraries not found. Use --with-winbind-lib-dir=<path>.])
+ AC_MSG_WARN([Samba must be version 4.2.1 or higher to use this feature.])
+ FR_MODULE_FEATURE([wbclient], [without direct winbind support])
+ else
+ mschap_sources="$mschap_sources auth_wbclient.c"
+ AC_DEFINE([WITH_AUTH_WINBIND],[1],[Build with direct winbind auth support])
+ FR_MODULE_FEATURE([wbclient], [with direct winbind support])
+ fi
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$mod_ldflags $SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mschap_sources)
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([rlm_mschap.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_mschap/mschap.c b/src/modules/rlm_mschap/mschap.c
new file mode 100644
index 0000000..4e088ed
--- /dev/null
+++ b/src/modules/rlm_mschap/mschap.c
@@ -0,0 +1,147 @@
+/*
+ * mschap.c
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2001,2006,2010 The FreeRADIUS server project
+ */
+
+
+/*
+ * This implements MS-CHAP, as described in RFC 2548
+ *
+ * http://www.freeradius.org/rfc/rfc2548.txt
+ *
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/sha1.h>
+
+#include <ctype.h>
+
+#include "smbdes.h"
+#include "mschap.h"
+
+/** Converts Unicode password to 16-byte NT hash with MD4
+ *
+ * @param[out] out Pointer to 16 byte output buffer.
+ * @param[in] password to encode.
+ * @return 0 on success else -1 on failure.
+ */
+int mschap_ntpwdhash(uint8_t *out, char const *password)
+{
+ ssize_t len;
+ uint8_t ucs2_password[512];
+
+ len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password));
+ if (len < 0) {
+ *out = '\0';
+ return -1;
+ }
+ fr_md4_calc(out, (uint8_t *) ucs2_password, len);
+
+ return 0;
+}
+
+/*
+ * challenge_hash() is used by mschap2() and auth_response()
+ * implements RFC2759 ChallengeHash()
+ * generates 64 bit challenge
+ */
+void mschap_challenge_hash(uint8_t const *peer_challenge,
+ uint8_t const *auth_challenge,
+ char const *user_name, uint8_t *challenge )
+{
+ fr_sha1_ctx Context;
+ uint8_t hash[20];
+
+ fr_sha1_init(&Context);
+ fr_sha1_update(&Context, peer_challenge, 16);
+ fr_sha1_update(&Context, auth_challenge, 16);
+ fr_sha1_update(&Context, (uint8_t const *) user_name,
+ strlen(user_name));
+ fr_sha1_final(hash, &Context);
+ memcpy(challenge, hash, 8);
+}
+
+/*
+ * auth_response() generates MS-CHAP v2 SUCCESS response
+ * according to RFC 2759 GenerateAuthenticatorResponse()
+ * returns 42-octet response string
+ */
+void mschap_auth_response(char const *username,
+ uint8_t const *nt_hash_hash,
+ uint8_t const *ntresponse,
+ uint8_t const *peer_challenge, uint8_t const *auth_challenge,
+ char *response)
+{
+ fr_sha1_ctx Context;
+ static const uint8_t magic1[39] =
+ {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+ 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+ 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+ 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
+
+ static const uint8_t magic2[41] =
+ {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+ 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+ 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+ 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+ 0x6E};
+
+ static char const hex[] = "0123456789ABCDEF";
+
+ size_t i;
+ uint8_t challenge[8];
+ uint8_t digest[20];
+
+ fr_sha1_init(&Context);
+ fr_sha1_update(&Context, nt_hash_hash, 16);
+ fr_sha1_update(&Context, ntresponse, 24);
+ fr_sha1_update(&Context, magic1, 39);
+ fr_sha1_final(digest, &Context);
+ mschap_challenge_hash(peer_challenge, auth_challenge, username, challenge);
+ fr_sha1_init(&Context);
+ fr_sha1_update(&Context, digest, 20);
+ fr_sha1_update(&Context, challenge, 8);
+ fr_sha1_update(&Context, magic2, 41);
+ fr_sha1_final(digest, &Context);
+
+ /*
+ * Encode the value of 'Digest' as "S=" followed by
+ * 40 ASCII hexadecimal digits and return it in
+ * AuthenticatorResponse.
+ * For example,
+ * "S=0123456789ABCDEF0123456789ABCDEF01234567"
+ */
+ response[0] = 'S';
+ response[1] = '=';
+
+ /*
+ * The hexadecimal digits [A-F] MUST be uppercase.
+ */
+ for (i = 0; i < sizeof(digest); i++) {
+ response[2 + (i * 2)] = hex[(digest[i] >> 4) & 0x0f];
+ response[3 + (i * 2)] = hex[digest[i] & 0x0f];
+ }
+}
+
diff --git a/src/modules/rlm_mschap/mschap.h b/src/modules/rlm_mschap/mschap.h
new file mode 100644
index 0000000..6fcc485
--- /dev/null
+++ b/src/modules/rlm_mschap/mschap.h
@@ -0,0 +1,25 @@
+/* Copyright 2006 The FreeRADIUS server project */
+
+#ifndef _MSCHAP_H
+#define _MSCHAP_H
+
+RCSIDH(mschap_h, "$Id$")
+
+#define NT_DIGEST_LENGTH 16
+#define LM_DIGEST_LENGTH 16
+
+int mschap_ntpwdhash(uint8_t *out, char const *password);
+void mschap_challenge_hash(uint8_t const *peer_challenge,
+ uint8_t const *auth_challenge,
+ char const *user_name, uint8_t *challenge );
+
+void mschap_auth_response(char const *username,
+ uint8_t const *nt_hash_hash,
+ uint8_t const *ntresponse,
+ uint8_t const *peer_challenge, uint8_t const *auth_challenge,
+ char *response);
+void mschap_add_reply(REQUEST *request, unsigned char ident,
+ char const *name, char const *value, size_t len);
+
+
+#endif /*_MSCHAP_H*/
diff --git a/src/modules/rlm_mschap/opendir.c b/src/modules/rlm_mschap/opendir.c
new file mode 100644
index 0000000..b3fd9ff
--- /dev/null
+++ b/src/modules/rlm_mschap/opendir.c
@@ -0,0 +1,418 @@
+#ifdef __APPLE__
+/*
+ * Open Directory support from Apple Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only, as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License version 2
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2007 Apple Inc.
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/md5.h>
+
+#include <ctype.h>
+
+#include "smbdes.h"
+
+#include <DirectoryService/DirectoryService.h>
+
+#define kActiveDirLoc "/Active Directory/"
+
+/*
+ * In rlm_mschap.c
+ */
+void mschap_add_reply(REQUEST *request, unsigned char ident,
+ char const *name, char const *value, size_t len);
+
+/*
+ * Only used by rlm_mschap.c
+ */
+rlm_rcode_t od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge, VALUE_PAIR * usernamepair);
+
+
+static rlm_rcode_t getUserNodeRef(REQUEST *request, char* inUserName, char **outUserName,
+ tDirNodeReference* userNodeRef, tDirReference dsRef)
+{
+ tDataBuffer *tDataBuff = NULL;
+ tDirNodeReference nodeRef = 0;
+ long status = eDSNoErr;
+ char const *what = NULL;
+ char *status_name = NULL;
+ tContextData context = 0;
+ uint32_t nodeCount = 0;
+ uint32_t attrIndex = 0;
+ tDataList *nodeName = NULL;
+ tAttributeEntryPtr pAttrEntry = NULL;
+ tDataList *pRecName = NULL;
+ tDataList *pRecType = NULL;
+ tDataList *pAttrType = NULL;
+ uint32_t recCount = 0;
+ tRecordEntry *pRecEntry = NULL;
+ tAttributeListRef attrListRef = 0;
+ char *pUserLocation = NULL;
+ tAttributeValueListRef valueRef = 0;
+ tDataList *pUserNode = NULL;
+ rlm_rcode_t result = RLM_MODULE_FAIL;
+
+ if (!inUserName) {
+ ERROR("rlm_mschap: getUserNodeRef(): no username");
+ return RLM_MODULE_FAIL;
+ }
+
+ tDataBuff = dsDataBufferAllocate(dsRef, 4096);
+ if (!tDataBuff) {
+ RERROR("Failed allocating buffer");
+ return RLM_MODULE_FAIL;
+ }
+
+ do {
+ /* find on search node */
+ status = dsFindDirNodes(dsRef, tDataBuff, NULL,
+ eDSAuthenticationSearchNodeName,
+ &nodeCount, &context);
+#define OPEN_DIR_ERROR(_x) do if (status != eDSNoErr) { \
+ what = _x; \
+ goto error; \
+ } while (0)
+
+ OPEN_DIR_ERROR("Failed to find directory");
+
+ if (nodeCount < 1) {
+ what = "No directories found.";
+ goto error;
+ }
+
+ status = dsGetDirNodeName(dsRef, tDataBuff, 1, &nodeName);
+ OPEN_DIR_ERROR("Failed getting directory name");
+
+ status = dsOpenDirNode(dsRef, nodeName, &nodeRef);
+ dsDataListDeallocate(dsRef, nodeName);
+ free(nodeName);
+ nodeName = NULL;
+
+ OPEN_DIR_ERROR("Failed opening directory");
+
+ pRecName = dsBuildListFromStrings(dsRef, inUserName, NULL);
+ pRecType = dsBuildListFromStrings(dsRef, kDSStdRecordTypeUsers,
+ NULL);
+ pAttrType = dsBuildListFromStrings(dsRef,
+ kDSNAttrMetaNodeLocation,
+ kDSNAttrRecordName, NULL);
+
+ recCount = 1;
+ status = dsGetRecordList(nodeRef, tDataBuff, pRecName,
+ eDSExact, pRecType, pAttrType, 0,
+ &recCount, &context);
+ OPEN_DIR_ERROR("Failed getting record list");
+
+ if (recCount == 0) {
+ what = "No user records returned";
+ goto error;
+ }
+
+ status = dsGetRecordEntry(nodeRef, tDataBuff, 1,
+ &attrListRef, &pRecEntry);
+ OPEN_DIR_ERROR("Failed getting record entry");
+
+ for (attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++) {
+ status = dsGetAttributeEntry(nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry);
+ if (status == eDSNoErr && pAttrEntry != NULL) {
+ tAttributeValueEntry *pValueEntry = NULL;
+
+ if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation) == 0) {
+ status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
+ if (status == eDSNoErr && pValueEntry != NULL) {
+ pUserLocation = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
+ memcpy(pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
+ }
+ } else if (strcmp(pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName) == 0) {
+ status = dsGetAttributeValue(nodeRef, tDataBuff, 1, valueRef, &pValueEntry);
+ if (status == eDSNoErr && pValueEntry != NULL) {
+ *outUserName = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
+ memcpy(*outUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength);
+ }
+ }
+
+ if (pValueEntry) {
+ dsDeallocAttributeValueEntry(dsRef, pValueEntry);
+ pValueEntry = NULL;
+ }
+
+ dsDeallocAttributeEntry(dsRef, pAttrEntry);
+ pAttrEntry = NULL;
+ dsCloseAttributeValueList(valueRef);
+ valueRef = 0;
+ }
+ }
+
+ if (!pUserLocation) {
+ DEBUG2("[mschap] OpenDirectory has no user location");
+ result = RLM_MODULE_NOOP;
+ break;
+ }
+
+ /* OpenDirectory doesn't support mschapv2 authentication against
+ * Active Directory. AD users need to be authenticated using the
+ * normal freeradius AD path (i.e. ntlm_auth).
+ */
+ if (strncmp(pUserLocation, kActiveDirLoc, strlen(kActiveDirLoc)) == 0) {
+ DEBUG2("[mschap] OpenDirectory authentication returning noop. OD doesn't support MSCHAPv2 for ActiveDirectory users");
+ result = RLM_MODULE_NOOP;
+ break;
+ }
+
+ pUserNode = dsBuildFromPath(dsRef, pUserLocation, "/");
+ if (!pUserNode) {
+ RERROR("Failed building user from path");
+ result = RLM_MODULE_FAIL;
+ break;
+ }
+
+ status = dsOpenDirNode(dsRef, pUserNode, userNodeRef);
+ dsDataListDeallocate(dsRef, pUserNode);
+ free(pUserNode);
+
+ if (status != eDSNoErr) {
+ error:
+ status_name = dsCopyDirStatusName(status);
+ RERROR("%s: status = %s", what, status_name);
+ free(status_name);
+ result = RLM_MODULE_FAIL;
+ break;
+ }
+
+ result = RLM_MODULE_OK;
+ }
+ while (0);
+
+ if (pRecEntry != NULL)
+ dsDeallocRecordEntry(dsRef, pRecEntry);
+
+ if (tDataBuff != NULL)
+ dsDataBufferDeAllocate(dsRef, tDataBuff);
+
+ if (pUserLocation != NULL)
+ talloc_free(pUserLocation);
+
+ if (pRecName != NULL) {
+ dsDataListDeallocate(dsRef, pRecName);
+ free(pRecName);
+ }
+ if (pRecType != NULL) {
+ dsDataListDeallocate(dsRef, pRecType);
+ free(pRecType);
+ }
+ if (pAttrType != NULL) {
+ dsDataListDeallocate(dsRef, pAttrType);
+ free(pAttrType);
+ }
+ if (nodeRef != 0)
+ dsCloseDirNode(nodeRef);
+
+ return result;
+}
+
+rlm_rcode_t od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge, VALUE_PAIR * usernamepair)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ tDirStatus status = eDSNoErr;
+ tDirReference dsRef = 0;
+ tDirNodeReference userNodeRef = 0;
+ tDataBuffer *tDataBuff = NULL;
+ tDataBuffer *pStepBuff = NULL;
+ tDataNode *pAuthType = NULL;
+ uint32_t uiCurr = 0;
+ uint32_t uiLen = 0;
+ char *username_string = NULL;
+ char *shortUserName = NULL;
+ VALUE_PAIR *response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+#ifndef NDEBUG
+ unsigned int t;
+#endif
+
+ username_string = talloc_array(request, char, usernamepair->vp_length + 1);
+ if (!username_string)
+ return RLM_MODULE_FAIL;
+
+ strlcpy(username_string, usernamepair->vp_strvalue, usernamepair->vp_length + 1);
+
+ status = dsOpenDirService(&dsRef);
+ if (status != eDSNoErr) {
+ talloc_free(username_string);
+ RERROR("Failed opening directory service");
+ return RLM_MODULE_FAIL;
+ }
+
+ rcode = getUserNodeRef(request, username_string, &shortUserName, &userNodeRef, dsRef);
+ if (rcode != RLM_MODULE_OK) {
+ if (rcode != RLM_MODULE_NOOP) {
+ RDEBUG2("od_mschap_auth: getUserNodeRef() failed");
+ }
+ if (username_string != NULL)
+ talloc_free(username_string);
+ if (dsRef != 0)
+ dsCloseDirService(dsRef);
+ return rcode;
+ }
+
+ /* We got a node; fill the stepBuffer
+ kDSStdAuthMSCHAP2
+ MS-CHAPv2 authentication method. The Open Directory plug-in generates the reply data for the client.
+ The input buffer format consists of
+ a four byte length specifying the length of the user name that follows, the user name,
+ a four byte value specifying the length of the server challenge that follows, the server challenge,
+ a four byte value specifying the length of the peer challenge that follows, the peer challenge,
+ a four byte value specifying the length of the client's digest that follows, and the client's digest.
+ The output buffer consists of a four byte value specifying the length of the return digest for the client's challenge.
+ r = FillAuthBuff(pAuthBuff, 5,
+ strlen(inName), inName, // Directory Services long or short name
+ strlen(schal), schal, // server challenge
+ strlen(peerchal), peerchal, // client challenge
+ strlen(p24), p24, // P24 NT-Response
+ 4, "User"); // must match the username that was used for the hash
+
+ inName = username_string
+ schal = challenge->vp_strvalue
+ peerchal = response->vp_strvalue + 2 (16 octets)
+ p24 = response->vp_strvalue + 26 (24 octets)
+ */
+
+ pStepBuff = dsDataBufferAllocate(dsRef, 4096);
+ tDataBuff = dsDataBufferAllocate(dsRef, 4096);
+ pAuthType = dsDataNodeAllocateString(dsRef, kDSStdAuthMSCHAP2);
+ uiCurr = 0;
+
+ /* User name length + username */
+ uiLen = (uint32_t)(shortUserName ? strlen(shortUserName) : 0);
+
+ RDEBUG2("OD username_string = %s, OD shortUserName=%s (length = %d)\n",
+ username_string, shortUserName, uiLen);
+
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
+ uiCurr += sizeof(uiLen);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), shortUserName, uiLen);
+ uiCurr += uiLen;
+#ifndef NDEBUG
+ RINDENT();
+ RDEBUG2("Stepbuf server challenge : ");
+ for (t = 0; t < challenge->vp_length; t++) {
+ fprintf(stderr, "%02x", (unsigned int) challenge->vp_strvalue[t]);
+ }
+ fprintf(stderr, "\n");
+#endif
+
+ /* server challenge (ie. my (freeRADIUS) challenge) */
+ uiLen = 16;
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
+ uiCurr += sizeof(uiLen);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &(challenge->vp_strvalue[0]),
+ uiLen);
+ uiCurr += uiLen;
+
+#ifndef NDEBUG
+ RDEBUG2("Stepbuf peer challenge : ");
+ for (t = 2; t < 18; t++) {
+ fprintf(stderr, "%02x", (unsigned int) response->vp_strvalue[t]);
+ }
+ fprintf(stderr, "\n");
+#endif
+
+ /* peer challenge (ie. the client-generated response) */
+ uiLen = 16;
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
+ uiCurr += sizeof(uiLen);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[2]),
+ uiLen);
+ uiCurr += uiLen;
+
+#ifndef NDEBUG
+ RDEBUG2("Stepbuf p24 : ");
+ REXDENT();
+ for (t = 26; t < 50; t++) {
+ fprintf(stderr, "%02x", (unsigned int) response->vp_strvalue[t]);
+ }
+ fprintf(stderr, "\n");
+#endif
+
+ /* p24 (ie. second part of client-generated response) */
+ uiLen = 24; /* strlen(&(response->vp_strvalue[26])); may contain NULL byte in the middle. */
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
+ uiCurr += sizeof(uiLen);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &(response->vp_strvalue[26]),
+ uiLen);
+ uiCurr += uiLen;
+
+ /* Client generated use name (short name?) */
+ uiLen = (uint32_t)strlen(username_string);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), &uiLen, sizeof(uiLen));
+ uiCurr += sizeof(uiLen);
+ memcpy(&(tDataBuff->fBufferData[uiCurr]), username_string, uiLen);
+ uiCurr += uiLen;
+
+ tDataBuff->fBufferLength = uiCurr;
+
+ status = dsDoDirNodeAuth(userNodeRef, pAuthType, 1, tDataBuff,
+ pStepBuff, NULL);
+ if (status == eDSNoErr) {
+ if (pStepBuff->fBufferLength > 4) {
+ uint32_t len;
+
+ memcpy(&len, pStepBuff->fBufferData, sizeof(len));
+ if (len == 40) {
+ char mschap_reply[42] = { '\0' };
+ mschap_reply[0] = 'S';
+ mschap_reply[1] = '=';
+ memcpy(&(mschap_reply[2]), &(pStepBuff->fBufferData[4]), len);
+ mschap_add_reply(request,
+ *response->vp_strvalue,
+ "MS-CHAP2-Success",
+ mschap_reply, len+2);
+ RDEBUG2("dsDoDirNodeAuth returns stepbuff: %s (len=%u)\n", mschap_reply, (unsigned int) len);
+ }
+ }
+ }
+
+ /* clean up */
+ if (username_string != NULL)
+ talloc_free(username_string);
+ if (shortUserName != NULL)
+ talloc_free(shortUserName);
+
+ if (tDataBuff != NULL)
+ dsDataBufferDeAllocate(dsRef, tDataBuff);
+ if (pStepBuff != NULL)
+ dsDataBufferDeAllocate(dsRef, pStepBuff);
+ if (pAuthType != NULL)
+ dsDataNodeDeAllocate(dsRef, pAuthType);
+ if (userNodeRef != 0)
+ dsCloseDirNode(userNodeRef);
+ if (dsRef != 0)
+ dsCloseDirService(dsRef);
+
+ if (status != eDSNoErr) {
+ char *status_name = dsCopyDirStatusName(status);
+ RERROR("rlm_mschap: authentication failed - status = %s", status_name);
+ free(status_name);
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+#endif /* __APPLE__ */
diff --git a/src/modules/rlm_mschap/rlm_mschap.c b/src/modules/rlm_mschap/rlm_mschap.c
new file mode 100644
index 0000000..00ab90d
--- /dev/null
+++ b/src/modules/rlm_mschap/rlm_mschap.c
@@ -0,0 +1,2150 @@
+/*
+ * 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_mschap.c
+ * @brief Implemented mschap authentication.
+ *
+ * @copyright 2000,2001,2006 The FreeRADIUS server project
+ */
+
+/* MPPE support from Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp> */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/sha1.h>
+
+#include <ctype.h>
+
+#include "rlm_mschap.h"
+#include "mschap.h"
+#include "smbdes.h"
+
+#ifdef WITH_AUTH_WINBIND
+#include "auth_wbclient.h"
+#endif
+
+#ifdef HAVE_OPENSSL_CRYPTO_H
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+# include <openssl/rc4.h>
+#endif
+
+#ifdef __APPLE__
+int od_mschap_auth(REQUEST *request, VALUE_PAIR *challenge, VALUE_PAIR * usernamepair);
+#endif
+
+/* Allowable account control bits */
+#define ACB_DISABLED 0x00010000 //!< User account disabled.
+#define ACB_HOMDIRREQ 0x00020000 //!< Home directory required.
+#define ACB_PWNOTREQ 0x00040000 //!< User password not required.
+#define ACB_TEMPDUP 0x00080000 //!< Temporary duplicate account.
+#define ACB_NORMAL 0x00100000 //!< Normal user account.
+#define ACB_MNS 0x00200000 //!< MNS logon user account.
+#define ACB_DOMTRUST 0x00400000 //!< Interdomain trust account.
+#define ACB_WSTRUST 0x00800000 //!< Workstation trust account.
+#define ACB_SVRTRUST 0x01000000 //!< Server trust account.
+#define ACB_PWNOEXP 0x02000000 //!< User password does not expire.
+#define ACB_AUTOLOCK 0x04000000 //!< Account auto locked.
+#define ACB_PW_EXPIRED 0x00020000 //!< Password Expired.
+
+static int pdb_decode_acct_ctrl(char const *p)
+{
+ int acct_ctrl = 0;
+ int done = 0;
+
+ /*
+ * Check if the account type bits have been encoded after the
+ * NT password (in the form [NDHTUWSLXI]).
+ */
+
+ if (*p != '[') return 0;
+
+ for (p++; *p && !done; p++) {
+ switch (*p) {
+ case 'N': /* 'N'o password. */
+ acct_ctrl |= ACB_PWNOTREQ;
+ break;
+
+ case 'D': /* 'D'isabled. */
+ acct_ctrl |= ACB_DISABLED ;
+ break;
+
+ case 'H': /* 'H'omedir required. */
+ acct_ctrl |= ACB_HOMDIRREQ;
+ break;
+
+ case 'T': /* 'T'emp account. */
+ acct_ctrl |= ACB_TEMPDUP;
+ break;
+
+ case 'U': /* 'U'ser account (normal). */
+ acct_ctrl |= ACB_NORMAL;
+ break;
+
+ case 'M': /* 'M'NS logon user account. What is this? */
+ acct_ctrl |= ACB_MNS;
+ break;
+
+ case 'W': /* 'W'orkstation account. */
+ acct_ctrl |= ACB_WSTRUST;
+ break;
+
+ case 'S': /* 'S'erver account. */
+ acct_ctrl |= ACB_SVRTRUST;
+ break;
+
+ case 'L': /* 'L'ocked account. */
+ acct_ctrl |= ACB_AUTOLOCK;
+ break;
+
+ case 'X': /* No 'X'piry on password */
+ acct_ctrl |= ACB_PWNOEXP;
+ break;
+
+ case 'I': /* 'I'nterdomain trust account. */
+ acct_ctrl |= ACB_DOMTRUST;
+ break;
+
+ case 'e': /* 'e'xpired, the password has */
+ acct_ctrl |= ACB_PW_EXPIRED;
+ break;
+
+ case ' ': /* ignore spaces */
+ break;
+
+ case ':':
+ case '\n':
+ case '\0':
+ case ']':
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ return acct_ctrl;
+}
+
+
+/*
+ * Does dynamic translation of strings.
+ *
+ * Pulls NT-Response, LM-Response, or Challenge from MSCHAP
+ * attributes.
+ */
+static ssize_t mschap_xlat(void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ size_t i, data_len;
+ uint8_t const *data = NULL;
+ uint8_t buffer[32];
+ VALUE_PAIR *user_name;
+ VALUE_PAIR *chap_challenge, *response;
+ rlm_mschap_t *inst = instance;
+
+ response = NULL;
+
+ /*
+ * Challenge means MS-CHAPv1 challenge, or
+ * hash of MS-CHAPv2 challenge, and peer challenge.
+ */
+ if (strncasecmp(fmt, "Challenge", 9) == 0) {
+ chap_challenge = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!chap_challenge) {
+ REDEBUG("No MS-CHAP-Challenge in the request");
+ return -1;
+ }
+
+ /*
+ * MS-CHAP-Challenges are 8 octets,
+ * for MS-CHAPv1
+ */
+ if (chap_challenge->vp_length == 8) {
+ RDEBUG2("mschap1: %02x", chap_challenge->vp_octets[0]);
+ data = chap_challenge->vp_octets;
+ data_len = 8;
+
+ /*
+ * MS-CHAP-Challenges are 16 octets,
+ * for MS-CHAPv2.
+ */
+ } else if (chap_challenge->vp_length == 16) {
+ VALUE_PAIR *name_attr, *response_name;
+ char const *username_string;
+
+ response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!response) {
+ REDEBUG("MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge");
+ return -1;
+ }
+
+ /*
+ * FIXME: Much of this is copied from
+ * below. We should put it into a
+ * separate function.
+ */
+
+ /*
+ * Responses are 50 octets.
+ */
+ if (response->vp_length < 50) {
+ REDEBUG("MS-CHAP-Response has the wrong format");
+ return -1;
+ }
+
+ user_name = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!user_name) {
+ REDEBUG("User-Name is required to calculate MS-CHAPv1 Challenge");
+ return -1;
+ }
+
+ /*
+ * Check for MS-CHAP-User-Name and if found, use it
+ * to construct the MSCHAPv1 challenge. This is
+ * set by rlm_eap_mschap to the MS-CHAP Response
+ * packet Name field.
+ *
+ * We prefer this to the User-Name in the
+ * packet.
+ */
+ response_name = fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_USER_NAME, 0, TAG_ANY);
+ if (response_name) {
+ name_attr = response_name;
+ } else {
+ name_attr = user_name;
+ }
+
+ /*
+ * with_ntdomain_hack moved here, too.
+ */
+ if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
+ if (inst->with_ntdomain_hack) {
+ username_string++;
+ } else {
+ RWDEBUG2("NT Domain delimiter found, should we have enabled with_ntdomain_hack?");
+ username_string = name_attr->vp_strvalue;
+ }
+ } else {
+ username_string = name_attr->vp_strvalue;
+ }
+
+ if (response_name &&
+ ((user_name->vp_length != response_name->vp_length) ||
+ (strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue,
+ user_name->vp_length) != 0))) {
+ RWDEBUG2("User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2",
+ user_name->vp_strvalue, response_name->vp_strvalue);
+ }
+
+ /*
+ * Get the MS-CHAPv1 challenge
+ * from the MS-CHAPv2 peer challenge,
+ * our challenge, and the user name.
+ */
+ RDEBUG2("Creating challenge hash with username: %s", username_string);
+ mschap_challenge_hash(response->vp_octets + 2,
+ chap_challenge->vp_octets,
+ username_string, buffer);
+ data = buffer;
+ data_len = 8;
+ } else {
+ REDEBUG("Invalid MS-CHAP challenge length");
+ return -1;
+ }
+
+ /*
+ * Get the MS-CHAPv1 response, or the MS-CHAPv2
+ * response.
+ */
+ } else if (strncasecmp(fmt, "NT-Response", 11) == 0) {
+ response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!response) response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!response) {
+ REDEBUG("No MS-CHAP-Response or MS-CHAP2-Response was found in the request");
+ return -1;
+ }
+
+ /*
+ * For MS-CHAPv1, the NT-Response exists only
+ * if the second octet says so.
+ */
+ if ((response->da->vendor == VENDORPEC_MICROSOFT) &&
+ (response->da->attr == PW_MSCHAP_RESPONSE) &&
+ ((response->vp_octets[1] & 0x01) == 0)) {
+ REDEBUG("No NT-Response in MS-CHAP-Response");
+ return -1;
+ }
+
+ /*
+ * MS-CHAP-Response and MS-CHAP2-Response have
+ * the NT-Response at the same offset, and are
+ * the same length.
+ */
+ data = response->vp_octets + 26;
+ data_len = 24;
+
+ /*
+ * LM-Response is deprecated, and exists only
+ * in MS-CHAPv1, and not often there.
+ */
+ } else if (strncasecmp(fmt, "LM-Response", 11) == 0) {
+ response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!response) {
+ REDEBUG("No MS-CHAP-Response was found in the request");
+ return -1;
+ }
+
+ /*
+ * For MS-CHAPv1, the LM-Response exists only
+ * if the second octet says so.
+ */
+ if ((response->vp_octets[1] & 0x01) != 0) {
+ REDEBUG("No LM-Response in MS-CHAP-Response");
+ return -1;
+ }
+ data = response->vp_octets + 2;
+ data_len = 24;
+
+ /*
+ * Pull the domain name out of the User-Name, if it exists.
+ *
+ * This is the full domain name, not just the name after host/
+ */
+ } else if (strncasecmp(fmt, "Domain-Name", 11) == 0) {
+ char *p;
+
+ user_name = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!user_name) {
+ REDEBUG("No User-Name was found in the request");
+ return -1;
+ }
+
+ /*
+ * First check to see if this is a host/ style User-Name
+ * (a la Kerberos host principal)
+ */
+ if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
+ /*
+ * If we're getting a User-Name formatted in this way,
+ * it's likely due to PEAP. The Windows Domain will be
+ * the first domain component following the hostname,
+ * or the machine name itself if only a hostname is supplied
+ */
+ p = strchr(user_name->vp_strvalue, '.');
+ if (!p) {
+ RDEBUG2("setting NT-Domain to same as machine name");
+ strlcpy(out, user_name->vp_strvalue + 5, outlen);
+ } else {
+ p++; /* skip the period */
+ strlcpy(out, p, outlen);
+ }
+ } else {
+ p = strchr(user_name->vp_strvalue, '\\');
+ if (!p) {
+ REDEBUG("No NT-Domain was found in the User-Name");
+ return -1;
+ }
+
+ /*
+ * Hack. This is simpler than the alternatives.
+ */
+ *p = '\0';
+ strlcpy(out, user_name->vp_strvalue, outlen);
+ *p = '\\';
+ }
+
+ return strlen(out);
+
+ /*
+ * Pull the NT-Domain out of the User-Name, if it exists.
+ */
+ } else if (strncasecmp(fmt, "NT-Domain", 9) == 0) {
+ char *p, *q;
+
+ user_name = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!user_name) {
+ REDEBUG("No User-Name was found in the request");
+ return -1;
+ }
+
+ /*
+ * First check to see if this is a host/ style User-Name
+ * (a la Kerberos host principal)
+ */
+ if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
+ /*
+ * If we're getting a User-Name formatted in this way,
+ * it's likely due to PEAP. The Windows Domain will be
+ * the first domain component following the hostname,
+ * or the machine name itself if only a hostname is supplied
+ */
+ p = strchr(user_name->vp_strvalue, '.');
+ if (!p) {
+ RDEBUG2("setting NT-Domain to same as machine name");
+ strlcpy(out, user_name->vp_strvalue + 5, outlen);
+ } else {
+ p++; /* skip the period */
+ q = strchr(p, '.');
+ /*
+ * use the same hack as below
+ * only if another period was found
+ */
+ if (q) *q = '\0';
+ strlcpy(out, p, outlen);
+ if (q) *q = '.';
+ }
+ } else {
+ p = strchr(user_name->vp_strvalue, '\\');
+ if (!p) {
+ REDEBUG("No NT-Domain was found in the User-Name");
+ return -1;
+ }
+
+ /*
+ * Hack. This is simpler than the alternatives.
+ */
+ *p = '\0';
+ strlcpy(out, user_name->vp_strvalue, outlen);
+ *p = '\\';
+ }
+
+ return strlen(out);
+
+ /*
+ * Pull the User-Name out of the User-Name...
+ */
+ } else if (strncasecmp(fmt, "User-Name", 9) == 0) {
+ char const *p, *q;
+
+ user_name = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!user_name) {
+ REDEBUG("No User-Name was found in the request");
+ return -1;
+ }
+
+ /*
+ * First check to see if this is a host/ style User-Name
+ * (a la Kerberos host principal)
+ */
+ if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) {
+ p = user_name->vp_strvalue + 5;
+ /*
+ * If we're getting a User-Name formatted in this way,
+ * it's likely due to PEAP. When authenticating this against
+ * a Domain, Windows will expect the User-Name to be in the
+ * format of hostname$, the SAM version of the name, so we
+ * have to convert it to that here. We do so by stripping
+ * off the first 5 characters (host/), and copying everything
+ * from that point to the first period into a string and appending
+ * a $ to the end.
+ */
+ q = strchr(p, '.');
+
+ /*
+ * use the same hack as above
+ * only if a period was found
+ */
+ if (q) {
+ snprintf(out, outlen, "%.*s$",
+ (int) (q - p), p);
+ } else {
+ snprintf(out, outlen, "%s$", p);
+ }
+ } else {
+ p = strchr(user_name->vp_strvalue, '\\');
+ if (p) {
+ p++; /* skip the backslash */
+ } else {
+ p = user_name->vp_strvalue; /* use the whole User-Name */
+ }
+ strlcpy(out, p, outlen);
+ }
+
+ return strlen(out);
+
+ /*
+ * Return the NT-Hash of the passed string
+ */
+ } else if (strncasecmp(fmt, "NT-Hash ", 8) == 0) {
+ char const *p;
+
+ p = fmt + 8; /* 7 is the length of 'NT-Hash' */
+ if ((*p == '\0') || (outlen <= 32))
+ return 0;
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if (mschap_ntpwdhash(buffer, p) < 0) {
+ REDEBUG("Failed generating NT-Password");
+ *buffer = '\0';
+ return -1;
+ }
+
+ fr_bin2hex(out, buffer, NT_DIGEST_LENGTH);
+ out[32] = '\0';
+ RDEBUG("NT-Hash of \"known-good\" password: %s", out);
+ return 32;
+
+ /*
+ * Return the LM-Hash of the passed string
+ */
+ } else if (strncasecmp(fmt, "LM-Hash ", 8) == 0) {
+ char const *p;
+
+ p = fmt + 8; /* 7 is the length of 'LM-Hash' */
+ if ((*p == '\0') || (outlen <= 32))
+ return 0;
+
+ while (isspace((uint8_t) *p)) p++;
+
+ smbdes_lmpwdhash(p, buffer);
+ fr_bin2hex(out, buffer, LM_DIGEST_LENGTH);
+ out[32] = '\0';
+ RDEBUG("LM-Hash of %s = %s", p, out);
+ return 32;
+ } else {
+ REDEBUG("Unknown expansion string '%s'", fmt);
+ return -1;
+ }
+
+ if (outlen == 0) return 0; /* nowhere to go, don't do anything */
+
+ /*
+ * Didn't set anything: this is bad.
+ */
+ if (!data) {
+ RWDEBUG2("Failed to do anything intelligent");
+ return 0;
+ }
+
+ /*
+ * Check the output length.
+ */
+ if (outlen < ((data_len * 2) + 1)) {
+ data_len = (outlen - 1) / 2;
+ }
+
+ /*
+ *
+ */
+ for (i = 0; i < data_len; i++) {
+ sprintf(out + (2 * i), "%02x", data[i]);
+ }
+ out[data_len * 2] = '\0';
+
+ return data_len * 2;
+}
+
+
+#ifdef WITH_AUTH_WINBIND
+/*
+ * Free connection pool winbind context
+ */
+static int _mod_conn_free(struct wbcContext **wb_ctx)
+{
+ wbcCtxFree(*wb_ctx);
+
+ return 0;
+}
+
+/*
+ * Create connection pool winbind context
+ */
+static void *mod_conn_create(TALLOC_CTX *ctx, UNUSED void *instance)
+{
+ struct wbcContext **wb_ctx;
+
+ wb_ctx = talloc_zero(ctx, struct wbcContext *);
+ *wb_ctx = wbcCtxCreate();
+
+ if (*wb_ctx == NULL) {
+ ERROR("failed to create winbind context");
+ talloc_free(wb_ctx);
+ return NULL;
+ }
+
+ talloc_set_destructor(wb_ctx, _mod_conn_free);
+
+ return *wb_ctx;
+}
+#endif
+
+
+static const CONF_PARSER passchange_config[] = {
+ { "ntlm_auth", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_mschap_t, ntlm_cpw), NULL },
+ { "ntlm_auth_username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_mschap_t, ntlm_cpw_username), NULL },
+ { "ntlm_auth_domain", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_mschap_t, ntlm_cpw_domain), NULL },
+ { "local_cpw", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_mschap_t, local_cpw), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER module_config[] = {
+ /*
+ * Cache the password by default.
+ */
+ { "use_mppe", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, use_mppe), "yes" },
+ { "require_encryption", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, require_encryption), "no" },
+ { "require_strong", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, require_strong), "no" },
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, with_ntdomain_hack), "yes" },
+ { "ntlm_auth", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_mschap_t, ntlm_auth), NULL },
+ { "ntlm_auth_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_mschap_t, ntlm_auth_timeout), NULL },
+ { "passchange", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) passchange_config },
+ { "allow_retry", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, allow_retry), "yes" },
+ { "retry_msg", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_mschap_t, retry_msg), NULL },
+ { "winbind_username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_mschap_t, wb_username), NULL },
+ { "winbind_domain", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_TMPL, rlm_mschap_t, wb_domain), NULL },
+ { "winbind_retry_with_normalised_username", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, wb_retry_with_normalised_username), "no" },
+#ifdef __APPLE__
+ { "use_open_directory", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_mschap_t, open_directory), "yes" },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ char const *name;
+ rlm_mschap_t *inst = instance;
+
+ /*
+ * Create the dynamic translation.
+ */
+ name = cf_section_name2(conf);
+ if (!name) name = cf_section_name1(conf);
+ inst->xlat_name = name;
+ xlat_register(inst->xlat_name, mschap_xlat, NULL, inst);
+
+ return 0;
+}
+
+/*
+ * Create instance for our module. Allocate space for
+ * instance structure and read configuration parameters
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_mschap_t *inst = instance;
+
+ /*
+ * For backwards compatibility
+ */
+ if (!dict_valbyname(PW_AUTH_TYPE, 0, inst->xlat_name)) {
+ inst->auth_type = "MS-CHAP";
+ } else {
+ inst->auth_type = inst->xlat_name;
+ }
+
+ /*
+ * Set auth method
+ */
+ inst->method = AUTH_INTERNAL;
+
+ if (inst->wb_username) {
+#ifdef WITH_AUTH_WINBIND
+ inst->method = AUTH_WBCLIENT;
+
+ inst->wb_pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, NULL);
+ if (!inst->wb_pool) {
+ cf_log_err_cs(conf, "Unable to initialise winbind connection pool");
+ return -1;
+ }
+#else
+ cf_log_err_cs(conf, "'winbind' is not enabled in this build.");
+ return -1;
+#endif
+ }
+
+ /* preserve existing behaviour: this option overrides all */
+ if (inst->ntlm_auth) {
+ inst->method = AUTH_NTLMAUTH_EXEC;
+ }
+
+ switch (inst->method) {
+ case AUTH_INTERNAL:
+ DEBUG("rlm_mschap (%s): using internal authentication", inst->xlat_name);
+ break;
+ case AUTH_NTLMAUTH_EXEC:
+ DEBUG("rlm_mschap (%s): authenticating by calling 'ntlm_auth'", inst->xlat_name);
+ break;
+#ifdef WITH_AUTH_WINBIND
+ case AUTH_WBCLIENT:
+ DEBUG("rlm_mschap (%s): authenticating directly to winbind", inst->xlat_name);
+ break;
+#endif
+ }
+
+ /*
+ * Check ntlm_auth_timeout is sane
+ */
+ if (!inst->ntlm_auth_timeout) {
+ inst->ntlm_auth_timeout = EXEC_TIMEOUT;
+ }
+ if (inst->ntlm_auth_timeout < 1) {
+ cf_log_err_cs(conf, "ntml_auth_timeout '%d' is too small (minimum: 1)",
+ inst->ntlm_auth_timeout);
+ return -1;
+ }
+ if (inst->ntlm_auth_timeout > 10) {
+ cf_log_err_cs(conf, "ntlm_auth_timeout '%d' is too large (maximum: 10)",
+ inst->ntlm_auth_timeout);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Tidy up instance
+ */
+static int mod_detach(UNUSED void *instance)
+{
+#ifdef WITH_AUTH_WINBIND
+ rlm_mschap_t *inst = instance;
+
+ fr_connection_pool_free(inst->wb_pool);
+#endif
+
+ return 0;
+}
+
+/*
+ * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
+ * attribute to reply packet
+ */
+void mschap_add_reply(REQUEST *request, unsigned char ident,
+ char const *name, char const *value, size_t len)
+{
+ VALUE_PAIR *vp;
+
+ vp = pair_make_reply(name, NULL, T_OP_EQ);
+ if (!vp) {
+ REDEBUG("Failed to create attribute %s: %s", name, fr_strerror());
+ return;
+ }
+
+ /* Account for the ident byte */
+ vp->vp_length = len + 1;
+ if (vp->da->type == PW_TYPE_STRING) {
+ char *p;
+
+ vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
+ p[vp->vp_length] = '\0'; /* Always \0 terminate */
+ p[0] = ident;
+ memcpy(p + 1, value, len);
+ } else {
+ uint8_t *p;
+
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+ p[0] = ident;
+ memcpy(p + 1, value, len);
+ }
+}
+
+/*
+ * Add MPPE attributes to the reply.
+ */
+static void mppe_add_reply(REQUEST *request, char const* name, uint8_t const * value, size_t len)
+{
+ VALUE_PAIR *vp;
+
+ vp = pair_make_reply(name, NULL, T_OP_EQ);
+ if (!vp) {
+ REDEBUG("mppe_add_reply failed to create attribute %s: %s", name, fr_strerror());
+ return;
+ }
+
+ fr_pair_value_memcpy(vp, value, len);
+}
+
+static int write_all(int fd, char const *buf, int len) {
+ int rv,done=0;
+
+ while (done < len) {
+ rv = write(fd, buf+done, len-done);
+ if (rv <= 0)
+ break;
+ done += rv;
+ }
+ return done;
+}
+
+/*
+ * Perform an MS-CHAP2 password change
+ */
+
+static int CC_HINT(nonnull (1, 2, 4, 5)) do_mschap_cpw(rlm_mschap_t *inst,
+ REQUEST *request,
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ VALUE_PAIR *nt_password,
+#else
+ UNUSED VALUE_PAIR *nt_password,
+#endif
+ uint8_t *new_nt_password,
+ uint8_t *old_nt_hash,
+ MSCHAP_AUTH_METHOD method)
+{
+ if (inst->ntlm_cpw && method != AUTH_INTERNAL) {
+ /*
+ * we're going to run ntlm_auth in helper-mode
+ * we're expecting to use the ntlm-change-password-1 protocol
+ * which needs the following on stdin:
+ *
+ * username: %{mschap:User-Name}
+ * nt-domain: %{mschap:NT-Domain}
+ * new-nt-password-blob: bin2hex(new_nt_password) - 1032 bytes encoded
+ * old-nt-hash-blob: bin2hex(old_nt_hash) - 32 bytes encoded
+ * new-lm-password-blob: 00000...0000 - 1032 bytes null
+ * old-lm-hash-blob: 000....000 - 32 bytes null
+ * .\n
+ *
+ * ...and it should then print out
+ *
+ * Password-Change: Yes
+ *
+ * or
+ *
+ * Password-Change: No
+ * Password-Change-Error: blah
+ */
+
+ int to_child=-1;
+ int from_child=-1;
+ pid_t pid, child_pid;
+ int status, len;
+ char buf[2048];
+ char *pmsg;
+ char const *emsg;
+
+ RDEBUG("Doing MS-CHAPv2 password change via ntlm_auth helper");
+
+ /*
+ * Start up ntlm_auth with a pipe on stdin and stdout
+ */
+
+ pid = radius_start_program(inst->ntlm_cpw, request, true, &to_child, &from_child, NULL, false);
+ if (pid < 0) {
+ REDEBUG("could not exec ntlm_auth cpw command");
+ return -1;
+ }
+
+ /*
+ * write the stuff to the client
+ */
+
+ if (inst->ntlm_cpw_username) {
+ len = radius_xlat(buf, sizeof(buf) - 2, request, inst->ntlm_cpw_username, NULL, NULL);
+ if (len < 0) {
+ goto ntlm_auth_err;
+ }
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
+ if (write_all(to_child, buf, len) != len) {
+ REDEBUG("Failed to write username to child");
+ goto ntlm_auth_err;
+ }
+ } else {
+ RWDEBUG2("No ntlm_auth username set, passchange will definitely fail!");
+ }
+
+ if (inst->ntlm_cpw_domain) {
+ len = radius_xlat(buf, sizeof(buf) - 2, request, inst->ntlm_cpw_domain, NULL, NULL);
+ if (len < 0) {
+ goto ntlm_auth_err;
+ }
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
+ if (write_all(to_child, buf, len) != len) {
+ REDEBUG("Failed to write domain to child");
+ goto ntlm_auth_err;
+ }
+ } else {
+ RWDEBUG2("No ntlm_auth domain set, username must be full-username to work");
+ }
+
+ /* now the password blobs */
+ len = sprintf(buf, "new-nt-password-blob: ");
+ fr_bin2hex(buf+len, new_nt_password, 516);
+ buf[len+1032] = '\n';
+ buf[len+1033] = '\0';
+ len = strlen(buf);
+ if (write_all(to_child, buf, len) != len) {
+ RDEBUG2("failed to write new password blob to child");
+ goto ntlm_auth_err;
+ }
+
+ len = sprintf(buf, "old-nt-hash-blob: ");
+ fr_bin2hex(buf+len, old_nt_hash, NT_DIGEST_LENGTH);
+ buf[len+32] = '\n';
+ buf[len+33] = '\0';
+ len = strlen(buf);
+ if (write_all(to_child, buf, len) != len) {
+ REDEBUG("Failed to write old hash blob to child");
+ goto ntlm_auth_err;
+ }
+
+ /*
+ * In current samba versions, failure to supply empty LM password/hash
+ * blobs causes the change to fail.
+ */
+ len = sprintf(buf, "new-lm-password-blob: %01032i\n", 0);
+ if (write_all(to_child, buf, len) != len) {
+ REDEBUG("Failed to write dummy LM password to child");
+ goto ntlm_auth_err;
+ }
+ len = sprintf(buf, "old-lm-hash-blob: %032i\n", 0);
+ if (write_all(to_child, buf, len) != len) {
+ REDEBUG("Failed to write dummy LM hash to child");
+ goto ntlm_auth_err;
+ }
+ if (write_all(to_child, ".\n", 2) != 2) {
+ REDEBUG("Failed to send finish to child");
+ goto ntlm_auth_err;
+ }
+ close(to_child);
+ to_child = -1;
+
+ /*
+ * Read from the child
+ */
+ len = radius_readfrom_program(from_child, pid, 10, buf, sizeof(buf));
+ if (len < 0) {
+ /* radius_readfrom_program will have closed from_child for us */
+ REDEBUG("Failure reading from child");
+ return -1;
+ }
+ close(from_child);
+ from_child = -1;
+
+ buf[len] = 0;
+ RDEBUG2("ntlm_auth said: %s", buf);
+
+ child_pid = rad_waitpid(pid, &status);
+ if (child_pid == 0) {
+ REDEBUG("Timeout waiting for child");
+ return -1;
+ }
+ if (child_pid != pid) {
+ REDEBUG("Abnormal exit status: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ if (strstr(buf, "Password-Change: Yes")) {
+ RDEBUG2("ntlm_auth password change succeeded");
+ return 0;
+ }
+
+ pmsg = strstr(buf, "Password-Change-Error: ");
+ if (pmsg) {
+ emsg = strsep(&pmsg, "\n");
+ } else {
+ emsg = "could not find error";
+ }
+ REDEBUG("ntlm auth password change failed: %s", emsg);
+
+ntlm_auth_err:
+ /* safe because these either need closing or are == -1 */
+ close(to_child);
+ close(from_child);
+
+ return -1;
+
+ } else if (inst->local_cpw) {
+#ifdef HAVE_OPENSSL_CRYPTO_H
+ /*
+ * Decrypt the new password blob, add it as a temporary request
+ * variable, xlat the local_cpw string, then remove it
+ *
+ * this allows is to write e..g
+ *
+ * %{sql:insert into ...}
+ *
+ * ...or...
+ *
+ * %{exec:/path/to %{mschap:User-Name} %{MS-CHAP-New-Password}}"
+ *
+ */
+ VALUE_PAIR *new_pass, *new_hash;
+ uint8_t *p, *q;
+ char *x;
+ size_t i;
+ size_t passlen;
+ ssize_t result_len;
+ char result[253];
+ uint8_t nt_pass_decrypted[516], old_nt_hash_expected[NT_DIGEST_LENGTH];
+
+ if (!nt_password) {
+ RDEBUG("Local MS-CHAPv2 password change requires NT-Password attribute");
+ return -1;
+ } else {
+ RDEBUG("Doing MS-CHAPv2 password change locally");
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ {
+ EVP_CIPHER_CTX *ctx;
+ int ntlen = sizeof(nt_pass_decrypted);
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx) {
+ REDEBUG("Failed getting RC4 from OpenSSL");
+ error:
+ if (ctx) EVP_CIPHER_CTX_free(ctx);
+ return -1;
+ }
+
+ if (!EVP_CIPHER_CTX_set_key_length(ctx, nt_password->vp_length)) {
+ REDEBUG("Failed setting key length");
+ goto error;
+ }
+
+ if (!EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, nt_password->vp_octets, NULL)) {
+ REDEBUG("Failed setting key value");
+ goto error;;
+ }
+
+ if (!EVP_EncryptUpdate(ctx, nt_pass_decrypted, &ntlen, new_nt_password, ntlen)) {
+ REDEBUG("Failed getting output");
+ goto error;
+ }
+
+ EVP_CIPHER_CTX_free(ctx);
+ }
+#else
+ {
+ RC4_KEY key;
+
+ /*
+ * Decrypt the blob
+ */
+ RC4_set_key(&key, nt_password->vp_length, nt_password->vp_octets);
+ RC4(&key, 516, new_nt_password, nt_pass_decrypted);
+ }
+#endif
+
+ /*
+ * pwblock is
+ * 512-N bytes random pad
+ * N bytes password as utf-16-le
+ * 4 bytes - N as big-endian int
+ */
+ passlen = nt_pass_decrypted[512];
+ passlen += nt_pass_decrypted[513] << 8;
+ if ((nt_pass_decrypted[514] != 0) ||
+ (nt_pass_decrypted[515] != 0)) {
+ REDEBUG("Decrypted new password blob claims length > 65536, "
+ "probably an invalid NT-Password");
+ return -1;
+ }
+
+ /*
+ * Sanity check - passlen positive and <= 512 if not, crypto has probably gone wrong
+ */
+ if (passlen > 512) {
+ REDEBUG("Decrypted new password blob claims length %zu > 512, "
+ "probably an invalid NT-Password", passlen);
+ return -1;
+ }
+
+ p = nt_pass_decrypted + 512 - passlen;
+
+ /*
+ * The new NT hash - this should be preferred over the
+ * cleartext password as it avoids unicode hassles.
+ */
+ new_hash = pair_make_request("MS-CHAP-New-NT-Password", NULL, T_OP_EQ);
+ new_hash->vp_length = NT_DIGEST_LENGTH;
+ new_hash->vp_octets = q = talloc_array(new_hash, uint8_t, new_hash->vp_length);
+ fr_md4_calc(q, p, passlen);
+
+ /*
+ * Check that nt_password encrypted with new_hash
+ * matches the old_hash value from the client.
+ */
+ smbhash(old_nt_hash_expected, nt_password->vp_octets, q);
+ smbhash(old_nt_hash_expected+8, nt_password->vp_octets+8, q + 7);
+ if (memcmp(old_nt_hash_expected, old_nt_hash, NT_DIGEST_LENGTH)!=0) {
+ REDEBUG("Old NT hash value from client does not match our value");
+ return -1;
+ }
+
+ /*
+ * The new cleartext password, which is utf-16 do some unpleasant vileness
+ * to turn it into utf8 without pulling in libraries like iconv.
+ *
+ * First pass: get the length of the converted string.
+ */
+ new_pass = pair_make_request("MS-CHAP-New-Cleartext-Password", NULL, T_OP_EQ);
+ new_pass->vp_length = 0;
+
+ i = 0;
+ while (i < passlen) {
+ int c;
+
+ c = p[i++];
+ c += p[i++] << 8;
+
+ /*
+ * Gah. nasty. maybe we should just pull in iconv?
+ */
+ if (c < 0x7f) {
+ new_pass->vp_length++;
+ } else if (c < 0x7ff) {
+ new_pass->vp_length += 2;
+ } else {
+ new_pass->vp_length += 3;
+ }
+ }
+
+ new_pass->vp_strvalue = x = talloc_array(new_pass, char, new_pass->vp_length + 1);
+
+ /*
+ * Second pass: convert the characters from UTF-16 to UTF-8.
+ */
+ i = 0;
+ while (i < passlen) {
+ int c;
+
+ c = p[i++];
+ c += p[i++] << 8;
+
+ /*
+ * Gah. nasty. maybe we should just pull in iconv?
+ */
+ if (c < 0x7f) {
+ *x++ = c;
+
+ } else if (c < 0x7ff) {
+ *x++ = 0xc0 + (c >> 6);
+ *x++ = 0x80 + (c & 0x3f);
+
+ } else {
+ *x++ = 0xe0 + (c >> 12);
+ *x++ = 0x80 + ((c>>6) & 0x3f);
+ *x++ = 0x80 + (c & 0x3f);
+ }
+ }
+
+ *x = '\0';
+
+ /* Perform the xlat */
+ result_len = radius_xlat(result, sizeof(result), request, inst->local_cpw, NULL, NULL);
+ if (result_len < 0){
+ return -1;
+ } else if (result_len == 0) {
+ REDEBUG("Local MS-CHAPv2 password change - xlat didn't give any result, assuming failure");
+ return -1;
+ }
+
+ RDEBUG("MS-CHAPv2 password change succeeded: %s", result);
+
+ /*
+ * Update the NT-Password attribute with the new hash this lets us
+ * fall through to the authentication code using the new hash,
+ * not the old one.
+ */
+ fr_pair_value_memcpy(nt_password, new_hash->vp_octets, new_hash->vp_length);
+
+ /*
+ * Rock on! password change succeeded.
+ */
+ return 0;
+#else
+ REDEBUG("Local MS-CHAPv2 password changes require OpenSSL support");
+ return -1;
+#endif
+ } else {
+ REDEBUG("MS-CHAPv2 password change not configured");
+ }
+
+ return -1;
+}
+
+/*
+ * Do the MS-CHAP stuff.
+ *
+ * This function is here so that all of the MS-CHAP related
+ * authentication is in one place, and we can perhaps later replace
+ * it with code to call winbindd, or something similar.
+ */
+static int CC_HINT(nonnull (1, 2, 4, 5 ,6)) do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password,
+ uint8_t const *challenge, uint8_t const *response,
+ uint8_t nthashhash[NT_DIGEST_LENGTH], MSCHAP_AUTH_METHOD method)
+{
+ uint8_t calculated[24];
+
+ memset(nthashhash, 0, NT_DIGEST_LENGTH);
+
+ switch (method) {
+ /*
+ * Do normal authentication.
+ */
+ case AUTH_INTERNAL:
+ /*
+ * No password: can't do authentication.
+ */
+ if (!password) {
+ REDEBUG("FAILED: No NT-Password. Cannot perform authentication");
+ return -1;
+ }
+
+ smbdes_mschap(password->vp_octets, challenge, calculated);
+ if (rad_digest_cmp(response, calculated, 24) != 0) {
+ return -1;
+ }
+
+ /*
+ * If the password exists, and is an NT-Password,
+ * then calculate the hash of the NT hash. Doing this
+ * here minimizes work for later.
+ */
+ if (!password->da->vendor &&
+ (password->da->attr == PW_NT_PASSWORD)) {
+ fr_md4_calc(nthashhash, password->vp_octets, MD4_DIGEST_LENGTH);
+ }
+ break;
+
+ /*
+ * Run ntlm_auth
+ */
+ case AUTH_NTLMAUTH_EXEC: {
+ int result;
+ char buffer[256];
+ size_t len;
+
+ /*
+ * Run the program, and expect that we get 16
+ */
+ result = radius_exec_program(request, buffer, sizeof(buffer), NULL, request, inst->ntlm_auth, NULL,
+ true, true, inst->ntlm_auth_timeout);
+ if (result != 0) {
+ char *p;
+
+ /*
+ * Do checks for numbers, which are
+ * language neutral. They're also
+ * faster.
+ */
+ p = strcasestr(buffer, "0xC0000");
+ if (p) {
+ int rcode = 0;
+
+ p += 7;
+ if (strcmp(p, "224") == 0) {
+ rcode = -648;
+
+ } else if (strcmp(p, "234") == 0) {
+ rcode = -647;
+
+ } else if (strcmp(p, "072") == 0) {
+ rcode = -691;
+
+ } else if (strcasecmp(p, "05E") == 0) {
+ rcode = -2;
+ }
+
+ if (rcode != 0) {
+ REDEBUG2("%s", buffer);
+ return rcode;
+ }
+
+ /*
+ * Else fall through to more ridiculous checks.
+ */
+ }
+
+ /*
+ * Look for variants of expire password.
+ */
+ if (strcasestr(buffer, "0xC0000224") ||
+ strcasestr(buffer, "Password expired") ||
+ strcasestr(buffer, "Password has expired") ||
+ strcasestr(buffer, "Password must be changed") ||
+ strcasestr(buffer, "Must change password")) {
+ return -648;
+ }
+
+ if (strcasestr(buffer, "0xC0000234") ||
+ strcasestr(buffer, "Account locked out")) {
+ REDEBUG2("%s", buffer);
+ return -647;
+ }
+
+ if (strcasestr(buffer, "0xC0000072") ||
+ strcasestr(buffer, "Account disabled")) {
+ REDEBUG2("%s", buffer);
+ return -691;
+ }
+
+ if (strcasestr(buffer, "0xC000005E") ||
+ strcasestr(buffer, "No logon servers")) {
+ REDEBUG2("%s", buffer);
+ return -2;
+ }
+
+ if (strcasestr(buffer, "could not obtain winbind separator") ||
+ strcasestr(buffer, "Reading winbind reply failed")) {
+ REDEBUG2("%s", buffer);
+ return -2;
+ }
+
+ RDEBUG2("External script failed");
+ p = strchr(buffer, '\n');
+ if (p) *p = '\0';
+
+ REDEBUG("External script says: %s", buffer);
+ return -1;
+ }
+
+ /*
+ * Parse the answer as an nthashhash.
+ *
+ * ntlm_auth currently returns:
+ * NT_KEY: 000102030405060708090a0b0c0d0e0f
+ */
+ if (memcmp(buffer, "NT_KEY: ", 8) != 0) {
+ REDEBUG("Invalid output from ntlm_auth: expecting 'NT_KEY: ' prefix");
+ return -1;
+ }
+
+ /*
+ * Check the length. It should be at least 32, with an LF at the end.
+ */
+ len = strlen(buffer + 8);
+ if (len < 32) {
+ REDEBUG2("Invalid output from ntlm_auth: NT_KEY too short, expected 32 bytes got %zu bytes",
+ len);
+
+ return -1;
+ }
+
+ /*
+ * Update the NT hash hash, from the NT key.
+ */
+ if (fr_hex2bin(nthashhash, NT_DIGEST_LENGTH, buffer + 8, len) != NT_DIGEST_LENGTH) {
+ REDEBUG("Invalid output from ntlm_auth: NT_KEY has non-hex values");
+ return -1;
+ }
+ break;
+ }
+
+#ifdef WITH_AUTH_WINBIND
+ /*
+ * Process auth via the wbclient library
+ */
+ case AUTH_WBCLIENT:
+ return do_auth_wbclient(inst, request, challenge, response, nthashhash);
+#endif
+
+ /* We should never reach this line */
+ default:
+ RERROR("Internal error: Unknown mschap auth method (%d)", method);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Data for the hashes.
+ */
+static const uint8_t SHSpad1[40] =
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const uint8_t SHSpad2[40] =
+ { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
+
+static const uint8_t magic1[27] =
+ { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
+
+static const uint8_t magic2[84] =
+ { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+ 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+
+static const uint8_t magic3[84] =
+ { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+ 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+ 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+ 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+ 0x6b, 0x65, 0x79, 0x2e };
+
+
+static void mppe_GetMasterKey(uint8_t const *nt_hashhash,uint8_t const *nt_response,
+ uint8_t *masterkey)
+{
+ uint8_t digest[20];
+ fr_sha1_ctx Context;
+
+ fr_sha1_init(&Context);
+ fr_sha1_update(&Context,nt_hashhash,NT_DIGEST_LENGTH);
+ fr_sha1_update(&Context,nt_response,24);
+ fr_sha1_update(&Context,magic1,27);
+ fr_sha1_final(digest,&Context);
+
+ memcpy(masterkey,digest,16);
+}
+
+
+static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
+ int keylen,int issend)
+{
+ uint8_t digest[20];
+ const uint8_t *s;
+ fr_sha1_ctx Context;
+
+ memset(digest,0,20);
+
+ if(issend) {
+ s = magic3;
+ } else {
+ s = magic2;
+ }
+
+ fr_sha1_init(&Context);
+ fr_sha1_update(&Context,masterkey,16);
+ fr_sha1_update(&Context,SHSpad1,40);
+ fr_sha1_update(&Context,s,84);
+ fr_sha1_update(&Context,SHSpad2,40);
+ fr_sha1_final(digest,&Context);
+
+ memcpy(sesskey,digest,keylen);
+}
+
+
+static void mppe_chap2_get_keys128(uint8_t const *nt_hashhash,uint8_t const *nt_response,
+ uint8_t *sendkey,uint8_t *recvkey)
+{
+ uint8_t masterkey[16];
+
+ mppe_GetMasterKey(nt_hashhash,nt_response,masterkey);
+
+ mppe_GetAsymmetricStartKey(masterkey,sendkey,16,1);
+ mppe_GetAsymmetricStartKey(masterkey,recvkey,16,0);
+}
+
+/*
+ * Generate MPPE keys.
+ */
+static void mppe_chap2_gen_keys128(uint8_t const *nt_hashhash,uint8_t const *response,
+ uint8_t *sendkey,uint8_t *recvkey)
+{
+ uint8_t enckey1[16];
+ uint8_t enckey2[16];
+
+ mppe_chap2_get_keys128(nt_hashhash,response,enckey1,enckey2);
+
+ /*
+ * dictionary.microsoft defines these attributes as
+ * 'encrypt=2'. The functions in src/lib/radius.c will
+ * take care of encrypting/decrypting them as appropriate,
+ * so that we don't have to.
+ */
+ memcpy (sendkey, enckey1, 16);
+ memcpy (recvkey, enckey2, 16);
+}
+
+
+/*
+ * mod_authorize() - authorize user if we can authenticate
+ * it later. Add Auth-Type attribute if present in module
+ * configuration (usually Auth-Type must be "MS-CHAP")
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void * instance, REQUEST *request)
+{
+ rlm_mschap_t *inst = instance;
+ VALUE_PAIR *challenge = NULL;
+
+ challenge = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!challenge) {
+ return RLM_MODULE_NOOP;
+ }
+
+ if (!fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY) &&
+ !fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY) &&
+ !fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_CPW, VENDORPEC_MICROSOFT, TAG_ANY)) {
+ RDEBUG2("Found MS-CHAP-Challenge, but no MS-CHAP response or change-password");
+ return RLM_MODULE_NOOP;
+ }
+
+ if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY)) {
+ RWDEBUG2("Auth-Type already set. Not setting to MS-CHAP");
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("Found MS-CHAP attributes. Setting 'Auth-Type = %s'", inst->xlat_name);
+
+ /*
+ * Set Auth-Type to MS-CHAP. The authentication code
+ * will take care of turning cleartext passwords into
+ * NT/LM passwords.
+ */
+ if (!pair_make_config("Auth-Type", inst->auth_type, T_OP_EQ)) {
+ return RLM_MODULE_FAIL;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t mschap_error(rlm_mschap_t *inst, REQUEST *request, unsigned char ident,
+ int mschap_result, int mschap_version, VALUE_PAIR *smb_ctrl)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ int error = 0;
+ int retry = 0;
+ char const *message = NULL;
+
+ int i;
+ char new_challenge[33], buffer[128];
+ char *p;
+
+ if ((mschap_result == -648) ||
+ ((mschap_result == 0) &&
+ (smb_ctrl && ((smb_ctrl->vp_integer & ACB_PW_EXPIRED) != 0)))) {
+ REDEBUG("Password has expired. User should retry authentication");
+ error = 648;
+
+ /*
+ * A password change is NOT a retry! We MUST have retry=0 here.
+ */
+ retry = 0;
+ message = "Password expired";
+ rcode = RLM_MODULE_REJECT;
+
+ /*
+ * Account is disabled.
+ *
+ * They're found, but they don't exist, so we
+ * return 'not found'.
+ */
+ } else if ((mschap_result == -691) ||
+ (smb_ctrl && (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
+ ((smb_ctrl->vp_integer & (ACB_NORMAL|ACB_WSTRUST)) == 0)))) {
+ REDEBUG("SMB-Account-Ctrl (or ntlm_auth) "
+ "says that the account is disabled, "
+ "or is not a normal or workstation trust account");
+ error = 691;
+ retry = 0;
+ message = "Account disabled";
+ rcode = RLM_MODULE_NOTFOUND;
+
+ /*
+ * User is locked out.
+ */
+ } else if ((mschap_result == -647) ||
+ (smb_ctrl && ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0))) {
+ REDEBUG("SMB-Account-Ctrl (or ntlm_auth) "
+ "says that the account is locked out");
+ error = 647;
+ retry = 0;
+ message = "Account locked out";
+ rcode = RLM_MODULE_USERLOCK;
+ } else if (mschap_result == -2) {
+ RDEBUG("Authentication failed");
+ error = 691;
+ retry = inst->allow_retry;
+ message = "Authentication failed";
+ rcode = RLM_MODULE_FAIL;
+
+ } else if (mschap_result < 0) {
+ REDEBUG("MS-CHAP2-Response is incorrect");
+ error = 691;
+ retry = inst->allow_retry;
+ message = "Authentication rejected";
+ rcode = RLM_MODULE_REJECT;
+ }
+
+ if (rcode == RLM_MODULE_OK) return RLM_MODULE_OK;
+
+ switch (mschap_version) {
+ case 1:
+ for (p = new_challenge, i = 0; i < 2; i++) p += snprintf(p, 9, "%08x", fr_rand());
+ snprintf(buffer, sizeof(buffer), "E=%i R=%i C=%s V=2",
+ error, retry, new_challenge);
+ break;
+
+ case 2:
+ for (p = new_challenge, i = 0; i < 4; i++) p += snprintf(p, 9, "%08x", fr_rand());
+ snprintf(buffer, sizeof(buffer), "E=%i R=%i C=%s V=3 M=%s",
+ error, retry, new_challenge, message);
+ break;
+
+ default:
+ return RLM_MODULE_FAIL;
+ }
+ mschap_add_reply(request, ident, "MS-CHAP-Error", buffer, strlen(buffer));
+
+ return rcode;
+}
+
+/*
+ * mod_authenticate() - authenticate user based on given
+ * attributes and configuration.
+ * We will try to find out password in configuration
+ * or in configured passwd file.
+ * If one is found we will check paraneters given by NAS.
+ *
+ * If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
+ * one of:
+ * PAP: PW_USER_PASSWORD or
+ * MS-CHAP: PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
+ * MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
+ * In case of password mismatch or locked account we MAY return
+ * PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
+ * If MS-CHAP2 succeeds we MUST return
+ * PW_MSCHAP2_SUCCESS
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_mschap_t *inst = instance;
+ VALUE_PAIR *challenge = NULL;
+ VALUE_PAIR *response = NULL;
+ VALUE_PAIR *cpw = NULL;
+ VALUE_PAIR *password = NULL;
+ VALUE_PAIR *nt_password, *smb_ctrl;
+ VALUE_PAIR *username;
+ uint8_t nthashhash[NT_DIGEST_LENGTH];
+ char msch2resp[42];
+ char const *username_string;
+ int mschap_version = 0;
+ int mschap_result;
+ MSCHAP_AUTH_METHOD auth_method;
+
+ /*
+ * If we have ntlm_auth configured, use it unless told
+ * otherwise
+ */
+ auth_method = inst->method;
+
+ /*
+ * If we have an ntlm_auth configuration, then we may
+ * want to suppress it.
+ */
+ if (auth_method != AUTH_INTERNAL) {
+ VALUE_PAIR *vp = fr_pair_find_by_num(request->config, PW_MS_CHAP_USE_NTLM_AUTH, 0, TAG_ANY);
+ if (vp && vp->vp_integer == 0) auth_method = AUTH_INTERNAL;
+ }
+
+ /*
+ * Find the SMB-Account-Ctrl attribute, or the
+ * SMB-Account-Ctrl-Text attribute.
+ */
+ smb_ctrl = fr_pair_find_by_num(request->config, PW_SMB_ACCOUNT_CTRL, 0, TAG_ANY);
+ if (!smb_ctrl) {
+ password = fr_pair_find_by_num(request->config, PW_SMB_ACCOUNT_CTRL_TEXT, 0, TAG_ANY);
+ if (password) {
+ smb_ctrl = pair_make_config("SMB-Account-CTRL", "0", T_OP_SET);
+ if (smb_ctrl) {
+ smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
+ }
+ }
+ }
+
+ /*
+ * We're configured to do MS-CHAP authentication.
+ * and account control information exists. Enforce it.
+ */
+ if (smb_ctrl) {
+ /*
+ * Password is not required.
+ */
+ if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
+ RDEBUG2("SMB-Account-Ctrl says no password is required");
+ return RLM_MODULE_OK;
+ }
+ }
+
+ /*
+ * Decide how to get the passwords.
+ */
+ password = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
+
+ /*
+ * We need an NT-Password.
+ */
+ nt_password = fr_pair_find_by_num(request->config, PW_NT_PASSWORD, 0, TAG_ANY);
+ if (nt_password) {
+ VERIFY_VP(nt_password);
+
+ switch (nt_password->vp_length) {
+ case NT_DIGEST_LENGTH:
+ RDEBUG2("Found NT-Password");
+ break;
+
+ /* 0x */
+ case 34:
+ case 32:
+ RWDEBUG("NT-Password has not been normalized by the 'pap' module (likely still in hex format). "
+ "Authentication may fail");
+ nt_password = NULL;
+ break;
+
+ default:
+ RWDEBUG("NT-Password found but incorrect length, expected " STRINGIFY(NT_DIGEST_LENGTH)
+ " bytes got %zu bytes. Authentication may fail", nt_password->vp_length);
+ nt_password = NULL;
+ break;
+ }
+ }
+
+ /*
+ * ... or a Cleartext-Password, which we now transform into an NT-Password
+ */
+ if (!nt_password) {
+ uint8_t *p;
+
+ if (password) {
+ RDEBUG2("Found Cleartext-Password, hashing to create NT-Password");
+ nt_password = pair_make_config("NT-Password", NULL, T_OP_EQ);
+ if (!nt_password) {
+ RERROR("No memory");
+ return RLM_MODULE_FAIL;
+ }
+ nt_password->vp_length = NT_DIGEST_LENGTH;
+ nt_password->vp_octets = p = talloc_array(nt_password, uint8_t, nt_password->vp_length);
+
+ if (mschap_ntpwdhash(p, password->vp_strvalue) < 0) {
+ RERROR("Failed generating NT-Password");
+ return RLM_MODULE_FAIL;
+ }
+ } else if (auth_method == AUTH_INTERNAL) {
+ RWDEBUG2("No Cleartext-Password configured. Cannot create NT-Password");
+ }
+ }
+
+ cpw = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_CPW, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (cpw) {
+ /*
+ * mschap2 password change request
+ * we cheat - first decode and execute the passchange
+ * we then extract the response, add it into the request
+ * then jump into mschap2 auth with the chal/resp
+ */
+ uint8_t new_nt_encrypted[516], old_nt_encrypted[NT_DIGEST_LENGTH];
+ VALUE_PAIR *nt_enc=NULL;
+ int seq, new_nt_enc_len;
+ uint8_t *p;
+
+ RDEBUG("MS-CHAPv2 password change request received");
+
+ if (cpw->vp_length != 68) {
+ REDEBUG("MS-CHAP2-CPW has the wrong format: length %zu != 68", cpw->vp_length);
+ return RLM_MODULE_INVALID;
+ }
+
+ if (cpw->vp_octets[0] != 7) {
+ REDEBUG("MS-CHAP2-CPW has the wrong format: code %d != 7", cpw->vp_octets[0]);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * look for the new (encrypted) password
+ * bah stupid composite attributes
+ * we're expecting 3 attributes with the leading bytes
+ * 06:<mschapid>:00:01:<1st chunk>
+ * 06:<mschapid>:00:02:<2nd chunk>
+ * 06:<mschapid>:00:03:<3rd chunk>
+ */
+ new_nt_enc_len = 0;
+ for (seq = 1; seq < 4; seq++) {
+ vp_cursor_t cursor;
+ int found = 0;
+
+ for (nt_enc = fr_cursor_init(&cursor, &request->packet->vps);
+ nt_enc;
+ nt_enc = fr_cursor_next(&cursor)) {
+ if (nt_enc->da->vendor != VENDORPEC_MICROSOFT)
+ continue;
+
+ if (nt_enc->da->attr != PW_MSCHAP_NT_ENC_PW)
+ continue;
+
+ if (nt_enc->vp_length < 4) {
+ REDEBUG("MS-CHAP-NT-Enc-PW with invalid format");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (nt_enc->vp_octets[0] != 6) {
+ REDEBUG("MS-CHAP-NT-Enc-PW with invalid format");
+ return RLM_MODULE_INVALID;
+ }
+
+ if ((nt_enc->vp_octets[2] == 0) && (nt_enc->vp_octets[3] == seq)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ REDEBUG("Could not find MS-CHAP-NT-Enc-PW w/ sequence number %d", seq);
+ return RLM_MODULE_INVALID;
+ }
+
+ if ((new_nt_enc_len + nt_enc->vp_length - 4) > sizeof(new_nt_encrypted)) {
+ REDEBUG("Unpacked MS-CHAP-NT-Enc-PW length > 516");
+ return RLM_MODULE_INVALID;
+ }
+
+ memcpy(new_nt_encrypted + new_nt_enc_len, nt_enc->vp_octets + 4, nt_enc->vp_length - 4);
+ new_nt_enc_len += nt_enc->vp_length - 4;
+ }
+
+ if (new_nt_enc_len != 516) {
+ REDEBUG("Unpacked MS-CHAP-NT-Enc-PW length != 516");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * RFC 2548 is confusing here
+ * it claims:
+ *
+ * 1 byte code
+ * 1 byte ident
+ * 16 octets - old hash encrypted with new hash
+ * 24 octets - peer challenge
+ * this is actually:
+ * 16 octets - peer challenge
+ * 8 octets - reserved
+ * 24 octets - nt response
+ * 2 octets - flags (ignored)
+ */
+
+ memcpy(old_nt_encrypted, cpw->vp_octets + 2, sizeof(old_nt_encrypted));
+
+ RDEBUG2("Password change payload valid");
+
+ /* perform the actual password change */
+ if (do_mschap_cpw(inst, request, nt_password, new_nt_encrypted, old_nt_encrypted, auth_method) < 0) {
+ char buffer[128];
+
+ REDEBUG("Password change failed");
+
+ snprintf(buffer, sizeof(buffer), "E=709 R=0 M=Password change failed");
+ mschap_add_reply(request, cpw->vp_octets[1], "MS-CHAP-Error", buffer, strlen(buffer));
+
+ return RLM_MODULE_REJECT;
+ }
+ RDEBUG("Password change successful");
+
+ /*
+ * Clear any expiry bit so the user can now login;
+ * obviously the password change action will need
+ * to have cleared this bit in the config/SQL/wherever
+ */
+ if (smb_ctrl && smb_ctrl->vp_integer & ACB_PW_EXPIRED) {
+ RDEBUG("Clearing expiry bit in SMB-Acct-Ctrl to allow authentication");
+ smb_ctrl->vp_integer &= ~ACB_PW_EXPIRED;
+ }
+
+ /*
+ * Extract the challenge & response from the end of the password
+ * change, add them into the request and then continue with
+ * the authentication
+ */
+ response = radius_pair_create(request->packet, &request->packet->vps,
+ PW_MSCHAP2_RESPONSE,
+ VENDORPEC_MICROSOFT);
+ response->vp_length = 50;
+ response->vp_octets = p = talloc_array(response, uint8_t, response->vp_length);
+
+ /* ident & flags */
+ p[0] = cpw->vp_octets[1];
+ p[1] = 0;
+ /* peer challenge and client NT response */
+ memcpy(p + 2, cpw->vp_octets + 18, 48);
+ }
+
+ challenge = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!challenge) {
+ REDEBUG("You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
+ return RLM_MODULE_REJECT;
+ }
+
+ /*
+ * We also require an MS-CHAP-Response.
+ */
+ response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ /*
+ * MS-CHAP-Response, means MS-CHAPv1
+ */
+ if (response) {
+ int offset;
+ rlm_rcode_t rcode;
+ mschap_version = 1;
+
+ /*
+ * MS-CHAPv1 challenges are 8 octets.
+ */
+ if (challenge->vp_length < 8) {
+ REDEBUG("MS-CHAP-Challenge has the wrong format");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Responses are 50 octets.
+ */
+ if (response->vp_length < 50) {
+ REDEBUG("MS-CHAP-Response has the wrong format");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * We are doing MS-CHAP. Calculate the MS-CHAP
+ * response
+ */
+ if (response->vp_octets[1] & 0x01) {
+ RDEBUG2("Client is using MS-CHAPv1 with NT-Password");
+ password = nt_password;
+ offset = 26;
+ } else {
+ REDEBUG2("Client is using MS-CHAPv1 with unsupported method LM-Password");
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Do the MS-CHAP authentication.
+ */
+ mschap_result = do_mschap(inst, request, password, challenge->vp_octets,
+ response->vp_octets + offset, nthashhash, auth_method);
+ /*
+ * Check for errors, and add MSCHAP-Error if necessary.
+ */
+ rcode = mschap_error(inst, request, *response->vp_octets,
+ mschap_result, mschap_version, smb_ctrl);
+ if (rcode != RLM_MODULE_OK) return rcode;
+ } else if ((response = fr_pair_find_by_num(request->packet->vps, PW_MSCHAP2_RESPONSE,
+ VENDORPEC_MICROSOFT, TAG_ANY)) != NULL) {
+ uint8_t mschapv1_challenge[16];
+ VALUE_PAIR *name_attr, *response_name, *peer_challenge_attr;
+ rlm_rcode_t rcode;
+ uint8_t const *peer_challenge;
+
+ mschap_version = 2;
+
+ /*
+ * MS-CHAPv2 challenges are 16 octets.
+ */
+ if (challenge->vp_length < 16) {
+ REDEBUG("MS-CHAP-Challenge has the wrong format");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Responses are 50 octets.
+ */
+ if (response->vp_length < 50) {
+ REDEBUG("MS-CHAP-Response has the wrong format");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * We also require a User-Name
+ */
+ username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ if (!username) {
+ REDEBUG("We require a User-Name for MS-CHAPv2");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Check for MS-CHAP-User-Name and if found, use it
+ * to construct the MSCHAPv1 challenge. This is
+ * set by rlm_eap_mschap to the MS-CHAP Response
+ * packet Name field.
+ *
+ * We prefer this to the User-Name in the
+ * packet.
+ */
+ response_name = fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_USER_NAME, 0, TAG_ANY);
+ if (response_name) {
+ name_attr = response_name;
+ } else {
+ name_attr = username;
+ }
+
+ /*
+ * with_ntdomain_hack moved here, too.
+ */
+ if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
+ if (inst->with_ntdomain_hack) {
+ username_string++;
+ } else {
+ RWDEBUG2("NT Domain delimiter found, should with_ntdomain_hack of been enabled?");
+ username_string = name_attr->vp_strvalue;
+ }
+ } else {
+ username_string = name_attr->vp_strvalue;
+ }
+
+ if (response_name && ((username->vp_length != response_name->vp_length) ||
+ (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->vp_length) != 0))) {
+ RWDEBUG("User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2",
+ username->vp_strvalue, response_name->vp_strvalue);
+ }
+
+#ifdef __APPLE__
+ /*
+ * No "known good" NT-Password attribute. Try to do
+ * OpenDirectory authentication.
+ *
+ * If OD determines the user is an OD user it will return noop, which
+ * indicates the auth process should continue directly to OD.
+ * Otherwise OD will determine auth success/fail.
+ */
+ if (!nt_password && inst->open_directory) {
+ RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication");
+ int odStatus = od_mschap_auth(request, challenge, username);
+ if (odStatus != RLM_MODULE_NOOP) {
+ return odStatus;
+ }
+ }
+#endif
+ peer_challenge = response->vp_octets + 2;
+
+ peer_challenge_attr = fr_pair_find_by_num(request->config, PW_MS_CHAP_PEER_CHALLENGE, 0, TAG_ANY);
+ if (peer_challenge_attr) {
+ RDEBUG2("Overriding peer challenge");
+ peer_challenge = peer_challenge_attr->vp_octets;
+ }
+
+ /*
+ * The old "mschapv2" function has been moved to
+ * here.
+ *
+ * MS-CHAPv2 takes some additional data to create an
+ * MS-CHAPv1 challenge, and then does MS-CHAPv1.
+ */
+ RDEBUG2("Creating challenge hash with username: %s", username_string);
+ mschap_challenge_hash(peer_challenge, /* peer challenge */
+ challenge->vp_octets, /* our challenge */
+ username_string, /* user name */
+ mschapv1_challenge); /* resulting challenge */
+
+ RDEBUG2("Client is using MS-CHAPv2");
+ mschap_result = do_mschap(inst, request, nt_password, mschapv1_challenge,
+ response->vp_octets + 26, nthashhash, auth_method);
+ rcode = mschap_error(inst, request, *response->vp_octets,
+ mschap_result, mschap_version, smb_ctrl);
+ if (rcode != RLM_MODULE_OK) return rcode;
+
+#ifdef WITH_AUTH_WINBIND
+ if (inst->wb_retry_with_normalised_username) {
+ if ((response_name = fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_USER_NAME, 0, TAG_ANY))) {
+ if (strcmp(username_string, response_name->vp_strvalue)) {
+ RDEBUG2("Changing username %s to %s", username_string, response_name->vp_strvalue);
+ username_string = response_name->vp_strvalue;
+ }
+ }
+ }
+#endif
+
+ mschap_auth_response(username_string, /* without the domain */
+ nthashhash, /* nt-hash-hash */
+ response->vp_octets + 26, /* peer response */
+ peer_challenge, /* peer challenge */
+ challenge->vp_octets, /* our challenge */
+ msch2resp); /* calculated MPPE key */
+ mschap_add_reply(request, *response->vp_octets, "MS-CHAP2-Success", msch2resp, 42);
+
+ } else { /* Neither CHAPv1 or CHAPv2 response: die */
+ REDEBUG("You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
+ return RLM_MODULE_INVALID;
+ }
+
+ /* now create MPPE attributes */
+ if (inst->use_mppe) {
+ uint8_t mppe_sendkey[34];
+ uint8_t mppe_recvkey[34];
+
+ if (mschap_version == 1) {
+ RDEBUG2("adding MS-CHAPv1 MPPE keys");
+ memset(mppe_sendkey, 0, 32);
+
+ /*
+ * According to RFC 2548 we
+ * should send NT hash. But in
+ * practice it doesn't work.
+ * Instead, we should send nthashhash
+ *
+ * This is an error in RFC 2548.
+ */
+ /*
+ * do_mschap cares to zero nthashhash if NT hash
+ * is not available.
+ */
+ memcpy(mppe_sendkey + 8, nthashhash, NT_DIGEST_LENGTH);
+ mppe_add_reply(request, "MS-CHAP-MPPE-Keys", mppe_sendkey, 24);
+
+ } else if (mschap_version == 2) {
+ RDEBUG2("Adding MS-CHAPv2 MPPE keys");
+ mppe_chap2_gen_keys128(nthashhash, response->vp_octets + 26, mppe_sendkey, mppe_recvkey);
+
+ mppe_add_reply(request, "MS-MPPE-Recv-Key", mppe_recvkey, 16);
+ mppe_add_reply(request, "MS-MPPE-Send-Key", mppe_sendkey, 16);
+
+ }
+ pair_make_reply("MS-MPPE-Encryption-Policy",
+ (inst->require_encryption) ? "0x00000002":"0x00000001", T_OP_EQ);
+ pair_make_reply("MS-MPPE-Encryption-Types",
+ (inst->require_strong) ? "0x00000004":"0x00000006", T_OP_EQ);
+ } /* else we weren't asked to use MPPE */
+
+ return RLM_MODULE_OK;
+#undef inst
+}
+
+extern module_t rlm_mschap;
+module_t rlm_mschap = {
+ .magic = RLM_MODULE_INIT,
+ .name = "mschap",
+ .type = 0,
+ .inst_size = sizeof(rlm_mschap_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_mschap/rlm_mschap.h b/src/modules/rlm_mschap/rlm_mschap.h
new file mode 100644
index 0000000..7309919
--- /dev/null
+++ b/src/modules/rlm_mschap/rlm_mschap.h
@@ -0,0 +1,55 @@
+/* Copyright 2006-2015 The FreeRADIUS server project */
+
+#ifndef _RLM_MSCHAP_H
+#define _RLM_MSCHAP_H
+
+RCSIDH(rlm_mschap_h, "$Id$")
+
+#include "config.h"
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#ifdef WITH_AUTH_WINBIND
+# include <wbclient.h>
+#endif
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+/* Method of authentication we are going to use */
+typedef enum {
+ AUTH_INTERNAL = 0,
+ AUTH_NTLMAUTH_EXEC = 1
+#ifdef WITH_AUTH_WINBIND
+ ,AUTH_WBCLIENT = 2
+#endif
+} MSCHAP_AUTH_METHOD;
+
+typedef struct rlm_mschap_t {
+ bool use_mppe;
+ bool require_encryption;
+ bool require_strong;
+ bool with_ntdomain_hack; /* this should be in another module */
+ char const *xlat_name;
+ char const *ntlm_auth;
+ uint32_t ntlm_auth_timeout;
+ char const *ntlm_cpw;
+ char const *ntlm_cpw_username;
+ char const *ntlm_cpw_domain;
+ char const *local_cpw;
+ char const *auth_type;
+ bool allow_retry;
+ char const *retry_msg;
+ MSCHAP_AUTH_METHOD method;
+ vp_tmpl_t *wb_username;
+ vp_tmpl_t *wb_domain;
+ fr_connection_pool_t *wb_pool;
+ bool wb_retry_with_normalised_username;
+#ifdef __APPLE__
+ bool open_directory;
+#endif
+} rlm_mschap_t;
+
+#endif
+
diff --git a/src/modules/rlm_mschap/rlm_mschap.mk.in b/src/modules/rlm_mschap/rlm_mschap.mk.in
new file mode 100644
index 0000000..0d046df
--- /dev/null
+++ b/src/modules/rlm_mschap/rlm_mschap.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c smbdes.c mschap.c @mschap_sources@
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_mschap/smbdes.c b/src/modules/rlm_mschap/smbdes.c
new file mode 100644
index 0000000..d80de34
--- /dev/null
+++ b/src/modules/rlm_mschap/smbdes.c
@@ -0,0 +1,349 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ Copyright (C) Andrew Tridgell 1998
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Copyright 2006 The FreeRADIUS server project
+*/
+
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+#include <ctype.h>
+#include "smbdes.h"
+
+
+#define uchar unsigned char
+
+static const uchar perm1[56] = {57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4};
+
+static const uchar perm2[48] = {14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32};
+
+static const uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7};
+
+static const uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1};
+
+static const uchar perm5[32] = { 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25};
+
+
+static const uchar perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static const uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static const uchar sbox[8][4][16] = {
+ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void permute(char *out, char const *in, uchar const *p, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in[p[i]-1];
+}
+
+static void lshift(char *d, int count, int n)
+{
+ char out[64];
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = d[(i+count)%n];
+ for (i=0;i<n;i++)
+ d[i] = out[i];
+}
+
+static void concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+ while (l1--)
+ *out++ = *in1++;
+ while (l2--)
+ *out++ = *in2++;
+}
+
+static void xor(char *out, char *in1, char *in2, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void dohash(char *out, char *in, char *key)
+{
+ int i, j, k;
+ char pk1[56];
+ char c[28];
+ char d[28];
+ char cd[56];
+ char ki[16][48];
+ char pd1[64];
+ char l[32], r[32];
+ char rl[64];
+
+ permute(pk1, key, perm1, 56);
+
+ for (i=0;i<28;i++)
+ c[i] = pk1[i];
+ for (i=0;i<28;i++)
+ d[i] = pk1[i+28];
+
+ for (i=0;i<16;i++) {
+ lshift(c, sc[i], 28);
+ lshift(d, sc[i], 28);
+
+ concat(cd, c, d, 28, 28);
+ permute(ki[i], cd, perm2, 48);
+ }
+
+ permute(pd1, in, perm3, 64);
+
+ for (j=0;j<32;j++) {
+ l[j] = pd1[j];
+ r[j] = pd1[j+32];
+ }
+
+ for (i=0;i<16;i++) {
+ char er[48];
+ char erk[48];
+ char b[8][6];
+ char cb[32];
+ char pcb[32];
+ char r2[32];
+
+ permute(er, r, perm4, 48);
+
+ xor(erk, er, ki[i], 48);
+
+ for (j=0;j<8;j++)
+ for (k=0;k<6;k++)
+ b[j][k] = erk[j*6 + k];
+
+ for (j=0;j<8;j++) {
+ int m, n;
+ m = (b[j][0]<<1) | b[j][5];
+
+ n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
+
+ for (k=0;k<4;k++)
+ b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
+ }
+
+ for (j=0;j<8;j++)
+ for (k=0;k<4;k++)
+ cb[j*4+k] = b[j][k];
+ permute(pcb, cb, perm5, 32);
+
+ xor(r2, l, pcb, 32);
+
+ for (j=0;j<32;j++)
+ l[j] = r[j];
+
+ for (j=0;j<32;j++)
+ r[j] = r2[j];
+ }
+
+ concat(rl, r, l, 32, 32);
+
+ permute(out, rl, perm6, 64);
+}
+
+static void str_to_key(unsigned char *str,unsigned char *key)
+{
+ int i;
+
+ key[0] = str[0]>>1;
+ key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+ key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+ key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+ key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+ key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+ key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+ key[7] = str[6]&0x7F;
+ for (i=0;i<8;i++) {
+ key[i] = (key[i]<<1);
+ }
+}
+
+
+void smbhash(unsigned char *out, unsigned char const *in, unsigned char *key)
+{
+ int i;
+ char outb[64];
+ char inb[64];
+ char keyb[64];
+ unsigned char key2[8];
+
+ str_to_key(key, key2);
+
+ for (i=0;i<64;i++) {
+ inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb);
+
+ for (i=0;i<8;i++) {
+ out[i] = 0;
+ }
+
+ for (i=0;i<64;i++) {
+ if (outb[i])
+ out[i/8] |= (1<<(7-(i%8)));
+ }
+}
+
+/*
+ * Converts the password to uppercase, and creates the LM
+ * password hash.
+ */
+void smbdes_lmpwdhash(char const *password, uint8_t *lmhash)
+{
+ int i;
+ uint8_t p14[14];
+ static uint8_t sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+
+ memset(p14, 0, sizeof(p14));
+ for (i = 0; i < 14 && password[i]; i++) {
+ p14[i] = toupper((uint8_t) password[i]);
+ }
+
+ smbhash(lmhash, sp8, p14);
+ smbhash(lmhash+8, sp8, p14+7);
+}
+
+/*
+ * Take the NT or LM password, and return the MSCHAP response
+ *
+ * The win_password MUST be exactly 16 bytes long.
+ */
+void smbdes_mschap(uint8_t const win_password[16],
+ uint8_t const *challenge, uint8_t *response)
+{
+ uint8_t p21[21];
+
+ memset(p21, 0, sizeof(p21));
+ memcpy(p21, win_password, 16);
+
+ smbhash(response, challenge, p21);
+ smbhash(response+8, challenge, p21+7);
+ smbhash(response+16, challenge, p21+14);
+}
diff --git a/src/modules/rlm_mschap/smbdes.h b/src/modules/rlm_mschap/smbdes.h
new file mode 100644
index 0000000..aa06d76
--- /dev/null
+++ b/src/modules/rlm_mschap/smbdes.h
@@ -0,0 +1,13 @@
+/* Copyright 2006 The FreeRADIUS server project */
+
+#ifndef _SMBDES_H
+#define _SMBDES_H
+
+RCSIDH(smbdes_h, "$Id$")
+
+void smbhash(unsigned char *out, unsigned char const *in, unsigned char *key);
+void smbdes_lmpwdhash(char const *password, uint8_t *lmhash);
+void smbdes_mschap(uint8_t const win_password[16],
+ uint8_t const *challenge, uint8_t *response);
+
+#endif /*_SMBDES_H*/
diff --git a/src/modules/rlm_mschap/smbencrypt.c b/src/modules/rlm_mschap/smbencrypt.c
new file mode 100644
index 0000000..9a8a5ab
--- /dev/null
+++ b/src/modules/rlm_mschap/smbencrypt.c
@@ -0,0 +1,147 @@
+/*
+ * smbencrypt.c Produces LM-Password and NT-Password from
+ * cleartext password
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2002 3APA3A for FreeRADIUS project
+ Copyright 2006 The FreeRADIUS server project
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#include <freeradius-devel/openssl3.h>
+#endif
+
+#include <freeradius-devel/md4.h>
+#include <freeradius-devel/md5.h>
+#include <freeradius-devel/sha1.h>
+#include <ctype.h>
+
+
+#include "smbdes.h"
+
+static char const hex[] = "0123456789ABCDEF";
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/provider.h>
+
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+
+#define ERROR(_x) fprintf(stderr, _x)
+
+static int openssl3_init(void)
+{
+ /*
+ * Load the default provider for most algorithms
+ */
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+ if (!openssl_default_provider) {
+ ERROR("(TLS) Failed loading default provider");
+ return -1;
+ }
+
+ /*
+ * Needed for MD4
+ *
+ * https://www.openssl.org/docs/man3.0/man7/migration_guide.html#Legacy-Algorithms
+ */
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+ if (!openssl_legacy_provider) {
+ ERROR("(TLS) Failed loading legacy provider");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void openssl3_free(void)
+{
+ if (openssl_default_provider && !OSSL_PROVIDER_unload(openssl_default_provider)) {
+ ERROR("Failed unloading default provider");
+ }
+ openssl_default_provider = NULL;
+
+ if (openssl_legacy_provider && !OSSL_PROVIDER_unload(openssl_legacy_provider)) {
+ ERROR("Failed unloading legacy provider");
+ }
+ openssl_legacy_provider = NULL;
+}
+#else
+#define openssl3_init()
+#define openssl3_free()
+#endif
+
+
+
+/*
+ * FIXME: use functions in freeradius
+ */
+static void tohex (unsigned char const *src, size_t len, char *dst)
+{
+ size_t i;
+ for (i=0; i<len; i++) {
+ dst[(i*2)] = hex[(src[i] >> 4)];
+ dst[(i*2) + 1] = hex[(src[i]&0x0F)];
+ }
+ dst[(i*2)] = 0;
+}
+
+static void ntpwdhash(uint8_t *out, char const *password)
+{
+ ssize_t len;
+ uint8_t ucs2_password[512];
+
+ len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), password, strlen(password));
+ if (len < 0) {
+ *out = '\0';
+ return;
+ }
+ fr_md4_calc(out, (uint8_t *) ucs2_password, len);
+}
+
+int main (int argc, char *argv[])
+{
+ int i, l;
+ char password[1024];
+ uint8_t hash[16];
+ char ntpass[33];
+ char lmpass[33];
+
+ openssl3_init();
+
+ fprintf(stderr, "LM Hash \tNT Hash\n");
+ fprintf(stderr, "--------------------------------\t--------------------------------\n");
+ fflush(stderr);
+ for (i = 1; i < argc; i++ ) {
+ strlcpy(password, argv[i], sizeof(password));
+ l = strlen(password);
+ if (l && password[l-1] == '\n') password [l-1] = 0;
+ smbdes_lmpwdhash(password, hash);
+ tohex (hash, 16, lmpass);
+ ntpwdhash (hash, password);
+ tohex (hash, 16, ntpass);
+ printf("%s\t%s\n", lmpass, ntpass);
+ }
+
+ openssl3_free();
+
+ return 0;
+}
diff --git a/src/modules/rlm_mschap/smbencrypt.mk b/src/modules/rlm_mschap/smbencrypt.mk
new file mode 100644
index 0000000..70e8b7b
--- /dev/null
+++ b/src/modules/rlm_mschap/smbencrypt.mk
@@ -0,0 +1,8 @@
+TARGET := smbencrypt
+SOURCES := smbencrypt.c smbdes.c
+
+TGT_PREREQS := libfreeradius-radius.a
+
+SRC_CFLAGS :=
+TGT_LDLIBS := $(LIBS)
+
diff --git a/src/modules/rlm_opendirectory/.gitignore b/src/modules/rlm_opendirectory/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_opendirectory/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_opendirectory/README.md b/src/modules/rlm_opendirectory/README.md
new file mode 100644
index 0000000..87edc4b
--- /dev/null
+++ b/src/modules/rlm_opendirectory/README.md
@@ -0,0 +1,13 @@
+# rlm_opendirectory
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Integrates with an Apple OpenDirectory service on the same host as
+FreeRADIUS to allow OpenDirectory users to authenticate.
+
+This module does not provide the user's password, so cannot be
+used with other authentication modules such as rlm_eap_peap.
diff --git a/src/modules/rlm_opendirectory/all.mk.in b/src/modules/rlm_opendirectory/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_opendirectory/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_opendirectory/configure b/src/modules/rlm_opendirectory/configure
new file mode 100755
index 0000000..e44a9ff
--- /dev/null
+++ b/src/modules/rlm_opendirectory/configure
@@ -0,0 +1,4211 @@
+#! /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_opendirectory.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_opendirectory
+'
+ 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_opendirectory
+ build without OpenDirectory support
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_opendirectory
+echo
+
+
+# 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_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+ (void) $as_decl_use;
+#else
+ (void) $as_decl_name;
+#endif
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+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_opendirectory was given.
+if test "${with_rlm_opendirectory+set}" = set; then :
+ withval=$with_rlm_opendirectory;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_opendirectory" != 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
+
+
+mod_ldflags="${mod_ldflags} -F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks -framework DirectoryService"
+
+
+
+
+ac_safe=`echo "membership.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 membership.h in $try" >&5
+$as_echo_n "checking for membership.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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}/membership.h" >&5
+$as_echo_n "checking for ${_prefix}/membership.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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 membership.h" >&5
+$as_echo_n "checking for membership.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.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 membership.h in $try" >&5
+$as_echo_n "checking for membership.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <membership.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_membership_h" != "yes"; then
+
+fail="$fail membership.h"
+
+else
+ ac_fn_c_check_decl "$LINENO" "mbr_check_service_membership" "ac_cv_have_decl_mbr_check_service_membership" "#include <membership.h>
+"
+if test "x$ac_cv_have_decl_mbr_check_service_membership" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+ mod_cflags="${mod_cflags} -DHAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP"
+fi
+
+ ac_fn_c_check_decl "$LINENO" "mbr_check_membership_refresh" "ac_cv_have_decl_mbr_check_membership_refresh" "#include <membership.h>
+"
+if test "x$ac_cv_have_decl_mbr_check_membership_refresh" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+ mod_cflags="${mod_cflags} -DHAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH"
+fi
+
+fi
+
+
+ targetname=rlm_opendirectory
+else
+ targetname=
+ echo \*\*\* module rlm_opendirectory is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_opendirectory to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_opendirectory." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_opendirectory." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_opendirectory requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_opendirectory requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_opendirectory/configure.ac b/src/modules/rlm_opendirectory/configure.ac
new file mode 100644
index 0000000..2b99e9a
--- /dev/null
+++ b/src/modules/rlm_opendirectory/configure.ac
@@ -0,0 +1,32 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_opendirectory.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_opendirectory], [OpenDirectory support])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+mod_ldflags="${mod_ldflags} -F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks -framework DirectoryService"
+
+FR_SMART_CHECK_INCLUDE(membership.h)
+if test "$ac_cv_header_membership_h" != "yes"; then
+ FR_MODULE_FAIL([membership.h])
+else
+ AC_CHECK_DECLS(mbr_check_service_membership,
+ [mod_cflags="${mod_cflags} -DHAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP"],
+ [],[#include <membership.h>])
+ AC_CHECK_DECLS(mbr_check_membership_refresh,
+ [mod_cflags="${mod_cflags} -DHAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH"],
+ [],[#include <membership.h>])
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_opendirectory/rlm_opendirectory.c b/src/modules/rlm_opendirectory/rlm_opendirectory.c
new file mode 100644
index 0000000..580c62b
--- /dev/null
+++ b/src/modules/rlm_opendirectory/rlm_opendirectory.c
@@ -0,0 +1,483 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_opendirectory.c
+ * @brief Allows authentication against OpenDirectory and enforces ACLS.
+ *
+ * authentication: Apple Open Directory authentication
+ * authorization: enforces ACLs
+ *
+ * @copyright 2007 Apple Inc.
+ */
+
+/*
+ * For a typical Makefile, add linker flag like this:
+ * LDFLAGS = -framework DirectoryService
+ */
+USES_APPLE_DEPRECATED_API
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <DirectoryService/DirectoryService.h>
+#include <membership.h>
+
+#ifndef HAVE_DECL_MBR_CHECK_SERVICE_MEMBERSHIP
+int mbr_check_service_membership(uuid_t const user, char const *servicename, int *ismember);
+#endif
+#ifndef HAVE_DECL_MBR_CHECK_MEMBERSHIP_REFRESH
+int mbr_check_membership_refresh(uuid_t const user, uuid_t group, int *ismember);
+#endif
+
+/* RADIUS service ACL constants */
+#define kRadiusSACLName "com.apple.access_radius"
+#define kRadiusServiceName "radius"
+
+#define kAuthType "opendirectory"
+
+/*
+ * od_check_passwd
+ *
+ * Returns: ds err
+ */
+
+static long od_check_passwd(REQUEST *request, char const *uname, char const *password)
+{
+ long result = eDSAuthFailed;
+ tDirReference dsRef = 0;
+ tDataBuffer *tDataBuff;
+ tDirNodeReference nodeRef = 0;
+ long status = eDSNoErr;
+ tContextData context = 0;
+ uint32_t nodeCount = 0;
+ uint32_t attrIndex = 0;
+ tDataList *nodeName = NULL;
+ tAttributeEntryPtr pAttrEntry = NULL;
+ tDataList *pRecName = NULL;
+ tDataList *pRecType = NULL;
+ tDataList *pAttrType = NULL;
+ uint32_t recCount = 0;
+ tRecordEntry *pRecEntry = NULL;
+ tAttributeListRef attrListRef = 0;
+ char *pUserLocation = NULL;
+ char *pUserName = NULL;
+ tAttributeValueListRef valueRef = 0;
+ tAttributeValueEntry *pValueEntry = NULL;
+ tDataList *pUserNode = NULL;
+ tDirNodeReference userNodeRef = 0;
+ tDataBuffer *pStepBuff = NULL;
+ tDataNode *pAuthType = NULL;
+ tAttributeValueEntry *pRecordType = NULL;
+ uint32_t uiCurr = 0;
+ uint32_t uiLen = 0;
+ uint32_t pwLen = 0;
+
+ if (!uname || !password)
+ return result;
+
+ do
+ {
+ status = dsOpenDirService( &dsRef );
+ if ( status != eDSNoErr )
+ return result;
+
+ tDataBuff = dsDataBufferAllocate( dsRef, 4096 );
+ if (!tDataBuff)
+ break;
+
+ /* find user on search node */
+ status = dsFindDirNodes( dsRef, tDataBuff, NULL, eDSSearchNodeName, &nodeCount, &context );
+ if (status != eDSNoErr || nodeCount < 1)
+ break;
+
+ status = dsGetDirNodeName( dsRef, tDataBuff, 1, &nodeName );
+ if (status != eDSNoErr)
+ break;
+
+ status = dsOpenDirNode( dsRef, nodeName, &nodeRef );
+ dsDataListDeallocate( dsRef, nodeName );
+ free( nodeName );
+ nodeName = NULL;
+ if (status != eDSNoErr)
+ break;
+
+ pRecName = dsBuildListFromStrings( dsRef, uname, NULL );
+ pRecType = dsBuildListFromStrings( dsRef, kDSStdRecordTypeUsers, kDSStdRecordTypeComputers, kDSStdRecordTypeMachines, NULL );
+ pAttrType = dsBuildListFromStrings( dsRef, kDSNAttrMetaNodeLocation, kDSNAttrRecordName, kDSNAttrRecordType, NULL );
+
+ recCount = 1;
+ status = dsGetRecordList( nodeRef, tDataBuff, pRecName, eDSExact, pRecType,
+ pAttrType, 0, &recCount, &context );
+ if ( status != eDSNoErr || recCount == 0 )
+ break;
+
+ status = dsGetRecordEntry( nodeRef, tDataBuff, 1, &attrListRef, &pRecEntry );
+ if ( status != eDSNoErr )
+ break;
+
+ for ( attrIndex = 1; (attrIndex <= pRecEntry->fRecordAttributeCount) && (status == eDSNoErr); attrIndex++ )
+ {
+ status = dsGetAttributeEntry( nodeRef, tDataBuff, attrListRef, attrIndex, &valueRef, &pAttrEntry );
+ if ( status == eDSNoErr && pAttrEntry != NULL )
+ {
+ if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrMetaNodeLocation ) == 0 )
+ {
+ status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
+ if ( status == eDSNoErr && pValueEntry != NULL )
+ {
+ pUserLocation = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
+ memcpy( pUserLocation, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
+ }
+ }
+ else
+ if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordName ) == 0 )
+ {
+ status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
+ if ( status == eDSNoErr && pValueEntry != NULL )
+ {
+ pUserName = talloc_zero_array(request, char, pValueEntry->fAttributeValueData.fBufferLength + 1);
+ memcpy( pUserName, pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueData.fBufferLength );
+ }
+ }
+ else
+ if ( strcmp( pAttrEntry->fAttributeSignature.fBufferData, kDSNAttrRecordType ) == 0 )
+ {
+ status = dsGetAttributeValue( nodeRef, tDataBuff, 1, valueRef, &pValueEntry );
+ if ( status == eDSNoErr && pValueEntry != NULL )
+ {
+ pRecordType = pValueEntry;
+ pValueEntry = NULL;
+ }
+ }
+
+ if ( pValueEntry != NULL ) {
+ dsDeallocAttributeValueEntry( dsRef, pValueEntry );
+ pValueEntry = NULL;
+ }
+ if ( pAttrEntry != NULL ) {
+ dsDeallocAttributeEntry( dsRef, pAttrEntry );
+ pAttrEntry = NULL;
+ }
+ dsCloseAttributeValueList( valueRef );
+ valueRef = 0;
+ }
+ }
+
+ pUserNode = dsBuildFromPath( dsRef, pUserLocation, "/" );
+ status = dsOpenDirNode( dsRef, pUserNode, &userNodeRef );
+ dsDataListDeallocate( dsRef, pUserNode );
+ free( pUserNode );
+ pUserNode = NULL;
+ if ( status != eDSNoErr )
+ break;
+
+ pStepBuff = dsDataBufferAllocate( dsRef, 128 );
+
+ pAuthType = dsDataNodeAllocateString( dsRef, kDSStdAuthNodeNativeClearTextOK );
+ uiCurr = 0;
+
+ if (!pUserName) {
+ RDEBUG("Failed to find user name");
+ break;
+ }
+
+ /* User name */
+ uiLen = (uint32_t)strlen( pUserName );
+ memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &uiLen, sizeof(uiLen) );
+ uiCurr += (uint32_t)sizeof( uiLen );
+ memcpy( &(tDataBuff->fBufferData[ uiCurr ]), pUserName, uiLen );
+ uiCurr += uiLen;
+
+ /* pw */
+ pwLen = (uint32_t)strlen( password );
+ memcpy( &(tDataBuff->fBufferData[ uiCurr ]), &pwLen, sizeof(pwLen) );
+ uiCurr += (uint32_t)sizeof( pwLen );
+ memcpy( &(tDataBuff->fBufferData[ uiCurr ]), password, pwLen );
+ uiCurr += pwLen;
+
+ tDataBuff->fBufferLength = uiCurr;
+
+ result = dsDoDirNodeAuthOnRecordType( userNodeRef, pAuthType, 1, tDataBuff, pStepBuff, NULL, &pRecordType->fAttributeValueData );
+ }
+ while ( 0 );
+
+ /* clean up */
+ if (pAuthType != NULL) {
+ dsDataNodeDeAllocate( dsRef, pAuthType );
+ pAuthType = NULL;
+ }
+ if (pRecordType != NULL) {
+ dsDeallocAttributeValueEntry( dsRef, pRecordType );
+ pRecordType = NULL;
+ }
+ if (tDataBuff != NULL) {
+ bzero( tDataBuff, tDataBuff->fBufferSize );
+ dsDataBufferDeAllocate( dsRef, tDataBuff );
+ tDataBuff = NULL;
+ }
+ if (pStepBuff != NULL) {
+ dsDataBufferDeAllocate( dsRef, pStepBuff );
+ pStepBuff = NULL;
+ }
+ if (pUserLocation != NULL) {
+ talloc_free(pUserLocation);
+ pUserLocation = NULL;
+ }
+ if (pUserName != NULL) {
+ talloc_free(pUserName);
+ pUserName = NULL;
+ }
+ if (pRecName != NULL) {
+ dsDataListDeallocate( dsRef, pRecName );
+ free( pRecName );
+ pRecName = NULL;
+ }
+ if (pRecType != NULL) {
+ dsDataListDeallocate( dsRef, pRecType );
+ free( pRecType );
+ pRecType = NULL;
+ }
+ if (pAttrType != NULL) {
+ dsDataListDeallocate( dsRef, pAttrType );
+ free( pAttrType );
+ pAttrType = NULL;
+ }
+ if (nodeRef != 0) {
+ dsCloseDirNode(nodeRef);
+ nodeRef = 0;
+ }
+ if (dsRef != 0) {
+ dsCloseDirService(dsRef);
+ dsRef = 0;
+ }
+
+ return result;
+}
+
+
+/*
+ * Check the users password against the standard UNIX
+ * password table.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
+{
+ int ret;
+ long odResult = eDSAuthFailed;
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
+ */
+ if (!request->username) {
+ REDEBUG("You set 'Auth-Type = OpenDirectory' for a request that does not contain a User-Name attribute!");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Can't do OpenDirectory if there's no password.
+ */
+ if (!request->password ||
+ (request->password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("You set 'Auth-Type = OpenDirectory' for a request that does not contain a User-Password attribute!");
+ return RLM_MODULE_INVALID;
+ }
+
+ odResult = od_check_passwd(request, request->username->vp_strvalue,
+ request->password->vp_strvalue);
+ switch (odResult) {
+ case eDSNoErr:
+ ret = RLM_MODULE_OK;
+ break;
+
+ case eDSAuthUnknownUser:
+ case eDSAuthInvalidUserName:
+ case eDSAuthNewPasswordRequired:
+ case eDSAuthPasswordExpired:
+ case eDSAuthAccountDisabled:
+ case eDSAuthAccountExpired:
+ case eDSAuthAccountInactive:
+ case eDSAuthInvalidLogonHours:
+ case eDSAuthInvalidComputer:
+ ret = RLM_MODULE_USERLOCK;
+ break;
+
+ default:
+ ret = RLM_MODULE_REJECT;
+ break;
+ }
+
+ if (ret != RLM_MODULE_OK) {
+ RDEBUG("[%s]: Invalid password", request->username->vp_strvalue);
+ return ret;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * member of the radius group?
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ struct passwd *userdata = NULL;
+ int ismember = 0;
+ RADCLIENT *rad_client = NULL;
+ uuid_t uuid;
+ uuid_t guid_sacl;
+ uuid_t guid_nasgroup;
+ int err;
+ char host_ipaddr[128] = {0};
+ gid_t gid;
+
+ if (!request->username) {
+ RDEBUG("OpenDirectory requires a User-Name attribute");
+ return RLM_MODULE_NOOP;
+ }
+
+ /* resolve SACL */
+ uuid_clear(guid_sacl);
+
+ if (rad_getgid(request, &gid, kRadiusSACLName) < 0) {
+ RDEBUG("The SACL group \"%s\" does not exist on this system.", kRadiusSACLName);
+ } else {
+ err = mbr_gid_to_uuid(gid, guid_sacl);
+ if (err != 0) {
+ ERROR("rlm_opendirectory: The group \"%s\" does not have a GUID.", kRadiusSACLName);
+ return RLM_MODULE_FAIL;
+ }
+ }
+
+ /* resolve client access list */
+ uuid_clear(guid_nasgroup);
+
+ rad_client = request->client;
+#if 0
+ if (rad_client->community[0] != '\0' )
+ {
+ /*
+ * The "community" can be a GUID (Globally Unique ID) or
+ * a group name
+ */
+ if (uuid_parse(rad_client->community, guid_nasgroup) != 0) {
+ /* attempt to resolve the name */
+ groupdata = getgrnam(rad_client->community);
+ if (!groupdata) {
+ AUTH("rlm_opendirectory: The group \"%s\" does not exist on this system.", rad_client->community);
+ return RLM_MODULE_FAIL;
+ }
+ err = mbr_gid_to_uuid(groupdata->gr_gid, guid_nasgroup);
+ if (err != 0) {
+ AUTH("rlm_opendirectory: The group \"%s\" does not have a GUID.", rad_client->community);
+ return RLM_MODULE_FAIL;
+ }
+ }
+ }
+ else
+#endif
+ {
+ if (!rad_client) {
+ RDEBUG("The client record could not be found for host %s.",
+ ip_ntoh(&request->packet->src_ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ }
+ else {
+ RDEBUG("The host %s does not have an access group.",
+ ip_ntoh(&request->packet->src_ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ }
+ }
+
+ if (uuid_is_null(guid_sacl) && uuid_is_null(guid_nasgroup)) {
+ RDEBUG("no access control groups, all users allowed");
+ if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) {
+ pair_make_config("Auth-Type", kAuthType, T_OP_EQ);
+ RDEBUG("Setting Auth-Type = %s", kAuthType);
+ }
+ return RLM_MODULE_OK;
+ }
+
+ /* resolve user */
+ uuid_clear(uuid);
+
+ rad_getpwnam(request, &userdata, request->username->vp_strvalue);
+ if (userdata != NULL) {
+ err = mbr_uid_to_uuid(userdata->pw_uid, uuid);
+ if (err != 0)
+ uuid_clear(uuid);
+ }
+ talloc_free(userdata);
+
+ if (uuid_is_null(uuid)) {
+ REDEBUG("Could not get the user's uuid");
+ return RLM_MODULE_NOTFOUND;
+ }
+
+ if (!uuid_is_null(guid_sacl)) {
+ err = mbr_check_service_membership(uuid, kRadiusServiceName, &ismember);
+ if (err != 0) {
+ REDEBUG("Failed to check group membership");
+ return RLM_MODULE_FAIL;
+ }
+
+ if (ismember == 0) {
+ REDEBUG("User is not authorized");
+ return RLM_MODULE_USERLOCK;
+ }
+ }
+
+ if (!uuid_is_null(guid_nasgroup)) {
+ err = mbr_check_membership_refresh(uuid, guid_nasgroup, &ismember);
+ if (err != 0) {
+ REDEBUG("Failed to check group membership");
+ return RLM_MODULE_FAIL;
+ }
+
+ if (ismember == 0) {
+ REDEBUG("User is not authorized");
+ return RLM_MODULE_USERLOCK;
+ }
+ }
+
+ if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) {
+ pair_make_config("Auth-Type", kAuthType, T_OP_EQ);
+ RDEBUG("Setting Auth-Type = %s", kAuthType);
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+/* globally exported name */
+extern module_t rlm_opendirectory;
+module_t rlm_opendirectory = {
+ .magic = RLM_MODULE_INIT,
+ .name = "opendirectory",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_pam/.gitignore b/src/modules/rlm_pam/.gitignore
new file mode 100644
index 0000000..589d7ff
--- /dev/null
+++ b/src/modules/rlm_pam/.gitignore
@@ -0,0 +1,2 @@
+all.mk
+config.h
diff --git a/src/modules/rlm_pam/README.md b/src/modules/rlm_pam/README.md
new file mode 100644
index 0000000..d40c31d
--- /dev/null
+++ b/src/modules/rlm_pam/README.md
@@ -0,0 +1,9 @@
+# rlm_pam
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Performs password checking via the Pluggable Authentication Module (PAM) framework.
diff --git a/src/modules/rlm_pam/all.mk.in b/src/modules/rlm_pam/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_pam/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_pam/config.h.in b/src/modules/rlm_pam/config.h.in
new file mode 100644
index 0000000..0654924
--- /dev/null
+++ b/src/modules/rlm_pam/config.h.in
@@ -0,0 +1,43 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if you have the <pam/pam_modules.h> header file. */
+#undef HAVE_PAM_PAM_MODULES_H
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the <security/pam_modules.h> header file. */
+#undef HAVE_SECURITY_PAM_MODULES_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/src/modules/rlm_pam/configure b/src/modules/rlm_pam/configure
new file mode 100755
index 0000000..3045bdd
--- /dev/null
+++ b/src/modules/rlm_pam/configure
@@ -0,0 +1,4709 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_pam.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_pam
+'
+ 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_pam build without support for PAM authentication
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_pam
+echo
+
+
+# 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_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $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
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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; } && { ac_try='./conftest$ac_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 :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ 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_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ 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. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_pam was given.
+if test "${with_rlm_pam+set}" = set; then :
+ withval=$with_rlm_pam;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_pam" != 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
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ mod_ldflags="-ldl"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5
+$as_echo_n "checking for pam_start in -lpam... " >&6; }
+if ${ac_cv_lib_pam_pam_start+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam $mod_ldflags
+ $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pam_start ();
+int
+main ()
+{
+return pam_start ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pam_pam_start=yes
+else
+ ac_cv_lib_pam_pam_start=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_start" >&5
+$as_echo "$ac_cv_lib_pam_pam_start" >&6; }
+if test "x$ac_cv_lib_pam_pam_start" = xyes; then :
+ mod_ldflags="-lpam $mod_ldflags"
+else
+
+fail="$fail libpam"
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in \
+ security/pam_appl.h \
+ pam/pam_appl.h \
+
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in security/pam_modules.h pam/pam_modules.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "
+ #ifdef HAVE_SECURITY_PAM_APPL_H
+ # include <security/pam_appl.h>
+ #endif
+ #ifdef HAVE_PAM_PAM_APPL_H
+ # include <pam/pam_appl.h>
+ #endif
+
+
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+mod_cflags="-I."
+
+
+ targetname=rlm_pam
+else
+ targetname=
+ echo \*\*\* module rlm_pam is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_pam to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_pam." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_pam." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_pam requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_pam requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_pam/configure.ac b/src/modules/rlm_pam/configure.ac
new file mode 100644
index 0000000..9f69845
--- /dev/null
+++ b/src/modules/rlm_pam/configure.ac
@@ -0,0 +1,50 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_pam.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_pam], [support for PAM authentication])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_CHECK_LIB(dl, dlopen,
+ [ mod_ldflags="-ldl" ]
+)
+
+AC_CHECK_LIB(pam, pam_start,
+ [ mod_ldflags="-lpam $mod_ldflags" ],
+ [ FR_MODULE_FAIL([libpam]) ],
+ [ $mod_ldflags ]
+)
+
+dnl #
+dnl # Yes, these DO have to be on separate lines,
+dnl # otherwise autoheader won't pick them up.
+dnl #
+AC_CHECK_HEADERS( \
+ security/pam_appl.h \
+ pam/pam_appl.h \
+ )
+
+AC_CHECK_HEADERS(security/pam_modules.h pam/pam_modules.h, [], [],
+[
+ #ifdef HAVE_SECURITY_PAM_APPL_H
+ # include <security/pam_appl.h>
+ #endif
+ #ifdef HAVE_PAM_PAM_APPL_H
+ # include <pam/pam_appl.h>
+ #endif
+]
+)
+mod_cflags="-I."
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_pam/rlm_pam.c b/src/modules/rlm_pam/rlm_pam.c
new file mode 100644
index 0000000..70d8332
--- /dev/null
+++ b/src/modules/rlm_pam/rlm_pam.c
@@ -0,0 +1,244 @@
+/*
+ * 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_pam.c
+ * @brief Interfaces with the PAM library to allow auth via PAM.
+ *
+ * @note This was taken from the hacks that miguel a.l. paraz <map@iphil.net>
+ * did on radiusd-cistron-1.5.3 and migrated to a separate file.
+ * That, in fact, was again based on the original stuff from
+ * Jeph Blaize <jblaize@kiva.net> done in May 1997.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 1997 Jeph Blaize <jblaize@kiva.net>
+ * @copyright 1999 miguel a.l. paraz <map@iphil.net>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "config.h"
+
+#ifdef HAVE_SECURITY_PAM_APPL_H
+# include <security/pam_appl.h>
+#endif
+
+#ifdef HAVE_PAM_PAM_APPL_H
+# include <pam/pam_appl.h>
+#endif
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+typedef struct rlm_pam_t {
+ char const *pam_auth_name;
+} rlm_pam_t;
+
+static const CONF_PARSER module_config[] = {
+ { "pam_auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_pam_t, pam_auth_name), "radiusd" },
+ CONF_PARSER_TERMINATOR
+};
+
+typedef struct rlm_pam_data_t {
+ REQUEST *request; //!< The current request.
+ char const *username; //!< Username to provide to PAM when prompted.
+ char const *password; //!< Password to provide to PAM when prompted.
+ bool error; //!< True if pam_conv failed.
+} rlm_pam_data_t;
+
+/** Dialogue between RADIUS and PAM modules
+ *
+ * Uses PAM's appdata_ptr so it's thread safe, and doesn't
+ * have any nasty static variables hanging around.
+ */
+static int pam_conv(int num_msg, struct pam_message const **msg, struct pam_response **resp, void *appdata_ptr)
+{
+ int count;
+ struct pam_response *reply;
+ REQUEST *request;
+ rlm_pam_data_t *pam_config = (rlm_pam_data_t *) appdata_ptr;
+
+ request = pam_config->request;
+
+/* strdup(NULL) doesn't work on some platforms */
+#define COPY_STRING(s) ((s) ? strdup(s) : NULL)
+
+ reply = rad_malloc(num_msg * sizeof(struct pam_response));
+ memset(reply, 0, num_msg * sizeof(struct pam_response));
+ for (count = 0; count < num_msg; count++) {
+ switch (msg[count]->msg_style) {
+ case PAM_PROMPT_ECHO_ON:
+ reply[count].resp_retcode = PAM_SUCCESS;
+ reply[count].resp = COPY_STRING(pam_config->username);
+ break;
+
+ case PAM_PROMPT_ECHO_OFF:
+ reply[count].resp_retcode = PAM_SUCCESS;
+ reply[count].resp = COPY_STRING(pam_config->password);
+ break;
+
+ case PAM_TEXT_INFO:
+ RDEBUG2("%s", msg[count]->msg);
+ break;
+
+ case PAM_ERROR_MSG:
+ default:
+ RERROR("PAM conversation failed");
+ /* Must be an error of some sort... */
+ for (count = 0; count < num_msg; count++) {
+ if (msg[count]->msg_style == PAM_ERROR_MSG) RERROR("%s", msg[count]->msg);
+ if (reply[count].resp) {
+ /* could be a password, let's be sanitary */
+ memset(reply[count].resp, 0, strlen(reply[count].resp));
+ free(reply[count].resp);
+ }
+ }
+ free(reply);
+ pam_config->error = true;
+ return PAM_CONV_ERR;
+ }
+ }
+ *resp = reply;
+ /* PAM frees reply (including reply[].resp) */
+
+ return PAM_SUCCESS;
+}
+
+/** Check the users password against the standard UNIX password table + PAM.
+ *
+ * @note For most flexibility, passing a pamauth type to this function
+ * allows you to have multiple authentication types (i.e. multiple
+ * files associated with radius in /etc/pam.d).
+ *
+ * @param request The current request.
+ * @param username User to authenticate.
+ * @param passwd Password to authenticate with,
+ * @param pamauth Type of PAM authentication.
+ * @return 0 on success -1 on failure.
+ */
+static int do_pam(REQUEST *request, char const *username, char const *passwd, char const *pamauth)
+{
+ pam_handle_t *handle = NULL;
+ int ret;
+ rlm_pam_data_t pam_config;
+ struct pam_conv conv;
+
+ /*
+ * Initialize the structures
+ */
+ conv.conv = pam_conv;
+ conv.appdata_ptr = &pam_config;
+ pam_config.request = request;
+ pam_config.username = username;
+ pam_config.password = passwd;
+ pam_config.error = false;
+
+ RDEBUG2("Using pamauth string \"%s\" for pam.conf lookup", pamauth);
+
+ ret = pam_start(pamauth, username, &conv, &handle);
+ if (ret != PAM_SUCCESS) {
+ RERROR("pam_start failed: %s", pam_strerror(handle, ret));
+ return -1;
+ }
+
+ ret = pam_authenticate(handle, 0);
+ if (ret != PAM_SUCCESS) {
+ RERROR("pam_authenticate failed: %s", pam_strerror(handle, ret));
+ pam_end(handle, ret);
+ return -1;
+ }
+
+ /*
+ * FreeBSD 3.x doesn't have account and session management
+ * functions in PAM, while 4.0 does.
+ */
+#if !defined(__FreeBSD_version) || (__FreeBSD_version >= 400000)
+ ret = pam_acct_mgmt(handle, 0);
+ if (ret != PAM_SUCCESS) {
+ RERROR("pam_acct_mgmt failed: %s", pam_strerror(handle, ret));
+ pam_end(handle, ret);
+ return -1;
+ }
+#endif
+ RDEBUG2("Authentication succeeded");
+ pam_end(handle, ret);
+ return 0;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ int ret;
+ VALUE_PAIR *pair;
+ rlm_pam_t *data = (rlm_pam_t *) instance;
+
+ char const *pam_auth_string = data->pam_auth_name;
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
+ */
+ if (!request->username) {
+ RAUTH("Attribute \"User-Name\" is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Password attribute.
+ */
+ if (!request->password) {
+ RAUTH("Attribute \"User-Password\" is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Ensure that we're being passed a plain-text password,
+ * and not anything else.
+ */
+ if (request->password->da->attr != PW_USER_PASSWORD) {
+ RAUTH("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->da->name);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Let the 'users' file over-ride the PAM auth name string,
+ * for backwards compatibility.
+ */
+ pair = fr_pair_find_by_num(request->config, PW_PAM_AUTH, 0, TAG_ANY);
+ if (pair) pam_auth_string = pair->vp_strvalue;
+
+ ret = do_pam(request, request->username->vp_strvalue, request->password->vp_strvalue, pam_auth_string);
+ if (ret < 0) return RLM_MODULE_REJECT;
+
+ return RLM_MODULE_OK;
+}
+
+extern module_t rlm_pam;
+module_t rlm_pam = {
+ .magic = RLM_MODULE_INIT,
+ .name = "pam",
+ .type = RLM_TYPE_THREAD_UNSAFE, /* The PAM libraries are not thread-safe */
+ .inst_size = sizeof(rlm_pam_t),
+ .config = module_config,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate
+ },
+};
+
diff --git a/src/modules/rlm_pap/README.md b/src/modules/rlm_pap/README.md
new file mode 100644
index 0000000..333c60b
--- /dev/null
+++ b/src/modules/rlm_pap/README.md
@@ -0,0 +1,13 @@
+# rlm_pap
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Accepts a large number of formats for the "known good" (reference)
+password, such as crypt hashes, md5 hashes, and etc. The module
+takes the User-Password and performs the necessary transformations
+of the user submitted password to match the copy of the password
+the server has retrieved.
diff --git a/src/modules/rlm_pap/all.mk b/src/modules/rlm_pap/all.mk
new file mode 100644
index 0000000..adec9cd
--- /dev/null
+++ b/src/modules/rlm_pap/all.mk
@@ -0,0 +1,2 @@
+SOURCES := rlm_pap.c
+TARGET := rlm_pap.a
diff --git a/src/modules/rlm_pap/rlm_pap.c b/src/modules/rlm_pap/rlm_pap.c
new file mode 100644
index 0000000..463ff66
--- /dev/null
+++ b/src/modules/rlm_pap/rlm_pap.c
@@ -0,0 +1,1422 @@
+/*
+ * 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_pap.c
+ * @brief Hashes plaintext passwords to compare against a prehashed reference.
+ *
+ * @copyright 2001-2012 The FreeRADIUS server project.
+ * @copyright 2012 Matthew Newton <matthew@newtoncomputing.co.uk>
+ * @copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
+ */
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/base64.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include "../../include/md5.h"
+#include "../../include/sha1.h"
+
+#ifdef HAVE_OPENSSL_EVP_H
+# include <openssl/evp.h>
+#endif
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_pap_t {
+ char const *name; /* CONF_SECTION->name, not strdup'd */
+ int auth_type;
+ bool normify;
+} rlm_pap_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "normalise", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_pap_t, normify), "yes" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * For auto-header discovery.
+ *
+ * @note Header comparison is case insensitive.
+ */
+static const FR_NAME_NUMBER header_names[] = {
+ { "{clear}", PW_CLEARTEXT_PASSWORD },
+ { "{cleartext}", PW_CLEARTEXT_PASSWORD },
+ { "{md5}", PW_MD5_PASSWORD },
+ { "{base64_md5}", PW_MD5_PASSWORD },
+ { "{smd5}", PW_SMD5_PASSWORD },
+ { "{crypt}", PW_CRYPT_PASSWORD },
+#ifdef HAVE_OPENSSL_EVP_H
+ /*
+ * It'd make more sense for the headers to be
+ * ssha2-* with SHA3 coming soon but we're at
+ * the mercy of directory implementors.
+ */
+ { "{sha2}", PW_SHA2_PASSWORD },
+ { "{sha224}", PW_SHA2_PASSWORD },
+ { "{sha256}", PW_SHA2_PASSWORD },
+ { "{sha384}", PW_SHA2_PASSWORD },
+ { "{sha512}", PW_SHA2_PASSWORD },
+ { "{ssha224}", PW_SSHA2_224_PASSWORD },
+ { "{ssha256}", PW_SSHA2_256_PASSWORD },
+ { "{ssha384}", PW_SSHA2_384_PASSWORD },
+ { "{ssha512}", PW_SSHA2_512_PASSWORD },
+ { "{x-pbkdf2}", PW_PBKDF2_PASSWORD },
+#endif
+ { "{sha}", PW_SHA_PASSWORD },
+ { "{ssha}", PW_SSHA_PASSWORD },
+ { "{md4}", PW_NT_PASSWORD },
+ { "{nt}", PW_NT_PASSWORD },
+ { "{nthash}", PW_NT_PASSWORD },
+ { "{x-nthash}", PW_NT_PASSWORD },
+ { "{ns-mta-md5}", PW_NS_MTA_MD5_PASSWORD },
+ { "{x- orcllmv}", PW_LM_PASSWORD },
+ { "{X- orclntv}", PW_NT_PASSWORD },
+ { NULL, 0 }
+};
+
+#ifdef HAVE_OPENSSL_EVP_H
+static const FR_NAME_NUMBER pbkdf2_crypt_names[] = {
+ { "HMACSHA1", PW_SSHA1_PASSWORD },
+ { "HMACSHA2+224", PW_SSHA2_224_PASSWORD },
+ { "HMACSHA2+256", PW_SSHA2_256_PASSWORD },
+ { "HMACSHA2+384", PW_SSHA2_384_PASSWORD },
+ { "HMACSHA2+512", PW_SSHA2_512_PASSWORD },
+# if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ { "HMACSHA3+224", PW_SSHA3_224_PASSWORD },
+ { "HMACSHA3+256", PW_SSHA3_256_PASSWORD },
+ { "HMACSHA3+384", PW_SSHA3_384_PASSWORD },
+ { "HMACSHA3+512", PW_SSHA3_512_PASSWORD },
+# endif
+};
+
+static const FR_NAME_NUMBER pbkdf2_passlib_names[] = {
+ { "sha1", PW_SSHA1_PASSWORD },
+ { "sha256", PW_SSHA2_256_PASSWORD },
+ { "sha512", PW_SSHA2_512_PASSWORD }
+};
+#endif
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_pap_t *inst = instance;
+ DICT_VALUE *dval;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->name);
+ if (dval) {
+ inst->auth_type = dval->value;
+ } else {
+ inst->auth_type = 0;
+ }
+
+ return 0;
+}
+
+/** Hex or base64 or bin auto-discovery
+ *
+ * Here we try and autodiscover what encoding was used for the password/hash, and
+ * convert it back to binary or plaintext.
+ *
+ * @note Earlier versions used a 0x prefix as a hard indicator that the string was
+ * hex encoded, and would fail if the 0x was present but the string didn't
+ * consist of hexits. The base64 char set is a superset of hex, and it was
+ * observed in the wild, that occasionally base64 encoded data really could
+ * start with 0x. That's why min_len (and decodability) are used as the
+ * only heuristics now.
+ *
+ * @param[in] request Current request.
+ * @param[in,out] vp to normify.
+ * @param[in] min_len we expect the decoded version to be.
+ */
+static void normify(REQUEST *request, VALUE_PAIR *vp, size_t min_len)
+{
+ uint8_t buffer[256];
+
+ if (min_len >= sizeof(buffer)) return; /* paranoia */
+
+ rad_assert((vp->da->type == PW_TYPE_OCTETS) || (vp->da->type == PW_TYPE_STRING));
+
+ /*
+ * Hex encoding. Length is even, and it's greater than
+ * twice the minimum length.
+ */
+ if (!(vp->vp_length & 0x01) && vp->vp_length >= (2 * min_len)) {
+ size_t decoded;
+
+ decoded = fr_hex2bin(buffer, sizeof(buffer), vp->vp_strvalue, vp->vp_length);
+ if (decoded == (vp->vp_length >> 1)) {
+ RDEBUG2("Normalizing %s from hex encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->vp_length, decoded);
+ fr_pair_value_memcpy(vp, buffer, decoded);
+ return;
+ }
+ }
+
+ /*
+ * Base 64 encoding. It's at least 4/3 the original size,
+ * and we want to avoid division...
+ */
+ if ((vp->vp_length * 3) >= ((min_len * 4))) {
+ ssize_t decoded;
+ decoded = fr_base64_decode(buffer, sizeof(buffer), vp->vp_strvalue, vp->vp_length);
+ if (decoded < 0) return;
+ if (decoded >= (ssize_t) min_len) {
+ RDEBUG2("Normalizing %s from base64 encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->vp_length, decoded);
+ fr_pair_value_memcpy(vp, buffer, decoded);
+ return;
+ }
+ }
+
+ /*
+ * Else unknown encoding, or already binary. Leave it.
+ */
+}
+
+/** Convert a Password-With-Header attribute to the correct type
+ *
+ * Attribute may be base64 encoded, in which case it will be decoded
+ * first, then evaluated.
+ *
+ * @note The buffer for octets types\ attributes is extended by one byte
+ * and '\0' terminated, to allow it to be used as a char buff.
+ *
+ * @param request Current request.
+ * @param vp Password-With-Header attribute to convert.
+ * @return a new VALUE_PAIR on success, NULL on error.
+ */
+static VALUE_PAIR *normify_with_header(REQUEST *request, VALUE_PAIR *vp)
+{
+ int attr;
+ char const *p, *q;
+ size_t len;
+
+ uint8_t digest[257]; /* +1 for \0 */
+ ssize_t decoded;
+
+ char buffer[256];
+
+ VALUE_PAIR *new;
+
+ VERIFY_VP(vp);
+
+ /*
+ * Ensure this is only ever called with a
+ * string type attribute.
+ */
+ rad_assert(vp->da->type == PW_TYPE_STRING);
+
+redo:
+ p = vp->vp_strvalue;
+ len = vp->vp_length;
+
+ /*
+ * Has a header {...} prefix
+ */
+ q = strchr(p, '}');
+ if (q) {
+ size_t hlen;
+
+ hlen = (q + 1) - p;
+ if (hlen >= sizeof(buffer)) {
+ REDEBUG("Password header too long. Got %zu bytes must be less than %zu bytes",
+ hlen, sizeof(buffer));
+ return NULL;
+ }
+
+ memcpy(buffer, p, hlen);
+ buffer[hlen] = '\0';
+
+ attr = fr_str2int(header_names, buffer, 0);
+ if (!attr) {
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Unknown header %s in Password-With-Header = \"%s\", re-writing to "
+ "Cleartext-Password", buffer, vp->vp_strvalue);
+ } else {
+ RDEBUG("Unknown header %s in Password-With-Header, re-writing to "
+ "Cleartext-Password", buffer);
+ }
+ goto unknown_header;
+ }
+
+ /*
+ * The data after the '}' may be binary, so we copy it via
+ * memcpy. BUT it might be a string (or used as one), so
+ * we ensure that there's a trailing zero, too.
+ */
+ new = fr_pair_afrom_num(request, attr, 0);
+ if (new->da->type == PW_TYPE_OCTETS) {
+ fr_pair_value_memcpy(new, (uint8_t const *) q + 1, (len - hlen) + 1);
+ new->vp_length = (len - hlen); /* lie about the length */
+ } else {
+ fr_pair_value_strcpy(new, q + 1);
+ }
+
+ if (RDEBUG_ENABLED3) {
+ char *old_value, *new_value;
+
+ old_value = vp_aprints_value(request, vp, '\'');
+ new_value = vp_aprints_value(request, new, '\'');
+ RDEBUG3("Converted: &control:%s = '%s' -> &control:%s = '%s'",
+ vp->da->name, old_value, new->da->name, new_value);
+ talloc_free(old_value);
+ talloc_free(new_value);
+ } else {
+ RDEBUG2("Converted: &control:%s -> &control:%s", vp->da->name, new->da->name);
+ }
+
+ return new;
+ }
+
+ /*
+ * Doesn't have a header {...} prefix
+ *
+ * See if it's base64, if it is, decode it and check again!
+ */
+ decoded = fr_base64_decode(digest, sizeof(digest) - 1, vp->vp_strvalue, len);
+ if ((decoded > 0) && (digest[0] == '{') && (memchr(digest, '}', decoded) != NULL)) {
+ RDEBUG2("Normalizing %s from base64 encoding, %zu bytes -> %zu bytes",
+ vp->da->name, vp->vp_length, decoded);
+ /*
+ * Password-With-Header is a string attribute.
+ * Even though we're handling binary data, the buffer
+ * must be \0 terminated.
+ */
+ digest[decoded] = '\0';
+ fr_pair_value_memcpy(vp, digest, decoded + 1);
+ vp->vp_length = decoded; /* lie about the length */
+
+ goto redo;
+ }
+
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("No {...} in Password-With-Header = \"%s\", re-writing to "
+ "Cleartext-Password", vp->vp_strvalue);
+ } else {
+ RDEBUG("No {...} in Password-With-Header, re-writing to Cleartext-Password");
+ }
+
+unknown_header:
+ new = fr_pair_afrom_num(request, PW_CLEARTEXT_PASSWORD, 0);
+ fr_pair_value_strcpy(new, vp->vp_strvalue);
+
+ return new;
+}
+
+/*
+ * Authorize the user for PAP authentication.
+ *
+ * This isn't strictly necessary, but it does make the
+ * server simpler to configure.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_pap_t *inst = instance;
+ bool auth_type = false;
+ bool found_pw = false;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &request->config);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+
+ next:
+
+ VERIFY_VP(vp);
+
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ case PW_USER_PASSWORD: /* deprecated */
+ RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ RWDEBUG("!!! Ignoring control:User-Password. Update your !!!");
+ RWDEBUG("!!! configuration so that the \"known good\" clear text !!!");
+ RWDEBUG("!!! password is in Cleartext-Password and NOT in !!!");
+ RWDEBUG("!!! User-Password. !!!");
+ RWDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ break;
+
+ case PW_PASSWORD_WITH_HEADER: /* preferred */
+ {
+ VALUE_PAIR *new;
+
+ /*
+ * Password already exists: use that instead of this one.
+ */
+ if (fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) {
+ RWDEBUG("Config already contains a \"known good\" password "
+ "(&control:Cleartext-Password). Ignoring &control:Password-With-Header");
+ break;
+ }
+
+ new = normify_with_header(request, vp);
+ if (new) fr_cursor_insert(&cursor, new); /* inserts at the end of the list */
+
+ RDEBUG2("Removing &control:Password-With-Header");
+ vp = fr_cursor_remove(&cursor); /* advances the cursor for us */
+ talloc_free(vp);
+
+ found_pw = true;
+
+ vp = fr_cursor_current(&cursor);
+ if (vp) goto next;
+ }
+ break;
+
+ case PW_CLEARTEXT_PASSWORD:
+ case PW_CRYPT_PASSWORD:
+ case PW_NS_MTA_MD5_PASSWORD:
+ found_pw = true;
+ break; /* don't touch these */
+
+ case PW_MD5_PASSWORD:
+ case PW_SMD5_PASSWORD:
+ case PW_NT_PASSWORD:
+ case PW_LM_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 16); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+#ifdef HAVE_OPENSSL_EVP_H
+ case PW_SHA2_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 28); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+ case PW_SSHA2_224_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 28); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+ case PW_SSHA2_256_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 32); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+ case PW_SSHA2_384_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 48); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+ case PW_SSHA2_512_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 64); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+#endif
+
+ case PW_SHA_PASSWORD:
+ case PW_SSHA_PASSWORD:
+ if (inst->normify) {
+ normify(request, vp, 20); /* ensure it's in the right format */
+ }
+ found_pw = true;
+ break;
+
+ /*
+ * If it's proxied somewhere, don't complain
+ * about not having passwords or Auth-Type.
+ */
+ case PW_PROXY_TO_REALM:
+ {
+ REALM *realm = realm_find(vp->vp_strvalue);
+ if (realm && realm->auth_pool) {
+ return RLM_MODULE_NOOP;
+ }
+ break;
+ }
+
+ case PW_AUTH_TYPE:
+ auth_type = true;
+
+ /*
+ * Auth-Type := Accept
+ * Auth-Type := Reject
+ */
+ if ((vp->vp_integer == PW_AUTH_TYPE_ACCEPT) ||
+ (vp->vp_integer == PW_AUTH_TYPE_REJECT)) {
+ found_pw = true;
+ }
+ break;
+
+ default:
+ break; /* ignore it */
+
+ }
+ }
+
+ /*
+ * Print helpful warnings if there was no password.
+ */
+ if (!found_pw) {
+ /*
+ * Likely going to be proxied. Avoid printing
+ * warning message.
+ */
+ if (fr_pair_find_by_num(request->config, PW_REALM, 0, TAG_ANY) ||
+ (fr_pair_find_by_num(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY))) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * The TLS types don't need passwords.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_EAP_TYPE, 0, TAG_ANY);
+ if (vp &&
+ ((vp->vp_integer == 13) || /* EAP-TLS */
+ (vp->vp_integer == 21) || /* EAP-TTLS */
+ (vp->vp_integer == 25))) { /* PEAP */
+ return RLM_MODULE_NOOP;
+ }
+
+ if (auth_type) {
+ DEBUG("Not doing PAP as Auth-Type is already set.");
+ return RLM_MODULE_NOOP;
+ }
+
+ RWDEBUG("No \"known good\" password found for the user. Not setting Auth-Type");
+ RWDEBUG("Authentication will fail unless a \"known good\" password is available");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Don't touch existing Auth-Types.
+ */
+ if (auth_type) {
+ if (auth_type != inst->auth_type) RWDEBUG2("Auth-Type already set. Not setting to PAP");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Can't do PAP if there's no password.
+ */
+ if (!request->password ||
+ (request->password->da->attr != PW_USER_PASSWORD)) {
+ RDEBUG2("No User-Password attribute in the request. Cannot do PAP");
+ return RLM_MODULE_NOOP;
+ }
+
+ if (inst->auth_type) {
+ vp = radius_pair_create(request, &request->config,
+ PW_AUTH_TYPE, 0);
+ vp->vp_integer = inst->auth_type;
+ }
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * PAP authentication functions
+ */
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_clear(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Comparing with \"known good\" Cleartext-Password \"%s\" (%zd)", vp->vp_strvalue, vp->vp_length);
+ } else {
+ RDEBUG("Comparing with \"known good\" Cleartext-Password");
+ }
+
+ if ((vp->vp_length != request->password->vp_length) ||
+ (rad_digest_cmp(vp->vp_octets,
+ request->password->vp_octets,
+ vp->vp_length) != 0)) {
+ REDEBUG("Cleartext password does not match \"known good\" password");
+ return RLM_MODULE_REJECT;
+ }
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_crypt(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Comparing with \"known good\" Crypt-Password \"%s\"", vp->vp_strvalue);
+ } else {
+ RDEBUG("Comparing with \"known-good\" Crypt-password");
+ }
+
+ if (fr_crypt_check(request->password->vp_strvalue,
+ vp->vp_strvalue) != 0) {
+ REDEBUG("Crypt digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_md5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ FR_MD5_CTX md5_context;
+ uint8_t digest[128];
+
+ RDEBUG("Comparing with \"known-good\" MD5-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 16);
+ }
+ if (vp->vp_length != 16) {
+ REDEBUG("\"known-good\" MD5 password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, request->password->vp_octets,
+ request->password->vp_length);
+ fr_md5_final(digest, &md5_context);
+ fr_md5_destroy(&md5_context);
+
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->vp_length) != 0) {
+ REDEBUG("MD5 digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_smd5(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ FR_MD5_CTX md5_context;
+ uint8_t digest[128];
+
+ RDEBUG("Comparing with \"known-good\" SMD5-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 16);
+ }
+ if (vp->vp_length <= 16) {
+ REDEBUG("\"known-good\" SMD5-Password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, request->password->vp_octets,
+ request->password->vp_length);
+ fr_md5_update(&md5_context, &vp->vp_octets[16], vp->vp_length - 16);
+ fr_md5_final(digest, &md5_context);
+ fr_md5_destroy(&md5_context);
+
+ /*
+ * Compare only the MD5 hash results, not the salt.
+ */
+ if (rad_digest_cmp(digest, vp->vp_octets, 16) != 0) {
+ REDEBUG("SMD5 digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_sha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ fr_sha1_ctx sha1_context;
+ uint8_t digest[128];
+
+ RDEBUG("Comparing with \"known-good\" SHA-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 20);
+ }
+ if (vp->vp_length != 20) {
+ REDEBUG("\"known-good\" SHA1-password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ fr_sha1_init(&sha1_context);
+ fr_sha1_update(&sha1_context, request->password->vp_octets,
+ request->password->vp_length);
+ fr_sha1_final(digest,&sha1_context);
+
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->vp_length) != 0) {
+ REDEBUG("SHA1 digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_ssha(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ fr_sha1_ctx sha1_context;
+ uint8_t digest[128];
+
+ RDEBUG("Comparing with \"known-good\" SSHA-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 20);
+ }
+ if (vp->vp_length <= 20) {
+ REDEBUG("\"known-good\" SSHA-Password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ fr_sha1_init(&sha1_context);
+ fr_sha1_update(&sha1_context, request->password->vp_octets, request->password->vp_length);
+
+ fr_sha1_update(&sha1_context, &vp->vp_octets[20], vp->vp_length - 20);
+ fr_sha1_final(digest, &sha1_context);
+
+ if (rad_digest_cmp(digest, vp->vp_octets, 20) != 0) {
+ REDEBUG("SSHA digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+#ifdef HAVE_OPENSSL_EVP_H
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_sha2(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ EVP_MD_CTX *ctx;
+ EVP_MD const *md;
+ char const *name;
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_len;
+
+ RDEBUG("Comparing with \"known-good\" SHA2-Password");
+
+ if (inst->normify) normify(request, vp, 28);
+
+ /*
+ * All the SHA-2 algorithms produce digests of different lengths,
+ * so it's trivial to determine which EVP_MD to use.
+ */
+ switch (vp->vp_length) {
+ /* SHA-224 */
+ case 28:
+ name = "SHA2-224";
+ md = EVP_sha224();
+ break;
+
+ /* SHA-256 */
+ case 32:
+ name = "SHA2-256";
+ md = EVP_sha256();
+ break;
+
+ /* SHA-384 */
+ case 48:
+ name = "SHA2-384";
+ md = EVP_sha384();
+ break;
+
+ /* SHA-512 */
+ case 64:
+ name = "SHA2-512";
+ md = EVP_sha512();
+ break;
+
+ default:
+ REDEBUG("\"known good\" digest length (%zu) does not match output length of any SHA-2 digests",
+ vp->vp_length);
+ return RLM_MODULE_INVALID;
+ }
+
+ ctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(ctx, md, NULL);
+ EVP_DigestUpdate(ctx, request->password->vp_octets, request->password->vp_length);
+ EVP_DigestFinal_ex(ctx, digest, &digest_len);
+ EVP_MD_CTX_destroy(ctx);
+
+ rad_assert((size_t) digest_len == vp->vp_length); /* This would be an OpenSSL bug... */
+
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->vp_length) != 0) {
+ REDEBUG("%s digest does not match \"known good\" digest", name);
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_ssha2(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ EVP_MD_CTX *ctx;
+ EVP_MD const *md = NULL;
+ char const *name = NULL;
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ unsigned int digest_len, min_len = 0;
+
+ switch (vp->da->attr) {
+ case PW_SSHA2_224_PASSWORD:
+ name = "SSHA2-224";
+ md = EVP_sha224();
+ min_len = 28;
+ break;
+
+ case PW_SSHA2_256_PASSWORD:
+ name = "SSHA2-256";
+ md = EVP_sha256();
+ min_len = 32;
+ break;
+
+ case PW_SSHA2_384_PASSWORD:
+ name = "SSHA2-384";
+ md = EVP_sha384();
+ min_len = 48;
+ break;
+
+ case PW_SSHA2_512_PASSWORD:
+ name = "SSHA2-512";
+ min_len = 64;
+ md = EVP_sha512();
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ RDEBUG("Comparing with \"known-good\" %s-Password", name);
+
+ /*
+ * Unlike plain SHA2 we already know what length
+ * to expect, so can be more specific with the
+ * minimum digest length.
+ */
+ if (inst->normify) normify(request, vp, min_len + 1);
+
+ if (vp->vp_length <= min_len) {
+ REDEBUG("\"known-good\" %s-Password has incorrect length, got %zu bytes, need at least %u bytes",
+ name, vp->vp_length, min_len + 1);
+ return RLM_MODULE_INVALID;
+ }
+
+ ctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(ctx, md, NULL);
+ EVP_DigestUpdate(ctx, request->password->vp_octets, request->password->vp_length);
+ EVP_DigestUpdate(ctx, &vp->vp_octets[min_len], vp->vp_length - min_len);
+ EVP_DigestFinal_ex(ctx, digest, &digest_len);
+ EVP_MD_CTX_destroy(ctx);
+
+ rad_assert((size_t) digest_len == min_len); /* This would be an OpenSSL bug... */
+
+ /*
+ * Only compare digest_len bytes, the rest is salt.
+ */
+ if (rad_digest_cmp(digest, vp->vp_octets, (size_t)digest_len) != 0) {
+ REDEBUG("%s digest does not match \"known good\" digest", name);
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+/** Validates Crypt::PBKDF2 LDAP format strings
+ *
+ * @param[in] request The current request.
+ * @param[in] str Raw PBKDF2 string.
+ * @param[in] len Length of string.
+ * @return
+ * - RLM_MODULE_REJECT
+ * - RLM_MODULE_OK
+ */
+static inline rlm_rcode_t CC_HINT(nonnull) pap_auth_pbkdf2_parse(REQUEST *request, const uint8_t *str, size_t len,
+ const FR_NAME_NUMBER hash_names[],
+ char scheme_sep, char iter_sep, char salt_sep,
+ bool iter_is_base64, VALUE_PAIR const *password)
+{
+ rlm_rcode_t rcode = RLM_MODULE_INVALID;
+
+ uint8_t const *p, *q, *end;
+ ssize_t slen;
+
+ EVP_MD const *evp_md;
+ int digest_type;
+ size_t digest_len;
+
+ uint32_t iterations;
+
+ uint8_t *salt = NULL;
+ size_t salt_len;
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ uint8_t digest[EVP_MAX_MD_SIZE];
+
+ char hash_token[128];
+
+ RDEBUG2("Comparing with \"known-good\" PBKDF2-Password");
+
+ if (len <= 1) {
+ REDEBUG("PBKDF2-Password is too short");
+ goto finish;
+ }
+
+ /*
+ * Parse PBKDF string = {hash_algorithm}<scheme_sep><iterations><iter_sep>b64(<salt>)<salt_sep>b64(<hash>)
+ */
+ p = str;
+ end = p + len;
+
+ q = memchr(p, scheme_sep, end - p);
+ if (!q) {
+ REDEBUG("PBKDF2-Password has no component separators");
+ goto finish;
+ }
+
+ if ((q-p) >= (int)sizeof(hash_token)) {
+ REDEBUG("PBKDF2-Password has invalid hash token");
+ goto finish;
+ }
+
+ memcpy(hash_token, (char const *)p, (q - p));
+ hash_token[q - p] = '\0';
+
+ digest_type = fr_str2int(hash_names, hash_token, -1);
+ switch (digest_type) {
+ case PW_SSHA1_PASSWORD:
+ evp_md = EVP_sha1();
+ digest_len = SHA1_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA2_224_PASSWORD:
+ evp_md = EVP_sha224();
+ digest_len = SHA224_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA2_256_PASSWORD:
+ evp_md = EVP_sha256();
+ digest_len = SHA256_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA2_384_PASSWORD:
+ evp_md = EVP_sha384();
+ digest_len = SHA384_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA2_512_PASSWORD:
+ evp_md = EVP_sha512();
+ digest_len = SHA512_DIGEST_LENGTH;
+ break;
+
+# if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ case PW_SSHA3_224_PASSWORD:
+ evp_md = EVP_sha3_224();
+ digest_len = SHA224_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA3_256_PASSWORD:
+ evp_md = EVP_sha3_256();
+ digest_len = SHA256_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA3_384_PASSWORD:
+ evp_md = EVP_sha3_384();
+ digest_len = SHA384_DIGEST_LENGTH;
+ break;
+
+ case PW_SSHA3_512_PASSWORD:
+ evp_md = EVP_sha3_512();
+ digest_len = SHA512_DIGEST_LENGTH;
+ break;
+# endif
+
+ default:
+ REDEBUG("Unknown PBKDF2 hash method \"%.*s\"", (int)(q - p), p);
+ goto finish;
+ }
+
+ p = q + 1;
+
+ if (((end - p) < 1) || !(q = memchr(p, iter_sep, end - p))) {
+ REDEBUG("PBKDF2-Password missing iterations component");
+ goto finish;
+ }
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password iterations component too short");
+ goto finish;
+ }
+
+ /*
+ * If it's not base64 encoded, assume it's ascii
+ */
+ if (!iter_is_base64) {
+ char iterations_buff[sizeof("4294967295") + 1];
+ char *qq;
+
+ strlcpy(iterations_buff, (char const *)p, (q - p) + 1);
+
+ iterations = strtoul(iterations_buff, &qq, 10);
+ if (*qq != '\0') {
+ REMARKER(iterations_buff, qq - iterations_buff,
+ "PBKDF2-Password iterations field contains an invalid character");
+
+ goto finish;
+ }
+ p = q + 1;
+ /*
+ * base64 encoded and big endian
+ */
+ } else {
+ (void)fr_strerror();
+ slen = fr_base64_decode((uint8_t *)&iterations, sizeof(iterations), (char const *)p, q - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password iterations component (%.*s): %s",
+ (int)(q - p), p, fr_strerror());
+ goto finish;
+ }
+ if (slen != sizeof(iterations)) {
+ REDEBUG("Decoded PBKDF2-Password iterations component is wrong size");
+ }
+
+ iterations = ntohl(iterations);
+
+ p = q + 1;
+ }
+
+ /*
+ * Sanitise iterations. Seems OpenSSL 1.0 did this, but at least
+ * version 1.1 in RH8 does not, so safest to check ourselves.
+ */
+ if (iterations == 0) {
+ RWDEBUG("PBKDF2 can not have zero iterations; increasing to 1");
+ iterations = 1;
+ }
+
+ if (((end - p) < 1) || !(q = memchr(p, salt_sep, end - p))) {
+ REDEBUG("PBKDF2-Password missing salt component");
+ goto finish;
+ }
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password salt component too short");
+ goto finish;
+ }
+
+ MEM(salt = talloc_array(request, uint8_t, FR_BASE64_DEC_LENGTH(((size_t)(q - p)))));
+ slen = fr_base64_decode(salt, talloc_array_length(salt), (char const *) p, q - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password salt component: %s", fr_strerror());
+ goto finish;
+ }
+ salt_len = (size_t)slen;
+
+ p = q + 1;
+
+ if ((q - p) == 0) {
+ REDEBUG("PBKDF2-Password hash component too short");
+ goto finish;
+ }
+
+ slen = fr_base64_decode(hash, sizeof(hash), (char const *)p, end - p);
+ if (slen < 0) {
+ REDEBUG("Failed decoding PBKDF2-Password hash component: %s", fr_strerror());
+ goto finish;
+ }
+
+ if ((size_t)slen != digest_len) {
+ REDEBUG("PBKDF2-Password hash component length is incorrect for hash type, expected %zu, got %zd",
+ digest_len, slen);
+ goto finish;
+ }
+
+ RDEBUG2("PBKDF2 %s: Iterations %d, salt length %zu, hash length %zd",
+ fr_int2str(pbkdf2_crypt_names, digest_type, "<UNKNOWN>"),
+ iterations, salt_len, slen);
+
+ /*
+ * Hash and compare
+ */
+ if (PKCS5_PBKDF2_HMAC((char const *)password->vp_octets, (int)password->vp_length,
+ (unsigned char const *)salt, (int)salt_len,
+ (int)iterations,
+ evp_md,
+ (int)digest_len, (unsigned char *)digest) == 0) {
+ REDEBUG("PBKDF2 digest failure");
+ goto finish;
+ }
+
+ if (rad_digest_cmp(digest, hash, (size_t)digest_len) != 0) {
+ REDEBUG("PBKDF2 digest does not match \"known good\" digest");
+ rcode = RLM_MODULE_REJECT;
+ } else {
+ rcode = RLM_MODULE_OK;
+ }
+
+finish:
+ talloc_free(salt);
+
+ return rcode;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_pbkdf2(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *password)
+{
+ uint8_t const *p = password->vp_octets, *q, *end = p + password->vp_length;
+
+ rad_assert(request->password != NULL);
+ rad_assert(request->password->da->attr == PW_USER_PASSWORD);
+
+ if (end - p < 2) {
+ REDEBUG("PBKDF2-Password too short");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * If it doesn't begin with a $ assume
+ * It's Crypt::PBKDF2 LDAP format
+ *
+ * {X-PBKDF2}<digest>:<b64 rounds>:<b64_salt>:<b64_hash>
+ */
+ if (*p != '$') {
+ /*
+ * Strip the header if it's present
+ */
+ if (*p == '{') {
+ q = memchr(p, '}', end - p);
+ p = q + 1;
+ }
+ return pap_auth_pbkdf2_parse(request, p, end - p,
+ pbkdf2_crypt_names, ':', ':', ':', true, request->password);
+ }
+
+ /*
+ * Crypt::PBKDF2 Crypt format
+ *
+ * $PBKDF2$<digest>:<rounds>:<b64_salt>$<b64_hash>
+ */
+ if ((size_t)(end - p) >= sizeof("$PBKDF2$") && (memcmp(p, "$PBKDF2$", sizeof("$PBKDF2$") - 1) == 0)) {
+ p += sizeof("$PBKDF2$") - 1;
+ return pap_auth_pbkdf2_parse(request, p, end - p,
+ pbkdf2_crypt_names, ':', ':', '$', false, request->password);
+ }
+
+ /*
+ * Python's passlib format
+ *
+ * $pbkdf2-<digest>$<rounds>$<alt_b64_salt>$<alt_b64_hash>
+ *
+ * Note: Our base64 functions also work with alt_b64
+ */
+ if ((size_t)(end - p) >= sizeof("$pbkdf2-") && (memcmp(p, "$pbkdf2-", sizeof("$pbkdf2-") - 1) == 0)) {
+ p += sizeof("$pbkdf2-") - 1;
+ return pap_auth_pbkdf2_parse(request, p, end - p,
+ pbkdf2_passlib_names, '$', '$', '$', false, request->password);
+ }
+
+ REDEBUG("Can't determine format of PBKDF2-Password");
+
+ return RLM_MODULE_INVALID;
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_nt(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ ssize_t len;
+ uint8_t digest[16];
+ uint8_t ucs2_password[512];
+
+ RDEBUG("Comparing with \"known-good\" NT-Password");
+
+ rad_assert(request->password != NULL);
+ rad_assert(request->password->da->attr == PW_USER_PASSWORD);
+
+ if (inst->normify) {
+ normify(request, vp, 16);
+ }
+
+ if (vp->vp_length != 16) {
+ REDEBUG("\"known good\" NT-Password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ len = fr_utf8_to_ucs2(ucs2_password, sizeof(ucs2_password), request->password->vp_strvalue, request->password->vp_length);
+ if (len < 0) {
+ REDEBUG("User-Password is not in UCS2 format");
+ return RLM_MODULE_INVALID;
+ }
+
+ fr_md4_calc(digest, (uint8_t *) ucs2_password, len);
+
+ if (rad_digest_cmp(digest, vp->vp_octets, vp->vp_length) != 0) {
+ REDEBUG("NT digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_lm(rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ uint8_t digest[16];
+ char charbuf[32 + 1];
+ ssize_t len;
+
+ RDEBUG("Comparing with \"known-good\" LM-Password");
+
+ if (inst->normify) {
+ normify(request, vp, 16);
+ }
+ if (vp->vp_length != 16) {
+ REDEBUG("\"known good\" LM-Password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ len = radius_xlat(charbuf, sizeof(charbuf), request, "%{mschap:LM-Hash %{User-Password}}", NULL, NULL);
+ if (len < 0){
+ return RLM_MODULE_FAIL;
+ }
+
+ if ((fr_hex2bin(digest, sizeof(digest), charbuf, len) != vp->vp_length) ||
+ (rad_digest_cmp(digest, vp->vp_octets, vp->vp_length) != 0)) {
+ REDEBUG("LM digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) pap_auth_ns_mta_md5(UNUSED rlm_pap_t *inst, REQUEST *request, VALUE_PAIR *vp)
+{
+ FR_MD5_CTX md5_context;
+ uint8_t digest[128];
+ uint8_t buff[MAX_STRING_LEN];
+ uint8_t buff2[MAX_STRING_LEN + 50];
+
+ RDEBUG("Using NT-MTA-MD5-Password");
+
+ if (vp->vp_length != 64) {
+ REDEBUG("\"known good\" NS-MTA-MD5-Password has incorrect length");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Sanity check the value of NS-MTA-MD5-Password
+ */
+ if (fr_hex2bin(digest, sizeof(digest), vp->vp_strvalue, vp->vp_length) != 16) {
+ REDEBUG("\"known good\" NS-MTA-MD5-Password has invalid value");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Ensure we don't have buffer overflows.
+ *
+ * This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
+ */
+ if (request->password->vp_length >= (sizeof(buff) - 2 - 2 * 32)) {
+ REDEBUG("\"known good\" NS-MTA-MD5-Password is too long");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Set up the algorithm.
+ */
+ {
+ uint8_t *p = buff2;
+
+ memcpy(p, &vp->vp_octets[32], 32);
+ p += 32;
+ *(p++) = 89;
+ memcpy(p, (uint8_t const *)request->password->vp_strvalue, request->password->vp_length);
+ p += request->password->vp_length;
+ *(p++) = 247;
+ memcpy(p, &vp->vp_octets[32], 32);
+ p += 32;
+
+ fr_md5_init(&md5_context);
+ fr_md5_update(&md5_context, buff2, p - buff2);
+ fr_md5_final(buff, &md5_context);
+ }
+
+ if (rad_digest_cmp(digest, buff, 16) != 0) {
+ REDEBUG("NS-MTA-MD5 digest does not match \"known good\" digest");
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Authenticate the user via one of any well-known password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_pap_t *inst = instance;
+ VALUE_PAIR *vp;
+ rlm_rcode_t rc = RLM_MODULE_INVALID;
+ vp_cursor_t cursor;
+ rlm_rcode_t (*auth_func)(rlm_pap_t *, REQUEST *, VALUE_PAIR *) = NULL;
+
+ if (!request->password ||
+ (request->password->da->vendor != 0) ||
+ (request->password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("You set 'Auth-Type = PAP' for a request that does not contain a User-Password attribute!");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * The user MUST supply a non-zero-length password.
+ */
+ if (request->password->vp_length == 0) {
+ REDEBUG("Password must not be empty");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Login attempt with password \"%s\" (%zd)", request->password->vp_strvalue, request->password->vp_length);
+ } else {
+ RDEBUG("Login attempt with password");
+ }
+
+ /*
+ * Auto-detect passwords, by attribute in the
+ * config items, to find out which authentication
+ * function to call.
+ */
+ for (vp = fr_cursor_init(&cursor, &request->config);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ case PW_CLEARTEXT_PASSWORD:
+ auth_func = &pap_auth_clear;
+ break;
+
+ case PW_CRYPT_PASSWORD:
+ auth_func = &pap_auth_crypt;
+ break;
+
+ case PW_MD5_PASSWORD:
+ auth_func = &pap_auth_md5;
+ break;
+
+ case PW_SMD5_PASSWORD:
+ auth_func = &pap_auth_smd5;
+ break;
+
+#ifdef HAVE_OPENSSL_EVP_H
+ case PW_SHA2_PASSWORD:
+ auth_func = &pap_auth_sha2;
+ break;
+
+ case PW_SSHA2_224_PASSWORD:
+ case PW_SSHA2_256_PASSWORD:
+ case PW_SSHA2_384_PASSWORD:
+ case PW_SSHA2_512_PASSWORD:
+ auth_func = &pap_auth_ssha2;
+ break;
+
+ case PW_PBKDF2_PASSWORD:
+ auth_func = &pap_auth_pbkdf2;
+ break;
+#endif
+
+ case PW_SHA_PASSWORD:
+ auth_func = &pap_auth_sha;
+ break;
+
+ case PW_SSHA_PASSWORD:
+ auth_func = &pap_auth_ssha;
+ break;
+
+ case PW_NT_PASSWORD:
+ auth_func = &pap_auth_nt;
+ break;
+
+ case PW_LM_PASSWORD:
+ auth_func = &pap_auth_lm;
+ break;
+
+ case PW_NS_MTA_MD5_PASSWORD:
+ auth_func = &pap_auth_ns_mta_md5;
+ break;
+
+ default:
+ break;
+ }
+
+ if (auth_func != NULL) break;
+ }
+
+ /*
+ * No attribute was found that looked like a password to match.
+ */
+ if (!auth_func) {
+ RDEBUG("No password configured for the user. Cannot do authentication");
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Authenticate, and return.
+ */
+ rc = auth_func(inst, request, vp);
+
+ if (rc == RLM_MODULE_REJECT) {
+ RDEBUG("Passwords don't match");
+ }
+
+ if (rc == RLM_MODULE_OK) {
+ RDEBUG("User authenticated successfully");
+ }
+
+ return rc;
+}
+
+
+/*
+ * 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_pap;
+module_t rlm_pap = {
+ .magic = RLM_MODULE_INIT,
+ .name = "pap",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_pap_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_passwd/README.md b/src/modules/rlm_passwd/README.md
new file mode 100644
index 0000000..65c87d1
--- /dev/null
+++ b/src/modules/rlm_passwd/README.md
@@ -0,0 +1,15 @@
+# rlm_passwd
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Reads and caches line-oriented files that are in a format similar
+to `/etc/passwd`.
+
+It assumes that each line is composed of a series of records,
+separated by a delimiter. The records are read from the file,
+cached, then retrieved during request processing and inserted into
+the request.
diff --git a/src/modules/rlm_passwd/all.mk b/src/modules/rlm_passwd/all.mk
new file mode 100644
index 0000000..bb1bd58
--- /dev/null
+++ b/src/modules/rlm_passwd/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_passwd.a
+SOURCES := rlm_passwd.c
diff --git a/src/modules/rlm_passwd/rlm_passwd.c b/src/modules/rlm_passwd/rlm_passwd.c
new file mode 100644
index 0000000..cae5f0b
--- /dev/null
+++ b/src/modules/rlm_passwd/rlm_passwd.c
@@ -0,0 +1,624 @@
+/*
+ * 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_passwd.c
+ * @brief Enables authentication against unix passwd files.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+struct mypasswd {
+ struct mypasswd *next;
+ char *listflag;
+ char *field[1];
+};
+
+struct hashtable {
+ int tablesize;
+ int keyfield;
+ int nfields;
+ int islist;
+ int ignorenis;
+ char * filename;
+ struct mypasswd **table;
+ char buffer[1024];
+ FILE *fp;
+ char delimiter;
+};
+
+
+#ifdef TEST
+
+#define rad_malloc(s) malloc(s)
+
+void printpw(struct mypasswd *pw, int nfields){
+ int i;
+ if (pw) {
+ for( i = 0; i < nfields; i++ ) printf("%s:", pw->field[i]);
+ printf("\n");
+ }
+ else printf ("Not found\n");
+ fflush(stdout);
+}
+#endif
+
+
+static struct mypasswd * mypasswd_malloc(char const* buffer, int nfields, size_t* len)
+{
+ struct mypasswd *t;
+ /* reserve memory for (struct mypasswd) + listflag (nfields * sizeof (char*)) +
+ ** fields (nfields * sizeof (char)) + strlen (inst->format) + 1 */
+
+ *len=sizeof (struct mypasswd) + nfields * sizeof (char*) + nfields * sizeof (char ) + strlen(buffer) + 1;
+ t = (struct mypasswd *) rad_malloc(*len);
+ if (t) memset(t, 0, *len);
+ return (t);
+}
+
+static int string_to_entry(char const* string, int nfields, char delimiter,
+ struct mypasswd *passwd, size_t bufferlen)
+{
+ char *str;
+ size_t len, i;
+ int fn=0;
+ char *data_beg;
+
+
+ len = strlen(string);
+ if(!len) return 0;
+ if (string[len-1] == '\n') len--;
+ if(!len) return 0;
+ if (string[len-1] == '\r') len--;
+ if(!len) return 0;
+ if (!len || !passwd ||
+ bufferlen < (len + nfields * sizeof (char*) + nfields * sizeof (char) + sizeof (struct mypasswd) + 1) ) return 0;
+ passwd->next = NULL;
+ data_beg=(char *)passwd + sizeof(struct mypasswd);
+ str = data_beg + nfields * sizeof (char) + nfields * sizeof (char*);
+ memcpy (str, string, len);
+ str[len] = 0;
+ passwd->field[fn++] = str;
+ passwd->listflag = data_beg + nfields * sizeof (char *);
+ for(i=0; i < len; i++){
+ if (str[i] == delimiter) {
+ str[i] = 0;
+ passwd->field[fn++] = str + i + 1;
+ if (fn == nfields) break;
+ }
+ }
+ for (; fn < nfields; fn++) passwd->field[fn] = NULL;
+ return len + nfields * sizeof (char) + nfields * sizeof (char*) + sizeof (struct mypasswd) + 1;
+}
+
+
+static void destroy_password (struct mypasswd * pass)
+{
+ struct mypasswd *p;
+ while ((p=pass)!=NULL) {
+ pass = pass->next;
+ free(p);
+ }
+}
+
+
+static unsigned int hash(char const * username, unsigned int tablesize)
+{
+ uint32_t h = fr_hash_string(username);
+
+ return h%tablesize;
+}
+
+static void release_hash_table(struct hashtable * ht){
+ int i;
+
+ if (!ht) return;
+ if (ht->table) {
+ for (i = 0; i < ht->tablesize; i++) {
+ if (ht->table[i])
+ destroy_password(ht->table[i]);
+ }
+ free(ht->table);
+ ht->table = NULL;
+ }
+ if (ht->fp) {
+ fclose(ht->fp);
+ ht->fp = NULL;
+ }
+ ht->tablesize = 0;
+}
+
+static void release_ht(struct hashtable * ht){
+ if (!ht) return;
+ release_hash_table(ht);
+ if (ht->filename) {
+ free(ht->filename);
+ ht->filename = NULL;
+ }
+ free(ht);
+}
+
+static struct hashtable * build_hash_table (char const * file, int nfields,
+ int keyfield, int islist, int tablesize, int ignorenis, char delimiter)
+{
+ struct hashtable* ht;
+ size_t len;
+ unsigned int h;
+ struct mypasswd *hashentry, *hashentry1;
+ struct mypasswd **lastentry; /* temp pointers to end of lists */
+ char *list;
+ char *nextlist=0;
+ int i;
+ char buffer[1024];
+
+ ht = (struct hashtable *) rad_malloc(sizeof(struct hashtable));
+ if(!ht) {
+ return NULL;
+ }
+ memset(ht, 0, sizeof(struct hashtable));
+ ht->filename = strdup(file);
+ if(!ht->filename) {
+ free(ht);
+ return NULL;
+ }
+ ht->tablesize = tablesize;
+ ht->nfields = nfields;
+ ht->keyfield = keyfield;
+ ht->islist = islist;
+ ht->ignorenis = ignorenis;
+ if (delimiter) ht->delimiter = delimiter;
+ else ht->delimiter = ':';
+ if(!tablesize) return ht;
+ if(!(ht->fp = fopen(file,"r"))) {
+ ERROR("Failed opening %s - %s", file, fr_strerror());
+ free(ht->filename);
+ free(ht);
+ return NULL;
+ }
+
+ /*
+ * @todo: This code is SHIT. It's badly formatted. It's
+ * hard to understand. It re-implements tons of things
+ * which are already in the server core.
+ */
+ memset(ht->buffer, 0, 1024);
+ ht->table = (struct mypasswd **) rad_malloc (tablesize * sizeof(struct mypasswd *));
+ if (!ht->table) {
+ /*
+ * Unable allocate memory for hash table
+ * Still work without it
+ */
+ ht->tablesize = 0;
+ return ht;
+ }
+ memset(ht->table, 0, tablesize * sizeof(struct mypasswd *));
+
+ /*
+ * Initialise temporary pointers to last entries in has table
+ */
+ lastentry = (struct mypasswd **) rad_malloc (tablesize * sizeof(struct mypasswd *));
+ if (!lastentry) {
+ /*
+ * Unable to allocate memory for temp pointers
+ */
+ ht->tablesize = 0;
+ return ht;
+ }
+ memset(lastentry, 0, tablesize * sizeof(struct mypasswd *));
+
+ while (fgets(buffer, 1024, ht->fp)) {
+ if(*buffer && *buffer!='\n' && (!ignorenis || (*buffer != '+' && *buffer != '-')) ){
+ if(!(hashentry = mypasswd_malloc(buffer, nfields, &len))){
+ release_hash_table(ht);
+ return ht;
+ }
+ len = string_to_entry(buffer, nfields, ht->delimiter, hashentry, len);
+ if(!hashentry->field[keyfield] || *hashentry->field[keyfield] == '\0') {
+ free(hashentry);
+ continue;
+ }
+
+ if (islist) {
+ list = hashentry->field[keyfield];
+ for (nextlist = list; *nextlist && *nextlist!=','; nextlist++);
+ if (*nextlist) *nextlist++ = 0;
+ else nextlist = 0;
+ }
+ h = hash(hashentry->field[keyfield], tablesize);
+ if (!ht->table[h]) ht->table[h] = hashentry;
+ if (lastentry[h]) lastentry[h]->next = hashentry;
+ lastentry[h] = hashentry;
+ if (islist) {
+ for(list=nextlist; nextlist; list = nextlist){
+ for (nextlist = list; *nextlist && *nextlist!=','; nextlist++);
+ if (*nextlist) *nextlist++ = 0;
+ else nextlist = 0;
+ if(!(hashentry1 = mypasswd_malloc("", nfields, &len))){
+ release_hash_table(ht);
+ return ht;
+ }
+ for (i=0; i<nfields; i++) hashentry1->field[i] = hashentry->field[i];
+ hashentry1->field[keyfield] = list;
+ h = hash(list, tablesize);
+ if (!ht->table[h]) ht->table[h] = hashentry1;
+ if (lastentry[h]) lastentry[h]->next = hashentry1;
+ lastentry[h] = hashentry1;
+ }
+ }
+ }
+ }
+ free(lastentry);
+ fclose(ht->fp);
+ ht->fp = NULL;
+ return ht;
+#undef passwd
+}
+
+static struct mypasswd * get_next(char *name, struct hashtable *ht,
+ struct mypasswd **last_found)
+{
+ struct mypasswd * passwd;
+ struct mypasswd * hashentry;
+ char buffer[1024];
+ char *list, *nextlist;
+
+ if (ht->tablesize > 0) {
+ /* get saved address of next item to check from buffer */
+ hashentry = *last_found;
+ for (; hashentry; hashentry = hashentry->next) {
+ if (!strcmp(hashentry->field[ht->keyfield], name)) {
+ /* save new address */
+ *last_found = hashentry->next;
+ return hashentry;
+ }
+ }
+ return NULL;
+ }
+ /* printf("try to find in file\n"); */
+ if (!ht->fp) return NULL;
+
+ passwd = (struct mypasswd *) ht->buffer;
+
+ while (fgets(buffer, 1024,ht->fp)) {
+ if(*buffer && *buffer!='\n' && string_to_entry(buffer, ht->nfields, ht->delimiter, passwd, sizeof(ht->buffer)-1) &&
+ (!ht->ignorenis || (*buffer !='-' && *buffer != '+') ) ){
+ if(!ht->islist) {
+ if(!strcmp(passwd->field[ht->keyfield], name))
+ return passwd;
+ }
+ else {
+ for (list = passwd->field[ht->keyfield], nextlist = list; nextlist; list = nextlist) {
+ for(nextlist = list; *nextlist && *nextlist!=','; nextlist++);
+ if(!*nextlist) {
+ nextlist = 0;
+ } else {
+ *nextlist++ = 0;
+ }
+ if (!strcmp(list, name)) {
+ return passwd;
+ }
+ }
+ }
+
+ }
+ }
+ fclose(ht->fp);
+ ht->fp = NULL;
+ return NULL;
+}
+
+static struct mypasswd * get_pw_nam(char * name, struct hashtable* ht,
+ struct mypasswd **last_found)
+{
+ int h;
+ struct mypasswd * hashentry;
+
+ if (!ht || !name || *name == '\0') return NULL;
+ *last_found = NULL;
+ if (ht->tablesize > 0) {
+ h = hash (name, ht->tablesize);
+ for (hashentry = ht->table[h]; hashentry; hashentry = hashentry->next) {
+ if (!strcmp(hashentry->field[ht->keyfield], name)){
+ /* save address of next item to check into buffer */
+ *last_found=hashentry->next;
+ return hashentry;
+ }
+ }
+
+ return NULL;
+ }
+ if (ht->fp) {
+ fclose(ht->fp);
+ ht->fp = NULL;
+ }
+ if (!(ht->fp=fopen(ht->filename, "r"))) return NULL;
+ return get_next(name, ht, last_found);
+}
+
+#ifdef TEST
+
+#define MALLOC_CHECK_ 1
+
+int main(void){
+ struct hashtable *ht;
+ char *buffer;
+ struct mypasswd* pw, *last_found;
+ int i;
+
+ ht = build_hash_table("/etc/group", 4, 3, 1, 100, 0, ":");
+ if(!ht) {
+ printf("Hash table not built\n");
+ return -1;
+ }
+ for (i = 0; i < ht->tablesize; i++) {
+ if (ht->table[i]) {
+ printf("%d:\n", i);
+ for (pw = ht->table[i]; pw; pw = pw->next) {
+ printpw(pw, 4);
+ }
+ }
+ }
+
+ while(fgets(buffer, 1024, stdin)){
+ buffer[strlen(buffer)-1] = 0;
+ pw = get_pw_nam(buffer, ht, &last_found);
+ printpw(pw,4);
+ while ((pw = get_next(buffer, ht, &last_found))) printpw(pw,4);
+ }
+ release_ht(ht);
+}
+
+#else /* TEST */
+typedef struct rlm_passwd_t {
+ struct hashtable *ht;
+ struct mypasswd *pwdfmt;
+ char const *filename;
+ char const *format;
+ char const *delimiter;
+ bool allow_multiple;
+ bool ignore_nislike;
+ uint32_t hash_size;
+ uint32_t nfields;
+ uint32_t keyfield;
+ uint32_t listable;
+ DICT_ATTR const *keyattr;
+ bool ignore_empty;
+} rlm_passwd_t;
+
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_passwd_t, filename), NULL },
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_passwd_t, format), NULL },
+ { "delimiter", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_passwd_t, delimiter), ":" },
+
+ { "ignorenislike", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_passwd_t, ignore_nislike), NULL },
+ { "ignore_nislike", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_passwd_t, ignore_nislike), "yes" },
+
+ { "ignoreempty", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_passwd_t, ignore_empty), NULL },
+ { "ignore_empty", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_passwd_t, ignore_empty), "yes" },
+
+ { "allowmultiplekeys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_passwd_t, allow_multiple), NULL },
+ { "allow_multiple_keys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_passwd_t, allow_multiple), "no" },
+
+ { "hashsize", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_passwd_t, hash_size), NULL },
+ { "hash_size", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_passwd_t, hash_size), "100" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ int nfields=0, keyfield=-1, listable=0;
+ char const *s;
+ char *lf=NULL; /* destination list flags temporary */
+ size_t len;
+ int i;
+ DICT_ATTR const * da;
+ rlm_passwd_t *inst = instance;
+
+ rad_assert(inst->filename && *inst->filename);
+ rad_assert(inst->format && *inst->format);
+
+ if (inst->hash_size == 0) {
+ cf_log_err_cs(conf, "Invalid value '0' for hash_size");
+ return -1;
+ }
+
+ lf = talloc_typed_strdup(inst, inst->format);
+ if ( !lf) {
+ ERROR("rlm_passwd: memory allocation failed for lf");
+ return -1;
+ }
+ memset(lf, 0, strlen(inst->format));
+ s = inst->format - 1;
+ do {
+ if(s == inst->format - 1 || *s == ':'){
+ if(*(s+1) == '*'){
+ keyfield = nfields;
+ s++;
+ }
+ if(*(s+1) == ','){
+ listable = 1;
+ s++;
+ }
+ if(*(s+1) == '='){
+ lf[nfields]=1;
+ s++;
+ }
+ if(*(s+1) == '~'){
+ lf[nfields]=2;
+ s++;
+ }
+ nfields++;
+ }
+ s++;
+ }while(*s);
+ if(keyfield < 0) {
+ cf_log_err_cs(conf, "no field marked as key in format: %s",
+ inst->format);
+ return -1;
+ }
+ if (! (inst->ht = build_hash_table (inst->filename, nfields, keyfield, listable, inst->hash_size, inst->ignore_nislike, *inst->delimiter)) ){
+ ERROR("rlm_passwd: failed reading file.");
+ return -1;
+ }
+ if (! (inst->pwdfmt = mypasswd_malloc(inst->format, nfields, &len)) ){
+ ERROR("rlm_passwd: memory allocation failed");
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ return -1;
+ }
+ if (!string_to_entry(inst->format, nfields, ':', inst->pwdfmt , len)) {
+ ERROR("rlm_passwd: unable to convert format entry");
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ return -1;
+ }
+
+ memcpy(inst->pwdfmt->listflag, lf, nfields);
+
+ talloc_free(lf);
+ for (i=0; i<nfields; i++) {
+ if (*inst->pwdfmt->field[i] == '*') inst->pwdfmt->field[i]++;
+ if (*inst->pwdfmt->field[i] == ',') inst->pwdfmt->field[i]++;
+ if (*inst->pwdfmt->field[i] == '=') inst->pwdfmt->field[i]++;
+ if (*inst->pwdfmt->field[i] == '~') inst->pwdfmt->field[i]++;
+ }
+ if (!*inst->pwdfmt->field[keyfield]) {
+ cf_log_err_cs(conf, "key field is empty");
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ return -1;
+ }
+ if (! (da = dict_attrbyname (inst->pwdfmt->field[keyfield])) ) {
+ ERROR("rlm_passwd: unable to resolve attribute: %s", inst->pwdfmt->field[keyfield]);
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ return -1;
+ }
+ inst->keyattr = da;
+ inst->nfields = nfields;
+ inst->keyfield = keyfield;
+ inst->listable = listable;
+ DEBUG2("rlm_passwd: nfields: %d keyfield %d(%s) listable: %s", nfields, keyfield, inst->pwdfmt->field[keyfield], listable?"yes":"no");
+ return 0;
+
+#undef inst
+}
+
+static int mod_detach (void *instance) {
+#define inst ((rlm_passwd_t *)instance)
+ if(inst->ht) {
+ release_ht(inst->ht);
+ inst->ht = NULL;
+ }
+ free(inst->pwdfmt);
+ return 0;
+#undef inst
+}
+
+static void addresult (TALLOC_CTX *ctx, rlm_passwd_t *inst, REQUEST *request,
+ VALUE_PAIR **vps, struct mypasswd * pw, char when, char const *listname)
+{
+ uint32_t i;
+ VALUE_PAIR *vp;
+
+ for (i = 0; i < inst->nfields; i++) {
+ if (inst->pwdfmt->field[i] && *inst->pwdfmt->field[i] && pw->field[i] && i != inst->keyfield && inst->pwdfmt->listflag[i] == when) {
+ if ( !inst->ignore_empty || pw->field[i][0] != 0 ) { /* if value in key/value pair is not empty */
+ vp = fr_pair_make(ctx, vps, inst->pwdfmt->field[i], pw->field[i], T_OP_EQ);
+ if (vp) {
+ RDEBUG("Added %s: '%s' to %s ", inst->pwdfmt->field[i], pw->field[i], listname);
+ }
+ } else
+ RDEBUG("NOOP %s: '%s' to %s ", inst->pwdfmt->field[i], pw->field[i], listname);
+ }
+ }
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_passwd_map(void *instance, REQUEST *request)
+{
+#define inst ((rlm_passwd_t *)instance)
+ char buffer[1024];
+ VALUE_PAIR *key, *i;
+ struct mypasswd * pw, *last_found;
+ vp_cursor_t cursor;
+ int found = 0;
+
+ key = fr_pair_find_by_da(request->packet->vps, inst->keyattr, TAG_ANY);
+ if (!key) {
+ return RLM_MODULE_NOTFOUND;
+ }
+
+ fr_cursor_init(&cursor, &key);
+ while ((i = fr_cursor_next_by_num(&cursor, inst->keyattr->attr, inst->keyattr->vendor, TAG_ANY))) {
+ /*
+ * Ensure we have the string form of the attribute
+ */
+ vp_prints_value(buffer, sizeof(buffer), i, 0);
+ if (!(pw = get_pw_nam(buffer, inst->ht, &last_found)) ) {
+ continue;
+ }
+ do {
+ addresult(request, inst, request, &request->config, pw, 0, "config");
+ addresult(request->reply, inst, request, &request->reply->vps, pw, 1, "reply_items");
+ addresult(request->packet, inst, request, &request->packet->vps, pw, 2, "request_items");
+
+ if (!inst->allow_multiple) {
+ break;
+ }
+ } while ((pw = get_next(buffer, inst->ht, &last_found)));
+
+ found++;
+
+ if (!inst->allow_multiple) {
+ break;
+ }
+ }
+
+ if (!found) return RLM_MODULE_NOTFOUND;
+
+ return RLM_MODULE_OK;
+
+#undef inst
+}
+
+extern module_t rlm_passwd;
+module_t rlm_passwd = {
+ .magic = RLM_MODULE_INIT,
+ .name = "passwd",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_passwd_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_passwd_map,
+ [MOD_ACCOUNTING] = mod_passwd_map,
+ [MOD_POST_AUTH] = mod_passwd_map,
+ [MOD_PRE_PROXY] = mod_passwd_map,
+ [MOD_POST_PROXY] = mod_passwd_map,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_passwd_map,
+ [MOD_SEND_COA] = mod_passwd_map
+#endif
+ },
+};
+#endif /* TEST */
diff --git a/src/modules/rlm_perl/.gitignore b/src/modules/rlm_perl/.gitignore
new file mode 100644
index 0000000..589d7ff
--- /dev/null
+++ b/src/modules/rlm_perl/.gitignore
@@ -0,0 +1,2 @@
+all.mk
+config.h
diff --git a/src/modules/rlm_perl/README.md b/src/modules/rlm_perl/README.md
new file mode 100644
index 0000000..958c132
--- /dev/null
+++ b/src/modules/rlm_perl/README.md
@@ -0,0 +1,12 @@
+# rlm_perl
+## Metadata
+<dl>
+ <dt>category</dt><dd>languages</dd>
+</dl>
+
+## Summary
+
+Allows the server to call a persistent, embedded Perl script.
+
+When there are policies that cannot be implemented in unlang, it
+is usually possible to use rlm_perl or rlm_python3 instead.
diff --git a/src/modules/rlm_perl/all.mk.in b/src/modules/rlm_perl/all.mk.in
new file mode 100644
index 0000000..bf6b30b
--- /dev/null
+++ b/src/modules/rlm_perl/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := rlm_perl.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_perl/config.h.in b/src/modules/rlm_perl/config.h.in
new file mode 100644
index 0000000..b429c2f
--- /dev/null
+++ b/src/modules/rlm_perl/config.h.in
@@ -0,0 +1 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
diff --git a/src/modules/rlm_perl/configure b/src/modules/rlm_perl/configure
new file mode 100755
index 0000000..6ad58dd
--- /dev/null
+++ b/src/modules/rlm_perl/configure
@@ -0,0 +1,4721 @@
+#! /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_perl.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+PERL
+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_perl
+with_perl
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+PERL'
+
+
+# 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_perl build without support for embedded Perl functions
+ --with-perl=[PATH] absolute path to perl executable
+
+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
+ PERL Absolute path to perl executable
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_perl
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_perl was given.
+if test "${with_rlm_perl+set}" = set; then :
+ withval=$with_rlm_perl;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_perl" != 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
+
+
+
+
+
+
+
+
+
+
+
+
+ if test -z "$PERL"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether perl executable path has been provided" >&5
+$as_echo_n "checking whether perl executable path has been provided... " >&6; }
+
+# Check whether --with-perl was given.
+if test "${with_perl+set}" = set; then :
+ withval=$with_perl;
+ if test "$withval" != yes && test "$withval" != no; then :
+
+ PERL="$withval"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+$as_echo "$PERL" >&6; }
+
+else
+
+ PERL=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ if test "$withval" != no; then :
+
+ # Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PERL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_PERL="$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
+
+ test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="not-found"
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+if test -n "$PERL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+$as_echo "$PERL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ # Extract the first word of "perl", so it can be a program name with args.
+set dummy perl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PERL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PERL in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_PERL="$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
+
+ test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="not-found"
+ ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+if test -n "$PERL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5
+$as_echo "$PERL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+
+fi
+
+
+
+
+
+
+
+if test "$PERL" = "not-found" -o ! -x "$PERL"; then
+
+fail="$fail perl"
+
+else
+ old_CFLAGS="${CFLAGS}"
+ old_LIBS="${LIBS}"
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Calling ExtUtils::Embed to get 'ccopts'" >&5
+$as_echo "$as_me: Calling ExtUtils::Embed to get 'ccopts'" >&6;}
+ mod_cflags=$($PERL -MExtUtils::Embed -e ccopts)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ExtUtil's ccopts were \"${mod_cflags}\"" >&5
+$as_echo "$as_me: ExtUtil's ccopts were \"${mod_cflags}\"" >&6;}
+
+ mod_cflags=$(echo "$mod_cflags" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*//g;s/ / /g;s/^ *//;s/ *$//')
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized ccopts are \"${mod_cflags}\"" >&5
+$as_echo "$as_me: Sanitized ccopts are \"${mod_cflags}\"" >&6;}
+
+ CFLAGS="${mod_cflags} ${CFLAGS}"
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Calling ExtUtils::Embed to get 'ldflags'" >&5
+$as_echo "$as_me: Calling ExtUtils::Embed to get 'ldflags'" >&6;}
+ mod_ldflags=$($PERL -MExtUtils::Embed -e ldopts)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ExtUtil's ldopts were \"${mod_ldflags}\"" >&5
+$as_echo "$as_me: ExtUtil's ldopts were \"${mod_ldflags}\"" >&6;}
+
+ mod_ldflags=$(echo "$mod_ldflags" | sed 's/-arch [^ ]*//g;s/ / /g;s/^ *//;s/ *$//')
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized ldopts are \"${mod_ldflags}\"" >&5
+$as_echo "$as_me: Sanitized ldopts are \"${mod_ldflags}\"" >&6;}
+
+ LIBS="${mod_ldflags} ${LIBS}"
+
+
+ smart_try_dir=
+
+
+
+ac_safe=`echo "EXTERN.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 EXTERN.h in $try" >&5
+$as_echo_n "checking for EXTERN.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EXTERN.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}/EXTERN.h" >&5
+$as_echo_n "checking for ${_prefix}/EXTERN.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EXTERN.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 EXTERN.h" >&5
+$as_echo_n "checking for EXTERN.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EXTERN.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 EXTERN.h in $try" >&5
+$as_echo_n "checking for EXTERN.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <EXTERN.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_EXTERN_h" != "xyes"; then
+
+fail="$fail EXTERN.h"
+
+ fi
+
+
+
+ac_safe=`echo "perl.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 perl.h in $try" >&5
+$as_echo_n "checking for perl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <EXTERN.h>
+ #include <perl.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}/perl.h" >&5
+$as_echo_n "checking for ${_prefix}/perl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <EXTERN.h>
+ #include <perl.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 perl.h" >&5
+$as_echo_n "checking for perl.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <EXTERN.h>
+ #include <perl.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 perl.h in $try" >&5
+$as_echo_n "checking for perl.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <EXTERN.h>
+ #include <perl.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_perl_h" != "xyes"; then
+
+fail="$fail EXTERN.h"
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking we can link to boot_DynaLoader" >&5
+$as_echo_n "checking we can link to boot_DynaLoader... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern char boot_DynaLoader();
+ boot_DynaLoader();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LINKS="yes"
+else
+ LINKS="no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINKS" >&5
+$as_echo "$LINKS" >&6; }
+ if test "x$LINKS" = "xno"; then
+
+fail="$fail libperl.so"
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking we can link to Perl_hv_store()" >&5
+$as_echo_n "checking we can link to Perl_hv_store()... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ extern char Perl_hv_store();
+ Perl_hv_store();
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LINKS="yes"
+else
+ LINKS="no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINKS" >&5
+$as_echo "$LINKS" >&6; }
+ if test "x$LINKS" = "xno"; then
+
+fail="$fail libperl.so"
+
+ fi
+
+ CFLAGS="$old_CFLAGS"
+ LIBS="$old_LIBS"
+fi
+
+
+ targetname=rlm_perl
+else
+ targetname=
+ echo \*\*\* module rlm_perl is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_perl to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_perl." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_perl." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_perl requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_perl requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_perl/configure.ac b/src/modules/rlm_perl/configure.ac
new file mode 100644
index 0000000..81a21e6
--- /dev/null
+++ b/src/modules/rlm_perl/configure.ac
@@ -0,0 +1,102 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_perl.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_perl], [support for embedded Perl functions])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AX_WITH_PROG([PERL],[perl],[not-found],[${PATH}:/usr/bin:/usr/local/bin])
+
+if test "$PERL" = "not-found" -o ! -x "$PERL"; then
+ FR_MODULE_FAIL([perl])
+else
+ old_CFLAGS="${CFLAGS}"
+ old_LIBS="${LIBS}"
+
+ dnl ############################################################
+ dnl # Call ExtUtils::Embed to get compiler flags
+ dnl ############################################################
+
+ AC_MSG_NOTICE([Calling ExtUtils::Embed to get 'ccopts'])
+ mod_cflags=$($PERL -MExtUtils::Embed -e ccopts)
+
+ AC_MSG_NOTICE([ExtUtil's ccopts were \"${mod_cflags}\"])
+
+ mod_cflags=[$(echo "$mod_cflags" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*//g;s/ / /g;s/^ *//;s/ *$//')]
+
+ AC_MSG_NOTICE([Sanitized ccopts are \"${mod_cflags}\"])
+
+ CFLAGS="${mod_cflags} ${CFLAGS}"
+
+ dnl ############################################################
+ dnl # Call ExtUtils::Embed to get linker flags
+ dnl ############################################################
+
+ AC_MSG_NOTICE([Calling ExtUtils::Embed to get 'ldflags'])
+ mod_ldflags=$($PERL -MExtUtils::Embed -e ldopts)
+
+ AC_MSG_NOTICE([ExtUtil's ldopts were \"${mod_ldflags}\"])
+
+ mod_ldflags=[$(echo "$mod_ldflags" | sed 's/-arch [^ ]*//g;s/ / /g;s/^ *//;s/ *$//')]
+
+ AC_MSG_NOTICE([Sanitized ldopts are \"${mod_ldflags}\"])
+
+ LIBS="${mod_ldflags} ${LIBS}"
+
+ dnl ############################################################
+ dnl # Check required headers are available
+ dnl ############################################################
+
+ smart_try_dir=
+ FR_SMART_CHECK_INCLUDE(EXTERN.h)
+ if test "x$ac_cv_header_EXTERN_h" != "xyes"; then
+ FR_MODULE_FAIL([EXTERN.h])
+ fi
+
+ FR_SMART_CHECK_INCLUDE(perl.h, [#include <EXTERN.h>])
+ if test "x$ac_cv_header_perl_h" != "xyes"; then
+ FR_MODULE_FAIL([EXTERN.h])
+ fi
+
+ dnl ############################################################
+ dnl # Link test functions
+ dnl ############################################################
+
+ AC_MSG_CHECKING([we can link to boot_DynaLoader])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
+ extern char boot_DynaLoader();
+ boot_DynaLoader();
+ ]])],[LINKS="yes"],[LINKS="no"])
+
+ AC_MSG_RESULT($LINKS)
+ if test "x$LINKS" = "xno"; then
+ FR_MODULE_FAIL([libperl.so])
+ fi
+
+ AC_MSG_CHECKING([we can link to Perl_hv_store()])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
+ extern char Perl_hv_store();
+ Perl_hv_store();
+ ]])],[LINKS="yes"],[LINKS="no"])
+
+ AC_MSG_RESULT($LINKS)
+ if test "x$LINKS" = "xno"; then
+ FR_MODULE_FAIL([libperl.so])
+ fi
+
+ CFLAGS="$old_CFLAGS"
+ LIBS="$old_LIBS"
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_perl/rlm_perl.c b/src/modules/rlm_perl/rlm_perl.c
new file mode 100644
index 0000000..59759ae
--- /dev/null
+++ b/src/modules/rlm_perl/rlm_perl.c
@@ -0,0 +1,1195 @@
+/*
+ * 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_perl.c
+ * @brief Translates requests between the server an a perl interpreter.
+ *
+ * @copyright 2002,2006 The FreeRADIUS server project
+ * @copyright 2002 Boian Jordanov <bjordanov@orbitel.bg>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+DIAG_OFF(DIAG_UNKNOWN_PRAGMAS)
+DIAG_OFF(compound-token-split-by-macro) /* Perl does horrible things with macros */
+DIAG_ON(DIAG_UNKNOWN_PRAGMAS)
+
+#ifdef INADDR_ANY
+# undef INADDR_ANY
+#endif
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+#include <dlfcn.h>
+#include <semaphore.h>
+
+#ifdef __APPLE__
+extern char **environ;
+#endif
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_perl_t {
+ /* Name of the perl module */
+ char const *module;
+
+ /* Name of the functions for each module method */
+ char const *func_authorize;
+ char const *func_authenticate;
+ char const *func_accounting;
+ char const *func_start_accounting;
+ char const *func_stop_accounting;
+ char const *func_preacct;
+ char const *func_checksimul;
+ char const *func_detach;
+ char const *func_xlat;
+#ifdef WITH_PROXY
+ char const *func_pre_proxy;
+ char const *func_post_proxy;
+#endif
+ char const *func_post_auth;
+#ifdef WITH_COA
+ char const *func_recv_coa;
+ char const *func_send_coa;
+#endif
+ char const *xlat_name;
+ char const *perl_flags;
+ PerlInterpreter *perl;
+ bool perl_parsed;
+ pthread_key_t *thread_key;
+
+#ifdef USE_ITHREADS
+ pthread_mutex_t clone_mutex;
+#endif
+
+ HV *rad_perlconf_hv; //!< holds "config" items (perl %RAD_PERLCONF hash).
+
+} rlm_perl_t;
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+#define RLM_PERL_CONF(_x) { "func_" STRINGIFY(_x), PW_TYPE_STRING, \
+ offsetof(rlm_perl_t,func_##_x), NULL, STRINGIFY(_x)}
+
+static const CONF_PARSER module_config[] = {
+ { "module", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_DEPRECATED, rlm_perl_t, module), NULL },
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_perl_t, module), NULL },
+
+ RLM_PERL_CONF(authorize),
+ RLM_PERL_CONF(authenticate),
+ RLM_PERL_CONF(post_auth),
+ RLM_PERL_CONF(accounting),
+ RLM_PERL_CONF(preacct),
+ RLM_PERL_CONF(checksimul),
+ RLM_PERL_CONF(detach),
+ RLM_PERL_CONF(xlat),
+
+#ifdef WITH_PROXY
+ RLM_PERL_CONF(pre_proxy),
+ RLM_PERL_CONF(post_proxy),
+#endif
+#ifdef WITH_COA
+ RLM_PERL_CONF(recv_coa),
+ RLM_PERL_CONF(send_coa),
+#endif
+ { "perl_flags", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, perl_flags), NULL },
+
+ { "func_start_accounting", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, func_start_accounting), NULL },
+
+ { "func_stop_accounting", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_perl_t, func_stop_accounting), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * man perlembed
+ */
+EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
+
+static int perl_sys_init3_called = 0;
+
+#ifdef USE_ITHREADS
+# define dl_librefs "DynaLoader::dl_librefs"
+# define dl_modules "DynaLoader::dl_modules"
+static void rlm_perl_clear_handles(pTHX)
+{
+ AV *librefs = get_av(dl_librefs, false);
+ if (librefs) {
+ av_clear(librefs);
+ }
+}
+
+static void **rlm_perl_get_handles(pTHX)
+{
+ I32 i;
+ AV *librefs = get_av(dl_librefs, false);
+ AV *modules = get_av(dl_modules, false);
+ void **handles;
+
+ if (!librefs) return NULL;
+
+ if (!(AvFILL(librefs) >= 0)) {
+ return NULL;
+ }
+
+ handles = (void **)rad_malloc(sizeof(void *) * (AvFILL(librefs)+2));
+
+ for (i = 0; i <= AvFILL(librefs); i++) {
+ void *handle;
+ SV *handle_sv = *av_fetch(librefs, i, false);
+ if (!handle_sv) {
+ ERROR("Could not fetch $%s[%d]!", dl_librefs, (int)i);
+ continue;
+ }
+ handle = (void *)SvIV(handle_sv);
+
+ if (handle) handles[i] = handle;
+ }
+
+ av_clear(modules);
+ av_clear(librefs);
+
+ handles[i] = (void *)0;
+
+ return handles;
+}
+
+static void rlm_perl_close_handles(void **handles)
+{
+ int i;
+
+ if (!handles) {
+ return;
+ }
+
+ for (i = 0; handles[i]; i++) {
+ DEBUG("Close %p", handles[i]);
+ dlclose(handles[i]);
+ }
+
+ free(handles);
+}
+
+DIAG_OFF(shadow)
+static void rlm_perl_destruct(PerlInterpreter *perl)
+{
+ dTHXa(perl);
+
+ PERL_SET_CONTEXT(perl);
+
+ PL_perl_destruct_level = 2;
+
+ PL_origenviron = environ;
+
+
+ {
+ dTHXa(perl);
+ }
+ /*
+ * FIXME: This shouldn't happen
+ *
+ */
+ while (PL_scopestack_ix > 1) {
+ LEAVE;
+ }
+
+ perl_destruct(perl);
+ perl_free(perl);
+}
+DIAG_ON(shadow)
+
+static void rlm_destroy_perl(PerlInterpreter *perl)
+{
+ void **handles;
+
+ dTHXa(perl);
+ PERL_SET_CONTEXT(perl);
+
+ handles = rlm_perl_get_handles(aTHX);
+ if (handles) rlm_perl_close_handles(handles);
+ rlm_perl_destruct(perl);
+}
+
+/* Create Key */
+static void rlm_perl_make_key(pthread_key_t *key)
+{
+ pthread_key_create(key, (void (*)(void *))rlm_destroy_perl);
+}
+
+static PerlInterpreter *rlm_perl_clone(PerlInterpreter *perl, pthread_key_t *key)
+{
+ int ret;
+
+ PerlInterpreter *interp;
+ UV clone_flags = 0;
+
+ PERL_SET_CONTEXT(perl);
+
+ interp = pthread_getspecific(*key);
+ if (interp) return interp;
+
+ interp = perl_clone(perl, clone_flags);
+ {
+ dTHXa(interp);
+ }
+# if PERL_REVISION >= 5 && PERL_VERSION <8
+ call_pv("CLONE",0);
+# endif
+ ptr_table_free(PL_ptr_table);
+ PL_ptr_table = NULL;
+
+ PERL_SET_CONTEXT(aTHX);
+ rlm_perl_clear_handles(aTHX);
+
+ ret = pthread_setspecific(*key, interp);
+ if (ret != 0) {
+ DEBUG("rlm_perl: Failed associating interpretor with thread %s", fr_syserror(ret));
+
+ rlm_perl_destruct(interp);
+ return NULL;
+ }
+
+ return interp;
+}
+#endif
+
+/*
+ * This is wrapper for radlog
+ * Now users can call radiusd::radlog(level,msg) wich is the same
+ * as calling radlog from C code.
+ */
+static XS(XS_radiusd_radlog)
+{
+ dXSARGS;
+ if (items !=2)
+ croak("Usage: radiusd::radlog(level, message)");
+ {
+ int level;
+ char *msg;
+
+ level = (int) SvIV(ST(0));
+ msg = (char *) SvPV(ST(1), PL_na);
+
+ /*
+ * Because 'msg' is a 'char *', we don't want '%s', etc.
+ * in it to give us printf-style vulnerabilities.
+ */
+ radlog(level, "rlm_perl: %s", msg);
+ }
+ XSRETURN_NO;
+}
+
+/*
+ * This is a wraper for radius_axlat
+ * Now users are able to get data that is accessible only via xlat
+ * e.g. %{client:...}
+ * Call syntax is radiusd::xlat(string), string will be handled the
+ * same way it is described in EXPANSIONS section of man unlang
+ */
+static XS(XS_radiusd_xlat)
+{
+ dXSARGS;
+ char *in_str;
+ char *expanded;
+ ssize_t slen;
+ SV *rad_requestp_sv;
+ REQUEST *request;
+
+ if (items != 1) croak("Usage: radiusd::xlat(string)");
+
+ rad_requestp_sv = get_sv("RAD___REQUESTP", 0);
+ if (rad_requestp_sv == NULL) croak("Can not evalue xlat, RAD___REQUESTP is not set!");
+
+ request = INT2PTR(REQUEST *, SvIV(rad_requestp_sv));
+
+ in_str = (char *) SvPV(ST(0), PL_na);
+ expanded = NULL;
+ slen = radius_axlat(&expanded, request, in_str, NULL, NULL);
+
+ if (slen < 0) {
+ REDEBUG("Error parsing xlat '%s'", in_str);
+ XSRETURN_UNDEF;
+ }
+
+
+ XST_mPV(0, expanded);
+ talloc_free(expanded);
+ XSRETURN(1);
+}
+
+static void xs_init(pTHX)
+{
+ char const *file = __FILE__;
+
+ /* DynaLoader is a special case */
+ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
+
+ newXS("radiusd::radlog",XS_radiusd_radlog, "rlm_perl");
+ newXS("radiusd::xlat",XS_radiusd_xlat, "rlm_perl");
+}
+
+/*
+ * The xlat function
+ */
+static ssize_t perl_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+
+ rlm_perl_t *inst = (rlm_perl_t *) instance;
+ char *tmp;
+ char const *p, *q;
+ int count;
+ size_t ret = 0;
+ STRLEN n_a;
+
+#ifdef USE_ITHREADS
+ PerlInterpreter *interp;
+
+ pthread_mutex_lock(&inst->clone_mutex);
+ interp = rlm_perl_clone(inst->perl, inst->thread_key);
+ {
+ dTHXa(interp);
+ PERL_SET_CONTEXT(interp);
+ }
+ pthread_mutex_unlock(&inst->clone_mutex);
+#else
+ PERL_SET_CONTEXT(inst->perl);
+#endif
+ {
+ dSP;
+ ENTER;SAVETMPS;
+
+ PUSHMARK(SP);
+
+ p = q = fmt;
+ while (*p == ' ') {
+ p++;
+ q++;
+ }
+ while (*q) {
+ if (*q == ' ') {
+ XPUSHs(sv_2mortal(newSVpvn(p, q - p)));
+ p = q + 1;
+
+ /*
+ * Don't use an empty string
+ */
+ while (*p == ' ') p++;
+ q = p;
+ }
+ q++;
+ }
+
+ /*
+ * And the last bit.
+ */
+ if (*p) {
+ XPUSHs(sv_2mortal(newSVpvn(p, strlen(p))));
+ }
+
+ PUTBACK;
+
+ count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);
+
+ SPAGAIN;
+ if (SvTRUE(ERRSV)) {
+ REDEBUG("Exit %s", SvPV(ERRSV,n_a));
+ (void)POPs;
+ } else if (count > 0) {
+ tmp = POPp;
+ strlcpy(out, tmp, freespace);
+ ret = strlen(out);
+
+ RDEBUG("Len is %zu , out is %s freespace is %zu", ret, out, freespace);
+ }
+
+ PUTBACK ;
+ FREETMPS ;
+ LEAVE ;
+
+ }
+
+ return ret;
+}
+
+/*
+ * Parse a configuration section, and populate a HV.
+ * This function is recursively called (allows to have nested hashes.)
+ */
+static void perl_parse_config(CONF_SECTION *cs, int lvl, HV *rad_hv)
+{
+ if (!cs || !rad_hv) return;
+
+ int indent_section = (lvl + 1) * 4;
+ int indent_item = (lvl + 2) * 4;
+
+ DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
+
+ CONF_ITEM *ci = NULL;
+
+ while ((ci = cf_item_find_next(cs, ci))) {
+ /*
+ * This is a section.
+ * Create a new HV, store it as a reference in current HV,
+ * Then recursively call perl_parse_config with this section and the new HV.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *sub_cs = cf_item_to_section(ci);
+ char const *key = cf_section_name1(sub_cs); /* hash key */
+ HV *sub_hv;
+ SV *ref;
+
+ if (!key) continue;
+
+ if (hv_exists(rad_hv, key, strlen(key))) {
+ WARN("rlm_perl: Ignoring duplicate config section '%s'", key);
+ continue;
+ }
+
+ sub_hv = newHV();
+ ref = newRV_inc((SV*) sub_hv);
+
+ (void)hv_store(rad_hv, key, strlen(key), ref, 0);
+
+ perl_parse_config(sub_cs, lvl + 1, sub_hv);
+ } else if (cf_item_is_pair(ci)){
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+ char const *key = cf_pair_attr(cp); /* hash key */
+ char const *value = cf_pair_value(cp); /* hash value */
+
+ if (!key || !value) continue;
+
+ /*
+ * This is an item.
+ * Store item attr / value in current HV.
+ */
+ if (hv_exists(rad_hv, key, strlen(key))) {
+ WARN("rlm_perl: Ignoring duplicate config item '%s'", key);
+ continue;
+ }
+
+ (void)hv_store(rad_hv, key, strlen(key), newSVpvn(value, strlen(value)), 0);
+
+ DEBUG("%*s%s = %s", indent_item, " ", key, value);
+ }
+ }
+
+ DEBUG("%*s}", indent_section, " ");
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_perl_t *inst = instance;
+
+ char const *xlat_name;
+
+ INFO("Perl version: %s", PERL_API_VERSION_STRING);
+
+ xlat_name = cf_section_name2(conf);
+ if (!xlat_name) xlat_name = cf_section_name1(conf);
+
+ xlat_register(xlat_name, perl_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.
+ *
+ * Setup a hashes wich we will use later
+ * parse a module and give him a chance to live
+ *
+ */
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_perl_t *inst = instance;
+ AV *end_AV;
+
+ char const **embed_c; /* Stupid Perl and lack of const consistency */
+ char **embed;
+ char **envp = NULL;
+ int exitstatus = 0, argc=0;
+ char arg[] = "0";
+
+ CONF_SECTION *cs;
+
+#ifdef USE_ITHREADS
+ /*
+ * Create pthread key. This key will be stored in instance
+ */
+ pthread_mutex_init(&inst->clone_mutex, NULL);
+
+ inst->thread_key = rad_malloc(sizeof(*inst->thread_key));
+ memset(inst->thread_key,0,sizeof(*inst->thread_key));
+
+ rlm_perl_make_key(inst->thread_key);
+#endif
+
+ /*
+ * Setup the argument array we pass to the perl interpreter
+ */
+ MEM(embed_c = talloc_zero_array(inst, char const *, 4));
+ memcpy(&embed, &embed_c, sizeof(embed));
+ embed_c[0] = NULL;
+ if (inst->perl_flags) {
+ embed_c[1] = inst->perl_flags;
+ embed_c[2] = inst->module;
+ embed_c[3] = arg;
+ argc = 4;
+ } else {
+ embed_c[1] = inst->module;
+ embed_c[2] = arg;
+ argc = 3;
+ }
+
+ /*
+ * Create tweak the server's environment to support
+ * perl. Docs say only call this once... Oops.
+ */
+ if (!perl_sys_init3_called) {
+ PERL_SYS_INIT3(&argc, &embed, &envp);
+ perl_sys_init3_called = 1;
+ }
+
+ /*
+ * Allocate a new perl interpreter to do the parsing
+ */
+ if ((inst->perl = perl_alloc()) == NULL) {
+ ERROR("rlm_perl: No memory for allocating new perl !");
+ return -1;
+ }
+ perl_construct(inst->perl); /* ...and initialise it */
+
+#ifdef USE_ITHREADS
+ PL_perl_destruct_level = 2;
+
+ {
+ dTHXa(inst->perl);
+ }
+ PERL_SET_CONTEXT(inst->perl);
+#endif
+
+#if PERL_REVISION >= 5 && PERL_VERSION >=8
+ PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+#endif
+
+ exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL);
+
+ end_AV = PL_endav;
+ PL_endav = (AV *)NULL;
+
+ if (exitstatus) {
+ ERROR("rlm_perl: perl_parse failed: %s not found or has syntax errors", inst->module);
+ return -1;
+ }
+
+ /* parse perl configuration sub-section */
+ cs = cf_section_sub_find(conf, "config");
+ if (cs) {
+ inst->rad_perlconf_hv = get_hv("RAD_PERLCONF", 1);
+ perl_parse_config(cs, 0, inst->rad_perlconf_hv);
+ }
+
+ inst->perl_parsed = true;
+ perl_run(inst->perl);
+
+ PL_endav = end_AV;
+
+ return 0;
+}
+
+static void perl_vp_to_svpvn_element(REQUEST *request, AV *av, VALUE_PAIR const *vp,
+ int *i, const char *hash_name, const char *list_name)
+{
+ size_t len;
+ SV *sv;
+ char buffer[1024];
+
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ if (vp->da->flags.secret && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUG("$%s{'%s'}[%i] = &%s:%s -> <<< secret >>>", hash_name, vp->da->name, *i,
+ list_name, vp->da->name);
+ } else {
+ RDEBUG("$%s{'%s'}[%i] = &%s:%s -> '%s'", hash_name, vp->da->name, *i,
+ list_name, vp->da->name, vp->vp_strvalue);
+ }
+ sv = newSVpvn(vp->vp_strvalue, vp->vp_length);
+ break;
+
+ default:
+ len = vp_prints_value(buffer, sizeof(buffer), vp, 0);
+ if (vp->da->flags.secret && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUG("$%s{'%s'}[%i] = &%s:%s -> <<< secret >>>", hash_name, vp->da->name, *i,
+ list_name, vp->da->name);
+ } else {
+ RDEBUG("$%s{'%s'}[%i] = &%s:%s -> '%s'", hash_name, vp->da->name, *i,
+ list_name, vp->da->name, buffer);
+ }
+ sv = newSVpvn(buffer, truncate_len(len, sizeof(buffer)));
+ break;
+ }
+
+ if (!sv) return;
+ SvTAINTED_on(sv);
+ av_push(av, sv);
+ (*i)++;
+}
+
+/*
+ * get the vps and put them in perl hash
+ * If one VP have multiple values it is added as array_ref
+ * Example for this is Cisco-AVPair that holds multiple values.
+ * Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
+ */
+static void perl_store_vps(UNUSED TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, HV *rad_hv,
+ const char *hash_name, const char *list_name)
+{
+ VALUE_PAIR *vp;
+ char *tbuff;
+ size_t tbufflen = 1024;
+
+ hv_undef(rad_hv);
+
+ vp_cursor_t cursor;
+
+ /*
+ * Find out how much room to allocate.
+ */
+ for (vp = fr_cursor_init(&cursor, vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (((vp->length * 2) + 3) > tbufflen) {
+ tbufflen = (vp->vp_length * 2) + 3;
+ }
+ }
+ tbuff = talloc_array(request, char, tbufflen);
+
+ RINDENT();
+ fr_pair_list_sort(vps, fr_pair_cmp_by_da_tag);
+ for (vp = fr_cursor_init(&cursor, vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VALUE_PAIR *next;
+ char const *name;
+ size_t len;
+ char namebuf[256];
+
+ /*
+ * Tagged attributes are added to the hash with name
+ * <attribute>:<tag>, others just use the normal attribute
+ * name as the key.
+ */
+ if (vp->da->flags.has_tag && (vp->tag != TAG_ANY)) {
+ snprintf(namebuf, sizeof(namebuf), "%s:%d", vp->da->name, vp->tag);
+ name = namebuf;
+ } else {
+ name = vp->da->name;
+ }
+
+ /*
+ * We've sorted by type, then tag, so attributes of the
+ * same type/tag should follow on from each other.
+ */
+ if ((next = fr_cursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next)) {
+ int i = 0;
+ AV *av;
+
+ av = newAV();
+
+ perl_vp_to_svpvn_element(request, av, vp, &i, hash_name, list_name);
+ do {
+ perl_vp_to_svpvn_element(request, av, next, &i, hash_name, list_name);
+ fr_cursor_next(&cursor);
+ } while ((next = fr_cursor_next_peek(&cursor)) && ATTRIBUTE_EQ(vp, next));
+ (void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
+
+ continue;
+ }
+
+ /*
+ * It's a normal single valued attribute
+ */
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ if (vp->da->flags.secret && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUG("$%s{'%s'} = &%s:%s -> <<< secret >>>", hash_name, vp->da->name, list_name,
+ vp->da->name);
+ } else {
+ RDEBUG("$%s{'%s'} = &%s:%s -> '%s'", hash_name, vp->da->name, list_name,
+ vp->da->name, vp->vp_strvalue);
+ }
+ (void)hv_store(rad_hv, name, strlen(name), newSVpvn(vp->vp_strvalue, vp->vp_length), 0);
+ break;
+
+ default:
+ len = vp_prints_value(tbuff, tbufflen, vp, 0);
+ if (vp->da->flags.secret && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ RDEBUG("$%s{'%s'} = &%s:%s -> <<< secret >>>", hash_name, vp->da->name, list_name,
+ vp->da->name);
+ } else {
+ RDEBUG("$%s{'%s'} = &%s:%s -> '%s'", hash_name, vp->da->name,
+ list_name, vp->da->name, tbuff);
+ }
+ (void)hv_store(rad_hv, name, strlen(name),
+ newSVpvn(tbuff, truncate_len(len, tbufflen)), 0);
+ break;
+ }
+ }
+ REXDENT();
+
+ talloc_free(tbuff);
+}
+
+/*
+ *
+ * Verify that a Perl SV is a string and save it in FreeRadius
+ * Value Pair Format
+ *
+ */
+static void pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op,
+ const char *hash_name, const char *list_name)
+{
+ char const *val = NULL;
+ VALUE_PAIR *vp;
+ STRLEN len;
+
+ if (!SvOK(sv)) {
+ REDEBUG("Internal failure creating pair &%s:%s %s $%s{'%s'} -> '%s'", list_name, key,
+ fr_int2str(fr_tokens, op, "<INVALID>"), hash_name, key, (val ? val : "undef"));
+ return;
+ }
+
+ val = SvPV(sv, len);
+ vp = fr_pair_make(ctx, vps, key, NULL, op);
+ if (!vp) {
+ fail:
+ REDEBUG("Failed to create pair - %s", fr_strerror());
+ REDEBUG(" &%s:%s %s $%s{'%s'} -> '%s'", list_name, key,
+ fr_int2str(fr_tokens, op, "<INVALID>"), hash_name, key, (val ? val : "undef"));
+ return;
+ }
+
+ switch (vp->da->type) {
+ case PW_TYPE_STRING:
+ fr_pair_value_bstrncpy(vp, val, len);
+ break;
+
+ default:
+ VERIFY_VP(vp);
+
+ if (fr_pair_value_from_str(vp, val, len) < 0) goto fail;
+ }
+
+ if (vp->da->flags.secret && request->root->suppress_secrets && (rad_debug_lvl < 3)) {
+ val = "<<< secret >>>";
+ }
+
+ RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"),
+ hash_name, key, val);
+}
+
+/*
+ * Gets the content from hashes
+ */
+static void get_hv_content(TALLOC_CTX *ctx, REQUEST *request, HV *my_hv, VALUE_PAIR **vps,
+ const char *hash_name, const char *list_name)
+{
+ SV *res_sv, **av_sv;
+ AV *av;
+ char *key;
+ I32 key_len, len, i, j;
+
+ *vps = NULL;
+ for (i = hv_iterinit(my_hv); i > 0; i--) {
+ res_sv = hv_iternextsv(my_hv,&key,&key_len);
+ if (SvROK(res_sv) && (SvTYPE(SvRV(res_sv)) == SVt_PVAV)) {
+ av = (AV*)SvRV(res_sv);
+ len = av_len(av);
+ for (j = 0; j <= len; j++) {
+ av_sv = av_fetch(av, j, 0);
+ pairadd_sv(ctx, request, vps, key, *av_sv, T_OP_ADD, hash_name, list_name);
+ }
+ } else {
+ pairadd_sv(ctx, request, vps, key, res_sv, T_OP_EQ, hash_name, list_name);
+ }
+ }
+
+ if (*vps) VERIFY_LIST(*vps, "perl");
+}
+
+/*
+ * Call the function_name inside the module
+ * Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
+ *
+ */
+static int do_perl(void *instance, REQUEST *request, char const *function_name)
+{
+
+ rlm_perl_t *inst = instance;
+ VALUE_PAIR *vp;
+ int exitstatus=0, count;
+ STRLEN n_a;
+
+ HV *rad_reply_hv;
+ HV *rad_check_hv;
+ HV *rad_config_hv;
+ HV *rad_request_hv;
+ HV *rad_state_hv;
+#ifdef WITH_PROXY
+ HV *rad_request_proxy_hv;
+ HV *rad_request_proxy_reply_hv;
+#endif
+ SV *rad_requestp_sv;
+
+ /*
+ * Radius has told us to call this function, but none
+ * is defined.
+ */
+ if (!function_name) return RLM_MODULE_FAIL;
+
+#ifdef USE_ITHREADS
+ pthread_mutex_lock(&inst->clone_mutex);
+
+ PerlInterpreter *interp;
+
+ interp = rlm_perl_clone(inst->perl,inst->thread_key);
+ {
+ dTHXa(interp);
+ PERL_SET_CONTEXT(interp);
+ }
+
+ pthread_mutex_unlock(&inst->clone_mutex);
+#else
+ PERL_SET_CONTEXT(inst->perl);
+#endif
+
+ {
+ dSP;
+
+ ENTER;
+ SAVETMPS;
+
+ rad_reply_hv = get_hv("RAD_REPLY", 1);
+ rad_check_hv = get_hv("RAD_CHECK", 1);
+ rad_config_hv = get_hv("RAD_CONFIG", 1);
+ rad_request_hv = get_hv("RAD_REQUEST", 1);
+ rad_state_hv = get_hv("RAD_STATE", 1);
+ rad_requestp_sv = get_sv("RAD___REQUESTP", 1);
+
+ perl_store_vps(request->packet, request, &request->packet->vps, rad_request_hv, "RAD_REQUEST", "request");
+ perl_store_vps(request->reply, request, &request->reply->vps, rad_reply_hv, "RAD_REPLY", "reply");
+ perl_store_vps(request, request, &request->config, rad_check_hv, "RAD_CHECK", "control");
+ perl_store_vps(request, request, &request->config, rad_config_hv, "RAD_CONFIG", "control");
+ perl_store_vps(request->state_ctx, request, &request->state, rad_state_hv, "RAD_STATE", "session-state");
+
+#ifdef WITH_PROXY
+ rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
+ rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);
+
+ if (request->proxy != NULL) {
+ perl_store_vps(request->proxy, request, &request->proxy->vps, rad_request_proxy_hv,
+ "RAD_REQUEST_PROXY", "proxy-request");
+ } else {
+ hv_undef(rad_request_proxy_hv);
+ }
+
+ if (request->proxy_reply != NULL) {
+ perl_store_vps(request->proxy_reply, request, &request->proxy_reply->vps,
+ rad_request_proxy_reply_hv, "RAD_REQUEST_PROXY_REPLY", "proxy-reply");
+ } else {
+ hv_undef(rad_request_proxy_reply_hv);
+ }
+#endif
+
+ /*
+ * Store pointer to request structure globally so xlat works
+ * We mark it read-only for interpreter so end users will not be
+ * in posession to change it and crash radiusd with bogus pointer
+ */
+ SvREADONLY_off(rad_requestp_sv);
+ sv_setiv(rad_requestp_sv, PTR2IV(request));
+ SvREADONLY_on(rad_requestp_sv);
+
+ PUSHMARK(SP);
+ /*
+ * This way %RAD_xx can be pushed onto stack as sub parameters.
+ * XPUSHs( newRV_noinc((SV *)rad_request_hv) );
+ * XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
+ * XPUSHs( newRV_noinc((SV *)rad_check_hv) );
+ * PUTBACK;
+ */
+
+ count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);
+
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ RDEBUG("perl_embed:: module = %s , func = %s exit status= %s\n",
+ inst->module, function_name, SvPV(ERRSV,n_a));
+ (void)POPs;
+ count = 0;
+ exitstatus = RLM_MODULE_FAIL;
+ }
+
+ if (count == 1) {
+ exitstatus = POPi;
+ if (exitstatus >= 100 || exitstatus < 0) {
+ exitstatus = RLM_MODULE_FAIL;
+ }
+ }
+
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ vp = NULL;
+ get_hv_content(request->packet, request, rad_request_hv, &vp, "RAD_REQUEST", "request");
+ if (vp) {
+ fr_pair_list_free(&request->packet->vps);
+ request->packet->vps = vp;
+ vp = NULL;
+
+ /*
+ * Update cached copies
+ */
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ if (!request->password)
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ }
+
+ get_hv_content(request->reply, request, rad_reply_hv, &vp, "RAD_REPLY", "reply");
+ if (vp) {
+ fr_pair_list_free(&request->reply->vps);
+ request->reply->vps = vp;
+ vp = NULL;
+ }
+
+ get_hv_content(request, request, rad_check_hv, &vp, "RAD_CHECK", "control");
+ if (vp) {
+ fr_pair_list_free(&request->config);
+ request->config = vp;
+ vp = NULL;
+ }
+
+ get_hv_content(request->state_ctx, request, rad_state_hv, &vp, "RAD_STATE", "session-state");
+ if (vp) {
+ fr_pair_list_free(&request->state);
+ request->state = vp;
+ vp = NULL;
+ }
+
+#ifdef WITH_PROXY
+ if (request->proxy) {
+ get_hv_content(request->proxy, request, rad_request_proxy_hv, &vp,
+ "RAD_REQUEST_PROXY", "proxy-request");
+ if (vp) {
+ fr_pair_list_free(&request->proxy->vps);
+ request->proxy->vps = vp;
+ vp = NULL;
+ }
+ }
+
+ if (request->proxy_reply) {
+ get_hv_content(request->proxy_reply, request, rad_request_proxy_reply_hv, &vp,
+ "RAD_REQUEST_PROXY_REPLY", "proxy-reply");
+ if (vp) {
+ fr_pair_list_free(&request->proxy_reply->vps);
+ request->proxy_reply->vps = vp;
+ vp = NULL;
+ }
+ }
+#endif
+
+ }
+ return exitstatus;
+}
+
+#define RLM_PERL_FUNC(_x) static rlm_rcode_t CC_HINT(nonnull) mod_##_x(void *instance, REQUEST *request) \
+ { \
+ return do_perl(instance, request, \
+ ((rlm_perl_t *)instance)->func_##_x); \
+ }
+
+RLM_PERL_FUNC(authorize)
+RLM_PERL_FUNC(authenticate)
+RLM_PERL_FUNC(post_auth)
+
+RLM_PERL_FUNC(checksimul)
+
+#ifdef WITH_PROXY
+RLM_PERL_FUNC(pre_proxy)
+RLM_PERL_FUNC(post_proxy)
+#endif
+
+#ifdef WITH_COA
+RLM_PERL_FUNC(recv_coa)
+RLM_PERL_FUNC(send_coa)
+#endif
+
+RLM_PERL_FUNC(preacct)
+
+/*
+ * Write accounting information to this modules database.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ VALUE_PAIR *pair;
+ int acctstatustype=0;
+
+ if ((pair = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) != NULL) {
+ acctstatustype = pair->vp_integer;
+ } else {
+ RDEBUG("Invalid Accounting Packet");
+ return RLM_MODULE_INVALID;
+ }
+
+ switch (acctstatustype) {
+ case PW_STATUS_START:
+ if (((rlm_perl_t *)instance)->func_start_accounting) {
+ return do_perl(instance, request,
+ ((rlm_perl_t *)instance)->func_start_accounting);
+ } else {
+ return do_perl(instance, request,
+ ((rlm_perl_t *)instance)->func_accounting);
+ }
+
+ case PW_STATUS_STOP:
+ if (((rlm_perl_t *)instance)->func_stop_accounting) {
+ return do_perl(instance, request,
+ ((rlm_perl_t *)instance)->func_stop_accounting);
+ } else {
+ return do_perl(instance, request,
+ ((rlm_perl_t *)instance)->func_accounting);
+ }
+
+ default:
+ return do_perl(instance, request,
+ ((rlm_perl_t *)instance)->func_accounting);
+ }
+}
+
+
+/*
+ * Detach a instance give a chance to a module to make some internal setup ...
+ */
+DIAG_OFF(nested-externs)
+static int mod_detach(void *instance)
+{
+ rlm_perl_t *inst = (rlm_perl_t *) instance;
+ int exitstatus = 0, count = 0;
+
+
+ if (inst->perl_parsed) {
+ dTHXa(inst->perl);
+ PERL_SET_CONTEXT(inst->perl);
+ if (inst->rad_perlconf_hv != NULL) hv_undef(inst->rad_perlconf_hv);
+
+ if (inst->func_detach) {
+ dSP; ENTER; SAVETMPS;
+ PUSHMARK(SP);
+
+ count = call_pv(inst->func_detach, G_SCALAR | G_EVAL );
+ SPAGAIN;
+
+ if (count == 1) {
+ exitstatus = POPi;
+ if (exitstatus >= 100 || exitstatus < 0) {
+ exitstatus = RLM_MODULE_FAIL;
+ }
+ }
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ }
+ }
+
+#ifdef USE_ITHREADS
+ rlm_perl_destruct(inst->perl);
+ pthread_mutex_destroy(&inst->clone_mutex);
+#else
+ perl_destruct(inst->perl);
+ perl_free(inst->perl);
+#endif
+
+ /*
+ * Hope this is not really needed.
+ * Is only allowed to be called once just before exit().
+ *
+ PERL_SYS_TERM();
+ */
+ return exitstatus;
+}
+DIAG_ON(nested-externs)
+
+/*
+ * 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_perl;
+module_t rlm_perl = {
+ .magic = RLM_MODULE_INIT,
+ .name = "perl",
+#ifdef USE_ITHREADS
+ .type = RLM_TYPE_THREAD_SAFE,
+#else
+ .type = RLM_TYPE_THREAD_UNSAFE,
+#endif
+ .inst_size = sizeof(rlm_perl_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_SESSION] = mod_checksimul,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ },
+};
diff --git a/src/modules/rlm_preprocess/README.md b/src/modules/rlm_preprocess/README.md
new file mode 100644
index 0000000..f3a6fc5
--- /dev/null
+++ b/src/modules/rlm_preprocess/README.md
@@ -0,0 +1,11 @@
+# rlm_preprocess
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Helper module to pre-process incoming packets. This processes
+'huntgroups' and 'hints' files, as well as fixing up a number of
+NAS attribute issues.
diff --git a/src/modules/rlm_preprocess/all.mk b/src/modules/rlm_preprocess/all.mk
new file mode 100644
index 0000000..6b18994
--- /dev/null
+++ b/src/modules/rlm_preprocess/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_preprocess.a
+SOURCES := rlm_preprocess.c
diff --git a/src/modules/rlm_preprocess/rlm_preprocess.c b/src/modules/rlm_preprocess/rlm_preprocess.c
new file mode 100644
index 0000000..e6e12d4
--- /dev/null
+++ b/src/modules/rlm_preprocess/rlm_preprocess.c
@@ -0,0 +1,736 @@
+/*
+ * 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_preprocess.c
+ * @brief Fixes up requests, and processes huntgroups/hints files.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+typedef struct rlm_preprocess_t {
+ char const *huntgroup_file;
+ char const *hints_file;
+ PAIR_LIST *huntgroups;
+ PAIR_LIST *hints;
+ bool with_ascend_hack;
+ uint32_t ascend_channels_per_line;
+ bool with_ntdomain_hack;
+ bool with_specialix_jetstream_hack;
+ bool with_cisco_vsa_hack;
+ bool with_alvarion_vsa_hack;
+ bool with_cablelabs_vsa_hack;
+} rlm_preprocess_t;
+
+static const CONF_PARSER module_config[] = {
+ { "huntgroups", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_preprocess_t, huntgroup_file), NULL },
+ { "hints", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_preprocess_t, hints_file), NULL },
+ { "with_ascend_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_ascend_hack), "no" },
+ { "ascend_channels_per_line", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_preprocess_t, ascend_channels_per_line), "23" },
+
+ { "with_ntdomain_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_ntdomain_hack), "no" },
+ { "with_specialix_jetstream_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_specialix_jetstream_hack), "no" },
+ { "with_cisco_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_cisco_vsa_hack), "no" },
+ { "with_alvarion_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_alvarion_vsa_hack), "no" },
+#if 0
+ { "with_cablelabs_vsa_hack", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_preprocess_t, with_cablelabs_vsa_hack), NULL },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * See if a VALUE_PAIR list contains Fall-Through = Yes
+ */
+static int fall_through(VALUE_PAIR *vp)
+{
+ VALUE_PAIR *tmp;
+ tmp = fr_pair_find_by_num(vp, PW_FALL_THROUGH, 0, TAG_ANY);
+
+ return tmp ? tmp->vp_integer : 0;
+}
+
+/*
+ * This hack changes Ascend's wierd port numberings
+ * to standard 0-??? port numbers so that the "+" works
+ * for IP address assignments.
+ */
+static void ascend_nasport_hack(VALUE_PAIR *nas_port, int channels_per_line)
+{
+ int service;
+ int line;
+ int channel;
+
+ if (!nas_port) {
+ return;
+ }
+
+ if (nas_port->vp_integer > 9999) {
+ service = nas_port->vp_integer/10000; /* 1=digital 2=analog */
+ line = (nas_port->vp_integer - (10000 * service)) / 100;
+ channel = nas_port->vp_integer - ((10000 * service) + (100 * line));
+ nas_port->vp_integer = (channel - 1) + ((line - 1) * channels_per_line);
+ }
+}
+
+/*
+ * This hack strips out Cisco's VSA duplicities in lines
+ * (Cisco not implemented VSA's in standard way.
+ *
+ * Cisco sends it's VSA attributes with the attribute name *again*
+ * in the string, like: H323-Attribute = "h323-attribute=value".
+ * This sort of behaviour is nonsense.
+ */
+static void cisco_vsa_hack(REQUEST *request)
+{
+ int vendorcode;
+ char *ptr;
+ char newattr[MAX_STRING_LEN];
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ vendorcode = vp->da->vendor;
+ if (!((vendorcode == 9) || (vendorcode == 6618) || (vendorcode == 35265))) {
+ continue; /* not a Cisco, Quintum or Eltex VSA, continue */
+ }
+
+ if (vp->da->type != PW_TYPE_STRING) {
+ continue;
+ }
+
+ /*
+ * No weird packing. Ignore it.
+ */
+ ptr = strchr(vp->vp_strvalue, '='); /* find an '=' */
+ if (!ptr) {
+ continue;
+ }
+
+ /*
+ * Cisco-AVPair's get packed as:
+ *
+ * Cisco-AVPair = "h323-foo-bar = baz"
+ * Cisco-AVPair = "h323-foo-bar=baz"
+ *
+ * which makes sense only if you're a lunatic.
+ * This code looks for the attribute named inside
+ * of the string, and if it exists, adds it as a new
+ * attribute.
+ */
+ if (vp->da->attr == 1) {
+ char const *p;
+
+ p = vp->vp_strvalue;
+ gettoken(&p, newattr, sizeof(newattr), false);
+
+ if (dict_attrbyname(newattr) != NULL) {
+ pair_make_request(newattr, ptr + 1, T_OP_EQ);
+ }
+ } else { /* h322-foo-bar = "h323-foo-bar = baz" */
+ /*
+ * We strip out the duplicity from the
+ * value field, we use only the value on
+ * the right side of the '=' character.
+ */
+ fr_pair_value_strcpy(vp, ptr + 1);
+ }
+ }
+}
+
+
+/*
+ * Don't even ask what this is doing...
+ */
+static void alvarion_vsa_hack(VALUE_PAIR *vp)
+{
+ int number = 1;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &vp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ DICT_ATTR const *da;
+
+ if (vp->da->vendor != 12394) {
+ continue;
+ }
+
+ if (vp->da->type != PW_TYPE_STRING) {
+ continue;
+ }
+
+ da = dict_attrbyvalue(number, 12394);
+ if (!da) {
+ continue;
+ }
+
+ vp->da = da;
+
+ number++;
+ }
+}
+
+/*
+ * Cablelabs magic, taken from:
+ *
+ * http://www.cablelabs.com/packetcable/downloads/specs/PKT-SP-EM-I12-05812.pdf
+ *
+ * Sample data is:
+ *
+ * 0x0001d2d2026d30310000000000003030
+ * 3130303030000e812333000100033031
+ * 00000000000030303130303030000000
+ * 00063230313230313331303630323231
+ * 2e3633390000000081000500
+ */
+
+typedef struct cl_timezone_t {
+ uint8_t dst;
+ uint8_t sign;
+ uint8_t hh[2];
+ uint8_t mm[2];
+ uint8_t ss[2];
+} cl_timezone_t;
+
+typedef struct cl_bcid_t {
+ uint32_t timestamp;
+ uint8_t element_id[8];
+ cl_timezone_t timezone;
+ uint32_t event_counter;
+} cl_bcid_t;
+
+typedef struct cl_em_hdr_t {
+ uint16_t version;
+ cl_bcid_t bcid;
+ uint16_t message_type;
+ uint16_t element_type;
+ uint8_t element_id[8];
+ cl_timezone_t time_zone;
+ uint32_t sequence_number;
+ uint8_t event_time[18];
+ uint8_t status[4];
+ uint8_t priority;
+ uint16_t attr_count; /* of normal Cablelabs VSAs */
+ uint8_t event_object;
+} cl_em_hdr_t;
+
+
+static void cablelabs_vsa_hack(VALUE_PAIR **list)
+{
+ VALUE_PAIR *ev;
+
+ ev = fr_pair_find_by_num(*list, 1, 4491, TAG_ANY); /* Cablelabs-Event-Message */
+ if (!ev) {
+ return;
+ }
+
+ /*
+ * FIXME: write 100's of lines of code to decode
+ * each data structure above.
+ */
+}
+
+/*
+ * Mangle username if needed, IN PLACE.
+ */
+static void rad_mangle(rlm_preprocess_t *inst, REQUEST *request)
+{
+ int num_proxy_state;
+ VALUE_PAIR *namepair;
+ VALUE_PAIR *request_pairs;
+ VALUE_PAIR *tmp;
+ vp_cursor_t cursor;
+
+ /*
+ * Get the username from the request
+ * If it isn't there, then we can't mangle the request.
+ */
+ request_pairs = request->packet->vps;
+ namepair = fr_pair_find_by_num(request_pairs, PW_USER_NAME, 0, TAG_ANY);
+ if (!namepair || (namepair->vp_length == 0)) {
+ return;
+ }
+
+ if (inst->with_ntdomain_hack) {
+ char *ptr;
+ char newname[MAX_STRING_LEN];
+
+ /*
+ * Windows NT machines often authenticate themselves as
+ * NT_DOMAIN\username. Try to be smart about this.
+ *
+ * FIXME: should we handle this as a REALM ?
+ */
+ if ((ptr = strchr(namepair->vp_strvalue, '\\')) != NULL) {
+ strlcpy(newname, ptr + 1, sizeof(newname));
+ /* Same size */
+ fr_pair_value_strcpy(namepair, newname);
+ }
+ }
+
+ if (inst->with_specialix_jetstream_hack) {
+ /*
+ * Specialix Jetstream 8500 24 port access server.
+ * If the user name is 10 characters or longer, a "/"
+ * and the excess characters after the 10th are
+ * appended to the user name.
+ *
+ * Reported by Lucas Heise <root@laonet.net>
+ */
+ if ((strlen(namepair->vp_strvalue) > 10) &&
+ (namepair->vp_strvalue[10] == '/')) {
+ fr_pair_value_strcpy(namepair, namepair->vp_strvalue + 11);
+ }
+ }
+
+ /*
+ * Small check: if Framed-Protocol present but Service-Type
+ * is missing, add Service-Type = Framed-User.
+ */
+ if (fr_pair_find_by_num(request_pairs, PW_FRAMED_PROTOCOL, 0, TAG_ANY) != NULL &&
+ fr_pair_find_by_num(request_pairs, PW_SERVICE_TYPE, 0, TAG_ANY) == NULL) {
+ tmp = radius_pair_create(request->packet, &request->packet->vps, PW_SERVICE_TYPE, 0);
+ tmp->vp_integer = PW_FRAMED_USER;
+ }
+
+ num_proxy_state = 0;
+ for (tmp = fr_cursor_init(&cursor, &request->packet->vps);
+ tmp;
+ tmp = fr_cursor_next(&cursor)) {
+ if (tmp->da->vendor != 0) {
+ continue;
+ }
+
+ if (tmp->da->attr != PW_PROXY_STATE) {
+ continue;
+ }
+
+ num_proxy_state++;
+ }
+
+ if (num_proxy_state > 10) {
+ RWDEBUG("There are more than 10 Proxy-State attributes in the request");
+ RWDEBUG("You have likely configured an infinite proxy loop");
+ }
+}
+
+/*
+ * Compare the request with the "reply" part in the
+ * huntgroup, which normally only contains username or group.
+ * At least one of the "reply" items has to match.
+ */
+static int hunt_paircmp(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check)
+{
+ vp_cursor_t cursor;
+ VALUE_PAIR *check_item;
+ VALUE_PAIR *tmp;
+ int result = -1;
+
+ if (!check) return 0;
+
+ for (check_item = fr_cursor_init(&cursor, &check);
+ check_item && (result != 0);
+ check_item = fr_cursor_next(&cursor)) {
+ /* FIXME: fr_pair_list_copy should be removed once VALUE_PAIRs are no longer in linked lists */
+ tmp = fr_pair_copy(request, check_item);
+ tmp->op = check_item->op;
+ result = paircompare(req, request, tmp, NULL);
+ fr_pair_list_free(&tmp);
+ }
+
+ return result;
+}
+
+
+/*
+ * Add hints to the info sent by the terminal server
+ * based on the pattern of the username, and other attributes.
+ */
+static int hints_setup(PAIR_LIST *hints, REQUEST *request)
+{
+ char const *name;
+ VALUE_PAIR *add;
+ VALUE_PAIR *tmp;
+ PAIR_LIST *i;
+ int updated = 0, ft;
+
+ if (!hints || !request->packet->vps)
+ return RLM_MODULE_NOOP;
+
+ /*
+ * Check for valid input, zero length names not permitted
+ */
+ name = (tmp = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY)) ?
+ tmp->vp_strvalue : NULL;
+ if (!name || name[0] == 0) {
+ /*
+ * No name, nothing to do.
+ */
+ return RLM_MODULE_NOOP;
+ }
+
+ for (i = hints; i; i = i->next) {
+ /*
+ * Use "paircompare", which is a little more general...
+ */
+ if (((strcmp(i->name, "DEFAULT") == 0) || (strcmp(i->name, name) == 0)) &&
+ (paircompare(request, request->packet->vps, i->check, NULL) == 0)) {
+ RDEBUG2("hints: Matched %s at %d", i->name, i->lineno);
+ /*
+ * Now add all attributes to the request list,
+ * except PW_STRIP_USER_NAME and PW_FALL_THROUGH
+ * and xlat them.
+ */
+ add = fr_pair_list_copy(request->packet, i->reply);
+ ft = fall_through(add);
+
+ fr_pair_delete_by_num(&add, PW_STRIP_USER_NAME, 0, TAG_ANY);
+ fr_pair_delete_by_num(&add, PW_FALL_THROUGH, 0, TAG_ANY);
+ radius_pairmove(request, &request->packet->vps, add, true);
+
+ updated = 1;
+ if (!ft) {
+ break;
+ }
+ }
+ }
+
+ if (updated == 0) {
+ return RLM_MODULE_NOOP;
+ }
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * See if we have access to the huntgroup.
+ */
+static int huntgroup_access(REQUEST *request, PAIR_LIST *huntgroups)
+{
+ PAIR_LIST *i;
+ int r = RLM_MODULE_OK;
+ VALUE_PAIR *request_pairs = request->packet->vps;
+
+ /*
+ * We're not controlling access by huntgroups:
+ * Allow them in.
+ */
+ if (!huntgroups) {
+ return RLM_MODULE_OK;
+ }
+
+ for (i = huntgroups; i; i = i->next) {
+ /*
+ * See if this entry matches.
+ */
+ if (paircompare(request, request_pairs, i->check, NULL) != 0) {
+ continue;
+ }
+
+ /*
+ * Now check for access.
+ */
+ r = RLM_MODULE_REJECT;
+ if (hunt_paircmp(request, request_pairs, i->reply) == 0) {
+ VALUE_PAIR *vp;
+
+ /*
+ * We've matched the huntgroup, so add it in
+ * to the list of request pairs.
+ */
+ vp = fr_pair_find_by_num(request_pairs, PW_HUNTGROUP_NAME, 0, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_HUNTGROUP_NAME, 0);
+ fr_pair_value_strcpy(vp, i->name);
+ }
+ r = RLM_MODULE_OK;
+ }
+ break;
+ }
+
+ return r;
+}
+
+/*
+ * If the NAS wasn't smart enought to add a NAS-IP-Address
+ * to the request, then add it ourselves.
+ */
+static int add_nas_attr(REQUEST *request)
+{
+ VALUE_PAIR *nas;
+
+ switch (request->packet->src_ipaddr.af) {
+ case AF_INET:
+ nas = fr_pair_find_by_num(request->packet->vps, PW_NAS_IP_ADDRESS, 0, TAG_ANY);
+ if (!nas) {
+ nas = radius_pair_create(request->packet, &request->packet->vps, PW_NAS_IP_ADDRESS, 0);
+ nas->vp_ipaddr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ }
+ break;
+
+ case AF_INET6:
+ nas = fr_pair_find_by_num(request->packet->vps, PW_NAS_IPV6_ADDRESS, 0, TAG_ANY);
+ if (!nas) {
+ nas = radius_pair_create(request->packet, &request->packet->vps, PW_NAS_IPV6_ADDRESS, 0);
+ memcpy(&nas->vp_ipv6addr, &request->packet->src_ipaddr.ipaddr,
+ sizeof(request->packet->src_ipaddr.ipaddr));
+ }
+ break;
+
+ default:
+ ERROR("Unknown address family for packet");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Initialize.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ int ret;
+ rlm_preprocess_t *inst = instance;
+
+ /*
+ * Read the huntgroups file.
+ */
+ if (inst->huntgroup_file) {
+ ret = pairlist_read(inst, inst->huntgroup_file, &(inst->huntgroups), 0);
+ if (ret < 0) {
+ ERROR("rlm_preprocess: Error reading %s", inst->huntgroup_file);
+
+ return -1;
+ }
+ }
+
+ /*
+ * Read the hints file.
+ */
+ if (inst->hints_file) {
+ ret = pairlist_read(inst, inst->hints_file, &(inst->hints), 0);
+ if (ret < 0) {
+ ERROR("rlm_preprocess: Error reading %s", inst->hints_file);
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Preprocess a request.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ int r;
+ rlm_preprocess_t *inst = instance;
+
+ VALUE_PAIR *vp;
+
+ /*
+ * Mangle the username, to get rid of stupid implementation
+ * bugs.
+ */
+ rad_mangle(inst, request);
+
+ if (inst->with_ascend_hack) {
+ /*
+ * If we're using Ascend systems, hack the NAS-Port-Id
+ * in place, to go from Ascend's weird values to something
+ * approaching rationality.
+ */
+ ascend_nasport_hack(fr_pair_find_by_num(request->packet->vps, PW_NAS_PORT, 0, TAG_ANY),
+ inst->ascend_channels_per_line);
+ }
+
+ if (inst->with_cisco_vsa_hack) {
+ /*
+ * We need to run this hack because the h323-conf-id
+ * attribute should be used.
+ */
+ cisco_vsa_hack(request);
+ }
+
+ if (inst->with_alvarion_vsa_hack) {
+ /*
+ * We need to run this hack because the Alvarion
+ * people are crazy.
+ */
+ alvarion_vsa_hack(request->packet->vps);
+ }
+
+ if (inst->with_cablelabs_vsa_hack) {
+ /*
+ * We need to run this hack because the Cablelabs
+ * people are crazy.
+ */
+ cablelabs_vsa_hack(&request->packet->vps);
+ }
+
+ /*
+ * Add an event timestamp. Means Event-Timestamp can be used
+ * consistently instead of one letter expansions.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_EVENT_TIMESTAMP, 0);
+ vp->vp_date = request->packet->timestamp.tv_sec;
+ }
+
+ /*
+ * Note that we add the Request-Src-IP-Address to the request
+ * structure BEFORE checking huntgroup access. This allows
+ * the Request-Src-IP-Address to be used for huntgroup
+ * comparisons.
+ */
+ if (add_nas_attr(request) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ hints_setup(inst->hints, request);
+
+ /*
+ * If there is a PW_CHAP_PASSWORD attribute but there
+ * is PW_CHAP_CHALLENGE we need to add it so that other
+ * modules can use it as a normal attribute.
+ */
+ if (fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) &&
+ fr_pair_find_by_num(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL) {
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_CHAP_CHALLENGE, 0);
+ fr_pair_value_memcpy(vp, request->packet->vector, AUTH_VECTOR_LEN);
+ }
+
+ if ((r = huntgroup_access(request, inst->huntgroups)) != RLM_MODULE_OK) {
+ char buf[1024];
+ RIDEBUG("No huntgroup access: [%s] (%s)",
+ request->username ? request->username->vp_strvalue : "<NO User-Name>",
+ auth_name(buf, sizeof(buf), request, 1));
+
+ return r;
+ }
+
+ return RLM_MODULE_OK; /* Meaning: try next authorization module */
+}
+
+/*
+ * Preprocess a request before accounting
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preaccounting(void *instance, REQUEST *request)
+{
+ int r;
+ VALUE_PAIR *vp;
+ rlm_preprocess_t *inst = instance;
+
+ /*
+ * Ensure that we have the SAME user name for both
+ * authentication && accounting.
+ */
+ rad_mangle(inst, request);
+
+ if (inst->with_cisco_vsa_hack) {
+ /*
+ * We need to run this hack because the h323-conf-id
+ * attribute should be used.
+ */
+ cisco_vsa_hack(request);
+ }
+
+ if (inst->with_alvarion_vsa_hack) {
+ /*
+ * We need to run this hack because the Alvarion
+ * people are crazy.
+ */
+ alvarion_vsa_hack(request->packet->vps);
+ }
+
+ if (inst->with_cablelabs_vsa_hack) {
+ /*
+ * We need to run this hack because the Cablelabs
+ * people are crazy.
+ */
+ cablelabs_vsa_hack(&request->packet->vps);
+ }
+
+ /*
+ * Ensure that we log the NAS IP Address in the packet.
+ */
+ if (add_nas_attr(request) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ hints_setup(inst->hints, request);
+
+ /*
+ * Add an event timestamp. This means that the rest of
+ * the server can use it, rather than various error-prone
+ * manual calculations.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_EVENT_TIMESTAMP, 0, TAG_ANY);
+ if (!vp) {
+ VALUE_PAIR *delay;
+
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_EVENT_TIMESTAMP, 0);
+ vp->vp_date = request->packet->timestamp.tv_sec;
+
+ delay = fr_pair_find_by_num(request->packet->vps, PW_ACCT_DELAY_TIME, 0, TAG_ANY);
+ if (delay) {
+ if ((delay->vp_integer >= vp->vp_date) || (delay->vp_integer == UINT32_MAX)) {
+ RWARN("Ignoring invalid Acct-Delay-time of %u seconds", delay->vp_integer);
+ } else {
+ vp->vp_date -= delay->vp_integer;
+ }
+ }
+ }
+
+ if ((r = huntgroup_access(request, inst->huntgroups)) != RLM_MODULE_OK) {
+ char buf[1024];
+ RIDEBUG("No huntgroup access: [%s] (%s)",
+ request->username ? request->username->vp_strvalue : "<NO User-Name>",
+ auth_name(buf, sizeof(buf), request, 1));
+ return r;
+ }
+
+ return r;
+}
+
+/* globally exported name */
+extern module_t rlm_preprocess;
+module_t rlm_preprocess = {
+ .magic = RLM_MODULE_INIT,
+ .name = "preprocess",
+ .inst_size = sizeof(rlm_preprocess_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preaccounting
+ },
+};
+
diff --git a/src/modules/rlm_python/.gitignore b/src/modules/rlm_python/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_python/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_python/README.md b/src/modules/rlm_python/README.md
new file mode 100644
index 0000000..621afe1
--- /dev/null
+++ b/src/modules/rlm_python/README.md
@@ -0,0 +1,12 @@
+# rlm_python
+## Metadata
+<dl>
+ <dt>category</dt><dd>languages</dd>
+</dl>
+
+## Summary
+
+Allows the server to call a persistent, embedded Python v2 script.
+
+When there are policies that cannot be implemented in unlang, it
+is usually possible to use rlm_perl or rlm_python instead.
diff --git a/src/modules/rlm_python/all.mk.in b/src/modules/rlm_python/all.mk.in
new file mode 100644
index 0000000..276a3a4
--- /dev/null
+++ b/src/modules/rlm_python/all.mk.in
@@ -0,0 +1,26 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TARGETNAME)" ""
+install: $(R)$(modconfdir)/python/radiusd.py $(R)$(modconfdir)/python/example.py
+
+$(R)$(modconfdir)/python: | $(R)$(modconfdir)
+ @echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
+ @$(INSTALL) -d -m 750 $@
+
+$(R)$(modconfdir)/python/radiusd.py: src/modules/rlm_python/radiusd.py | $(R)$(modconfdir)/python
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/python
+
+$(R)$(modconfdir)/python/example.py: src/modules/rlm_python/example.py | $(R)$(modconfdir)/python
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/python
+endif
diff --git a/src/modules/rlm_python/config.h.in b/src/modules/rlm_python/config.h.in
new file mode 100644
index 0000000..531c9a0
--- /dev/null
+++ b/src/modules/rlm_python/config.h.in
@@ -0,0 +1,4 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `dl_iterate_phdr' function. */
+#undef HAVE_DL_ITERATE_PHDR
diff --git a/src/modules/rlm_python/configure b/src/modules/rlm_python/configure
new file mode 100755
index 0000000..636acb1
--- /dev/null
+++ b/src/modules/rlm_python/configure
@@ -0,0 +1,4806 @@
+#! /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_python.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+PYTHON_BIN
+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_python
+with_rlm_python_bin
+with_rlm_python_lib_dir
+with_rlm_python_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_python build without support for embedded Python2
+ --with-rlm-python-bin=PATH
+ Path to python binary
+ --with-rlm-python-lib-dir=DIR
+ Directory for Python library files
+ --with-rlm-python-include-dir=DIR
+ Directory for Python include files
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_python
+echo
+
+
+# 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_python was given.
+if test "${with_rlm_python+set}" = set; then :
+ withval=$with_rlm_python;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_python" != 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
+
+
+PYTHON_BIN=
+
+# Check whether --with-rlm-python-bin was given.
+if test "${with_rlm_python_bin+set}" = set; then :
+ withval=$with_rlm_python_bin; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-python-bin" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ PYTHON_BIN="$withval"
+ ;;
+ esac
+fi
+
+
+if test "x$PYTHON_BIN" = x; then
+ for ac_prog in python2.7 python2.6 python
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PYTHON_BIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PYTHON_BIN"; then
+ ac_cv_prog_PYTHON_BIN="$PYTHON_BIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_PYTHON_BIN="$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
+PYTHON_BIN=$ac_cv_prog_PYTHON_BIN
+if test -n "$PYTHON_BIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_BIN" >&5
+$as_echo "$PYTHON_BIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PYTHON_BIN" && break
+done
+test -n "$PYTHON_BIN" || PYTHON_BIN="not-found"
+
+fi
+
+if test "x$PYTHON_BIN" = "xnot-found"; then
+
+fail="$fail python-binary"
+
+fi
+
+PY_LIB_DIR=
+
+# Check whether --with-rlm-python-lib-dir was given.
+if test "${with_rlm_python_lib_dir+set}" = set; then :
+ withval=$with_rlm_python_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-python-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ PY_LIB_DIR="$withval"
+ ;;
+ esac
+fi
+
+
+PY_INC_DIR=
+
+# Check whether --with-rlm-python-include-dir was given.
+if test "${with_rlm_python_include_dir+set}" = set; then :
+ withval=$with_rlm_python_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-python-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ PY_INC_DIR="$withval"
+ ;;
+ esac
+fi
+
+
+
+if test x"$fail" = x""; then :
+
+ PY_MAJOR_VER=`${PYTHON_BIN} -x 'import sys ; print(sys.version[0])'`
+ if test $PY_MAJOR_VER -ne 2; then
+
+fail="$fail not-python2"
+
+ fi
+
+fi
+
+
+
+
+if test x"$fail" = x""; then :
+
+ PY_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.prefix)'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.prefix \"${PY_PREFIX}\"" >&5
+$as_echo "$as_me: Python sys.prefix \"${PY_PREFIX}\"" >&6;}
+
+ PY_EXEC_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.exec_prefix)'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"" >&5
+$as_echo "$as_me: Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"" >&6;}
+
+ PY_SYS_VERSION=`${PYTHON_BIN} -c 'import sys ; print(sys.version[0:3])'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python sys.version \"${PY_SYS_VERSION}\"" >&5
+$as_echo "$as_me: Python sys.version \"${PY_SYS_VERSION}\"" >&6;}
+
+ if test "x$PY_LIB_DIR" = "x"; then
+ PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+ PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+ fi
+
+ PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config/Makefile"
+ if test -f ${PY_MAKEFILE}; then
+ PY_LOCAL_MOD_LIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/^ *//;s/ *$//'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"" >&5
+$as_echo "$as_me: Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"" >&6;}
+
+ PY_BASE_MOD_LIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/^ *//;s/ *$//'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"" >&5
+$as_echo "$as_me: Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"" >&6;}
+
+ PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/ / /g;s/^ *//;s/ *$//'`
+ PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[:blank:]]/ /g;s/ / /g;s/^ *//;s/ *$//'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"" >&5
+$as_echo "$as_me: Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"" >&6;}
+ fi
+ PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASE_MOD_LIBS $PY_OTHER_LIBS"
+
+ old_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $PY_CFLAGS"
+ smart_try_dir="$PY_PREFIX/include/python$PY_SYS_VERSION"
+
+
+ac_safe=`echo "Python.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 Python.h in $try" >&5
+$as_echo_n "checking for Python.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <Python.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}/Python.h" >&5
+$as_echo_n "checking for ${_prefix}/Python.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <Python.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 Python.h" >&5
+$as_echo_n "checking for Python.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <Python.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 Python.h in $try" >&5
+$as_echo_n "checking for Python.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <Python.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=
+
+ CFLAGS=$old_CFLAGS
+
+ if test "x$ac_cv_header_Python_h" = "xyes"; then
+ mod_cflags="$SMART_CPPFLAGS"
+ else
+
+fail="$fail Python.h"
+
+ fi
+
+ old_LIBS=$LIBS
+ LIBS="$LIBS $PY_LIB_LOC $PY_EXTRA_LIBS -lm"
+ smart_try_dir=$PY_LIB_DIR
+
+
+sm_lib_safe=`echo "python${PY_SYS_VERSION}" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "Py_Initialize" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ 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 Py_Initialize in -lpython${PY_SYS_VERSION}" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}"
+ { $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 Py_Initialize in -lpython${PY_SYS_VERSION} in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION} in $try... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION} $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ 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
+
+ LIBS=$old_LIBS
+
+ eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
+ if test "x$t" = "xyes"; then
+ mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
+ else
+
+
+sm_lib_safe=`echo "python${PY_SYS_VERSION}m" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "Py_Initialize" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}m"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ 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 Py_Initialize in -lpython${PY_SYS_VERSION}m" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}m"
+ { $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 Py_Initialize in -lpython${PY_SYS_VERSION}m in $try" >&5
+$as_echo_n "checking for Py_Initialize in -lpython${PY_SYS_VERSION}m in $try... " >&6; }
+ LIBS="-lpython${PY_SYS_VERSION}m $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char Py_Initialize();
+int
+main ()
+{
+Py_Initialize()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpython${PY_SYS_VERSION}m"
+ smart_ldflags="-L$try -Wl,-rpath,$try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ 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
+
+ eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
+ if test "x$t" = "xyes"; then
+ mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
+ else
+
+fail="$fail libpython$PY_SYS_VERSION"
+
+ fi
+ fi
+
+fi
+
+
+for ac_func in dl_iterate_phdr
+do :
+ ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
+if test "x$ac_cv_func_dl_iterate_phdr" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DL_ITERATE_PHDR 1
+_ACEOF
+
+fi
+done
+
+
+
+ targetname=rlm_python
+else
+ targetname=
+ echo \*\*\* module rlm_python is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_python to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_python." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_python." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_python requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_python requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_python/configure.ac b/src/modules/rlm_python/configure.ac
new file mode 100644
index 0000000..c79c327
--- /dev/null
+++ b/src/modules/rlm_python/configure.ac
@@ -0,0 +1,145 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_python.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_python], [support for embedded Python2])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl extra argument: --with-rlm-python-bin
+PYTHON_BIN=
+AC_ARG_WITH(rlm-python-bin,
+ [AS_HELP_STRING([--with-rlm-python-bin=PATH],
+ [Path to python binary])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-python-bin)
+ ;;
+ yes)
+ ;;
+ *)
+ PYTHON_BIN="$withval"
+ ;;
+ esac])
+
+if test "x$PYTHON_BIN" = x; then
+ AC_CHECK_PROGS(PYTHON_BIN, [ python2.7 python2.6 python ], not-found, [${PATH}:/usr/bin:/usr/local/bin])
+fi
+
+if test "x$PYTHON_BIN" = "xnot-found"; then
+ FR_MODULE_FAIL([python-binary])
+fi
+
+dnl extra argument: --with-rlm-python-lib-dir
+PY_LIB_DIR=
+AC_ARG_WITH(rlm-python-lib-dir,
+ [AS_HELP_STRING([--with-rlm-python-lib-dir=DIR],
+ [Directory for Python library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-python-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ PY_LIB_DIR="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-rlm-python-include-dir
+PY_INC_DIR=
+AC_ARG_WITH(rlm-python-include-dir,
+ [AS_HELP_STRING([--with-rlm-python-include-dir=DIR],
+ [Directory for Python include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-python-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ PY_INC_DIR="$withval"
+ ;;
+ esac])
+
+FR_MODULE_TEST_PASS_DO([
+ PY_MAJOR_VER=`${PYTHON_BIN} -x 'import sys ; print(sys.version[[0]])'`
+ if test $PY_MAJOR_VER -ne 2; then
+ FR_MODULE_FAIL([not-python2])
+ fi
+])
+
+FR_MODULE_TEST_PASS_DO([
+ PY_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.prefix)'`
+ AC_MSG_NOTICE([Python sys.prefix \"${PY_PREFIX}\"])
+
+ PY_EXEC_PREFIX=`${PYTHON_BIN} -c 'import sys ; print(sys.exec_prefix)'`
+ AC_MSG_NOTICE([Python sys.exec_prefix \"${PY_EXEC_PREFIX}\"])
+
+ PY_SYS_VERSION=`${PYTHON_BIN} -c 'import sys ; print(sys.version[[0:3]])'`
+ AC_MSG_NOTICE([Python sys.version \"${PY_SYS_VERSION}\"])
+
+ if test "x$PY_LIB_DIR" = "x"; then
+ PY_LIB_DIR="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+ PY_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config"
+ fi
+
+ PY_MAKEFILE="$PY_EXEC_PREFIX/lib/python${PY_SYS_VERSION}/config/Makefile"
+ if test -f ${PY_MAKEFILE}; then
+ PY_LOCAL_MOD_LIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'`
+ AC_MSG_NOTICE([Python local_mod_libs \"${PY_LOCAL_MOD_LIBS}\"])
+
+ PY_BASE_MOD_LIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/^ *//;s/ *$//'`
+ AC_MSG_NOTICE([Python base_mod_libs \"${PY_BASE_MOD_LIBS}\"])
+
+ PY_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/ / /g;s/^ *//;s/ *$//'`
+ PY_OTHER_LDFLAGS=`sed -n -e 's/^LINKFORSHARED=\(.*\)/\1/p' $PY_MAKEFILE | sed -e 's/[[[:blank:]]]/ /g;s/ / /g;s/^ *//;s/ *$//'`
+ AC_MSG_NOTICE([Python other_libs \"${PY_OTHER_LDFLAGS} ${PY_OTHER_LIBS}\"])
+ fi
+ PY_EXTRA_LIBS="$PY_LOCALMODLIBS $PY_BASE_MOD_LIBS $PY_OTHER_LIBS"
+
+ old_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $PY_CFLAGS"
+ smart_try_dir="$PY_PREFIX/include/python$PY_SYS_VERSION"
+ FR_SMART_CHECK_INCLUDE(Python.h)
+ CFLAGS=$old_CFLAGS
+
+ if test "x$ac_cv_header_Python_h" = "xyes"; then
+ mod_cflags="$SMART_CPPFLAGS"
+ else
+ FR_MODULE_FAIL([Python.h])
+ fi
+
+ old_LIBS=$LIBS
+ LIBS="$LIBS $PY_LIB_LOC $PY_EXTRA_LIBS -lm"
+ smart_try_dir=$PY_LIB_DIR
+ FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}, Py_Initialize)
+ LIBS=$old_LIBS
+
+ eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
+ if test "x$t" = "xyes"; then
+ mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
+ else
+ FR_SMART_CHECK_LIB(python${PY_SYS_VERSION}m, Py_Initialize)
+ eval t=\${ac_cv_lib_${sm_lib_safe}_${sm_func_safe}}
+ if test "x$t" = "xyes"; then
+ mod_ldflags="$PY_LIB_LOC $PY_EXTRA_LIBS $SMART_LIBS -lm"
+ else
+ FR_MODULE_FAIL([libpython$PY_SYS_VERSION])
+ fi
+ fi
+])
+
+AC_CHECK_FUNCS([dl_iterate_phdr])
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_python/example.py b/src/modules/rlm_python/example.py
new file mode 100644
index 0000000..e9e9aea
--- /dev/null
+++ b/src/modules/rlm_python/example.py
@@ -0,0 +1,99 @@
+#! /usr/bin/env python2
+#
+# Python module example file
+# Miguel A.L. Paraz <mparaz@mparaz.com>
+#
+# $Id$
+
+import radiusd
+
+# Check post_auth for the most complete example using different
+# input and output formats
+
+def instantiate(p):
+ print "*** instantiate ***"
+ print p
+ # return 0 for success or -1 for failure
+
+
+def authorize(p):
+ print "*** authorize ***"
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
+ print
+ print p
+ print
+ print radiusd.config
+ return radiusd.RLM_MODULE_OK
+
+
+def preacct(p):
+ print "*** preacct ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def accounting(p):
+ print "*** accounting ***"
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in accounting (0) ***')
+ print
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def pre_proxy(p):
+ print "*** pre_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def post_proxy(p):
+ print "*** post_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def post_auth(p):
+ print "*** post_auth ***"
+
+ # This is true when using pass_all_vps_dict
+ if type(p) is dict:
+ print "Request:", p["request"]
+ print "Reply:", p["reply"]
+ print "Config:", p["config"]
+ print "State:", p["session-state"]
+ print "Proxy-Request:", p["proxy-request"]
+ print "Proxy-Reply:", p["proxy-reply"]
+
+ else:
+ print p
+
+ # Dictionary representing changes we want to make to the different VPS
+ update_dict = {
+ "request": (("User-Password", ":=", "A new password"),),
+ "reply": (("Reply-Message", "The module is doing its job"),
+ ("User-Name", "NewUserName")),
+ "config": (("Cleartext-Password", "A new password"),),
+ }
+
+ return radiusd.RLM_MODULE_OK, update_dict
+ # Alternatively, you could use the legacy 3-tuple output
+ # (only reply and config can be updated)
+ # return radiusd.RLM_MODULE_OK, update_dict["reply"], update_dict["config"]
+
+
+def recv_coa(p):
+ print "*** recv_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def send_coa(p):
+ print "*** send_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def detach(p):
+ print "*** goodbye from example.py ***"
+ return radiusd.RLM_MODULE_OK
+
diff --git a/src/modules/rlm_python/prepaid.py b/src/modules/rlm_python/prepaid.py
new file mode 100644
index 0000000..3b1dc2e
--- /dev/null
+++ b/src/modules/rlm_python/prepaid.py
@@ -0,0 +1,251 @@
+#! /usr/bin/env python2
+#
+# Example Python module for prepaid usage using MySQL
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+#
+# Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+# Copyright 2002 Imperium Technology, Inc.
+#
+# $Id$
+
+import radiusd
+import MySQLdb
+
+# Configuration
+configDb = 'python' # Database name
+configHost = 'localhost' # Database host
+configUser = 'python' # Database user and password
+configPasswd = 'python'
+
+# xxx Database
+
+# Globals
+dbHandle = None
+
+def log(level, s):
+ """Log function."""
+ radiusd.radlog(level, 'prepaid.py: ' + s)
+
+def instantiate(p):
+ """Module Instantiation. 0 for success, -1 for failure.
+ p is a dummy variable here."""
+ global dbHandle
+
+ p = p
+
+ try:
+ dbHandle = MySQLdb.connect(db=configDb, host=configHost,
+ user=configUser, passwd=configPasswd)
+
+ except MySQLdb.OperationalError, e:
+ # Report the error and return -1 for failure.
+ # xxx A more advanced module would retry the database.
+ log(radiusd.L_ERR, str(e))
+ return -1
+
+ log(radiusd.L_INFO, 'db connection: ' + str(dbHandle))
+
+ return 0
+
+
+def authorize(authData):
+ """Authorization and authentication are done in one step."""
+
+ # Extract the data we need.
+ userName = None
+ userPasswd = None
+
+ for t in authData:
+ if t[0] == 'User-Name':
+ userName = t[1]
+ elif t[0] == 'Password':
+ userPasswd = t[1]
+
+ # Build and log the SQL statement
+ # radiusd puts double quotes (") around the string representation of
+ # the RADIUS packet.
+ sql = 'select passwd, maxseconds from users where username = ' + userName
+
+ log(radiusd.L_DBG, sql)
+
+ # Get a cursor
+ # xxx Or should this be one cursor all throughout?
+ try:
+ dbCursor = dbHandle.cursor()
+ except MySQLdb.OperationalError, e:
+ log(radiusd.L_ERR, str(e))
+ return radiusd.RLM_MODULE_FAIL
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError, e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+ # Get the result. (passwd, maxseconds)
+ result = dbCursor.fetchone()
+ if not result:
+ # User not found
+ log(radiusd.L_INFO, 'user not found: ' + userName)
+ dbCursor.close()
+ return radiusd.RLM_MODULE_NOTFOUND
+
+
+
+ # Compare passwords
+ # Ignore the quotes around userPasswd.
+ if result[0] != userPasswd[1:-1]:
+ log(radiusd.L_DBG, 'user password mismatch: ' + userName)
+ return radiusd.RLM_MODULE_REJECT
+
+ maxSeconds = result[1]
+
+ # Compute their session limit
+
+ # Build and log the SQL statement
+ sql = 'select sum(seconds) from sessions where username = ' + userName
+
+ log(radiusd.L_DBG, sql)
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError, e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+ # Get the result. (sum,)
+ result = dbCursor.fetchone()
+ if (not result) or (not result[0]):
+ # No usage yet
+ secondsUsed = 0
+ else:
+ secondsUsed = result[0]
+
+ # Done with cursor
+ dbCursor.close()
+
+ # Note that MySQL returns the result of SUM() as a float.
+ sessionTimeout = maxSeconds - int(secondsUsed)
+
+ if sessionTimeout <= 0:
+ # No more time, reject outright
+ log(radiusd.L_INFO, 'user out of time: ' + userName)
+ return radiusd.RLM_MODULE_REJECT
+
+ # Log the success
+ log(radiusd.L_DBG, 'user accepted: %s, %d seconds' %
+ (userName, sessionTimeout))
+
+ # We are adding to the RADIUS packet
+ # Note that the session timeout integer must be converted to string.
+ # We need to set an Auth-Type.
+
+ return (radiusd.RLM_MODULE_UPDATED,
+ (('Session-Timeout', str(sessionTimeout)),),
+ (('Auth-Type', 'python'),))
+ # If you want to use different operators
+ # you can do
+ # return (radiusd.RLM_MODULE_UPDATED,
+ # (
+ # ('Session-Timeout', ':=', str(sessionTimeout)),
+ # ('Some-other-option', '-=', Value'),
+ # ),
+ # (
+ # ('Auth-Type', ':=', 'python'),
+ # ),
+ # )
+
+def authenticate(p):
+ p = p
+ return radiusd.RLM_MODULE_OK
+
+
+def preacct(p):
+ p = p
+ return radiusd.RLM_MODULE_OK
+
+
+def accounting(acctData):
+ """Accounting."""
+ # Extract the data we need.
+
+ userName = None
+ acctSessionTime = None
+ acctStatusType = None
+
+ # xxx A dict would make this nice.
+ for t in acctData:
+ if t[0] == 'User-Name':
+ userName = t[1]
+ elif t[0] == 'Acct-Session-Time':
+ acctSessionTime = t[1]
+ elif t[0] == 'Acct-Status-Type':
+ acctStatusType = t[1]
+
+
+ # We will not deal with Start for now.
+ # We may later, for simultaneous checks and the like.
+ if acctStatusType == 'Start':
+ return radiusd.RLM_MODULE_OK
+
+ # Build and log the SQL statement
+ # radiusd puts double quotes (") around the string representation of
+ # the RADIUS packet.
+ #
+ # xxx This is simplistic as it does not record the time, etc.
+ #
+ sql = 'insert into sessions (username, seconds) values (%s, %d)' % \
+ (userName, int(acctSessionTime))
+
+ log(radiusd.L_DBG, sql)
+
+ # Get a cursor
+ # xxx Or should this be one cursor all throughout?
+ try:
+ dbCursor = dbHandle.cursor()
+ except MySQLdb.OperationalError, e:
+ log(radiusd.L_ERR, str(e))
+ return radiusd.RLM_MODULE_FAIL
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError, e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+
+ return radiusd.RLM_MODULE_OK
+
+
+def detach():
+ """Detach and clean up."""
+ # Shut down the database connection.
+ global dbHandle
+ log(radiusd.L_DBG, 'closing database handle: ' + str(dbHandle))
+ dbHandle.close()
+
+ return radiusd.RLM_MODULE_OK
+
+
+
+# Test the modules
+if __name__ == '__main__':
+ instantiate(None)
+ print authorize((('User-Name', '"map"'), ('User-Password', '"abc"')))
diff --git a/src/modules/rlm_python/prepaid.sql b/src/modules/rlm_python/prepaid.sql
new file mode 100644
index 0000000..3e9ffed
--- /dev/null
+++ b/src/modules/rlm_python/prepaid.sql
@@ -0,0 +1,41 @@
+# MySQL dump 8.13
+#
+# Host: localhost Database: python
+#--------------------------------------------------------
+# Server version 3.23.36
+
+#
+# Table structure for table 'sessions'
+#
+
+CREATE TABLE sessions (
+ username char(32) default NULL,
+ seconds int(11) default NULL
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'sessions'
+#
+
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+
+#
+# Table structure for table 'users'
+#
+
+CREATE TABLE users (
+ username char(32) NOT NULL default '',
+ passwd char(32) default NULL,
+ maxseconds int(11) default NULL,
+ PRIMARY KEY (username)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'users'
+#
+
+INSERT INTO users VALUES ('map','abc',100);
+
diff --git a/src/modules/rlm_python/radiusd.py b/src/modules/rlm_python/radiusd.py
new file mode 100644
index 0000000..7129923
--- /dev/null
+++ b/src/modules/rlm_python/radiusd.py
@@ -0,0 +1,47 @@
+#! /usr/bin/env python2
+#
+# Definitions for RADIUS programs
+#
+# Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+#
+# This should only be used when testing modules.
+# Inside freeradius, the 'radiusd' Python module is created by the C module
+# and the definitions are automatically created.
+#
+# $Id$
+
+# from modules.h
+
+RLM_MODULE_REJECT = 0
+RLM_MODULE_FAIL = 1
+RLM_MODULE_OK = 2
+RLM_MODULE_HANDLED = 3
+RLM_MODULE_INVALID = 4
+RLM_MODULE_USERLOCK = 5
+RLM_MODULE_NOTFOUND = 6
+RLM_MODULE_NOOP = 7
+RLM_MODULE_UPDATED = 8
+RLM_MODULE_NUMCODES = 9
+
+# from log.h
+L_AUTH = 2
+L_INFO = 3
+L_ERR = 4
+L_WARN = 5
+L_PROXY = 6
+L_ACCT = 7
+
+L_DBG = 16
+L_DBG_WARN = 17
+L_DBG_ERR = 18
+L_DBG_WARN_REQ = 19
+L_DBG_ERR_REQ = 20
+
+# log function
+def radlog(level, msg):
+ import sys
+ sys.stdout.write(msg + '\n')
+
+ level = level
+
+
diff --git a/src/modules/rlm_python/radiusd_test.py b/src/modules/rlm_python/radiusd_test.py
new file mode 100644
index 0000000..97b5b64
--- /dev/null
+++ b/src/modules/rlm_python/radiusd_test.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python2
+#
+# Python module test
+# Miguel A.L. Paraz <mparaz@mparaz.com>
+#
+# $Id$
+
+import radiusd
+
+def instantiate(p):
+ print "*** instantiate ***"
+ print p
+
+def authorize(p):
+ print "*** authorize ***"
+ print
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
+ print
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def preacct(p):
+ print "*** preacct ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def accounting(p):
+ print "*** accounting ***"
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in accounting (0) ***')
+ print
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def pre_proxy(p):
+ print "*** pre_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def post_proxy(p):
+ print "*** post_proxy ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def post_auth(p):
+ print "*** post_auth ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def recv_coa(p):
+ print "*** recv_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+def send_coa(p):
+ print "*** send_coa ***"
+ print p
+ return radiusd.RLM_MODULE_OK
+
+
+def detach():
+ print "*** goodbye from radiusd_test.py ***"
+ return radiusd.RLM_MODULE_OK
+
diff --git a/src/modules/rlm_python/rlm_python.c b/src/modules/rlm_python/rlm_python.c
new file mode 100644
index 0000000..2adba0e
--- /dev/null
+++ b/src/modules/rlm_python/rlm_python.c
@@ -0,0 +1,1284 @@
+/*
+ * 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_python.c
+ * @brief Translates requests between the server an a python interpreter.
+ *
+ * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
+ *
+ * @copyright 2000,2006,2015-2016 The FreeRADIUS server project
+ * @copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+ * @copyright 2002 Imperium Technology, Inc.
+ */
+RCSID("$Id$")
+
+#define LOG_PREFIX "rlm_python - "
+
+#include "config.h"
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <Python.h>
+#include <frameobject.h> /* Python header not pulled in by default. */
+#include <dlfcn.h>
+#ifdef HAVE_DL_ITERATE_PHDR
+#include <link.h>
+#endif
+
+#define LIBPYTHON_LINKER_NAME \
+ "libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) LT_SHREXT
+
+static uint32_t python_instances = 0;
+static void *python_dlhandle;
+
+static PyThreadState *main_interpreter; //!< Main interpreter (cext safe)
+static PyObject *main_module; //!< Pthon configuration dictionary.
+
+/** Specifies the module.function to load for processing a section
+ *
+ */
+typedef struct python_func_def {
+ PyObject *module; //!< Python reference to module.
+ PyObject *function; //!< Python reference to function in module.
+
+ char const *module_name; //!< String name of module.
+ char const *function_name; //!< String name of function in module.
+} python_func_def_t;
+
+/** An instance of the rlm_python module
+ *
+ */
+typedef struct rlm_python_t {
+ char const *name; //!< Name of the module instance
+ PyThreadState *sub_interpreter; //!< The main interpreter/thread used for this instance.
+ char const *python_path; //!< Path to search for python files in.
+
+#if PY_VERSION_HEX > 0x03050000
+ wchar_t *wide_name; //!< Special wide char encoding of radiusd name.
+#endif
+ PyObject *module; //!< Local, interpreter specific module, containing
+ //!< FreeRADIUS functions.
+ bool cext_compat; //!< Whether or not to create sub-interpreters per module
+ //!< instance.
+
+ python_func_def_t
+ instantiate,
+ authorize,
+ authenticate,
+ preacct,
+ accounting,
+ checksimul,
+ pre_proxy,
+ post_proxy,
+ post_auth,
+#ifdef WITH_COA
+ recv_coa,
+ send_coa,
+#endif
+ detach;
+
+ PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
+ //!< made available to the python script.
+ bool pass_all_vps; //!< Pass all VPS lists (request, reply, config, state, proxy_req, proxy_reply)
+ bool pass_all_vps_dict; //!< Pass all VPS lists as a dictionary rather than a tuple
+} rlm_python_t;
+
+/** Tracks a python module inst/thread state pair
+ *
+ * Multiple instances of python create multiple interpreters and each
+ * thread must have a PyThreadState per interpreter, to track execution.
+ */
+typedef struct python_thread_state {
+ PyThreadState *state; //!< Module instance/thread specific state.
+ rlm_python_t *inst; //!< Module instance that created this thread state.
+} python_thread_state_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static CONF_PARSER module_config[] = {
+
+#define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), NULL }, \
+ { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
+
+ A(instantiate)
+ A(authorize)
+ A(authenticate)
+ A(preacct)
+ A(accounting)
+ A(checksimul)
+ A(pre_proxy)
+ A(post_proxy)
+ A(post_auth)
+#ifdef WITH_COA
+ A(recv_coa)
+ A(send_coa)
+#endif
+ A(detach)
+
+#undef A
+
+ { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
+ { "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
+ { "pass_all_vps", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps), "no" },
+ { "pass_all_vps_dict", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps_dict), "no" },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static struct {
+ char const *name;
+ int value;
+} radiusd_constants[] = {
+
+#define A(x) { #x, x },
+
+ A(L_DBG)
+ A(L_WARN)
+ A(L_AUTH)
+ A(L_INFO)
+ A(L_ERR)
+ A(L_PROXY)
+ A(L_ACCT)
+ A(L_DBG_WARN)
+ A(L_DBG_ERR)
+ A(L_DBG_WARN_REQ)
+ A(L_DBG_ERR_REQ)
+ A(RLM_MODULE_REJECT)
+ A(RLM_MODULE_FAIL)
+ A(RLM_MODULE_OK)
+ A(RLM_MODULE_HANDLED)
+ A(RLM_MODULE_INVALID)
+ A(RLM_MODULE_USERLOCK)
+ A(RLM_MODULE_NOTFOUND)
+ A(RLM_MODULE_NOOP)
+ A(RLM_MODULE_UPDATED)
+ A(RLM_MODULE_NUMCODES)
+
+#undef A
+
+ { NULL, 0 },
+};
+
+/*
+ * This allows us to initialise PyThreadState on a per thread basis
+ */
+fr_thread_local_setup(rbtree_t *, local_thread_state) /* macro */
+
+/*
+ * radiusd Python functions
+ */
+
+/** Allow radlog to be called from python
+ *
+ */
+static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
+{
+ int status;
+ char *msg;
+
+ if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
+ return NULL;
+ }
+
+ radlog(status, "%s", msg);
+ Py_INCREF(Py_None);
+
+ return Py_None;
+}
+
+static PyMethodDef module_methods[] = {
+ { "radlog", &mod_radlog, METH_VARARGS,
+ "radiusd.radlog(level, msg)\n\n" \
+ "Print a message using radiusd logging system. level should be one of the\n" \
+ "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
+ },
+ { NULL, NULL, 0, NULL },
+};
+
+/** Print out the current error
+ *
+ * Must be called with a valid thread state set
+ */
+static void python_error_log(void)
+{
+ PyObject *p_type = NULL, *p_value = NULL, *p_traceback = NULL, *p_str_1 = NULL, *p_str_2 = NULL;
+
+ PyErr_Fetch(&p_type, &p_value, &p_traceback);
+ PyErr_NormalizeException(&p_type, &p_value, &p_traceback);
+ if (!p_type || !p_value) goto failed;
+
+ if (((p_str_1 = PyObject_Str(p_type)) == NULL) || ((p_str_2 = PyObject_Str(p_value)) == NULL)) goto failed;
+
+ ERROR("%s (%s)", PyString_AsString(p_str_1), PyString_AsString(p_str_2));
+
+ if (p_traceback != Py_None) {
+ PyTracebackObject *ptb = (PyTracebackObject*)p_traceback;
+ size_t fnum = 0;
+
+ for (; ptb != NULL; ptb = ptb->tb_next, fnum++) {
+ PyFrameObject *cur_frame = ptb->tb_frame;
+
+ ERROR("[%ld] %s:%d at %s()",
+ fnum,
+ PyString_AsString(cur_frame->f_code->co_filename),
+ PyFrame_GetLineNumber(cur_frame),
+ PyString_AsString(cur_frame->f_code->co_name)
+ );
+ }
+ }
+
+failed:
+ Py_XDECREF(p_str_1);
+ Py_XDECREF(p_str_2);
+ Py_XDECREF(p_type);
+ Py_XDECREF(p_value);
+ Py_XDECREF(p_traceback);
+}
+
+static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
+ char const *funcname, char const *list_name)
+{
+ int i;
+ int tuplesize;
+ vp_tmpl_t dst;
+ VALUE_PAIR *vp;
+ REQUEST *current = request;
+
+ memset(&dst, 0, sizeof(dst));
+
+ /*
+ * If the Python function gave us None for the tuple,
+ * then just return.
+ */
+ if (pValue == Py_None || pValue == NULL) return;
+
+ if (!PyTuple_CheckExact(pValue)) {
+ ERROR("%s - non-tuple passed to %s", funcname, list_name);
+ return;
+ }
+ /* Get the tuple tuplesize. */
+ tuplesize = PyTuple_GET_SIZE(pValue);
+ for (i = 0; i < tuplesize; i++) {
+ PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
+ PyObject *pStr1;
+ PyObject *pStr2;
+ PyObject *pOp;
+ int pairsize;
+ char const *s1;
+ char const *s2;
+ FR_TOKEN op = T_OP_EQ;
+
+ if (!PyTuple_CheckExact(pTupleElement)) {
+ ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
+ continue;
+ }
+ /* Check if it's a pair */
+
+ pairsize = PyTuple_GET_SIZE(pTupleElement);
+ if ((pairsize < 2) || (pairsize > 3)) {
+ ERROR("%s - Tuple element %d of %s is a tuple of size %d. Must be 2 or 3",
+ funcname, i, list_name, pairsize);
+ continue;
+ }
+
+ pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
+ pStr2 = PyTuple_GET_ITEM(pTupleElement, pairsize-1);
+
+ if ((!PyString_CheckExact(pStr1)) || (!PyString_CheckExact(pStr2))) {
+ ERROR("%s - Tuple element %d of %s must be as (str, str)",
+ funcname, i, list_name);
+ continue;
+ }
+ s1 = PyString_AsString(pStr1);
+ s2 = PyString_AsString(pStr2);
+
+ if (pairsize == 3) {
+ pOp = PyTuple_GET_ITEM(pTupleElement, 1);
+ if (PyString_CheckExact(pOp)) {
+ if (!(op = fr_str2int(fr_tokens, PyString_AsString(pOp), 0))) {
+ ERROR("%s - Invalid operator %s:%s %s %s, falling back to '='",
+ funcname, list_name, s1, PyString_AsString(pOp), s2);
+ op = T_OP_EQ;
+ }
+ } else if (PyInt_Check(pOp)) {
+ op = PyInt_AsLong(pOp);
+ if (!fr_int2str(fr_tokens, op, NULL)) {
+ ERROR("%s - Invalid operator %s:%s %i %s, falling back to '='",
+ funcname, list_name, s1, op, s2);
+ op = T_OP_EQ;
+ }
+ } else {
+ ERROR("%s - Invalid operator type for %s:%s ? %s, using default '='",
+ funcname, list_name, s1, s2);
+ }
+ }
+
+ if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
+ ERROR("%s - Failed to find attribute %s:%s", funcname, list_name, s1);
+ continue;
+ }
+
+ if (radius_request(&current, dst.tmpl_request) < 0) {
+ ERROR("%s - Attribute name %s:%s refers to outer request but not in a tunnel, skipping...",
+ funcname, list_name, s1);
+ continue;
+ }
+
+ if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
+ ERROR("%s - Failed to create attribute %s:%s", funcname, list_name, s1);
+ continue;
+ }
+
+ vp->op = op;
+
+ /*
+ * @todo - use tmpl_cast_to_vp() instead ???
+ */
+ if (vp->da->flags.has_tag) vp->tag = dst.tmpl_tag;
+
+ if (fr_pair_value_from_str(vp, s2, -1) < 0) {
+ DEBUG("%s - Failed: '%s:%s' %s '%s'", funcname, list_name, s1,
+ fr_int2str(fr_tokens, op, "="), s2);
+ } else {
+ DEBUG("%s - '%s:%s' %s '%s'", funcname, list_name, s1,
+ fr_int2str(fr_tokens, op, "="), s2);
+ }
+
+ radius_pairmove(current, vps, vp, false);
+ }
+}
+
+
+/*
+ * This is the core Python function that the others wrap around.
+ * Pass the value-pair print strings in a tuple.
+ *
+ * FIXME: We're not checking the errors. If we have errors, what
+ * do we do?
+ */
+static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
+{
+ PyObject *pStr = NULL;
+ char buf[1024];
+
+ /* Look at the fr_pair_fprint_name? */
+
+ if (vp->da->flags.has_tag) {
+ pStr = PyString_FromFormat("%s:%d", vp->da->name, vp->tag);
+ } else {
+ pStr = PyString_FromString(vp->da->name);
+ }
+
+ if (!pStr) return -1;
+
+ PyTuple_SET_ITEM(pPair, 0, pStr);
+
+ vp_prints_value(buf, sizeof(buf), vp, '\0'); /* Python doesn't need any escaping */
+
+ pStr = PyString_FromString(buf);
+ if (pStr == NULL) return -1;
+
+ PyTuple_SET_ITEM(pPair, 1, pStr);
+
+ return 0;
+}
+
+/*
+ * This function generates a tuple representing a given VPS and inserts it into
+ * the indicated position in the tuple pArgs.
+ * Returns false on error.
+ */
+static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps)
+{
+ PyObject *vps_tuple = NULL;
+ int tuplelen = 0;
+ int i = 0;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ /* If vps is NULL, return None */
+ if (vps == NULL) {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(pArgs, pos, Py_None);
+ return true;
+ }
+
+ /*
+ * We will pass a tuple containing (name, value) tuples
+ * We can safely use the Python function to build up a
+ * tuple, since the tuple is not used elsewhere.
+ *
+ * Determine the size of our tuple by walking through the vps.
+ */
+ for (vp = fr_cursor_init(&cursor, &vps); vp; vp = fr_cursor_next(&cursor))
+ tuplelen++;
+
+ if ((vps_tuple = PyTuple_New(tuplelen)) == NULL) goto error;
+
+ for (vp = fr_cursor_init(&cursor, &vps); vp; vp = fr_cursor_next(&cursor), i++) {
+ PyObject *pPair = NULL;
+
+ /* The inside tuple has two only: */
+ if ((pPair = PyTuple_New(2)) == NULL) goto error;
+
+ if (mod_populate_vptuple(pPair, vp) == 0) {
+ /* Put the tuple inside the container */
+ PyTuple_SET_ITEM(vps_tuple, i, pPair);
+ } else {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(vps_tuple, i, Py_None);
+ Py_DECREF(pPair);
+ }
+ }
+ PyTuple_SET_ITEM(pArgs, pos, vps_tuple);
+ return true;
+
+error:
+ Py_XDECREF(vps_tuple);
+ return false;
+}
+
+static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname, bool pass_all_vps, bool pass_all_vps_dict)
+{
+ PyObject *pRet = NULL;
+ PyObject *pArgs = NULL;
+ PyObject *pDictInput = NULL;
+ int ret;
+ int i;
+
+ /* Default return value is "OK, continue" */
+ ret = RLM_MODULE_OK;
+
+ /*
+ * pArgs is a 6-tuple with (Request, Reply, Config, State, Proxy-Request, Proxy-Reply)
+ * If some list is not available, NONE is used instead
+ */
+ if ((pArgs = PyTuple_New(6)) == NULL) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* If there is a request, fill in the first 4 attribute lists */
+ if (request != NULL) {
+ if (!mod_populate_vps(pArgs, 0, request->packet->vps) ||
+ !mod_populate_vps(pArgs, 1, request->reply->vps) ||
+ !mod_populate_vps(pArgs, 2, request->config) ||
+ !mod_populate_vps(pArgs, 3, request->state)) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* fill proxy vps */
+ if (request->proxy) {
+ if (!mod_populate_vps(pArgs, 4, request->proxy->vps)) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ } else {
+ mod_populate_vps(pArgs, 4, NULL);
+ }
+
+ /* fill proxy_reply vps */
+ if (request->proxy_reply) {
+ if (!mod_populate_vps(pArgs, 5, request->proxy_reply->vps)) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ } else {
+ mod_populate_vps(pArgs, 5, NULL);
+ }
+
+ }
+ /* If there is no request, set all the elements to None */
+ else for (i = 0; i < 6; i++) mod_populate_vps(pArgs, i, NULL);
+
+ /*
+ * Call Python function. If pass_all_vps_dict is true, a dictionary with the
+ * appropriate "request", "reply"... keys is passed as argument to the
+ * module callback.
+ * Else, if pass_all_vps is true, a 6-tuple representing
+ * (Request, Reply, Config, State, Proxy-Request, Proxy-Reply) is passed.
+ * Otherwise, a tuple representing just the request is used.
+ */
+ if (pass_all_vps_dict) {
+ pDictInput = PyDict_New();
+ if (pDictInput == NULL ||
+ PyDict_SetItemString(pDictInput, "request", PyTuple_GET_ITEM(pArgs, 0)) ||
+ PyDict_SetItemString(pDictInput, "reply", PyTuple_GET_ITEM(pArgs, 1)) ||
+ PyDict_SetItemString(pDictInput, "config", PyTuple_GET_ITEM(pArgs, 2)) ||
+ PyDict_SetItemString(pDictInput, "session-state", PyTuple_GET_ITEM(pArgs, 3)) ||
+ PyDict_SetItemString(pDictInput, "proxy-request", PyTuple_GET_ITEM(pArgs, 4)) ||
+ PyDict_SetItemString(pDictInput, "proxy-reply", PyTuple_GET_ITEM(pArgs, 5))) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ pRet = PyObject_CallFunctionObjArgs(pFunc, pDictInput, NULL);
+ }
+ else if (pass_all_vps)
+ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
+ else
+ pRet = PyObject_CallFunctionObjArgs(pFunc, PyTuple_GET_ITEM(pArgs, 0), NULL);
+
+ if (!pRet) {
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ if (!request) {
+ // check return code at module instantiation time
+ if (PyInt_CheckExact(pRet)) ret = PyInt_AsLong(pRet);
+ goto finish;
+ }
+
+ /*
+ * The function returns either:
+ * 1. (returnvalue, replyTuple, configTuple), where
+ * - returnvalue is one of the constants RLM_*
+ * - replyTuple and configTuple are tuples of string
+ * tuples of size 2
+ *
+ * 2. the function return value alone
+ *
+ * 3. None - default return value is set
+ *
+ * xxx This code is messy!
+ */
+ if (PyTuple_CheckExact(pRet)) {
+ PyObject *pTupleInt;
+ int tuple_size = PyTuple_GET_SIZE(pRet);
+
+ if (tuple_size < 2 || tuple_size > 3) {
+ ERROR("%s - Tuple must be (return, updateDict) or (return, replyTuple, configTuple)", funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ pTupleInt = PyTuple_GET_ITEM(pRet, 0);
+ if (!PyInt_CheckExact(pTupleInt)) {
+ ERROR("%s - First tuple element not an integer", funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ /* Now have the return value */
+ ret = PyInt_AsLong(pTupleInt);
+
+ /* process updateDict */
+ if (tuple_size == 2) {
+ PyObject *updateDict = PyTuple_GET_ITEM(pRet, 1);
+ if (!PyDict_CheckExact(updateDict)) {
+ ERROR("%s - updateDict is not a dictionary", funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ mod_vptuple(request->reply, request, &request->reply->vps,
+ PyDict_GetItemString(updateDict, "reply"), funcname, "reply");
+ mod_vptuple(request, request, &request->config,
+ PyDict_GetItemString(updateDict, "config"), funcname, "config");
+ mod_vptuple(request->packet, request, &request->packet->vps,
+ PyDict_GetItemString(updateDict, "request"), funcname, "request");
+ mod_vptuple(request->state_ctx, request, &request->state,
+ PyDict_GetItemString(updateDict, "session-state"), funcname, "session-state");
+#ifdef WITH_PROXY
+ if (request->proxy)
+ mod_vptuple(request->proxy, request, &request->proxy->vps,
+ PyDict_GetItemString(updateDict, "proxy-request"), funcname, "proxy-request");
+ if (request->proxy_reply)
+ mod_vptuple(request->proxy_reply, request, &request->proxy_reply->vps,
+ PyDict_GetItemString(updateDict, "proxy-reply"), funcname, "proxy-reply");
+#endif
+ /*
+ * Update cached copies
+ */
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ if (!request->password)
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ }
+
+ /* process replyTuple and configTuple */
+ else if (tuple_size == 3) {
+ /* Reply item tuple */
+ mod_vptuple(request->reply, request, &request->reply->vps,
+ PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
+ /* Config item tuple */
+ mod_vptuple(request, request, &request->config,
+ PyTuple_GET_ITEM(pRet, 2), funcname, "config");
+ }
+ } else if (PyInt_CheckExact(pRet)) {
+ /* Just an integer */
+ ret = PyInt_AsLong(pRet);
+
+ } else if (pRet == Py_None) {
+ /* returned 'None', return value defaults to "OK, continue." */
+ ret = RLM_MODULE_OK;
+ } else {
+ /* Not tuple or None */
+ ERROR("%s - Function did not return a tuple or None", funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+
+finish:
+ Py_XDECREF(pArgs);
+ Py_XDECREF(pRet);
+ Py_XDECREF(pDictInput);
+
+ return ret;
+}
+
+static void python_interpreter_free(PyThreadState *interp)
+{
+ PyEval_AcquireLock();
+ PyThreadState_Swap(interp);
+ Py_EndInterpreter(interp);
+ PyEval_ReleaseLock();
+}
+
+/** Destroy a thread state
+ *
+ * @param thread to destroy.
+ * @return 0
+ */
+static int _python_thread_free(python_thread_state_t *thread)
+{
+ PyEval_RestoreThread(thread->state); /* Swap in our local thread state */
+ PyThreadState_Clear(thread->state);
+ PyEval_SaveThread();
+
+ PyThreadState_Delete(thread->state); /* Don't need to hold lock for this */
+
+ return 0;
+}
+
+/** Callback for rbtree delete walker
+ *
+ */
+static void _python_thread_entry_free(void *arg)
+{
+ talloc_free(arg);
+}
+
+/** Cleanup any thread local storage on pthread_exit()
+ *
+ * @param arg The thread currently exiting.
+ */
+static void _python_thread_tree_free(void *arg)
+{
+ rad_assert(arg == local_thread_state);
+
+ rbtree_t *tree = talloc_get_type_abort(arg, rbtree_t);
+ rbtree_free(tree); /* Needs to be this not talloc_free to execute delete walker */
+
+ local_thread_state = NULL; /* Prevent double free in unittest env */
+}
+
+/** Compare instance pointers
+ *
+ */
+static int _python_inst_cmp(const void *a, const void *b)
+{
+ python_thread_state_t const *a_p = a, *b_p = b;
+
+ if (a_p->inst < b_p->inst) return -1;
+ if (a_p->inst > b_p->inst) return +1;
+ return 0;
+}
+
+/** Thread safe call to a python function
+ *
+ * Will swap in thread state specific to module/thread.
+ */
+static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname)
+{
+ int ret;
+ rbtree_t *thread_tree;
+ python_thread_state_t *this_thread;
+ python_thread_state_t find;
+
+ /*
+ * It's a NOOP if the function wasn't defined
+ */
+ if (!pFunc) return RLM_MODULE_NOOP;
+
+ /*
+ * Check to see if we've got a thread state tree
+ * If not, create one.
+ */
+ thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
+ if (!thread_tree) {
+ thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
+ if (!thread_tree) {
+ RERROR("Failed allocating thread state tree");
+ return RLM_MODULE_FAIL;
+ }
+
+ ret = fr_thread_local_set(local_thread_state, thread_tree);
+ if (ret != 0) {
+ talloc_free(thread_tree);
+ return RLM_MODULE_FAIL;
+ }
+ }
+
+ find.inst = inst;
+ /*
+ * Find the thread state associated with this instance
+ * and this thread, or create a new thread state.
+ */
+ this_thread = rbtree_finddata(thread_tree, &find);
+ if (!this_thread) {
+ PyThreadState *state;
+
+ state = PyThreadState_New(inst->sub_interpreter->interp);
+
+ RDEBUG3("Initialised new thread state %p", state);
+ if (!state) {
+ REDEBUG("Failed initialising local PyThreadState on first run");
+ return RLM_MODULE_FAIL;
+ }
+
+ this_thread = talloc(NULL, python_thread_state_t);
+ this_thread->inst = inst;
+ this_thread->state = state;
+ talloc_set_destructor(this_thread, _python_thread_free);
+
+ if (!rbtree_insert(thread_tree, this_thread)) {
+ RERROR("Failed inserting thread state into TLS tree");
+ talloc_free(this_thread);
+
+ return RLM_MODULE_FAIL;
+ }
+ }
+ RDEBUG3("Using thread state %p", this_thread->state);
+
+ PyEval_RestoreThread(this_thread->state); /* Swap in our local thread state */
+ ret = do_python_single(request, pFunc, funcname, inst->pass_all_vps, inst->pass_all_vps_dict);
+ if (ret == RLM_MODULE_FAIL) python_error_log();
+ PyEval_SaveThread();
+
+ return ret;
+}
+
+#define MOD_FUNC(x) \
+static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
+ return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x);\
+}
+
+MOD_FUNC(authenticate)
+MOD_FUNC(authorize)
+MOD_FUNC(preacct)
+MOD_FUNC(accounting)
+MOD_FUNC(checksimul)
+MOD_FUNC(pre_proxy)
+MOD_FUNC(post_proxy)
+MOD_FUNC(post_auth)
+#ifdef WITH_COA
+MOD_FUNC(recv_coa)
+MOD_FUNC(send_coa)
+#endif
+static void python_obj_destroy(PyObject **ob)
+{
+ if (*ob != NULL) {
+ Py_DECREF(*ob);
+ *ob = NULL;
+ }
+}
+
+static void python_function_destroy(python_func_def_t *def)
+{
+ python_obj_destroy(&def->function);
+ python_obj_destroy(&def->module);
+}
+
+/** Import a user module and load a function from it
+ *
+ */
+static int python_function_load(char const *name, python_func_def_t *def)
+{
+ if (!def->module_name && !def->function_name) return 0; /* Just not set, it's fine */
+
+ if (!def->module_name) {
+ ERROR("Once you have set the 'func_%s = %s', you should set 'mod_%s = ...' too.",
+ name, def->function_name, name);
+ return -1;
+ }
+
+ if (!def->function_name) {
+ ERROR("Once you have set the 'mod_%s = %s', you should set 'func_%s = ...' too.",
+ name, def->module_name, name);
+ return -1;
+ }
+
+ def->module = PyImport_ImportModule(def->module_name);
+ if (!def->module) {
+ ERROR("%s - Module '%s' not found", __func__, def->module_name);
+
+ error:
+ python_error_log();
+ ERROR("%s - Failed to import python function '%s.%s'",
+ __func__, def->module_name, def->function_name);
+ Py_XDECREF(def->function);
+ def->function = NULL;
+ Py_XDECREF(def->module);
+ def->module = NULL;
+
+ return -1;
+ }
+
+ def->function = PyObject_GetAttrString(def->module, def->function_name);
+ if (!def->function) {
+ ERROR("%s - Function '%s.%s' is not found", __func__, def->module_name, def->function_name);
+ goto error;
+ }
+
+ if (!PyCallable_Check(def->function)) {
+ ERROR("%s - Function '%s.%s' is not callable", __func__, def->module_name, def->function_name);
+ goto error;
+ }
+
+ return 0;
+}
+
+/*
+ * Parse a configuration section, and populate a dict.
+ * This function is recursively called (allows to have nested dicts.)
+ */
+static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
+{
+ int indent_section = (lvl + 1) * 4;
+ int indent_item = (lvl + 2) * 4;
+ CONF_ITEM *ci = NULL;
+
+ if (!cs || !dict) return;
+
+ DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
+
+ while ((ci = cf_item_find_next(cs, ci))) {
+ /*
+ * This is a section.
+ * Create a new dict, store it in current dict,
+ * Then recursively call python_parse_config with this section and the new dict.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *sub_cs = cf_item_to_section(ci);
+ char const *key = cf_section_name1(sub_cs); /* dict key */
+ PyObject *sub_dict, *pKey;
+
+ if (!key) continue;
+
+ pKey = PyString_FromString(key);
+ if (!pKey) continue;
+
+ if (PyDict_Contains(dict, pKey)) {
+ WARN("rlm_python: Ignoring duplicate config section '%s'", key);
+ continue;
+ }
+
+ if (!(sub_dict = PyDict_New())) {
+ WARN("rlm_python: Unable to create subdict for config section '%s'", key);
+ }
+
+ (void)PyDict_SetItem(dict, pKey, sub_dict);
+
+ python_parse_config(sub_cs, lvl + 1, sub_dict);
+ } else if (cf_item_is_pair(ci)) {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+ char const *key = cf_pair_attr(cp); /* dict key */
+ char const *value = cf_pair_value(cp); /* dict value */
+ PyObject *pKey, *pValue;
+
+ if (!key || !value) continue;
+
+ pKey = PyString_FromString(key);
+ pValue = PyString_FromString(value);
+ if (!pKey || !pValue) continue;
+
+ /*
+ * This is an item.
+ * Store item attr / value in current dict.
+ */
+ if (PyDict_Contains(dict, pKey)) {
+ WARN("rlm_python: Ignoring duplicate config item '%s'", key);
+ continue;
+ }
+
+ (void)PyDict_SetItem(dict, pKey, pValue);
+
+ DEBUG("%*s%s = %s", indent_item, " ", key, value);
+ }
+ }
+
+ DEBUG("%*s}", indent_section, " ");
+}
+
+#ifdef HAVE_DL_ITERATE_PHDR
+static int dlopen_libpython_cb(struct dl_phdr_info *info,
+ UNUSED size_t size, void *data)
+{
+ const char *pattern = "/" LIBPYTHON_LINKER_NAME;
+ char **ppath = (char **)data;
+
+ if (strstr(info->dlpi_name, pattern) != NULL) {
+ if (*ppath != NULL) {
+ talloc_free(*ppath);
+ *ppath = NULL;
+ return EEXIST;
+ } else {
+ *ppath = talloc_strdup(NULL, info->dlpi_name);
+ if (*ppath == NULL) {
+ return errno;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Dlopen the already linked libpython */
+static void *dlopen_libpython(int flags)
+{
+ char *path = NULL;
+ int rc;
+ void *handle;
+
+ /* Find the linked libpython path */
+ rc = dl_iterate_phdr(dlopen_libpython_cb, &path);
+ if (rc != 0) {
+ WARN("Failed searching for libpython "
+ "among linked libraries: %s", strerror(rc));
+ return NULL;
+ } else if (path == NULL) {
+ WARN("Libpython is not found among linked libraries");
+ return NULL;
+ }
+
+ /* Dlopen the found library */
+ handle = dlopen(path, flags);
+ if (handle == NULL) {
+ WARN("Failed loading %s: %s", path, dlerror());
+ }
+ talloc_free(path);
+ return handle;
+}
+#else /* ! HAVE_DL_ITERATE_PHDR */
+/* Dlopen libpython by its linker name (bare soname) */
+static void *dlopen_libpython(int flags)
+{
+ const char *name = LIBPYTHON_LINKER_NAME;
+ void *handle;
+ handle = dlopen(name, flags);
+ if (handle == NULL) {
+ WARN("Failed loading %s: %s", name, dlerror());
+ }
+ return handle;
+}
+#endif /* ! HAVE_DL_ITERATE_PHDR */
+
+/** Initialises a separate python interpreter for this module instance
+ *
+ */
+static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
+{
+ int i;
+
+ /*
+ * Explicitly load libpython, so symbols will be available to lib-dynload modules
+ */
+ if (python_instances == 0) {
+ INFO("Python version: %s", Py_GetVersion());
+
+ python_dlhandle = dlopen_libpython(RTLD_NOW | RTLD_GLOBAL);
+ if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table");
+
+#if PY_VERSION_HEX > 0x03050000
+ {
+ inst->wide_name = Py_DecodeLocale(main_config.name, strlen(main_config.name));
+ Py_SetProgramName(inst->wide_name); /* The value of argv[0] as a wide char string */
+ }
+#else
+ {
+ char *name;
+
+ memcpy(&name, &main_config.name, sizeof(name));
+ Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
+ }
+#endif
+
+ Py_InitializeEx(0); /* Don't override signal handlers - noop on subs calls */
+ PyEval_InitThreads(); /* This also grabs a lock (which we then need to release) */
+ main_interpreter = PyThreadState_Get(); /* Store reference to the main interpreter */
+ }
+ rad_assert(PyEval_ThreadsInitialized());
+
+ /*
+ * Increment the reference counter
+ */
+ python_instances++;
+
+ /*
+ * This sets up a separate environment for each python module instance
+ * These will be destroyed on Py_Finalize().
+ */
+ if (!inst->cext_compat) {
+ inst->sub_interpreter = Py_NewInterpreter();
+ } else {
+ inst->sub_interpreter = main_interpreter;
+ }
+
+ PyThreadState_Swap(inst->sub_interpreter);
+
+ /*
+ * Due to limitations in Python, sub-interpreters don't work well
+ * with Python C extensions if they use GIL lock functions.
+ */
+ if (!inst->cext_compat || !main_module) {
+ CONF_SECTION *cs;
+
+ /*
+ * Set the python search path
+ *
+ * The path buffer does not appear to be dup'd
+ * so its lifetime should really be bound to
+ * the lifetime of the module.
+ */
+ if (inst->python_path) {
+ char *p, *path;
+ PyObject *sys = PyImport_ImportModule("sys");
+ PyObject *sys_path = PyObject_GetAttrString(sys, "path");
+
+ memcpy(&p, &inst->python_path, sizeof(path));
+
+ for (path = strtok(p, ":"); path != NULL; path = strtok(NULL, ":")) {
+ PyList_Append(sys_path, PyString_FromString(path));
+ }
+
+ PyObject_SetAttrString(sys, "path", sys_path);
+ Py_DecRef(sys);
+ Py_DecRef(sys_path);
+ }
+
+ /*
+ * Initialise a new module, with our default methods
+ */
+ inst->module = Py_InitModule3("radiusd", module_methods, "FreeRADIUS python module");
+ if (!inst->module) {
+ error:
+ python_error_log();
+ PyEval_SaveThread();
+ return -1;
+ }
+
+ /*
+ * Py_InitModule3 returns a borrowed ref, the actual
+ * module is owned by sys.modules, so we also need
+ * to own the module to prevent it being freed early.
+ */
+ Py_IncRef(inst->module);
+
+ if (inst->cext_compat) main_module = inst->module;
+
+ for (i = 0; radiusd_constants[i].name; i++) {
+ if ((PyModule_AddIntConstant(inst->module, radiusd_constants[i].name,
+ radiusd_constants[i].value)) < 0)
+ goto error;
+ }
+
+ /*
+ * Convert a FreeRADIUS config structure into a python
+ * dictionary.
+ */
+ inst->pythonconf_dict = PyDict_New();
+ if (!inst->pythonconf_dict) {
+ ERROR("Unable to create python dict for config");
+ python_error_log();
+ return -1;
+ }
+
+ /*
+ * Add module configuration as a dict
+ */
+ if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0) goto error;
+
+ cs = cf_section_sub_find(conf, "config");
+ if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
+ } else {
+ inst->module = main_module;
+ Py_IncRef(inst->module);
+ inst->pythonconf_dict = PyObject_GetAttrString(inst->module, "config");
+ Py_IncRef(inst->pythonconf_dict);
+ }
+
+ PyEval_SaveThread();
+
+ return 0;
+}
+
+/*
+ * 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_python_t *inst = instance;
+ int code = 0;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+ /*
+ * Load the python code required for this module instance
+ */
+ if (python_interpreter_init(inst, conf) < 0) return -1;
+
+ /*
+ * Switch to our module specific main thread
+ */
+ PyEval_RestoreThread(inst->sub_interpreter);
+
+ /*
+ * Process the various sections
+ */
+#define PYTHON_FUNC_LOAD(_x) if (python_function_load(#_x, &inst->_x) < 0) goto error
+ PYTHON_FUNC_LOAD(instantiate);
+ PYTHON_FUNC_LOAD(authenticate);
+ PYTHON_FUNC_LOAD(authorize);
+ PYTHON_FUNC_LOAD(preacct);
+ PYTHON_FUNC_LOAD(accounting);
+ PYTHON_FUNC_LOAD(checksimul);
+ PYTHON_FUNC_LOAD(pre_proxy);
+ PYTHON_FUNC_LOAD(post_proxy);
+ PYTHON_FUNC_LOAD(post_auth);
+#ifdef WITH_COA
+ PYTHON_FUNC_LOAD(recv_coa);
+ PYTHON_FUNC_LOAD(send_coa);
+#endif
+ PYTHON_FUNC_LOAD(detach);
+
+ /*
+ * Call the instantiate function only if the function and module is set.
+ */
+ if (inst->instantiate.module_name && inst->instantiate.function_name) {
+ code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict);
+ if (code == RLM_MODULE_FAIL) {
+ error:
+ python_error_log(); /* Needs valid thread with GIL */
+ PyEval_SaveThread();
+ return -1;
+ }
+ }
+ PyEval_SaveThread();
+
+ return 0;
+}
+
+static int mod_detach(void *instance)
+{
+ rlm_python_t *inst = instance;
+ int ret;
+
+ /*
+ * Call module destructor
+ */
+ PyEval_RestoreThread(inst->sub_interpreter);
+
+ ret = do_python_single(NULL, inst->detach.function, "detach", inst->pass_all_vps, inst->pass_all_vps_dict);
+ if (ret == RLM_MODULE_FAIL) python_error_log();
+
+#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
+ PYTHON_FUNC_DESTROY(instantiate);
+ PYTHON_FUNC_DESTROY(authorize);
+ PYTHON_FUNC_DESTROY(authenticate);
+ PYTHON_FUNC_DESTROY(preacct);
+ PYTHON_FUNC_DESTROY(accounting);
+ PYTHON_FUNC_DESTROY(checksimul);
+ PYTHON_FUNC_DESTROY(detach);
+
+ Py_DecRef(inst->pythonconf_dict);
+ Py_DecRef(inst->module);
+
+ PyEval_SaveThread();
+
+ /*
+ * Force cleaning up of threads if this is *NOT* a worker
+ * thread, which happens if this is being called from
+ * unittest framework, and probably with the server running
+ * in debug mode.
+ */
+ rbtree_free(local_thread_state);
+ local_thread_state = NULL;
+
+ /*
+ * Only destroy if it's a subinterpreter
+ */
+ if (!inst->cext_compat) python_interpreter_free(inst->sub_interpreter);
+
+ if ((--python_instances) == 0) {
+ PyThreadState_Swap(main_interpreter); /* Swap to the main thread */
+ Py_Finalize();
+ dlclose(python_dlhandle);
+
+#if PY_VERSION_HEX > 0x03050000
+ if (inst->wide_name) PyMem_RawFree(inst->wide_name);
+#endif
+ }
+
+
+ return ret;
+}
+
+/*
+ * 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_python;
+module_t rlm_python = {
+ .magic = RLM_MODULE_INIT,
+ .name = "python",
+ .type = RLM_TYPE_THREAD_UNSAFE,
+ .inst_size = sizeof(rlm_python_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_SESSION] = mod_checksimul,
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ }
+};
diff --git a/src/modules/rlm_python3/.gitignore b/src/modules/rlm_python3/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_python3/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_python3/README.md b/src/modules/rlm_python3/README.md
new file mode 100644
index 0000000..d855cdf
--- /dev/null
+++ b/src/modules/rlm_python3/README.md
@@ -0,0 +1,12 @@
+# rlm_python3
+## Metadata
+<dl>
+ <dt>category</dt><dd>languages</dd>
+</dl>
+
+## Summary
+
+Allows the server to call a persistent, embedded Python v3 script.
+
+When there are policies that cannot be implemented in unlang, it
+is usually possible to use rlm_perl or rlm_python3 instead.
diff --git a/src/modules/rlm_python3/all.mk.in b/src/modules/rlm_python3/all.mk.in
new file mode 100644
index 0000000..1c835c4
--- /dev/null
+++ b/src/modules/rlm_python3/all.mk.in
@@ -0,0 +1,26 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TARGETNAME)" ""
+install: $(R)$(modconfdir)/python3/radiusd.py $(R)$(modconfdir)/python3/example.py
+
+$(R)$(modconfdir)/python3: | $(R)$(modconfdir)
+ @echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
+ @$(INSTALL) -d -m 750 $@
+
+$(R)$(modconfdir)/python3/radiusd.py: src/modules/rlm_python3/radiusd.py | $(R)$(modconfdir)/python3
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/python3
+
+$(R)$(modconfdir)/python3/example.py: src/modules/rlm_python3/example.py | $(R)$(modconfdir)/python3
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/python3
+endif
diff --git a/src/modules/rlm_python3/config.h.in b/src/modules/rlm_python3/config.h.in
new file mode 100644
index 0000000..531c9a0
--- /dev/null
+++ b/src/modules/rlm_python3/config.h.in
@@ -0,0 +1,4 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `dl_iterate_phdr' function. */
+#undef HAVE_DL_ITERATE_PHDR
diff --git a/src/modules/rlm_python3/configure b/src/modules/rlm_python3/configure
new file mode 100755
index 0000000..0effe07
--- /dev/null
+++ b/src/modules/rlm_python3/configure
@@ -0,0 +1,4802 @@
+#! /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_python3.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+AWK
+PYTHON3_CONFIG_BIN
+pkgpyexecdir
+pyexecdir
+pkgpythondir
+pythondir
+PYTHON_EXEC_PREFIX
+PYTHON_PREFIX
+PYTHON_PLATFORM
+PYTHON_VERSION
+PYTHON
+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_python3
+with_python_sys_prefix
+with_python_prefix
+with_python_exec_prefix
+with_rlm_python3_config_bin
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+PYTHON'
+
+
+# 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_python3 build without support for embedded Python3
+ --with-python-sys-prefix
+ use Python's sys.prefix and sys.exec_prefix values
+ --with-python_prefix override the default PYTHON_PREFIX
+ --with-python_exec_prefix
+ override the default PYTHON_EXEC_PREFIX
+ --with-rlm-python3-config-bin=PATH
+ Path to python-config3 binary
+
+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
+ PYTHON the Python interpreter
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_python3
+echo
+
+
+# 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_python3 was given.
+if test "${with_rlm_python3+set}" = set; then :
+ withval=$with_rlm_python3;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_python3" != 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
+
+
+
+
+
+
+
+ if test -n "$PYTHON"; then
+ # If the user set $PYTHON, use it and don't search something else.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 3.0" >&5
+$as_echo_n "checking whether $PYTHON version is >= 3.0... " >&6; }
+ prog="import sys
+# split strings by '.' and convert to numeric. Append some zeros
+# because we need at least 4 digits for the hex conversion.
+# map returns an iterator in Python 3.0 and a list in 2.x
+minver = list(map(int, '3.0'.split('.'))) + [0, 0, 0]
+minverhex = 0
+# xrange is not present in Python 3.0 and range returns an iterator
+for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
+sys.exit(sys.hexversion < minverhex)"
+ if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5
+ ($PYTHON -c "$prog") >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Python interpreter is too old" "$LINENO" 5
+fi
+ am_display_PYTHON=$PYTHON
+ else
+ # Otherwise, try each interpreter until we find one that satisfies
+ # VERSION.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 3.0" >&5
+$as_echo_n "checking for a Python interpreter with version >= 3.0... " >&6; }
+if ${am_cv_pathless_PYTHON+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ for am_cv_pathless_PYTHON in python python2 python3 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
+ test "$am_cv_pathless_PYTHON" = none && break
+ prog="import sys
+# split strings by '.' and convert to numeric. Append some zeros
+# because we need at least 4 digits for the hex conversion.
+# map returns an iterator in Python 3.0 and a list in 2.x
+minver = list(map(int, '3.0'.split('.'))) + [0, 0, 0]
+minverhex = 0
+# xrange is not present in Python 3.0 and range returns an iterator
+for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i]
+sys.exit(sys.hexversion < minverhex)"
+ if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5
+ ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then :
+ break
+fi
+ done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5
+$as_echo "$am_cv_pathless_PYTHON" >&6; }
+ # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON.
+ if test "$am_cv_pathless_PYTHON" = none; then
+ PYTHON=:
+ else
+ # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args.
+set dummy $am_cv_pathless_PYTHON; 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_PYTHON+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PYTHON in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PYTHON="$PYTHON" # 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_PYTHON="$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
+PYTHON=$ac_cv_path_PYTHON
+if test -n "$PYTHON"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5
+$as_echo "$PYTHON" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+ am_display_PYTHON=$am_cv_pathless_PYTHON
+ fi
+
+
+ if test "$PYTHON" = :; then
+ :
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5
+$as_echo_n "checking for $am_display_PYTHON version... " >&6; }
+if ${am_cv_python_version+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_python_version=`$PYTHON -c "import sys; print ('%u.%u' % sys.version_info[:2])"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5
+$as_echo "$am_cv_python_version" >&6; }
+ PYTHON_VERSION=$am_cv_python_version
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5
+$as_echo_n "checking for $am_display_PYTHON platform... " >&6; }
+if ${am_cv_python_platform+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5
+$as_echo "$am_cv_python_platform" >&6; }
+ PYTHON_PLATFORM=$am_cv_python_platform
+
+
+ if test "x$prefix" = xNONE; then
+ am__usable_prefix=$ac_default_prefix
+ else
+ am__usable_prefix=$prefix
+ fi
+
+ # Allow user to request using sys.* values from Python,
+ # instead of the GNU $prefix values.
+
+# Check whether --with-python-sys-prefix was given.
+if test "${with_python_sys_prefix+set}" = set; then :
+ withval=$with_python_sys_prefix; am_use_python_sys=:
+else
+ am_use_python_sys=false
+fi
+
+
+ # Allow user to override whatever the default Python prefix is.
+
+# Check whether --with-python_prefix was given.
+if test "${with_python_prefix+set}" = set; then :
+ withval=$with_python_prefix; am_python_prefix_subst=$withval
+ am_cv_python_prefix=$withval
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for explicit $am_display_PYTHON prefix" >&5
+$as_echo_n "checking for explicit $am_display_PYTHON prefix... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_prefix" >&5
+$as_echo "$am_cv_python_prefix" >&6; }
+else
+
+ if $am_use_python_sys; then
+ # using python sys.prefix value, not GNU
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python default $am_display_PYTHON prefix" >&5
+$as_echo_n "checking for python default $am_display_PYTHON prefix... " >&6; }
+if ${am_cv_python_prefix+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_python_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_prefix" >&5
+$as_echo "$am_cv_python_prefix" >&6; }
+
+ case $am_cv_python_prefix in
+ $am__usable_prefix*)
+ am__strip_prefix=`echo "$am__usable_prefix" | sed 's|.|.|g'`
+ am_python_prefix_subst=`echo "$am_cv_python_prefix" | sed "s,^$am__strip_prefix,\\${prefix},"`
+ ;;
+ *)
+ am_python_prefix_subst=$am_cv_python_prefix
+ ;;
+ esac
+ else # using GNU prefix value, not python sys.prefix
+ am_python_prefix_subst='${prefix}'
+ am_python_prefix=$am_python_prefix_subst
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU default $am_display_PYTHON prefix" >&5
+$as_echo_n "checking for GNU default $am_display_PYTHON prefix... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_python_prefix" >&5
+$as_echo "$am_python_prefix" >&6; }
+ fi
+fi
+
+ # Substituting python_prefix_subst value.
+ PYTHON_PREFIX=$am_python_prefix_subst
+
+
+ # emacs-page Now do it all over again for Python exec_prefix, but with yet
+ # another conditional: fall back to regular prefix if that was specified.
+
+# Check whether --with-python_exec_prefix was given.
+if test "${with_python_exec_prefix+set}" = set; then :
+ withval=$with_python_exec_prefix; am_python_exec_prefix_subst=$withval
+ am_cv_python_exec_prefix=$withval
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for explicit $am_display_PYTHON exec_prefix" >&5
+$as_echo_n "checking for explicit $am_display_PYTHON exec_prefix... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5
+$as_echo "$am_cv_python_exec_prefix" >&6; }
+else
+
+ # no explicit --with-python_exec_prefix, but if
+ # --with-python_prefix was given, use its value for python_exec_prefix too.
+ if test -n "$with_python_prefix"; then :
+ am_python_exec_prefix_subst=$with_python_prefix
+ am_cv_python_exec_prefix=$with_python_prefix
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python_prefix-given $am_display_PYTHON exec_prefix" >&5
+$as_echo_n "checking for python_prefix-given $am_display_PYTHON exec_prefix... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5
+$as_echo "$am_cv_python_exec_prefix" >&6; }
+else
+
+ # Set am__usable_exec_prefix whether using GNU or Python values,
+ # since we use that variable for pyexecdir.
+ if test "x$exec_prefix" = xNONE; then
+ am__usable_exec_prefix=$am__usable_prefix
+ else
+ am__usable_exec_prefix=$exec_prefix
+ fi
+ #
+ if $am_use_python_sys; then # using python sys.exec_prefix, not GNU
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python default $am_display_PYTHON exec_prefix" >&5
+$as_echo_n "checking for python default $am_display_PYTHON exec_prefix... " >&6; }
+if ${am_cv_python_exec_prefix+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_python_exec_prefix=`$PYTHON -c "import sys; sys.stdout.write(sys.exec_prefix)"`
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_exec_prefix" >&5
+$as_echo "$am_cv_python_exec_prefix" >&6; }
+ case $am_cv_python_exec_prefix in
+ $am__usable_exec_prefix*)
+ am__strip_prefix=`echo "$am__usable_exec_prefix" | sed 's|.|.|g'`
+ am_python_exec_prefix_subst=`echo "$am_cv_python_exec_prefix" | sed "s,^$am__strip_prefix,\\${exec_prefix},"`
+ ;;
+ *)
+ am_python_exec_prefix_subst=$am_cv_python_exec_prefix
+ ;;
+ esac
+ else # using GNU $exec_prefix, not python sys.exec_prefix
+ am_python_exec_prefix_subst='${exec_prefix}'
+ am_python_exec_prefix=$am_python_exec_prefix_subst
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU default $am_display_PYTHON exec_prefix" >&5
+$as_echo_n "checking for GNU default $am_display_PYTHON exec_prefix... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_python_exec_prefix" >&5
+$as_echo "$am_python_exec_prefix" >&6; }
+ fi
+fi
+fi
+
+ # Substituting python_exec_prefix_subst.
+ PYTHON_EXEC_PREFIX=$am_python_exec_prefix_subst
+
+
+ # Factor out some code duplication into this shell variable.
+ am_python_setup_sysconfig="\
+import sys
+# Prefer sysconfig over distutils.sysconfig, for better compatibility
+# with python 3.x. See automake bug#10227.
+try:
+ import sysconfig
+except ImportError:
+ can_use_sysconfig = 0
+else:
+ can_use_sysconfig = 1
+# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
+# <https://github.com/pypa/virtualenv/issues/118>
+try:
+ from platform import python_implementation
+ if python_implementation() == 'CPython' and sys.version[:3] == '2.7':
+ can_use_sysconfig = 0
+except ImportError:
+ pass"
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory (pythondir)" >&5
+$as_echo_n "checking for $am_display_PYTHON script directory (pythondir)... " >&6; }
+if ${am_cv_python_pythondir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$am_cv_python_prefix" = x; then
+ am_py_prefix=$am__usable_prefix
+ else
+ am_py_prefix=$am_cv_python_prefix
+ fi
+ am_cv_python_pythondir=`$PYTHON -c "
+$am_python_setup_sysconfig
+if can_use_sysconfig:
+ if hasattr(sysconfig, 'get_default_scheme'):
+ scheme = sysconfig.get_default_scheme()
+ else:
+ scheme = sysconfig._get_default_scheme()
+ if scheme == 'posix_local':
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
+ scheme = 'posix_prefix'
+ sitedir = sysconfig.get_path('purelib', scheme, vars={'base':'$am_py_prefix'})
+else:
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
+sys.stdout.write(sitedir)"`
+ #
+ case $am_cv_python_pythondir in
+ $am_py_prefix*)
+ am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
+ am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,\\${PYTHON_PREFIX},"`
+ ;;
+ *)
+ case $am_py_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pythondir="\${PYTHON_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
+ esac
+ ;;
+ esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5
+$as_echo "$am_cv_python_pythondir" >&6; }
+ pythondir=$am_cv_python_pythondir
+
+
+ pkgpythondir=\${pythondir}/$PACKAGE
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory (pyexecdir)" >&5
+$as_echo_n "checking for $am_display_PYTHON extension module directory (pyexecdir)... " >&6; }
+if ${am_cv_python_pyexecdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$am_cv_python_exec_prefix" = x; then
+ am_py_exec_prefix=$am__usable_exec_prefix
+ else
+ am_py_exec_prefix=$am_cv_python_exec_prefix
+ fi
+ am_cv_python_pyexecdir=`$PYTHON -c "
+$am_python_setup_sysconfig
+if can_use_sysconfig:
+ if hasattr(sysconfig, 'get_default_scheme'):
+ scheme = sysconfig.get_default_scheme()
+ else:
+ scheme = sysconfig._get_default_scheme()
+ if scheme == 'posix_local':
+ # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/
+ scheme = 'posix_prefix'
+ sitedir = sysconfig.get_path('platlib', scheme, vars={'platbase':'$am_py_exec_prefix'})
+else:
+ from distutils import sysconfig
+ sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_exec_prefix')
+sys.stdout.write(sitedir)"`
+ #
+ case $am_cv_python_pyexecdir in
+ $am_py_exec_prefix*)
+ am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
+ am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,\\${PYTHON_EXEC_PREFIX},"`
+ ;;
+ *)
+ case $am_py_exec_prefix in
+ /usr|/System*) ;;
+ *) am_cv_python_pyexecdir="\${PYTHON_EXEC_PREFIX}/lib/python$PYTHON_VERSION/site-packages"
+ ;;
+ esac
+ ;;
+ esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5
+$as_echo "$am_cv_python_pyexecdir" >&6; }
+ pyexecdir=$am_cv_python_pyexecdir
+
+
+ pkgpyexecdir=\${pyexecdir}/$PACKAGE
+
+
+
+ fi
+
+
+PYTHON3_CONFIG_BIN=
+
+# Check whether --with-rlm-python3-config-bin was given.
+if test "${with_rlm_python3_config_bin+set}" = set; then :
+ withval=$with_rlm_python3_config_bin; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-python3-config-bin" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ PYTHON3_CONFIG_BIN="$withval"
+ ;;
+ esac
+fi
+
+
+if test "x$PYTHON3_CONFIG_BIN" = x; then
+ for ac_prog in python3-config
+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_PYTHON3_CONFIG_BIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PYTHON3_CONFIG_BIN"; then
+ ac_cv_prog_PYTHON3_CONFIG_BIN="$PYTHON3_CONFIG_BIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_PYTHON3_CONFIG_BIN="$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
+PYTHON3_CONFIG_BIN=$ac_cv_prog_PYTHON3_CONFIG_BIN
+if test -n "$PYTHON3_CONFIG_BIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON3_CONFIG_BIN" >&5
+$as_echo "$PYTHON3_CONFIG_BIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PYTHON3_CONFIG_BIN" && break
+done
+test -n "$PYTHON3_CONFIG_BIN" || PYTHON3_CONFIG_BIN="not-found"
+
+fi
+
+if test "x$PYTHON3_CONFIG_BIN" = xnot-found; then
+
+fail="$fail python3-config"
+
+else
+ old_CFLAGS="$CFLAGS"
+ unset CFLAGS
+
+ python3_cflags=`${PYTHON3_CONFIG_BIN} --cflags`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ${PYTHON3_CONFIG_BIN}'s cflags were \"${python3_cflags}\"" >&5
+$as_echo "$as_me: ${PYTHON3_CONFIG_BIN}'s cflags were \"${python3_cflags}\"" >&6;}
+
+ mod_cflags=`echo " $python3_cflags" | sed -e '\
+ s/ -I/ -isystem/g;\
+ s/ -isysroot[ =]\{0,1\}[^-]*/ /g;\
+ s/ -O[^[[:blank:]]]*/ /g;\
+ s/ -Wp,-D_FORTIFY_SOURCE=[[:digit:]]/ /g;\
+ s/ -g[^ ]*/ /g;\
+ s/ -W[^ ]*/ /g;\
+ s/ -DNDEBUG[[:blank:]]*/ /g;\
+ s/ -frecord-gcc-switches/ /g;\
+ s/ -specs=[^ ]*/ /g; \
+ s/ -ffat-lto-objects/ /g; \
+ s/ -flto=[^ ]*/ /g;
+ '`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized cflags were \"${mod_cflags}\"" >&5
+$as_echo "$as_me: Sanitized cflags were \"${mod_cflags}\"" >&6;}
+
+ 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
+
+
+
+
+ # Used to indicate true or false condition
+ ax_compare_version=false
+
+ # Convert the two version strings to be compared into a format that
+ # allows a simple string comparison. The end result is that a version
+ # string of the form 1.12.5-r617 will be converted to the form
+ # 0001001200050617. In other words, each number is zero padded to four
+ # digits, and non digits are removed.
+
+ ax_compare_version_A=`echo "${PYTHON_VERSION}" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
+
+
+ ax_compare_version_B=`echo "3.8" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
+
+
+ ax_compare_version=`echo "x$ax_compare_version_A
+x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"`
+
+
+
+ if test "$ax_compare_version" = "true" ; then
+ EMBED="--embed"
+ fi
+
+
+ python3_ldflags=`${PYTHON3_CONFIG_BIN} --ldflags $EMBED`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ${PYTHON3_CONFIG_BIN}'s ldflags were \"$python3_ldflags}\"" >&5
+$as_echo "$as_me: ${PYTHON3_CONFIG_BIN}'s ldflags were \"$python3_ldflags}\"" >&6;}
+
+ mod_ldflags=`echo $python3_ldflags | sed -e '\
+ s/-Wl,-O[[:digit:]][[:blank:]]*//g;\
+ s/-Wl,-Bsymbolic-functions[[:blank:]]*//g;\
+ s/-Xlinker -export-dynamic//g;\
+ s/-Wl,-stack_size,[[:digit:]]*[[:blank:]]//g;
+ '`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized ldflags were \"${mod_ldflags}\"" >&5
+$as_echo "$as_me: Sanitized ldflags were \"${mod_ldflags}\"" >&6;}
+
+ CFLAGS=$old_CFLAGS
+fi
+
+for ac_func in dl_iterate_phdr
+do :
+ ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr"
+if test "x$ac_cv_func_dl_iterate_phdr" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DL_ITERATE_PHDR 1
+_ACEOF
+
+fi
+done
+
+
+
+ targetname=rlm_python3
+else
+ targetname=
+ echo \*\*\* module rlm_python3 is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_python3 to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_python3." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_python3." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_python3 requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_python3 requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+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_python3/configure.ac b/src/modules/rlm_python3/configure.ac
new file mode 100644
index 0000000..33050ce
--- /dev/null
+++ b/src/modules/rlm_python3/configure.ac
@@ -0,0 +1,101 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_python3.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_python3], [support for embedded Python3])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+AM_PATH_PYTHON([3.0],, [:])
+
+dnl extra argument: --with-rlm-python3-config-bin
+PYTHON3_CONFIG_BIN=
+AC_ARG_WITH(rlm-python3-config-bin,
+ [AS_HELP_STRING([--with-rlm-python3-config-bin=PATH],
+ [Path to python-config3 binary])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-python3-config-bin)
+ ;;
+ yes)
+ ;;
+ *)
+ PYTHON3_CONFIG_BIN="$withval"
+ ;;
+ esac])
+
+if test "x$PYTHON3_CONFIG_BIN" = x; then
+ AC_CHECK_PROGS(PYTHON3_CONFIG_BIN, [ python3-config ], not-found, [${PATH}:/usr/bin:/usr/local/bin])
+fi
+
+if test "x$PYTHON3_CONFIG_BIN" = xnot-found; then
+ FR_MODULE_FAIL([python3-config])
+else
+ dnl #
+ dnl # It is necessary due to a weird behavior with 'python3-config'
+ dnl #
+ old_CFLAGS="$CFLAGS"
+ unset CFLAGS
+
+ python3_cflags=`${PYTHON3_CONFIG_BIN} --cflags`
+ AC_MSG_NOTICE([${PYTHON3_CONFIG_BIN}'s cflags were \"${python3_cflags}\"])
+
+ dnl # Convert -I to -isystem to get rid of warnings about issues in Python headers
+ dnl # Strip -systemroot
+ dnl # Strip optimisation flags (-O[0-9]?). We decide our optimisation level, not python.
+ dnl # -D_FORTIFY_SOURCE needs -O.
+ dnl # Strip debug symbol flags (-g[0-9]?). We decide on debugging symbols, not python
+ dnl # Strip -W*, we decide what warnings are important
+ dnl # Strip -DNDEBUG
+ dnl # Strip -frecord-gcc-switches, We decide if we need that, not python.
+ dnl # Strip -specs=/path/whatever.specs, We don't need the compiler .specs that comes from Python
+ dnl # Strip -ffat-lto-objects, We decide if we need that, not python.
+ dnl # Strip -flto=auto, We decide if we need that, not python.
+ mod_cflags=`echo " $python3_cflags" | sed -e '\
+ s/ -I/ -isystem/g;\
+ s/ -isysroot[[ =]]\{0,1\}[[^-]]*/ /g;\
+ s/ -O[[^[[:blank:]]]]*/ /g;\
+ s/ -Wp,-D_FORTIFY_SOURCE=[[[:digit:]]]/ /g;\
+ s/ -g[[^ ]]*/ /g;\
+ s/ -W[[^ ]]*/ /g;\
+ s/ -DNDEBUG[[[:blank:]]]*/ /g;\
+ s/ -frecord-gcc-switches/ /g;\
+ s/ -specs=[[^ ]]*/ /g; \
+ s/ -ffat-lto-objects/ /g; \
+ s/ -flto=[[^ ]]*/ /g;
+ '`
+ AC_MSG_NOTICE([Sanitized cflags were \"${mod_cflags}\"])
+
+ dnl # From python 3.8, --embed is required
+ dnl # https://bugs.python.org/issue36721
+ AX_COMPARE_VERSION(${PYTHON_VERSION}, [ge], [3.8], [EMBED="--embed"], [])
+
+ python3_ldflags=`${PYTHON3_CONFIG_BIN} --ldflags $EMBED`
+ AC_MSG_NOTICE([${PYTHON3_CONFIG_BIN}'s ldflags were \"$python3_ldflags}\"])
+
+ dnl # Strip -Wl,-O1... Is -O even a valid linker flag??
+ dnl # Strip -Wl,-Bsymbolic-functions as thats not always supported or required
+ dnl # Strip -Xlinker -export-dynamic as it causes weird linking issues on Linux
+ dnl # See: https://bugs.python.org/issue36508
+ mod_ldflags=`echo $python3_ldflags | sed -e '\
+ s/-Wl,-O[[[:digit:]]][[[:blank:]]]*//g;\
+ s/-Wl,-Bsymbolic-functions[[[:blank:]]]*//g;\
+ s/-Xlinker -export-dynamic//g;\
+ s/-Wl,-stack_size,[[[:digit:]]]*[[[:blank:]]]//g;
+ '`
+ AC_MSG_NOTICE([Sanitized ldflags were \"${mod_ldflags}\"])
+
+ CFLAGS=$old_CFLAGS
+fi
+AC_CHECK_FUNCS([dl_iterate_phdr])
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_python3/example.py b/src/modules/rlm_python3/example.py
new file mode 100644
index 0000000..bb2d997
--- /dev/null
+++ b/src/modules/rlm_python3/example.py
@@ -0,0 +1,99 @@
+#! /usr/bin/env python3
+#
+# Python module example file
+# Miguel A.L. Paraz <mparaz@mparaz.com>
+#
+# $Id$
+
+import radiusd
+
+# Check post_auth for the most complete example using different
+# input and output formats
+
+def instantiate(p):
+ print("*** instantiate ***")
+ print(p)
+ # return 0 for success or -1 for failure
+
+
+def authorize(p):
+ print("*** authorize ***")
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in authorize ***')
+ print()
+ print(p)
+ print()
+ print(radiusd.config)
+ return radiusd.RLM_MODULE_OK
+
+
+def preacct(p):
+ print("*** preacct ***")
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def accounting(p):
+ print("*** accounting ***")
+ radiusd.radlog(radiusd.L_INFO, '*** radlog call in accounting (0) ***')
+ print()
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def pre_proxy(p):
+ print("*** pre_proxy ***")
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def post_proxy(p):
+ print("*** post_proxy ***")
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def post_auth(p):
+ print("*** post_auth ***")
+
+ # This is true when using pass_all_vps_dict
+ if type(p) is dict:
+ print("Request:", p["request"])
+ print("Reply:", p["reply"])
+ print("Config:", p["config"])
+ print("State:", p["session-state"])
+ print("Proxy-Request:", p["proxy-request"])
+ print("Proxy-Reply:", p["proxy-reply"])
+
+ else:
+ print(p)
+
+ # Dictionary representing changes we want to make to the different VPS
+ update_dict = {
+ "request": (("User-Password", ":=", "A new password"),),
+ "reply": (("Reply-Message", "The module is doing its job"),
+ ("User-Name", "NewUserName")),
+ "config": (("Cleartext-Password", "A new password"),),
+ }
+
+ return radiusd.RLM_MODULE_OK, update_dict
+ # Alternatively, you could use the legacy 3-tuple output
+ # (only reply and config can be updated)
+ # return radiusd.RLM_MODULE_OK, update_dict["reply"], update_dict["config"]
+
+
+def recv_coa(p):
+ print("*** recv_coa ***")
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def send_coa(p):
+ print("*** send_coa ***")
+ print(p)
+ return radiusd.RLM_MODULE_OK
+
+
+def detach(p):
+ print("*** goodbye from example.py ***")
+ return radiusd.RLM_MODULE_OK
+
diff --git a/src/modules/rlm_python3/prepaid.py b/src/modules/rlm_python3/prepaid.py
new file mode 100644
index 0000000..28e548b
--- /dev/null
+++ b/src/modules/rlm_python3/prepaid.py
@@ -0,0 +1,247 @@
+#! /usr/bin/env python3
+#
+# Example Python module for prepaid usage using MySQL
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+#
+# Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+# Copyright 2002 Imperium Technology, Inc.
+#
+# $Id$
+
+import radiusd
+import MySQLdb
+
+# Configuration
+configDb = 'python' # Database name
+configHost = 'localhost' # Database host
+configUser = 'python' # Database user and password
+configPasswd = 'python'
+
+# xxx Database
+
+# Globals
+dbHandle = None
+
+def log(level, s):
+ """Log function."""
+ radiusd.radlog(level, 'prepaid.py: ' + s)
+
+def instantiate(p):
+ """Module Instantiation. 0 for success, -1 for failure.
+ p is a dummy variable here."""
+ global dbHandle
+
+ try:
+ dbHandle = MySQLdb.connect(db=configDb, host=configHost,
+ user=configUser, passwd=configPasswd)
+
+ except MySQLdb.OperationalError as e:
+ # Report the error and return -1 for failure.
+ # xxx A more advanced module would retry the database.
+ log(radiusd.L_ERR, str(e))
+ return -1
+
+ log(radiusd.L_INFO, 'db connection: ' + str(dbHandle))
+
+ return 0
+
+
+def authorize(authData):
+ """Authorization and authentication are done in one step."""
+
+ # Extract the data we need.
+ userName = None
+ userPasswd = None
+
+ for t in authData:
+ if t[0] == 'User-Name':
+ userName = t[1]
+ elif t[0] == 'Password':
+ userPasswd = t[1]
+
+ # Build and log the SQL statement
+ # radiusd puts double quotes (") around the string representation of
+ # the RADIUS packet.
+ sql = 'select passwd, maxseconds from users where username = ' + userName
+
+ log(radiusd.L_DBG, sql)
+
+ # Get a cursor
+ # xxx Or should this be one cursor all throughout?
+ try:
+ dbCursor = dbHandle.cursor()
+ except MySQLdb.OperationalError as e:
+ log(radiusd.L_ERR, str(e))
+ return radiusd.RLM_MODULE_FAIL
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError as e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+ # Get the result. (passwd, maxseconds)
+ result = dbCursor.fetchone()
+ if not result:
+ # User not found
+ log(radiusd.L_INFO, 'user not found: ' + userName)
+ dbCursor.close()
+ return radiusd.RLM_MODULE_NOTFOUND
+
+
+
+ # Compare passwords
+ # Ignore the quotes around userPasswd.
+ if result[0] != userPasswd[1:-1]:
+ log(radiusd.L_DBG, 'user password mismatch: ' + userName)
+ return radiusd.RLM_MODULE_REJECT
+
+ maxSeconds = result[1]
+
+ # Compute their session limit
+
+ # Build and log the SQL statement
+ sql = 'select sum(seconds) from sessions where username = ' + userName
+
+ log(radiusd.L_DBG, sql)
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError as e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+ # Get the result. (sum,)
+ result = dbCursor.fetchone()
+ if (not result) or (not result[0]):
+ # No usage yet
+ secondsUsed = 0
+ else:
+ secondsUsed = result[0]
+
+ # Done with cursor
+ dbCursor.close()
+
+ # Note that MySQL returns the result of SUM() as a float.
+ sessionTimeout = maxSeconds - int(secondsUsed)
+
+ if sessionTimeout <= 0:
+ # No more time, reject outright
+ log(radiusd.L_INFO, 'user out of time: ' + userName)
+ return radiusd.RLM_MODULE_REJECT
+
+ # Log the success
+ log(radiusd.L_DBG, 'user accepted: %s, %d seconds' %
+ (userName, sessionTimeout))
+
+ # We are adding to the RADIUS packet
+ # Note that the session timeout integer must be converted to string.
+ # We need to set an Auth-Type.
+
+ return (radiusd.RLM_MODULE_UPDATED,
+ (('Session-Timeout', str(sessionTimeout)),),
+ (('Auth-Type', 'python'),))
+ # If you want to use different operators
+ # you can do
+ # return (radiusd.RLM_MODULE_UPDATED,
+ # (
+ # ('Session-Timeout', ':=', str(sessionTimeout)),
+ # ('Some-other-option', '-=', Value'),
+ # ),
+ # (
+ # ('Auth-Type', ':=', 'python'),
+ # ),
+ # )
+
+def authenticate(p):
+ return radiusd.RLM_MODULE_OK
+
+
+def preacct(p):
+ return radiusd.RLM_MODULE_OK
+
+
+def accounting(acctData):
+ """Accounting."""
+ # Extract the data we need.
+
+ userName = None
+ acctSessionTime = None
+ acctStatusType = None
+
+ # xxx A dict would make this nice.
+ for t in acctData:
+ if t[0] == 'User-Name':
+ userName = t[1]
+ elif t[0] == 'Acct-Session-Time':
+ acctSessionTime = t[1]
+ elif t[0] == 'Acct-Status-Type':
+ acctStatusType = t[1]
+
+
+ # We will not deal with Start for now.
+ # We may later, for simultaneous checks and the like.
+ if acctStatusType == 'Start':
+ return radiusd.RLM_MODULE_OK
+
+ # Build and log the SQL statement
+ # radiusd puts double quotes (") around the string representation of
+ # the RADIUS packet.
+ #
+ # xxx This is simplistic as it does not record the time, etc.
+ #
+ sql = 'insert into sessions (username, seconds) values (%s, %d)' % \
+ (userName, int(acctSessionTime))
+
+ log(radiusd.L_DBG, sql)
+
+ # Get a cursor
+ # xxx Or should this be one cursor all throughout?
+ try:
+ dbCursor = dbHandle.cursor()
+ except MySQLdb.OperationalError as e:
+ log(radiusd.L_ERR, str(e))
+ return radiusd.RLM_MODULE_FAIL
+
+ # Execute the SQL statement
+ try:
+ dbCursor.execute(sql)
+ except MySQLdb.OperationalError as e:
+ log(radiusd.L_ERR, str(e))
+ dbCursor.close()
+ return radiusd.RLM_MODULE_FAIL
+
+
+ return radiusd.RLM_MODULE_OK
+
+
+def detach():
+ """Detach and clean up."""
+ # Shut down the database connection.
+ global dbHandle
+ log(radiusd.L_DBG, 'closing database handle: ' + str(dbHandle))
+ dbHandle.close()
+
+ return radiusd.RLM_MODULE_OK
+
+
+
+# Test the modules
+if __name__ == '__main__':
+ instantiate(None)
+ print(authorize((('User-Name', '"map"'), ('User-Password', '"abc"'))))
diff --git a/src/modules/rlm_python3/prepaid.sql b/src/modules/rlm_python3/prepaid.sql
new file mode 100644
index 0000000..3e9ffed
--- /dev/null
+++ b/src/modules/rlm_python3/prepaid.sql
@@ -0,0 +1,41 @@
+# MySQL dump 8.13
+#
+# Host: localhost Database: python
+#--------------------------------------------------------
+# Server version 3.23.36
+
+#
+# Table structure for table 'sessions'
+#
+
+CREATE TABLE sessions (
+ username char(32) default NULL,
+ seconds int(11) default NULL
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'sessions'
+#
+
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+INSERT INTO sessions VALUES ('map',10);
+
+#
+# Table structure for table 'users'
+#
+
+CREATE TABLE users (
+ username char(32) NOT NULL default '',
+ passwd char(32) default NULL,
+ maxseconds int(11) default NULL,
+ PRIMARY KEY (username)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table 'users'
+#
+
+INSERT INTO users VALUES ('map','abc',100);
+
diff --git a/src/modules/rlm_python3/radiusd.py b/src/modules/rlm_python3/radiusd.py
new file mode 100644
index 0000000..e9db28a
--- /dev/null
+++ b/src/modules/rlm_python3/radiusd.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python3
+#
+# Definitions for RADIUS programs
+#
+# Copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+#
+# This should only be used when testing modules.
+# Inside freeradius, the 'radiusd' Python module is created by the C module
+# and the definitions are automatically created.
+#
+# $Id$
+
+# from modules.h
+
+RLM_MODULE_REJECT = 0
+RLM_MODULE_FAIL = 1
+RLM_MODULE_OK = 2
+RLM_MODULE_HANDLED = 3
+RLM_MODULE_INVALID = 4
+RLM_MODULE_USERLOCK = 5
+RLM_MODULE_NOTFOUND = 6
+RLM_MODULE_NOOP = 7
+RLM_MODULE_UPDATED = 8
+RLM_MODULE_NUMCODES = 9
+
+# from log.h
+L_AUTH = 2
+L_INFO = 3
+L_ERR = 4
+L_WARN = 5
+L_PROXY = 6
+L_ACCT = 7
+
+L_DBG = 16
+L_DBG_WARN = 17
+L_DBG_ERR = 18
+L_DBG_WARN_REQ = 19
+L_DBG_ERR_REQ = 20
+
+# log function
+def radlog(level, msg):
+ import sys
+ sys.stdout.write(msg + '\n')
diff --git a/src/modules/rlm_python3/rlm_python3.c b/src/modules/rlm_python3/rlm_python3.c
new file mode 100644
index 0000000..aaa43ab
--- /dev/null
+++ b/src/modules/rlm_python3/rlm_python3.c
@@ -0,0 +1,1372 @@
+/*
+ * 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_python3.c
+ * @brief Translates requests between the server an a python interpreter.
+ *
+ * @note Rewritten by Paul P. Komkoff Jr <i@stingr.net>.
+ *
+ * @copyright 2000,2006,2015-2016 The FreeRADIUS server project
+ * @copyright 2002 Miguel A.L. Paraz <mparaz@mparaz.com>
+ * @copyright 2002 Imperium Technology, Inc.
+ */
+RCSID("$Id$")
+
+#define LOG_PREFIX "rlm_python3 - "
+
+#include "config.h"
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <Python.h>
+#include <dlfcn.h>
+#include "rlm_python3.h"
+#ifdef HAVE_DL_ITERATE_PHDR
+#include <link.h>
+#endif
+
+/*
+ * Since version 3.8, the "m" suffix is no longer available.
+ * https://bugs.python.org/issue36707
+ */
+#if PY_MINOR_VERSION >= 8
+#define LIBPYTHON_LINKER_NAME \
+ "libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) LT_SHREXT
+#else
+#define LIBPYTHON_LINKER_NAME \
+ "libpython" STRINGIFY(PY_MAJOR_VERSION) "." STRINGIFY(PY_MINOR_VERSION) "m" LT_SHREXT
+#endif
+
+static uint32_t python_instances = 0;
+static void *python_dlhandle;
+
+static PyThreadState *main_interpreter; //!< Main interpreter (cext safe)
+static PyObject *main_module; //!< Pthon configuration dictionary.
+
+static rlm_python_t *current_inst; //!< Needed to pass parameter to PyInit_radiusd
+static CONF_SECTION *current_conf; //!< Needed to pass parameter to PyInit_radiusd
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static CONF_PARSER module_config[] = {
+
+#define A(x) { "mod_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.module_name), NULL }, \
+ { "func_" #x, FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, x.function_name), NULL },
+
+ A(instantiate)
+ A(authorize)
+ A(authenticate)
+ A(preacct)
+ A(accounting)
+ A(checksimul)
+#ifdef WITH_PROXY
+ A(pre_proxy)
+ A(post_proxy)
+#endif
+ A(post_auth)
+#ifdef WITH_COA
+ A(recv_coa)
+ A(send_coa)
+#endif
+ A(detach)
+
+#undef A
+
+ { "python_path", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_python_t, python_path), NULL },
+ { "cext_compat", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, cext_compat), "yes" },
+ { "pass_all_vps", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps), "no" },
+ { "pass_all_vps_dict", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_python_t, pass_all_vps_dict), "no" },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static struct {
+ char const *name;
+ int value;
+} radiusd_constants[] = {
+
+#define A(x) { #x, x },
+
+ A(L_DBG)
+ A(L_WARN)
+ A(L_AUTH)
+ A(L_INFO)
+ A(L_ERR)
+#ifdef WITH_PROXY
+ A(L_PROXY)
+#endif
+ A(L_ACCT)
+ A(L_DBG_WARN)
+ A(L_DBG_ERR)
+ A(L_DBG_WARN_REQ)
+ A(L_DBG_ERR_REQ)
+ A(RLM_MODULE_REJECT)
+ A(RLM_MODULE_FAIL)
+ A(RLM_MODULE_OK)
+ A(RLM_MODULE_HANDLED)
+ A(RLM_MODULE_INVALID)
+ A(RLM_MODULE_USERLOCK)
+ A(RLM_MODULE_NOTFOUND)
+ A(RLM_MODULE_NOOP)
+ A(RLM_MODULE_UPDATED)
+ A(RLM_MODULE_NUMCODES)
+
+#undef A
+
+ { NULL, 0 },
+};
+
+/*
+ * This allows us to initialise PyThreadState on a per thread basis
+ */
+fr_thread_local_setup(rbtree_t *, local_thread_state) /* macro */
+
+/*
+ * radiusd Python functions
+ */
+
+/** Allow radlog to be called from python
+ *
+ */
+static PyObject *mod_radlog(UNUSED PyObject *module, PyObject *args)
+{
+ int status;
+ char *msg;
+
+ if (!PyArg_ParseTuple(args, "is", &status, &msg)) {
+ return NULL;
+ }
+
+ radlog(status, "%s", msg);
+ Py_INCREF(Py_None);
+
+ return Py_None;
+}
+
+static PyMethodDef module_methods[] = {
+ { "radlog", &mod_radlog, METH_VARARGS,
+ "radiusd.radlog(level, msg)\n\n" \
+ "Print a message using radiusd logging system. level should be one of the\n" \
+ "constants L_DBG, L_AUTH, L_INFO, L_ERR, L_PROXY\n"
+ },
+ { NULL, NULL, 0, NULL },
+};
+
+/*
+ * Initialise a new module, with our default methods
+ */
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "radiusd", /*m_doc*/
+ "FreeRADIUS python module", /*m_doc*/
+ -1, /*m_size*/
+ module_methods, /*m_methods*/
+ NULL, /*m_reload*/
+ NULL, /*m_traverse*/
+ NULL, /*m_clear*/
+ NULL, /*m_free*/
+
+};
+
+
+/** Print out the current error
+ *
+ * Must be called with a valid thread state set
+ */
+static void python_error_log(void)
+{
+ PyObject *pExcType = NULL, *pExcValue = NULL, *pExcTraceback = NULL, *pStr1 = NULL, *pStr2 = NULL;
+ PyErr_Fetch(&pExcType, &pExcValue, &pExcTraceback);
+
+ PyErr_NormalizeException(&pExcType, &pExcValue, &pExcTraceback);
+
+ if (!pExcType || !pExcValue) {
+ ERROR("%s:%d, Unknown error", __func__, __LINE__);
+ Py_XDECREF(pExcType);
+ Py_XDECREF(pExcValue);
+ return;
+ }
+
+ if (((pStr1 = PyObject_Str(pExcType)) != NULL) &&
+ ((pStr2 = PyObject_Str(pExcValue)) != NULL)) {
+ ERROR("%s:%d, Exception type: %s, Exception value: %s", __func__, __LINE__, PyUnicode_AsUTF8(pStr1), PyUnicode_AsUTF8(pStr2));
+ Py_DECREF(pStr1);
+ Py_DECREF(pStr2);
+ }
+
+ if (pExcTraceback) {
+ PyObject *pRepr = PyObject_Repr(pExcTraceback);
+ PyObject *module_name, *pyth_module;
+
+ module_name = PyUnicode_FromString("traceback");
+ pyth_module = PyImport_Import(module_name);
+
+ if (pyth_module) {
+ PyObject *pyth_func = PyObject_GetAttrString(pyth_module, "format_exception");
+
+ if (pyth_func && PyCallable_Check(pyth_func)) {
+ PyObject *pyth_val = PyObject_CallFunctionObjArgs(pyth_func, pExcType, pExcValue, pExcTraceback, NULL);
+ PyObject *pystr = PyObject_Str(pyth_val);
+ PyObject* pTraceString = PyUnicode_AsEncodedString(pystr, "UTF-8", "strict");
+ char *str = PyBytes_AsString(pTraceString);
+ ERROR("%s:%d, full_backtrace: %s", __func__, __LINE__, str);
+
+ Py_DECREF(pyth_val);
+ Py_DECREF(pystr);
+ Py_DECREF(pTraceString);
+ Py_DECREF(pyth_func);
+ }
+ Py_DECREF(pyth_module);
+ } else {
+ ERROR("%s:%d, py_module is null, name: %p", __func__, __LINE__, module_name);
+ }
+
+ Py_DECREF(module_name);
+ Py_DECREF(pRepr);
+ Py_DECREF(pExcTraceback);
+ }
+
+ Py_DECREF(pExcType);
+ Py_DECREF(pExcValue);
+}
+
+static void mod_vptuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, PyObject *pValue,
+ char const *funcname, char const *list_name)
+{
+ int i;
+ int tuplesize;
+ vp_tmpl_t dst;
+ VALUE_PAIR *vp;
+ REQUEST *current = request;
+
+ memset(&dst, 0, sizeof(dst));
+
+ /*
+ * If the Python function gave us None for the tuple,
+ * then just return.
+ */
+ if (pValue == Py_None || pValue == NULL) return;
+
+ if (!PyTuple_CheckExact(pValue)) {
+ ERROR("%s - non-tuple passed to %s", funcname, list_name);
+ return;
+ }
+ /* Get the tuple tuplesize. */
+ tuplesize = PyTuple_GET_SIZE(pValue);
+ for (i = 0; i < tuplesize; i++) {
+ PyObject *pTupleElement = PyTuple_GET_ITEM(pValue, i);
+ PyObject *pStr1;
+ PyObject *pStr2;
+ PyObject *pOp;
+ int pairsize;
+ char const *s1;
+ char const *s2;
+ FR_TOKEN op = T_OP_EQ;
+
+ if (!PyTuple_CheckExact(pTupleElement)) {
+ ERROR("%s - Tuple element %d of %s is not a tuple", funcname, i, list_name);
+ continue;
+ }
+ /* Check if it's a pair */
+
+ pairsize = PyTuple_GET_SIZE(pTupleElement);
+ if ((pairsize < 2) || (pairsize > 3)) {
+ ERROR("%s - Tuple element %d of %s is a tuple of size %d. Must be 2 or 3",
+ funcname, i, list_name, pairsize);
+ continue;
+ }
+
+ pStr1 = PyTuple_GET_ITEM(pTupleElement, 0);
+ pStr2 = PyTuple_GET_ITEM(pTupleElement, pairsize-1);
+
+ if (PyUnicode_CheckExact(pStr1) && PyUnicode_CheckExact(pStr2)) {
+ s1 = PyUnicode_AsUTF8(pStr1);
+ s2 = PyUnicode_AsUTF8(pStr2);
+ } else if (PyUnicode_CheckExact(pStr1) && PyBytes_CheckExact(pStr2)) {
+ s1 = PyUnicode_AsUTF8(pStr1);
+ s2 = PyBytes_AsString(pStr2);
+ } else{
+ ERROR("%s - Tuple element %d of %s must be as (str, str)",
+ funcname, i, list_name);
+ continue;
+ }
+
+ if (pairsize == 3) {
+ pOp = PyTuple_GET_ITEM(pTupleElement, 1);
+ if (PyUnicode_CheckExact(pOp)) {
+ if (!(op = fr_str2int(fr_tokens, PyUnicode_AsUTF8(pOp), 0))) {
+ ERROR("%s - Invalid operator %s:%s %s %s, falling back to '='",
+ funcname, list_name, s1, PyUnicode_AsUTF8(pOp), s2);
+ op = T_OP_EQ;
+ }
+ } else if (PyLong_Check(pOp)) {
+ op = PyLong_AsLong(pOp);
+ if (!fr_int2str(fr_tokens, op, NULL)) {
+ ERROR("%s - Invalid operator %s:%s %i %s, falling back to '='",
+ funcname, list_name, s1, op, s2);
+ op = T_OP_EQ;
+ }
+ } else {
+ ERROR("%s - Invalid operator type for %s:%s ? %s, using default '='",
+ funcname, list_name, s1, s2);
+ }
+ }
+
+ if (tmpl_from_attr_str(&dst, s1, REQUEST_CURRENT, PAIR_LIST_REPLY, false, false) <= 0) {
+ ERROR("%s - Failed to find attribute %s:%s", funcname, list_name, s1);
+ continue;
+ }
+
+ if (radius_request(&current, dst.tmpl_request) < 0) {
+ ERROR("%s - Attribute name %s:%s refers to outer request but not in a tunnel, skipping...",
+ funcname, list_name, s1);
+ continue;
+ }
+
+ if (!(vp = fr_pair_afrom_da(ctx, dst.tmpl_da))) {
+ ERROR("%s - Failed to create attribute %s:%s", funcname, list_name, s1);
+ continue;
+ }
+
+ vp->op = op;
+
+ /*
+ * @todo - use tmpl_cast_to_vp() instead ???
+ */
+ if (vp->da->flags.has_tag) vp->tag = dst.tmpl_tag;
+
+ if (fr_pair_value_from_str(vp, s2, -1) < 0) {
+ DEBUG("%s - Failed: '%s:%s' %s '%s'", funcname, list_name, s1,
+ fr_int2str(fr_tokens, op, "="), s2);
+ } else {
+ DEBUG("%s - '%s:%s' %s '%s'", funcname, list_name, s1,
+ fr_int2str(fr_tokens, op, "="), s2);
+ }
+
+ radius_pairmove(current, vps, vp, false);
+ }
+}
+
+
+/*
+ * This is the core Python function that the others wrap around.
+ * Pass the value-pair print strings in a tuple.
+ *
+ */
+static int mod_populate_vptuple(PyObject *pPair, VALUE_PAIR *vp)
+{
+ PyObject *pStr = NULL;
+ char buf[1024];
+
+ /* Look at the fr_pair_fprint_name? */
+
+ if (vp->da->flags.has_tag) {
+ pStr = PyUnicode_FromFormat("%s:%d", vp->da->name, vp->tag);
+ } else {
+ pStr = PyUnicode_FromString(vp->da->name);
+ }
+
+ if (!pStr) {
+ ERROR("%s:%d, vp->da->name: %s", __func__, __LINE__, vp->da->name);
+ if (PyErr_Occurred()) {
+ python_error_log();
+ }
+
+ return -1;
+ }
+
+ PyTuple_SET_ITEM(pPair, 0, pStr);
+
+ vp_prints_value(buf, sizeof(buf), vp, '\0'); /* Python doesn't need any escaping */
+
+ pStr = PyUnicode_FromString(buf);
+
+ if (pStr == NULL) {
+ ERROR("%s:%d, vp->da->name: %s", __func__, __LINE__, vp->da->name);
+ if (PyErr_Occurred()) {
+ python_error_log();
+ }
+ return -1;
+ }
+
+ PyTuple_SET_ITEM(pPair, 1, pStr);
+
+ return 0;
+}
+
+/*
+ * This function generates a tuple representing a given VPS and inserts it into
+ * the indicated position in the tuple pArgs.
+ * Returns false on error.
+ */
+static bool mod_populate_vps(PyObject* pArgs, const int pos, VALUE_PAIR *vps)
+{
+ PyObject *vps_tuple = NULL;
+ int tuplelen = 0;
+ int i = 0;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ /* If vps is NULL, return None */
+ if (vps == NULL) {
+ Py_INCREF(Py_None);
+ PyTuple_SET_ITEM(pArgs, pos, Py_None);
+ return true;
+ }
+
+ /*
+ * We will pass a tuple containing (name, value) tuples
+ * We can safely use the Python function to build up a
+ * tuple, since the tuple is not used elsewhere.
+ *
+ * Determine the size of our tuple by walking through the vps.
+ */
+ for (vp = fr_cursor_init(&cursor, &vps); vp; vp = fr_cursor_next(&cursor))
+ tuplelen++;
+
+ if ((vps_tuple = PyTuple_New(tuplelen)) == NULL) goto error;
+
+ for (vp = fr_cursor_init(&cursor, &vps); vp; vp = fr_cursor_next(&cursor), i++) {
+ PyObject *pPair = NULL;
+
+ /* The inside tuple has two only: */
+ if ((pPair = PyTuple_New(2)) == NULL) goto error;
+
+ if (mod_populate_vptuple(pPair, vp) == 0) {
+ /* Put the tuple inside the container */
+ PyTuple_SET_ITEM(vps_tuple, i, pPair);
+ } else {
+ Py_DECREF(pPair);
+ goto error;
+ }
+ }
+ PyTuple_SET_ITEM(pArgs, pos, vps_tuple);
+ return true;
+
+error:
+ Py_XDECREF(vps_tuple);
+ return false;
+}
+
+static rlm_rcode_t do_python_single(REQUEST *request, PyObject *pFunc, char const *funcname, bool pass_all_vps, bool pass_all_vps_dict)
+{
+ PyObject *pRet = NULL;
+ PyObject *pArgs = NULL;
+ PyObject *pDictInput = NULL;
+ int ret;
+ int i;
+
+ /* Default return value is "OK, continue" */
+ ret = RLM_MODULE_OK;
+
+ /*
+ * pArgs is a 6-tuple with (Request, Reply, Config, State, Proxy-Request, Proxy-Reply)
+ * If some list is not available, NONE is used instead
+ */
+ if ((pArgs = PyTuple_New(6)) == NULL) {
+ ERROR("%s:%d, %s - Memory cannot be allocated for PyTyple_New", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /* If there is a request, fill in the first 4 attribute lists */
+ if (request != NULL) {
+ if (!mod_populate_vps(pArgs, 0, request->packet->vps) ||
+ !mod_populate_vps(pArgs, 1, request->reply->vps) ||
+ !mod_populate_vps(pArgs, 2, request->config) ||
+ !mod_populate_vps(pArgs, 3, request->state)) {
+
+ ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+#ifdef WITH_PROXY
+ /* fill proxy vps */
+ if (request->proxy) {
+ if (!mod_populate_vps(pArgs, 4, request->proxy->vps)) {
+ ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ } else
+#endif
+ {
+ mod_populate_vps(pArgs, 4, NULL);
+ }
+
+#ifdef WITH_PROXY
+ /* fill proxy_reply vps */
+ if (request->proxy_reply) {
+ if (!mod_populate_vps(pArgs, 5, request->proxy_reply->vps)) {
+ ERROR("%s:%d, %s - mod_populate_vps failed", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ } else
+#endif
+ {
+ mod_populate_vps(pArgs, 5, NULL);
+ }
+
+ }
+ /* If there is no request, set all the elements to None */
+ else for (i = 0; i < 6; i++) mod_populate_vps(pArgs, i, NULL);
+
+ /*
+ * Call Python function. If pass_all_vps_dict is true, a dictionary with the
+ * appropriate "request", "reply"... keys is passed as argument to the
+ * module callback.
+ * Else, if pass_all_vps is true, a 6-tuple representing
+ * (Request, Reply, Config, State, Proxy-Request, Proxy-Reply) is passed.
+ * Otherwise, a tuple representing just the request is used.
+ */
+ if (pass_all_vps_dict) {
+ pDictInput = PyDict_New();
+ if (pDictInput == NULL ||
+ PyDict_SetItemString(pDictInput, "request", PyTuple_GET_ITEM(pArgs, 0)) ||
+ PyDict_SetItemString(pDictInput, "reply", PyTuple_GET_ITEM(pArgs, 1)) ||
+ PyDict_SetItemString(pDictInput, "config", PyTuple_GET_ITEM(pArgs, 2)) ||
+ PyDict_SetItemString(pDictInput, "session-state", PyTuple_GET_ITEM(pArgs, 3))
+#ifdef WITH_PROXY
+ ||
+ PyDict_SetItemString(pDictInput, "proxy-request", PyTuple_GET_ITEM(pArgs, 4)) ||
+ PyDict_SetItemString(pDictInput, "proxy-reply", PyTuple_GET_ITEM(pArgs, 5))
+#endif
+ ) {
+
+ ERROR("%s:%d, %s - PyDict_SetItemString failed", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ pRet = PyObject_CallFunctionObjArgs(pFunc, pDictInput, NULL);
+ }
+ else if (pass_all_vps)
+ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL);
+ else
+ pRet = PyObject_CallFunctionObjArgs(pFunc, PyTuple_GET_ITEM(pArgs, 0), NULL);
+
+ if (!pRet) {
+ ERROR("%s:%d, %s - pRet is NULL", __func__, __LINE__, funcname);
+ if (PyErr_Occurred()) {
+ python_error_log();
+ }
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ if (!request) {
+ // check return code at module instantiation time
+ if (PyLong_CheckExact(pRet)) ret = PyLong_AsLong(pRet);
+ goto finish;
+ }
+
+ /*
+ * The function returns either:
+ * 1. (returnvalue, replyTuple, configTuple), where
+ * - returnvalue is one of the constants RLM_*
+ * - replyTuple and configTuple are tuples of string
+ * tuples of size 2
+ *
+ * 2. the function return value alone
+ *
+ * 3. None - default return value is set
+ *
+ * xxx This code is messy!
+ */
+ if (PyTuple_CheckExact(pRet)) {
+ PyObject *pTupleInt;
+ int tuple_size = PyTuple_GET_SIZE(pRet);
+
+ if (tuple_size < 2 || tuple_size > 3) {
+ ERROR("%s:%d, %s - Tuple must be (return, updateDict) or (return, replyTuple, configTuple)", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ pTupleInt = PyTuple_GET_ITEM(pRet, 0);
+ if (!PyLong_CheckExact(pTupleInt)) {
+ ERROR("%s:%d, %s - First tuple element not an integer", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ /* Now have the return value */
+ ret = PyLong_AsLong(pTupleInt);
+
+ /* process updateDict */
+ if (tuple_size == 2) {
+ PyObject *updateDict = PyTuple_GET_ITEM(pRet, 1);
+ if (!PyDict_CheckExact(updateDict)) {
+ ret = RLM_MODULE_FAIL;
+ ERROR("%s:%d, %s - updateDict is not dictionary", __func__, __LINE__, funcname);
+ goto finish;
+ }
+ mod_vptuple(request->reply, request, &request->reply->vps,
+ PyDict_GetItemString(updateDict, "reply"), funcname, "reply");
+ mod_vptuple(request, request, &request->config,
+ PyDict_GetItemString(updateDict, "config"), funcname, "config");
+ mod_vptuple(request->packet, request, &request->packet->vps,
+ PyDict_GetItemString(updateDict, "request"), funcname, "request");
+ mod_vptuple(request->state_ctx, request, &request->state,
+ PyDict_GetItemString(updateDict, "session-state"), funcname, "session-state");
+#ifdef WITH_PROXY
+ if (request->proxy)
+ mod_vptuple(request->proxy, request, &request->proxy->vps,
+ PyDict_GetItemString(updateDict, "proxy-request"), funcname, "proxy-request");
+ if (request->proxy_reply)
+ mod_vptuple(request->proxy_reply, request, &request->proxy_reply->vps,
+ PyDict_GetItemString(updateDict, "proxy-reply"), funcname, "proxy-reply");
+#endif
+ /*
+ * Update cached copies
+ */
+ request->username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
+ if (!request->password)
+ request->password = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
+ }
+
+ /* process replyTuple and configTuple */
+ else if (tuple_size == 3) {
+ /* Reply item tuple */
+ mod_vptuple(request->reply, request, &request->reply->vps,
+ PyTuple_GET_ITEM(pRet, 1), funcname, "reply");
+ /* Config item tuple */
+ mod_vptuple(request, request, &request->config,
+ PyTuple_GET_ITEM(pRet, 2), funcname, "config");
+ }
+ } else if (PyLong_CheckExact(pRet)) {
+ /* Just an integer */
+ ret = PyLong_AsLong(pRet);
+ } else if (pRet == Py_None) {
+ /* returned 'None', return value defaults to "OK, continue." */
+ ret = RLM_MODULE_OK;
+ } else {
+ /* Not tuple or None */
+ ERROR("%s:%d, %s - Function did not return a tuple or None", __func__, __LINE__, funcname);
+ ret = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+
+finish:
+ Py_XDECREF(pArgs);
+ Py_XDECREF(pRet);
+ Py_XDECREF(pDictInput);
+
+ if (ret == RLM_MODULE_FAIL) {
+ ERROR("%s:%d, %s - RLM_MODULE_FAIL", __func__, __LINE__, funcname);
+ }
+ return ret;
+}
+
+static void python_interpreter_free(PyThreadState *interp)
+{
+DIAG_OFF(deprecated-declarations)
+ PyEval_AcquireLock();
+ PyThreadState_Swap(interp);
+ Py_EndInterpreter(interp);
+ PyEval_ReleaseLock();
+DIAG_ON(deprecated-declarations)
+}
+
+/** Destroy a thread state
+ *
+ * @param thread to destroy.
+ * @return 0
+ */
+static int _python_thread_free(python_thread_state_t *thread)
+{
+ PyEval_RestoreThread(thread->state); /* Swap in our local thread state */
+ PyThreadState_Clear(thread->state);
+ PyEval_SaveThread();
+
+ PyThreadState_Delete(thread->state); /* Don't need to hold lock for this */
+
+ return 0;
+}
+
+/** Callback for rbtree delete walker
+ *
+ */
+static void _python_thread_entry_free(void *arg)
+{
+ talloc_free(arg);
+}
+
+/** Cleanup any thread local storage on pthread_exit()
+ *
+ * @param arg The thread currently exiting.
+ */
+static void _python_thread_tree_free(void *arg)
+{
+ rad_assert(arg == local_thread_state);
+
+ rbtree_t *tree = talloc_get_type_abort(arg, rbtree_t);
+ rbtree_free(tree); /* Needs to be this not talloc_free to execute delete walker */
+
+ local_thread_state = NULL; /* Prevent double free in unittest env */
+}
+
+/** Compare instance pointers
+ *
+ */
+static int _python_inst_cmp(const void *a, const void *b)
+{
+ python_thread_state_t const *a_p = a, *b_p = b;
+
+ if (a_p->inst < b_p->inst) return -1;
+ if (a_p->inst > b_p->inst) return +1;
+ return 0;
+}
+
+/** Thread safe call to a python function
+ *
+ * Will swap in thread state specific to module/thread.
+ */
+static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname)
+{
+ int ret;
+ rbtree_t *thread_tree;
+ python_thread_state_t *this_thread;
+ python_thread_state_t find;
+
+ /*
+ * It's a NOOP if the function wasn't defined
+ */
+ if (!pFunc) return RLM_MODULE_NOOP;
+
+ /*
+ * Check to see if we've got a thread state tree
+ * If not, create one.
+ */
+ thread_tree = fr_thread_local_init(local_thread_state, _python_thread_tree_free);
+ if (!thread_tree) {
+ thread_tree = rbtree_create(NULL, _python_inst_cmp, _python_thread_entry_free, 0);
+ if (!thread_tree) {
+ RERROR("Failed allocating thread state tree");
+ return RLM_MODULE_FAIL;
+ }
+
+ ret = fr_thread_local_set(local_thread_state, thread_tree);
+ if (ret != 0) {
+ talloc_free(thread_tree);
+ return RLM_MODULE_FAIL;
+ }
+ }
+
+ find.inst = inst;
+ /*
+ * Find the thread state associated with this instance
+ * and this thread, or create a new thread state.
+ */
+ this_thread = rbtree_finddata(thread_tree, &find);
+ if (!this_thread) {
+ PyThreadState *state;
+
+ state = PyThreadState_New(inst->sub_interpreter->interp);
+
+ RDEBUG3("Initialised new thread state %p", state);
+ if (!state) {
+ REDEBUG("Failed initialising local PyThreadState on first run");
+ return RLM_MODULE_FAIL;
+ }
+
+ this_thread = talloc(NULL, python_thread_state_t);
+ this_thread->inst = inst;
+ this_thread->state = state;
+ talloc_set_destructor(this_thread, _python_thread_free);
+
+ if (!rbtree_insert(thread_tree, this_thread)) {
+ RERROR("Failed inserting thread state into TLS tree");
+ talloc_free(this_thread);
+
+ return RLM_MODULE_FAIL;
+ }
+ }
+ RDEBUG3("Using thread state %p", this_thread->state);
+
+ PyEval_RestoreThread(this_thread->state); /* Swap in our local thread state */
+ ret = do_python_single(request, pFunc, funcname, inst->pass_all_vps, inst->pass_all_vps_dict);
+ PyEval_SaveThread();
+
+ return ret;
+}
+
+#define MOD_FUNC(x) \
+static rlm_rcode_t CC_HINT(nonnull) mod_##x(void *instance, REQUEST *request) { \
+ return do_python((rlm_python_t *) instance, request, ((rlm_python_t *)instance)->x.function, #x);\
+}
+
+MOD_FUNC(authenticate)
+MOD_FUNC(authorize)
+MOD_FUNC(preacct)
+MOD_FUNC(accounting)
+MOD_FUNC(checksimul)
+#ifdef WITH_PROXY
+MOD_FUNC(pre_proxy)
+MOD_FUNC(post_proxy)
+#endif
+MOD_FUNC(post_auth)
+#ifdef WITH_COA
+MOD_FUNC(recv_coa)
+MOD_FUNC(send_coa)
+#endif
+static void python_obj_destroy(PyObject **ob)
+{
+ if (*ob != NULL) {
+ Py_DECREF(*ob);
+ *ob = NULL;
+ }
+}
+
+static void python_function_destroy(python_func_def_t *def)
+{
+ python_obj_destroy(&def->function);
+ python_obj_destroy(&def->module);
+}
+
+/** Import a user module and load a function from it
+ *
+ */
+static int python_function_load(char const *name, python_func_def_t *def)
+{
+ if (!def->module_name && !def->function_name) return 0; /* Just not set, it's fine */
+
+ if (!def->module_name) {
+ ERROR("Once you have set the 'func_%s = %s', you should set 'mod_%s = ...' too.",
+ name, def->function_name, name);
+ return -1;
+ }
+
+ if (!def->function_name) {
+ ERROR("Once you have set the 'mod_%s = %s', you should set 'func_%s = ...' too.",
+ name, def->module_name, name);
+ return -1;
+ }
+
+ def->module = PyImport_ImportModule(def->module_name);
+ if (!def->module) {
+ ERROR("%s - Module '%s' not found", __func__, def->module_name);
+
+ error:
+ python_error_log();
+ ERROR("%s - Failed to import python function '%s.%s'",
+ __func__, def->module_name, def->function_name);
+ Py_XDECREF(def->function);
+ def->function = NULL;
+ Py_XDECREF(def->module);
+ def->module = NULL;
+
+ return -1;
+ }
+
+ def->function = PyObject_GetAttrString(def->module, def->function_name);
+ if (!def->function) {
+ ERROR("%s - Function '%s.%s' is not found", __func__, def->module_name, def->function_name);
+ goto error;
+ }
+
+ if (!PyCallable_Check(def->function)) {
+ ERROR("%s - Function '%s.%s' is not callable", __func__, def->module_name, def->function_name);
+ goto error;
+ }
+
+ return 0;
+}
+
+/*
+ * Parse a configuration section, and populate a dict.
+ * This function is recursively called (allows to have nested dicts.)
+ */
+static void python_parse_config(CONF_SECTION *cs, int lvl, PyObject *dict)
+{
+ int indent_section = (lvl + 1) * 4;
+ int indent_item = (lvl + 2) * 4;
+ CONF_ITEM *ci = NULL;
+
+ if (!cs || !dict) return;
+
+ DEBUG("%*s%s {", indent_section, " ", cf_section_name1(cs));
+
+ while ((ci = cf_item_find_next(cs, ci))) {
+ /*
+ * This is a section.
+ * Create a new dict, store it in current dict,
+ * Then recursively call python_parse_config with this section and the new dict.
+ */
+ if (cf_item_is_section(ci)) {
+ CONF_SECTION *sub_cs = cf_item_to_section(ci);
+ char const *key = cf_section_name1(sub_cs); /* dict key */
+ PyObject *sub_dict, *pKey;
+
+ if (!key) continue;
+
+ pKey = PyUnicode_FromString(key);
+ if (!pKey) continue;
+
+ if (PyDict_Contains(dict, pKey)) {
+ WARN("rlm_python: Ignoring duplicate config section '%s'", key);
+ continue;
+ }
+
+ if (!(sub_dict = PyDict_New())) {
+ WARN("rlm_python: Unable to create subdict for config section '%s'", key);
+ }
+
+ (void)PyDict_SetItem(dict, pKey, sub_dict);
+
+ python_parse_config(sub_cs, lvl + 1, sub_dict);
+ } else if (cf_item_is_pair(ci)) {
+ CONF_PAIR *cp = cf_item_to_pair(ci);
+ char const *key = cf_pair_attr(cp); /* dict key */
+ char const *value = cf_pair_value(cp); /* dict value */
+ PyObject *pKey, *pValue;
+
+ if (!key || !value) continue;
+
+ pKey = PyUnicode_FromString(key);
+ pValue = PyUnicode_FromString(value);
+ if (!pKey || !pValue) continue;
+
+ /*
+ * This is an item.
+ * Store item attr / value in current dict.
+ */
+ if (PyDict_Contains(dict, pKey)) {
+ WARN("rlm_python: Ignoring duplicate config item '%s'", key);
+ continue;
+ }
+
+ (void)PyDict_SetItem(dict, pKey, pValue);
+
+ DEBUG("%*s%s = %s", indent_item, " ", key, value);
+ }
+ }
+
+ DEBUG("%*s}", indent_section, " ");
+}
+
+#ifdef HAVE_DL_ITERATE_PHDR
+static int dlopen_libpython_cb(struct dl_phdr_info *info,
+ UNUSED size_t size, void *data)
+{
+ const char *pattern = "/" LIBPYTHON_LINKER_NAME;
+ char **ppath = (char **)data;
+
+ if (strstr(info->dlpi_name, pattern) != NULL) {
+ if (*ppath != NULL) {
+ talloc_free(*ppath);
+ *ppath = NULL;
+ return EEXIST;
+ } else {
+ *ppath = talloc_strdup(NULL, info->dlpi_name);
+ if (*ppath == NULL) {
+ return errno;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Dlopen the already linked libpython */
+static void *dlopen_libpython(int flags)
+{
+ char *path = NULL;
+ int rc;
+ void *handle;
+
+ /* Find the linked libpython path */
+ rc = dl_iterate_phdr(dlopen_libpython_cb, &path);
+ if (rc != 0) {
+ WARN("Failed searching for libpython "
+ "among linked libraries: %s", strerror(rc));
+ return NULL;
+ } else if (path == NULL) {
+ WARN("Libpython is not found among linked libraries");
+ return NULL;
+ }
+
+ /* Dlopen the found library */
+ handle = dlopen(path, flags);
+ if (handle == NULL) {
+ WARN("Failed loading %s: %s", path, dlerror());
+ }
+ talloc_free(path);
+ return handle;
+}
+#else /* ! HAVE_DL_ITERATE_PHDR */
+/* Dlopen libpython by its linker name (bare soname) */
+static void *dlopen_libpython(int flags)
+{
+ const char *name = LIBPYTHON_LINKER_NAME;
+ void *handle;
+ handle = dlopen(name, flags);
+ if (handle == NULL) {
+ WARN("Failed loading %s: %s", name, dlerror());
+ }
+ return handle;
+}
+#endif /* ! HAVE_DL_ITERATE_PHDR */
+
+/*
+ * creates a module "radiusd"
+ */
+static PyMODINIT_FUNC PyInit_radiusd(void)
+{
+ CONF_SECTION *cs;
+ /*
+ * This is ugly, but there is no other way to pass parameters to PyMODINIT_FUNC
+ */
+ rlm_python_t *inst = current_inst;
+ CONF_SECTION *conf = current_conf;
+ int i;
+
+ inst->module = PyModule_Create(&moduledef);
+ if (!inst->module) {
+ python_error_log();
+ PyEval_SaveThread();
+ return Py_None;
+ }
+
+ /*
+ * Py_InitModule3 returns a borrowed ref, the actual
+ * module is owned by sys.modules, so we also need
+ * to own the module to prevent it being freed early.
+ */
+ //Py_IncRef(inst->module);
+
+ if (inst->cext_compat) main_module = inst->module;
+
+ for (i = 0; radiusd_constants[i].name; i++) {
+ if ((PyModule_AddIntConstant(inst->module, radiusd_constants[i].name,
+ radiusd_constants[i].value)) < 0){
+ python_error_log();
+ PyEval_SaveThread();
+ return Py_None;
+ }
+ }
+
+ /*
+ * Convert a FreeRADIUS config structure into a python
+ * dictionary.
+ */
+ inst->pythonconf_dict = PyDict_New();
+ if (!inst->pythonconf_dict) {
+ ERROR("Unable to create python dict for config");
+ python_error_log();
+ return Py_None;
+ }
+
+ /*
+ * Add module configuration as a dict
+ */
+ if (PyModule_AddObject(inst->module, "config", inst->pythonconf_dict) < 0){
+ python_error_log();
+ PyEval_SaveThread();
+ return Py_None;
+ }
+ cs = cf_section_sub_find(conf, "config");
+ if (cs) python_parse_config(cs, 0, inst->pythonconf_dict);
+
+ return inst->module;
+}
+
+/** Initialises a separate python interpreter for this module instance
+ *
+ */
+static int python_interpreter_init(rlm_python_t *inst, CONF_SECTION *conf)
+{
+ /*
+ * prepare radiusd module to be loaded
+ */
+ if (!inst->cext_compat || !main_module) {
+ /*
+ * This is ugly, but there is no other way to pass parameters to PyMODINIT_FUNC
+ */
+ current_inst = inst;
+ current_conf = conf;
+ PyImport_AppendInittab("radiusd",PyInit_radiusd);
+ }
+
+ /*
+ * Explicitly load libpython, so symbols will be available to lib-dynload modules
+ */
+ if (python_instances == 0) {
+ INFO("Python version: %s", Py_GetVersion());
+
+ python_dlhandle = dlopen_libpython(RTLD_NOW | RTLD_GLOBAL);
+ if (!python_dlhandle) WARN("Failed loading libpython symbols into global symbol table");
+
+#if PY_VERSION_HEX >= 0x03050000
+ {
+ wchar_t *name;
+
+ MEM(name = Py_DecodeLocale(main_config.name, NULL));
+ Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
+ PyMem_RawFree(name);
+ }
+#else
+ {
+ char *name;
+
+ memcpy(&name, &main_config.name, sizeof(name));
+ Py_SetProgramName(name); /* The value of argv[0] as a wide char string */
+ }
+#endif
+
+ Py_InitializeEx(0); /* Don't override signal handlers - noop on subs calls */
+ PyEval_InitThreads(); /* This also grabs a lock (which we then need to release) */
+ main_interpreter = PyThreadState_Get(); /* Store reference to the main interpreter */
+ }
+ rad_assert(PyEval_ThreadsInitialized());
+
+ /*
+ * Increment the reference counter
+ */
+ python_instances++;
+
+ /*
+ * This sets up a separate environment for each python module instance
+ * These will be destroyed on Py_Finalize().
+ */
+ if (!inst->cext_compat) {
+ inst->sub_interpreter = Py_NewInterpreter();
+ } else {
+ inst->sub_interpreter = main_interpreter;
+ }
+
+ PyThreadState_Swap(inst->sub_interpreter);
+
+ /*
+ * Due to limitations in Python, sub-interpreters don't work well
+ * with Python C extensions if they use GIL lock functions.
+ */
+ if (!inst->cext_compat || !main_module) {
+
+ /*
+ * Set the python search path
+ *
+ * The path buffer does not appear to be dup'd
+ * so its lifetime should really be bound to
+ * the lifetime of the module.
+ */
+ if (inst->python_path) {
+ char *p, *path;
+ PyObject *sys = PyImport_ImportModule("sys");
+ PyObject *sys_path = PyObject_GetAttrString(sys, "path");
+
+ memcpy(&p, &inst->python_path, sizeof(path));
+
+ for (path = strtok(p, ":"); path != NULL; path = strtok(NULL, ":")) {
+#if PY_VERSION_HEX > 0x03050000
+ wchar_t *py_path;
+
+ MEM(py_path = Py_DecodeLocale(path, NULL));
+ PyList_Append(sys_path, PyUnicode_FromWideChar(py_path, -1));
+ PyMem_RawFree(py_path);
+#elif PY_VERSION_HEX > 0x03000000
+ wchar_t *py_path;
+
+ MEM(py_path = _Py_char2wchar(path, NULL));
+ PyList_Append(sys_path, PyUnicode_FromWideChar(py_path, -1));
+ PyMem_RawFree(py_path);
+#else
+ PyList_Append(sys_path, PyLong_FromString(path));
+#endif
+ }
+
+ PyObject_SetAttrString(sys, "path", sys_path);
+ Py_DecRef(sys);
+ Py_DecRef(sys_path);
+ }
+ } else {
+ inst->module = main_module;
+ Py_IncRef(inst->module);
+ inst->pythonconf_dict = PyObject_GetAttrString(inst->module, "config");
+ Py_IncRef(inst->pythonconf_dict);
+ }
+
+ PyEval_SaveThread();
+
+ return 0;
+}
+
+/*
+ * 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_python_t *inst = instance;
+ int code = RLM_MODULE_OK;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+ /*
+ * Load the python code required for this module instance
+ */
+ if (python_interpreter_init(inst, conf) < 0) return -1;
+
+ /*
+ * Switch to our module specific main thread
+ */
+ PyEval_RestoreThread(inst->sub_interpreter);
+
+ /*
+ * Process the various sections
+ */
+#define PYTHON_FUNC_LOAD(_x) if (python_function_load(#_x, &inst->_x) < 0) goto error
+ PYTHON_FUNC_LOAD(instantiate);
+ PYTHON_FUNC_LOAD(authenticate);
+ PYTHON_FUNC_LOAD(authorize);
+ PYTHON_FUNC_LOAD(preacct);
+ PYTHON_FUNC_LOAD(accounting);
+ PYTHON_FUNC_LOAD(checksimul);
+#ifdef WITH_PROXY
+ PYTHON_FUNC_LOAD(pre_proxy);
+ PYTHON_FUNC_LOAD(post_proxy);
+#endif
+ PYTHON_FUNC_LOAD(post_auth);
+#ifdef WITH_COA
+ PYTHON_FUNC_LOAD(recv_coa);
+ PYTHON_FUNC_LOAD(send_coa);
+#endif
+ PYTHON_FUNC_LOAD(detach);
+
+ /*
+ * Call the instantiate function only if the function and module is set.
+ */
+ if (inst->instantiate.module_name && inst->instantiate.function_name) {
+
+ code = do_python_single(NULL, inst->instantiate.function, "instantiate", inst->pass_all_vps, inst->pass_all_vps_dict);
+ if (code < 0) {
+ error:
+ python_error_log(); /* Needs valid thread with GIL */
+ PyEval_SaveThread();
+ return -1;
+ }
+ }
+ PyEval_SaveThread();
+
+ return 0;
+}
+
+static int mod_detach(void *instance)
+{
+ rlm_python_t *inst = instance;
+ int ret = RLM_MODULE_OK;
+
+ /*
+ * Call module destructor
+ */
+ PyEval_RestoreThread(inst->sub_interpreter);
+
+ if (inst->detach.function) ret = do_python_single(NULL, inst->detach.function, "detach", inst->pass_all_vps, inst->pass_all_vps_dict);
+
+#define PYTHON_FUNC_DESTROY(_x) python_function_destroy(&inst->_x)
+ PYTHON_FUNC_DESTROY(instantiate);
+ PYTHON_FUNC_DESTROY(authenticate);
+ PYTHON_FUNC_DESTROY(authorize);
+ PYTHON_FUNC_DESTROY(preacct);
+ PYTHON_FUNC_DESTROY(accounting);
+ PYTHON_FUNC_DESTROY(checksimul);
+#ifdef WITH_PROXY
+ PYTHON_FUNC_DESTROY(pre_proxy);
+ PYTHON_FUNC_DESTROY(post_proxy);
+#endif
+ PYTHON_FUNC_DESTROY(post_auth);
+#ifdef WITH_COA
+ PYTHON_FUNC_DESTROY(recv_coa);
+ PYTHON_FUNC_DESTROY(send_coa);
+#endif
+ PYTHON_FUNC_DESTROY(detach);
+
+ Py_DecRef(inst->pythonconf_dict);
+ Py_DecRef(inst->module);
+
+ PyEval_SaveThread();
+
+ /*
+ * Force cleaning up of threads if this is *NOT* a worker
+ * thread, which happens if this is being called from
+ * unittest framework, and probably with the server running
+ * in debug mode.
+ */
+ rbtree_free(local_thread_state);
+ local_thread_state = NULL;
+
+ /*
+ * Only destroy if it's a subinterpreter
+ */
+ if (!inst->cext_compat) python_interpreter_free(inst->sub_interpreter);
+
+ if ((--python_instances) == 0) {
+ PyThreadState_Swap(main_interpreter); /* Swap to the main thread */
+ Py_Finalize();
+ dlclose(python_dlhandle);
+ }
+
+ return ret;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * 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_python3;
+module_t rlm_python3 = {
+ .magic = RLM_MODULE_INIT,
+ .name = "python3",
+ .type = RLM_TYPE_THREAD_UNSAFE,
+ .inst_size = sizeof(rlm_python_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_SESSION] = mod_checksimul,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ }
+};
diff --git a/src/modules/rlm_python3/rlm_python3.h b/src/modules/rlm_python3/rlm_python3.h
new file mode 100644
index 0000000..26cf29f
--- /dev/null
+++ b/src/modules/rlm_python3/rlm_python3.h
@@ -0,0 +1,63 @@
+#ifndef __RLM_PYTHON3_H__
+#define __RLM_PYTHON3_H__
+
+#include <Python.h>
+
+/** Specifies the module.function to load for processing a section
+ *
+ */
+typedef struct python_func_def {
+ PyObject *module; //!< Python reference to module.
+ PyObject *function; //!< Python reference to function in module.
+
+ char const *module_name; //!< String name of module.
+ char const *function_name; //!< String name of function in module.
+} python_func_def_t;
+
+/** An instance of the rlm_python module
+ *
+ */
+typedef struct rlm_python_t {
+ char const *name; //!< Name of the module instance
+ PyThreadState *sub_interpreter; //!< The main interpreter/thread used for this instance.
+ char const *python_path; //!< Path to search for python files in.
+ PyObject *module; //!< Local, interpreter specific module, containing
+ //!< FreeRADIUS functions.
+ bool cext_compat; //!< Whether or not to create sub-interpreters per module
+ //!< instance.
+
+ python_func_def_t
+ instantiate,
+ authorize,
+ authenticate,
+ preacct,
+ accounting,
+ checksimul,
+ pre_proxy,
+ post_proxy,
+ post_auth,
+#ifdef WITH_COA
+ recv_coa,
+ send_coa,
+#endif
+ detach;
+
+ PyObject *pythonconf_dict; //!< Configuration parameters defined in the module
+ //!< made available to the python script.
+ bool pass_all_vps; //!< Pass all VPS lists (request, reply, config, state, proxy_req, proxy_reply)
+ bool pass_all_vps_dict; //!< Pass all VPS lists as a dictionary rather than a tuple
+} rlm_python_t;
+
+/** Tracks a python module inst/thread state pair
+ *
+ * Multiple instances of python create multiple interpreters and each
+ * thread must have a PyThreadState per interpreter, to track execution.
+ */
+typedef struct python_thread_state {
+ PyThreadState *state; //!< Module instance/thread specific state.
+ rlm_python_t const *inst; //!< Module instance that created this thread state.
+} python_thread_state_t;
+
+
+#endif //__RLM_PYTHON_H__
+
diff --git a/src/modules/rlm_radutmp/.gitignore b/src/modules/rlm_radutmp/.gitignore
new file mode 100644
index 0000000..e936973
--- /dev/null
+++ b/src/modules/rlm_radutmp/.gitignore
@@ -0,0 +1,2 @@
+config.h
+all.mk
diff --git a/src/modules/rlm_radutmp/README.md b/src/modules/rlm_radutmp/README.md
new file mode 100644
index 0000000..5651fcc
--- /dev/null
+++ b/src/modules/rlm_radutmp/README.md
@@ -0,0 +1,11 @@
+# rlm_radutmp
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Writes a utmp style file that lists the users who are logged in.
+The file is used mainly for Simultaneous-Use checking and by
+radwho to see who has current sessions.
diff --git a/src/modules/rlm_radutmp/all.mk.in b/src/modules/rlm_radutmp/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_radutmp/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_radutmp/config.h.in b/src/modules/rlm_radutmp/config.h.in
new file mode 100644
index 0000000..ef5f2fd
--- /dev/null
+++ b/src/modules/rlm_radutmp/config.h.in
@@ -0,0 +1,34 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/src/modules/rlm_radutmp/configure b/src/modules/rlm_radutmp/configure
new file mode 100755
index 0000000..54b23c9
--- /dev/null
+++ b/src/modules/rlm_radutmp/configure
@@ -0,0 +1,4540 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_radutmp.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_radutmp
+'
+ 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_radutmp build without radutmp support
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_radutmp
+echo
+
+
+# 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_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $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
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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; } && { ac_try='./conftest$ac_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 :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ 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_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ 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. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_radutmp was given.
+if test "${with_rlm_radutmp+set}" = set; then :
+ withval=$with_rlm_radutmp;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_radutmp" != 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
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mman.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mman_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_MMAN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ targetname=rlm_radutmp
+else
+ targetname=
+ echo \*\*\* module rlm_radutmp is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_radutmp." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_radutmp." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_radutmp requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_radutmp requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_radutmp/configure.ac b/src/modules/rlm_radutmp/configure.ac
new file mode 100644
index 0000000..afac50e
--- /dev/null
+++ b/src/modules/rlm_radutmp/configure.ac
@@ -0,0 +1,18 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_radutmp.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_radutmp], [radutmp support])
+
+FR_MODULE_START_TESTS
+
+AC_CHECK_HEADERS(sys/mman.h)
+
+FR_MODULE_END_TESTS([nostrict])
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_radutmp/rlm_radutmp.c b/src/modules/rlm_radutmp/rlm_radutmp.c
new file mode 100644
index 0000000..b3d0037
--- /dev/null
+++ b/src/modules/rlm_radutmp/rlm_radutmp.c
@@ -0,0 +1,763 @@
+/*
+ * 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_radutmp.c
+ * @brief Tracks sessions.
+ *
+ * @copyright 2000-2013 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/radutmp.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <fcntl.h>
+
+#include "config.h"
+
+#define LOCK_LEN sizeof(struct radutmp)
+
+static char const porttypes[] = "ASITX";
+
+/*
+ * used for caching radutmp lookups in the accounting component. The
+ * session (checksimul) component doesn't use it, but probably should.
+ */
+typedef struct nas_port {
+ uint32_t nasaddr;
+ uint16_t port;
+ off_t offset;
+ struct nas_port *next;
+} NAS_PORT;
+
+typedef struct rlm_radutmp_t {
+ NAS_PORT *nas_port_list;
+ char const *filename;
+ char const *username;
+ bool case_sensitive;
+ bool check_nas;
+ uint32_t permission;
+ bool caller_id_ok;
+} rlm_radutmp_t;
+
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_radutmp_t, filename), RADUTMP },
+ { "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_radutmp_t, username), "%{User-Name}" },
+ { "case_sensitive", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, case_sensitive), "yes" },
+ { "check_with_nas", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, check_nas), "yes" },
+ { "perm", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_radutmp_t, permission), NULL },
+ { "permissions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_radutmp_t, permission), "0644" },
+ { "callerid", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_radutmp_t, caller_id_ok), NULL },
+ { "caller_id", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_radutmp_t, caller_id_ok), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Zap all users on a NAS from the radutmp file.
+ */
+static rlm_rcode_t radutmp_zap(REQUEST *request, char const *filename, uint32_t nasaddr, time_t t)
+{
+ struct radutmp u;
+ int fd;
+
+ if (t == 0) time(&t);
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ REDEBUG("Error accessing file %s: %s", filename, fr_syserror(errno));
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Lock the utmp file, prefer lockf() over flock().
+ */
+ if (rad_lockfd(fd, LOCK_LEN) < 0) {
+ REDEBUG("Failed to acquire lock on file %s: %s", filename, fr_syserror(errno));
+ close(fd);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Find the entry for this NAS / portno combination.
+ */
+ while (read(fd, &u, sizeof(u)) == sizeof(u)) {
+ if ((nasaddr != 0 && nasaddr != u.nas_address) || u.type != P_LOGIN) {
+ continue;
+ }
+ /*
+ * Match. Zap it.
+ */
+ if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
+ REDEBUG("radutmp_zap: negative lseek!");
+ lseek(fd, (off_t)0, SEEK_SET);
+ }
+ u.type = P_IDLE;
+ u.time = t;
+
+ if (write(fd, &u, sizeof(u)) < 0) {
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
+
+ close(fd);
+ return RLM_MODULE_FAIL;
+ }
+ }
+ close(fd); /* and implicitely release the locks */
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Lookup a NAS_PORT in the nas_port_list
+ */
+static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, uint16_t port)
+{
+ NAS_PORT *cl;
+
+ for(cl = nas_port_list; cl; cl = cl->next) {
+ if (nasaddr == cl->nasaddr &&
+ port == cl->port)
+ break;
+ }
+
+ return cl;
+}
+
+
+/*
+ * Store logins in the RADIUS utmp file.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ struct radutmp ut, u;
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+ int status = -1;
+ int protocol = -1;
+ time_t t;
+ int fd = -1;
+ bool port_seen = false;
+ int off;
+ rlm_radutmp_t *inst = instance;
+ char ip_name[32]; /* 255.255.255.255 */
+ char const *nas;
+ NAS_PORT *cache;
+ int r;
+
+ char *filename = NULL;
+ char *expanded = NULL;
+
+ if (request->packet->src_ipaddr.af != AF_INET) {
+ DEBUG("rlm_radutmp: IPv6 not supported!");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Which type is this.
+ */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY)) == NULL) {
+ RDEBUG("No Accounting-Status-Type record");
+ return RLM_MODULE_NOOP;
+ }
+ status = vp->vp_integer;
+
+ /*
+ * Look for weird reboot packets.
+ *
+ * ComOS (up to and including 3.5.1b20) does not send
+ * standard PW_STATUS_ACCOUNTING_XXX messages.
+ *
+ * Check for: o no Acct-Session-Time, or time of 0
+ * o Acct-Session-Id of "00000000".
+ *
+ * We could also check for NAS-Port, that attribute
+ * should NOT be present (but we don't right now).
+ */
+ if ((status != PW_STATUS_ACCOUNTING_ON) &&
+ (status != PW_STATUS_ACCOUNTING_OFF)) do {
+ int check1 = 0;
+ int check2 = 0;
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_SESSION_TIME, 0, TAG_ANY))
+ == NULL || vp->vp_date == 0)
+ check1 = 1;
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_SESSION_ID, 0, TAG_ANY))
+ != NULL && vp->vp_length == 8 &&
+ memcmp(vp->vp_strvalue, "00000000", 8) == 0)
+ check2 = 1;
+ if (check1 == 0 || check2 == 0) {
+ break;
+ }
+ INFO("rlm_radutmp: converting reboot records");
+ if (status == PW_STATUS_STOP)
+ status = PW_STATUS_ACCOUNTING_OFF;
+ if (status == PW_STATUS_START)
+ status = PW_STATUS_ACCOUNTING_ON;
+ } while(0);
+
+ time(&t);
+ memset(&ut, 0, sizeof(ut));
+ ut.porttype = 'A';
+ ut.nas_address = htonl(INADDR_NONE);
+
+ /*
+ * First, find the interesting attributes.
+ */
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ case PW_LOGIN_IP_HOST:
+ case PW_FRAMED_IP_ADDRESS:
+ ut.framed_address = vp->vp_ipaddr;
+ break;
+
+ case PW_FRAMED_PROTOCOL:
+ protocol = vp->vp_integer;
+ break;
+
+ case PW_NAS_IP_ADDRESS:
+ ut.nas_address = vp->vp_ipaddr;
+ break;
+
+ case PW_NAS_PORT:
+ ut.nas_port = vp->vp_integer;
+ port_seen = true;
+ break;
+
+ case PW_ACCT_DELAY_TIME:
+ ut.delay = vp->vp_integer;
+ break;
+
+ case PW_ACCT_SESSION_ID:
+ /*
+ * If length > 8, only store the
+ * last 8 bytes.
+ */
+ off = vp->vp_length - sizeof(ut.session_id);
+ /*
+ * Ascend is br0ken - it adds a \0
+ * to the end of any string.
+ * Compensate.
+ */
+ if (vp->vp_length > 0 &&
+ vp->vp_strvalue[vp->vp_length - 1] == 0)
+ off--;
+ if (off < 0) off = 0;
+ memcpy(ut.session_id, vp->vp_strvalue + off,
+ sizeof(ut.session_id));
+ break;
+
+ case PW_NAS_PORT_TYPE:
+ if (vp->vp_integer <= 4)
+ ut.porttype = porttypes[vp->vp_integer];
+ break;
+
+ case PW_CALLING_STATION_ID:
+ if (inst->caller_id_ok) strlcpy(ut.caller_id, vp->vp_strvalue, sizeof(ut.caller_id));
+ break;
+ }
+ }
+
+ /*
+ * If we didn't find out the NAS address, use the
+ * originator's IP address.
+ */
+ if (ut.nas_address == htonl(INADDR_NONE)) {
+ ut.nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ nas = request->client->shortname;
+
+ } else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr == ut.nas_address) { /* might be a client, might not be. */
+ nas = request->client->shortname;
+
+ } else {
+ /*
+ * The NAS isn't a client, it's behind
+ * a proxy server. In that case, just
+ * get the IP address.
+ */
+ nas = ip_ntoa(ip_name, ut.nas_address);
+ }
+
+ /*
+ * Set the protocol field.
+ */
+ if (protocol == PW_PPP) {
+ ut.proto = 'P';
+ } else if (protocol == PW_SLIP) {
+ ut.proto = 'S';
+ } else {
+ ut.proto = 'T';
+ }
+
+ ut.time = t - ut.delay;
+
+ /*
+ * Get the utmp filename, via xlat.
+ */
+ filename = NULL;
+ if (radius_axlat(&filename, request, inst->filename, NULL, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * See if this was a reboot.
+ *
+ * Hmm... we may not want to zap all of the users when the NAS comes up, because of issues with receiving
+ * UDP packets out of order.
+ */
+ if (status == PW_STATUS_ACCOUNTING_ON && (ut.nas_address != htonl(INADDR_NONE))) {
+ RIDEBUG("NAS %s restarted (Accounting-On packet seen)", nas);
+ rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
+
+ goto finish;
+ }
+
+ if (status == PW_STATUS_ACCOUNTING_OFF && (ut.nas_address != htonl(INADDR_NONE))) {
+ RIDEBUG("NAS %s rebooted (Accounting-Off packet seen)", nas);
+ rcode = radutmp_zap(request, filename, ut.nas_address, ut.time);
+
+ goto finish;
+ }
+
+ /*
+ * If we don't know this type of entry pretend we succeeded.
+ */
+ if (status != PW_STATUS_START && status != PW_STATUS_STOP && status != PW_STATUS_ALIVE) {
+ REDEBUG("NAS %s port %u unknown packet type %d)", nas, ut.nas_port, status);
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ /*
+ * Translate the User-Name attribute, or whatever else they told us to use.
+ */
+ if (radius_axlat(&expanded, request, inst->username, NULL, NULL) < 0) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+ strlcpy(ut.login, expanded, RUT_NAMESIZE);
+ TALLOC_FREE(expanded);
+
+ /*
+ * Perhaps we don't want to store this record into
+ * radutmp. We skip records:
+ *
+ * - without a NAS-Port (telnet / tcp access)
+ * - with the username "!root" (console admin login)
+ */
+ if (!port_seen) {
+ RWDEBUG2("No NAS-Port seen. Cannot do anything. Checkrad will probably not work!");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) {
+ RDEBUG2("Not recording administrative user");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ /*
+ * Enter into the radutmp file.
+ */
+ fd = open(filename, O_RDWR|O_CREAT, inst->permission);
+ if (fd < 0) {
+ REDEBUG("Error accessing file %s: %s", filename, fr_syserror(errno));
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ /*
+ * Lock the utmp file, prefer lockf() over flock().
+ */
+ if (rad_lockfd(fd, LOCK_LEN) < 0) {
+ REDEBUG("Error acquiring lock on %s: %s", filename, fr_syserror(errno));
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ /*
+ * Find the entry for this NAS / portno combination.
+ */
+ if ((cache = nas_port_find(inst->nas_port_list, ut.nas_address, ut.nas_port)) != NULL) {
+ if (lseek(fd, (off_t)cache->offset, SEEK_SET) < 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+
+ r = 0;
+ off = 0;
+ while (read(fd, &u, sizeof(u)) == sizeof(u)) {
+ off += sizeof(u);
+ if ((u.nas_address != ut.nas_address) || (u.nas_port != ut.nas_port)) {
+ continue;
+ }
+
+ /*
+ * Don't compare stop records to unused entries.
+ */
+ if (status == PW_STATUS_STOP && u.type == P_IDLE) {
+ continue;
+ }
+
+ if ((status == PW_STATUS_STOP) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) != 0) {
+ /*
+ * Don't complain if this is not a
+ * login record (some clients can
+ * send _only_ logout records).
+ */
+ if (u.type == P_LOGIN) {
+ RWDEBUG("Logout entry for NAS %s port %u has wrong ID", nas, u.nas_port);
+ }
+
+ r = -1;
+ break;
+ }
+
+ if ((status == PW_STATUS_START) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0 &&
+ u.time >= ut.time) {
+ if (u.type == P_LOGIN) {
+ INFO("rlm_radutmp: Login entry for NAS %s port %u duplicate",
+ nas, u.nas_port);
+ r = -1;
+ break;
+ }
+
+ RWDEBUG("Login entry for NAS %s port %u wrong order", nas, u.nas_port);
+ r = -1;
+ break;
+ }
+
+ /*
+ * FIXME: the ALIVE record could need some more checking, but anyway I'd
+ * rather rewrite this mess -- miquels.
+ */
+ if ((status == PW_STATUS_ALIVE) && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0 &&
+ u.type == P_LOGIN) {
+ /*
+ * Keep the original login time.
+ */
+ ut.time = u.time;
+ }
+
+ if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
+ RWDEBUG("negative lseek!");
+ lseek(fd, (off_t)0, SEEK_SET);
+ off = 0;
+ } else {
+ off -= sizeof(u);
+ }
+
+ r = 1;
+ break;
+ } /* read the file until we find a match */
+
+ /*
+ * Found the entry, do start/update it with
+ * the information from the packet.
+ */
+ if ((r >= 0) && (status == PW_STATUS_START || status == PW_STATUS_ALIVE)) {
+ /*
+ * Remember where the entry was, because it's
+ * easier than searching through the entire file.
+ */
+ if (!cache) {
+ cache = talloc_zero(NULL, NAS_PORT);
+ if (cache) {
+ cache->nasaddr = ut.nas_address;
+ cache->port = ut.nas_port;
+ cache->offset = off;
+ cache->next = inst->nas_port_list;
+ inst->nas_port_list = cache;
+ }
+ }
+
+ ut.type = P_LOGIN;
+ if (write(fd, &ut, sizeof(u)) < 0) {
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+
+ /*
+ * The user has logged off, delete the entry by
+ * re-writing it in place.
+ */
+ if (status == PW_STATUS_STOP) {
+ if (r > 0) {
+ u.type = P_IDLE;
+ u.time = ut.time;
+ u.delay = ut.delay;
+ if (write(fd, &u, sizeof(u)) < 0) {
+ REDEBUG("Failed writing: %s", fr_syserror(errno));
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ } else if (r == 0) {
+ RWDEBUG("Logout for NAS %s port %u, but no Login record", nas, ut.nas_port);
+ }
+ }
+
+ finish:
+
+ talloc_free(filename);
+
+ if (fd > -1) {
+ close(fd); /* and implicitely release the locks */
+ }
+
+ return rcode;
+}
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * See if a user is already logged in. Sets request->simul_count to the
+ * current session count for this user and sets request->simul_mpp to 2
+ * if it looks like a multilink attempt based on the requested IP
+ * address, otherwise leaves request->simul_mpp alone.
+ *
+ * Check twice. If on the first pass the user exceeds his
+ * max. number of logins, do a second pass and validate all
+ * logins by querying the terminal server (using eg. SNMP).
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ struct radutmp u;
+ int fd = -1;
+ VALUE_PAIR *vp;
+ uint32_t ipno = 0;
+ char const *call_num = NULL;
+ rlm_radutmp_t *inst = instance;
+
+ char *expanded = NULL;
+ ssize_t len;
+
+ /*
+ * Get the filename, via xlat.
+ */
+ if (radius_axlat(&expanded, request, inst->filename, NULL, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ fd = open(expanded, O_RDWR);
+ if (fd < 0) {
+ /*
+ * If the file doesn't exist, then no users
+ * are logged in.
+ */
+ if (errno == ENOENT) {
+ request->simul_count=0;
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Error accessing the file.
+ */
+ ERROR("rlm_radumtp: Error accessing file %s: %s", expanded, fr_syserror(errno));
+
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ TALLOC_FREE(expanded);
+
+ len = radius_axlat(&expanded, request, inst->username, NULL, NULL);
+ if (len < 0) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (!len) {
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ /*
+ * WTF? This is probably wrong... we probably want to
+ * be able to check users across multiple session accounting
+ * methods.
+ */
+ request->simul_count = 0;
+
+ /*
+ * Loop over utmp, counting how many people MAY be logged in.
+ */
+ while (read(fd, &u, sizeof(u)) == sizeof(u)) {
+ if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) ||
+ (!inst->case_sensitive && (strncasecmp(expanded, u.login, RUT_NAMESIZE) == 0))) &&
+ (u.type == P_LOGIN)) {
+ ++request->simul_count;
+ }
+ }
+
+ /*
+ * The number of users logged in is OK,
+ * OR, we've been told to not check the NAS.
+ */
+ if ((request->simul_count < request->simul_max) || !inst->check_nas) {
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+ lseek(fd, (off_t)0, SEEK_SET);
+
+ /*
+ * Setup some stuff, like for MPP detection.
+ */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
+ ipno = vp->vp_ipaddr;
+ }
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
+ call_num = vp->vp_strvalue;
+ }
+
+ /*
+ * lock the file while reading/writing.
+ */
+ rad_lockfd(fd, LOCK_LEN);
+
+ /*
+ * FIXME: If we get a 'Start' for a user/nas/port which is
+ * listed, but for which we did NOT get a 'Stop', then
+ * it's not a duplicate session. This happens with
+ * static IP's like DSL.
+ */
+ request->simul_count = 0;
+ while (read(fd, &u, sizeof(u)) == sizeof(u)) {
+ fr_ipaddr_t nasaddr;
+
+ if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) || (!inst->case_sensitive &&
+ (strncasecmp(expanded, u.login, RUT_NAMESIZE) == 0))) && (u.type == P_LOGIN)) {
+ char session_id[sizeof(u.session_id) + 1];
+ char utmp_login[sizeof(u.login) + 1];
+
+ /* Guarantee string is NULL terminated */
+ u.session_id[sizeof(u.session_id) - 1] = '\0';
+ strlcpy(session_id, u.session_id, sizeof(session_id));
+
+ /*
+ * The login name MAY fill the whole field,
+ * and thus won't be zero-filled.
+ *
+ * Note that we take the user name from
+ * the utmp file, as that's the canonical
+ * form. The 'login' variable may contain
+ * a string which is an upper/lowercase
+ * version of u.login. When we call the
+ * routine to check the terminal server,
+ * the NAS may be case sensitive.
+ *
+ * e.g. We ask if "bob" is using a port,
+ * and the NAS says "no", because "BOB"
+ * is using the port.
+ */
+ memset(utmp_login, 0, sizeof(utmp_login));
+ memcpy(utmp_login, u.login, sizeof(u.login));
+
+ nasaddr.af = AF_INET;
+ nasaddr.ipaddr.ip4addr.s_addr = u.nas_address;
+
+ /*
+ * rad_check_ts may take seconds
+ * to return, and we don't want
+ * to block everyone else while
+ * that's happening. */
+ rad_unlockfd(fd, LOCK_LEN);
+ rcode = rad_check_ts(&nasaddr, u.nas_port, NULL, utmp_login, session_id);
+ rad_lockfd(fd, LOCK_LEN);
+
+ if (rcode == 0) {
+ /*
+ * Stale record - zap it.
+ */
+ session_zap(request, &nasaddr, u.nas_port, NULL, expanded, session_id,
+ u.framed_address, u.proto, 0);
+ }
+ else if (rcode == 1) {
+ /*
+ * User is still logged in.
+ */
+ ++request->simul_count;
+
+ /*
+ * Does it look like a MPP attempt?
+ */
+ if (strchr("SCPA", u.proto) && ipno && u.framed_address == ipno) {
+ request->simul_mpp = 2;
+ } else if (strchr("SCPA", u.proto) && call_num && !strncmp(u.caller_id, call_num,16)) {
+ request->simul_mpp = 2;
+ }
+ } else {
+ RWDEBUG("Failed to check the terminal server for user '%s'.", utmp_login);
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+ }
+ }
+ finish:
+
+ talloc_free(expanded);
+
+ if (fd > -1) {
+ close(fd); /* and implicitely release the locks */
+ }
+
+ return rcode;
+}
+#endif
+
+/* globally exported name */
+extern module_t rlm_radutmp;
+module_t rlm_radutmp = {
+ .magic = RLM_MODULE_INIT,
+ .name = "radutmp",
+ .type = RLM_TYPE_THREAD_UNSAFE | RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_radutmp_t),
+ .config = module_config,
+ .methods = {
+#ifdef WITH_ACCOUNTING
+ [MOD_ACCOUNTING] = mod_accounting,
+#endif
+#ifdef WITH_SESSION_MGMT
+ [MOD_SESSION] = mod_checksimul
+#endif
+ },
+};
+
diff --git a/src/modules/rlm_realm/.gitignore b/src/modules/rlm_realm/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_realm/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_realm/README.md b/src/modules/rlm_realm/README.md
new file mode 100644
index 0000000..8f0d9cd
--- /dev/null
+++ b/src/modules/rlm_realm/README.md
@@ -0,0 +1,10 @@
+# rlm_realm
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Decode different format usernames and ensure that the correct
+proxy server is set based on the encoded realm.
diff --git a/src/modules/rlm_realm/all.mk.in b/src/modules/rlm_realm/all.mk.in
new file mode 100644
index 0000000..6795992
--- /dev/null
+++ b/src/modules/rlm_realm/all.mk.in
@@ -0,0 +1,17 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := rlm_realm.c
+
+TRUSTROUTER = @trustrouter@
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TRUSTROUTER)" ""
+TGT_LDLIBS += -ltr_tid
+SOURCES += trustrouter.c
+endif
diff --git a/src/modules/rlm_realm/configure b/src/modules/rlm_realm/configure
new file mode 100755
index 0000000..1620fac
--- /dev/null
+++ b/src/modules/rlm_realm/configure
@@ -0,0 +1,4438 @@
+#! /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_realm.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+trustrouter
+mod_ldflags
+mod_cflags
+targetname
+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_realm
+'
+ 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_realm build without rlm_realm
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_realm
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_realm was given.
+if test "${with_rlm_realm+set}" = set; then :
+ withval=$with_rlm_realm;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_realm" != xno; then
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+sm_lib_safe=`echo "tr_tid" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "tidc_create" | 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 tidc_create in -ltr_tid in $try" >&5
+$as_echo_n "checking for tidc_create in -ltr_tid in $try... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tidc_create();
+int
+main ()
+{
+tidc_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ 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 tidc_create in -ltr_tid" >&5
+$as_echo_n "checking for tidc_create in -ltr_tid... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tidc_create();
+int
+main ()
+{
+tidc_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ { $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 tidc_create in -ltr_tid in $try" >&5
+$as_echo_n "checking for tidc_create in -ltr_tid in $try... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tidc_create();
+int
+main ()
+{
+tidc_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ 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
+
+
+
+sm_lib_safe=`echo "tr_tid" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "tid_srvr_get_key_expiration" | 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 tid_srvr_get_key_expiration in -ltr_tid in $try" >&5
+$as_echo_n "checking for tid_srvr_get_key_expiration in -ltr_tid in $try... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tid_srvr_get_key_expiration();
+int
+main ()
+{
+tid_srvr_get_key_expiration()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ 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 tid_srvr_get_key_expiration in -ltr_tid" >&5
+$as_echo_n "checking for tid_srvr_get_key_expiration in -ltr_tid... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tid_srvr_get_key_expiration();
+int
+main ()
+{
+tid_srvr_get_key_expiration()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ { $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 tid_srvr_get_key_expiration in -ltr_tid in $try" >&5
+$as_echo_n "checking for tid_srvr_get_key_expiration in -ltr_tid in $try... " >&6; }
+ LIBS="-ltr_tid $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char tid_srvr_get_key_expiration();
+int
+main ()
+{
+tid_srvr_get_key_expiration()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ltr_tid"
+ 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
+
+
+
+ac_safe=`echo "trust_router/tr_dh.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 trust_router/tr_dh.h in $try" >&5
+$as_echo_n "checking for trust_router/tr_dh.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <trust_router/tr_dh.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}/trust_router/tr_dh.h" >&5
+$as_echo_n "checking for ${_prefix}/trust_router/tr_dh.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <trust_router/tr_dh.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 trust_router/tr_dh.h" >&5
+$as_echo_n "checking for trust_router/tr_dh.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <trust_router/tr_dh.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 trust_router/tr_dh.h in $try" >&5
+$as_echo_n "checking for trust_router/tr_dh.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <trust_router/tr_dh.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=
+
+
+trustrouter=
+
+if test "x$ac_cv_lib_tr_tid_tidc_create" != "x"; then
+ if test "x$ac_cv_header_trust_router_tr_dh_h" != "x"; then
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_TRUST_ROUTER_TR_DH_H"
+ trustrouter=yes
+ if test "x$ac_cv_lib_tr_tid_tid_srvr_get_key_expiration" != "x"; then
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_TRUST_ROUTER_GET_KEY_EXP"
+ fi
+
+if echo "$fr_features" | grep -q "+trustrouter+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with trust router support" >> config.report.tmp
+ fr_features="$fr_features +trustrouter+"
+fi
+
+ fi
+fi
+
+
+ targetname=rlm_realm
+else
+ targetname=
+ echo \*\*\* module rlm_realm is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_realm to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_realm." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_realm." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_realm requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_realm requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_realm/configure.ac b/src/modules/rlm_realm/configure.ac
new file mode 100644
index 0000000..3e878f7
--- /dev/null
+++ b/src/modules/rlm_realm/configure.ac
@@ -0,0 +1,39 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_realm.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_realm])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_SMART_CHECK_LIB(tr_tid, tidc_create)
+FR_SMART_CHECK_LIB(tr_tid, tid_srvr_get_key_expiration)
+FR_SMART_CHECK_INCLUDE(trust_router/tr_dh.h)
+
+trustrouter=
+
+if test "x$ac_cv_lib_tr_tid_tidc_create" != "x"; then
+ if test "x$ac_cv_header_trust_router_tr_dh_h" != "x"; then
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_TRUST_ROUTER_TR_DH_H"
+ trustrouter=yes
+ if test "x$ac_cv_lib_tr_tid_tid_srvr_get_key_expiration" != "x"; then
+ SMART_CPPFLAGS="$SMART_CPPFLAGS -DHAVE_TRUST_ROUTER_GET_KEY_EXP"
+ fi
+ FR_MODULE_FEATURE([trustrouter], [with trust router support])
+ fi
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+AC_SUBST(trustrouter)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_realm/rlm_realm.c b/src/modules/rlm_realm/rlm_realm.c
new file mode 100644
index 0000000..3f7e3fb
--- /dev/null
+++ b/src/modules/rlm_realm/rlm_realm.c
@@ -0,0 +1,542 @@
+/*
+ * 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_realm.c
+ * @brief Parses NAIs and assigns requests to realms.
+ *
+ * @copyright 2000-2013 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "trustrouter.h"
+
+#define REALM_FORMAT_PREFIX 0
+#define REALM_FORMAT_SUFFIX 1
+
+typedef struct rlm_realm_t {
+ int format;
+ char const *format_string;
+ char const *delim;
+ bool ignore_default;
+ bool ignore_null;
+
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+ char const *default_community;
+ char const *rp_realm;
+ char const *trust_router;
+ uint32_t tr_port;
+ bool rekey_enabled;
+ uint32_t realm_lifetime;
+#endif
+} rlm_realm_t;
+
+static CONF_PARSER module_config[] = {
+ { "format", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_realm_t, format_string), "suffix" },
+ { "delimiter", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_realm_t, delim), "@" },
+ { "ignore_default", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_realm_t, ignore_default), "no" },
+ { "ignore_null", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_realm_t, ignore_null), "no" },
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+ { "default_community", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_realm_t, default_community), "none" },
+ { "rp_realm", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_realm_t, rp_realm), "none" },
+ { "trust_router", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_realm_t, trust_router), "none" },
+ { "tr_port", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_realm_t, tr_port), "0" },
+ { "rekey_enabled", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_realm_t, rekey_enabled), "no" },
+ { "realm_lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_realm_t, realm_lifetime), "0" },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Internal function to cut down on duplicated code.
+ *
+ * Returns -1 on failure, 0 on no failure. returnrealm
+ * is NULL on don't proxy, realm otherwise.
+ */
+static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
+{
+ char *namebuf;
+ char *username;
+ char const *realmname = NULL;
+ char *ptr;
+ VALUE_PAIR *vp;
+ REALM *realm;
+
+ struct rlm_realm_t *inst = instance;
+
+ /* initiate returnrealm */
+ *returnrealm = NULL;
+
+ /*
+ * If the request has a proxy entry, then it's a proxy
+ * reply, and we're walking through the module list again.
+ *
+ * In that case, don't bother trying to proxy the request
+ * again.
+ *
+ * Also, if there's no User-Name attribute, we can't
+ * proxy it, either.
+ */
+ if ((!request->username)
+#ifdef WITH_PROXY
+ || (request->proxy != NULL)
+#endif
+ ) {
+
+ RDEBUG2("Proxy reply, or no User-Name. Ignoring");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Check for 'Realm' attribute. If it exists, then we've proxied
+ * it already ( via another rlm_realm instance ) and should return.
+ */
+
+ if (fr_pair_find_by_num(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL ) {
+ RDEBUG2("Request already has destination realm set. Ignoring");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * We will be modifing this later, so we want our own copy
+ * of it.
+ */
+ namebuf = talloc_typed_strdup(request, request->username->vp_strvalue);
+ username = namebuf;
+
+ switch (inst->format) {
+ case REALM_FORMAT_SUFFIX:
+ RDEBUG2("Checking for suffix after \"%c\"", inst->delim[0]);
+ ptr = strrchr(username, inst->delim[0]);
+ if (ptr) {
+ *ptr = '\0';
+ realmname = ptr + 1;
+ }
+ break;
+
+ case REALM_FORMAT_PREFIX:
+ RDEBUG2("Checking for prefix before \"%c\"", inst->delim[0]);
+ ptr = strchr(username, inst->delim[0]);
+ if (ptr) {
+ *ptr = '\0';
+ ptr++;
+ realmname = username;
+ username = ptr;
+ }
+ break;
+
+ default:
+ realmname = NULL;
+ break;
+ }
+
+ /*
+ * Print out excruciatingly descriptive debugging messages
+ * for the people who find it too difficult to think about
+ * what's going on.
+ */
+ if (realmname) {
+ RDEBUG2("Looking up realm \"%s\" for User-Name = \"%s\"",
+ realmname, request->username->vp_strvalue);
+ } else {
+ if (inst->ignore_null ) {
+ RDEBUG2("No '%c' in User-Name = \"%s\", skipping NULL due to config.",
+ inst->delim[0], request->username->vp_strvalue);
+ talloc_free(namebuf);
+ return RLM_MODULE_NOOP;
+ }
+ RDEBUG2("No '%c' in User-Name = \"%s\", looking up realm NULL",
+ inst->delim[0], request->username->vp_strvalue);
+ }
+
+ /*
+ * Allow DEFAULT realms unless told not to.
+ */
+ realm = realm_find(realmname);
+
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+ /*
+ * Try querying for the dynamic realm.
+ */
+ if (!realm) {
+ if (inst->trust_router) {
+ realm = tr_query_realm(request, realmname, inst->default_community, inst->rp_realm,
+ inst->trust_router, inst->tr_port);
+ }
+ else {
+ RDEBUG2("No trust router configured, skipping dynamic realm lookup");
+ }
+ }
+#endif
+
+ if (!realm) {
+ RDEBUG2("No such realm \"%s\"", (!realmname) ? "NULL" : realmname);
+ talloc_free(namebuf);
+ return RLM_MODULE_NOOP;
+ }
+
+ if (inst->ignore_default && (strcmp(realm->name, "DEFAULT")) == 0) {
+ RDEBUG2("Found DEFAULT, but skipping due to config");
+ talloc_free(namebuf);
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("Found realm \"%s\"", realm->name);
+
+ /*
+ * If we've been told to strip the realm off, then do so.
+ */
+ if (realm->strip_realm) {
+ /*
+ * Create the Stripped-User-Name attribute, if it
+ * doesn't exist.
+ *
+ */
+ if (request->username->da->attr != PW_STRIPPED_USER_NAME) {
+ vp = radius_pair_create(request->packet, &request->packet->vps,
+ PW_STRIPPED_USER_NAME, 0);
+ RDEBUG2("Adding Stripped-User-Name = \"%s\"", username);
+ } else {
+ vp = request->username;
+ RDEBUG2("Setting Stripped-User-Name = \"%s\"", username);
+ }
+
+ fr_pair_value_strcpy(vp, username);
+ request->username = vp;
+ }
+
+ /*
+ * Add the realm name to the request.
+ * If the realm is a regex, the use the realm as entered
+ * by the user. Otherwise, use the configured realm name,
+ * as realm name comparison is case insensitive. We want
+ * to use the configured name, rather than what the user
+ * entered.
+ */
+ if (realm->name[0] != '~') realmname = realm->name;
+
+ /*
+ * A NULL realmname is allowed.
+ */
+ if (realmname) {
+ pair_make_request("Realm", realmname, T_OP_EQ);
+ RDEBUG2("Adding Realm = \"%s\"", realmname);
+ }
+
+ talloc_free(namebuf);
+ username = NULL;
+
+ /*
+ * Figure out what to do with the request.
+ */
+ switch (request->packet->code) {
+ default:
+ RDEBUG2("Unknown packet code %d\n",
+ request->packet->code);
+ return RLM_MODULE_NOOP;
+
+ /*
+ * Perhaps accounting proxying was turned off.
+ */
+ case PW_CODE_ACCOUNTING_REQUEST:
+ if (!realm->acct_pool) {
+ RDEBUG2("Accounting realm is LOCAL");
+ return RLM_MODULE_OK;
+ }
+ break;
+
+ /*
+ * Perhaps authentication proxying was turned off.
+ */
+ case PW_CODE_ACCESS_REQUEST:
+ if (!realm->auth_pool) {
+ RDEBUG2("Authentication realm is LOCAL");
+ return RLM_MODULE_OK;
+ }
+ break;
+ }
+
+#ifdef WITH_PROXY
+ RDEBUG2("Proxying request from user %s to realm %s",
+ request->username->vp_strvalue, realm->name);
+
+ /*
+ * Skip additional checks if it's not an accounting
+ * request.
+ */
+ if (request->packet->code != PW_CODE_ACCOUNTING_REQUEST) {
+ *returnrealm = realm;
+ return RLM_MODULE_UPDATED;
+ }
+
+ /*
+ * FIXME: Each server should have a unique server key,
+ * and put it in the accounting packet. Every server
+ * should know about the keys, and NOT proxy requests to
+ * a server with key X if the packet already contains key
+ * X.
+ */
+
+ /*
+ * If this request has arrived from another freeradius server
+ * that has already proxied the request, we don't need to do
+ * it again.
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_FREERADIUS_PROXIED_TO, 0, TAG_ANY);
+ if (vp && (request->packet->src_ipaddr.af == AF_INET)) {
+ int i;
+ fr_ipaddr_t my_ipaddr;
+
+ my_ipaddr.af = AF_INET;
+ my_ipaddr.prefix = 32;
+ my_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
+
+ /*
+ * Loop over the home accounting servers for this
+ * realm. If one of them has the same IP as the
+ * FreeRADIUS-Proxied-To attribute, then the
+ * packet has already been sent there. Don't
+ * send it there again.
+ */
+ for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
+ if (realm->acct_pool->servers[i]->ipaddr.af == AF_UNSPEC) continue;
+
+ if (fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr, &my_ipaddr) == 0) {
+ RDEBUG2("Suppressing proxy due to FreeRADIUS-Proxied-To");
+ return RLM_MODULE_OK;
+ }
+ }
+
+ /*
+ * See detail_recv() in src/main/listen.c for the
+ * additional checks.
+ */
+#ifdef WITH_DETAIL
+ } else if ((request->listener->type == RAD_LISTEN_DETAIL) &&
+ !fr_inaddr_any(&request->packet->src_ipaddr)) {
+ int i;
+
+ /*
+ * Loop over the home accounting servers for this
+ * realm. If one of them has the same IP as the
+ * FreeRADIUS-Proxied-To attribute, then the
+ * packet has already been sent there. Don't
+ * send it there again.
+ */
+ for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
+ if (realm->acct_pool->servers[i]->ipaddr.af == AF_UNSPEC) continue;
+
+ if ((fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr,
+ &request->packet->src_ipaddr) == 0) &&
+ (realm->acct_pool->servers[i]->port == request->packet->src_port)) {
+ RDEBUG2("Suppressing proxy because packet was already sent to a server in that realm");
+ return RLM_MODULE_OK;
+ }
+ }
+#endif /* WITH_DETAIL */
+ }
+#endif /* WITH_PROXY */
+
+ /*
+ * We got this far, which means we have a realm, set returnrealm
+ */
+ *returnrealm = realm;
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * Perform the realm module instantiation. Configuration info is
+ * stored in *instance for later use.
+ */
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ struct rlm_realm_t *inst = instance;
+
+ if (strcasecmp(inst->format_string, "suffix") == 0) {
+ inst->format = REALM_FORMAT_SUFFIX;
+
+ } else if (strcasecmp(inst->format_string, "prefix") == 0) {
+ inst->format = REALM_FORMAT_PREFIX;
+
+ } else {
+ cf_log_err_cs(conf, "Invalid value \"%s\" for format",
+ inst->format_string);
+ return -1;
+ }
+
+ if (cf_new_escape && (strcmp(inst->delim, "\\\\") == 0)) {
+ /* it's OK */
+ } else
+
+ if (strlen(inst->delim) != 1) {
+ cf_log_err_cs(conf, "Invalid value \"%s\" for delimiter",
+ inst->delim);
+ return -1;
+ }
+
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+ /* initialize the trust router integration code */
+ if (strcmp(inst->trust_router, "none") != 0) {
+ if (!tr_init(inst->rekey_enabled, inst->realm_lifetime)) return -1;
+ } else {
+ rad_const_free(inst->trust_router);
+ inst->trust_router = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+
+/*
+ * Examine a request for a username with an realm, and if it
+ * corresponds to something in the realms file, set that realm as
+ * Proxy-To.
+ *
+ * This should very nearly duplicate the old proxy_send() code
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode;
+ REALM *realm;
+
+ /*
+ * Check if we've got to proxy the request.
+ * If not, return without adding a Proxy-To-Realm
+ * attribute.
+ */
+ rcode = check_for_realm(instance, request, &realm);
+ if (rcode != RLM_MODULE_UPDATED) return rcode;
+ if (!realm) return RLM_MODULE_NOOP;
+
+ /*
+ * Maybe add a Proxy-To-Realm attribute to the request.
+ */
+ RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n",
+ realm->name);
+ pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
+
+ return RLM_MODULE_UPDATED; /* try the next module */
+}
+
+/*
+ * This does the exact same thing as the mod_authorize, it's just called
+ * differently.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
+{
+ int rcode;
+ REALM *realm;
+
+ if (!request->username) {
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Check if we've got to proxy the request.
+ * If not, return without adding a Proxy-To-Realm
+ * attribute.
+ */
+ rcode = check_for_realm(instance, request, &realm);
+ if (rcode != RLM_MODULE_UPDATED) return rcode;
+ if (!realm) return RLM_MODULE_NOOP;
+
+ /*
+ * Maybe add a Proxy-To-Realm attribute to the request.
+ */
+ RDEBUG2("Preparing to proxy accounting request to realm \"%s\"\n",
+ realm->name);
+ pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
+
+ return RLM_MODULE_UPDATED; /* try the next module */
+}
+
+#ifdef WITH_COA
+/*
+ * CoA realms via Operator-Name. Because the realm isn't in a
+ * User-Name, concepts like "prefix" and "suffix' don't matter.
+ */
+static rlm_rcode_t mod_realm_recv_coa(UNUSED void *instance, REQUEST *request)
+{
+ VALUE_PAIR *vp;
+ REALM *realm;
+
+ if (fr_pair_find_by_num(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL) {
+ RDEBUG2("Request already has destination realm set. Ignoring");
+ return RLM_MODULE_NOOP;
+ }
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_OPERATOR_NAME, 0, TAG_ANY);
+ if (!vp) return RLM_MODULE_NOOP;
+
+ /*
+ * Catch the case of broken dictionaries.
+ */
+ if (vp->da->type != PW_TYPE_STRING) return RLM_MODULE_NOOP;
+
+ /*
+ * The string is too short.
+ */
+ if (vp->vp_length == 1) return RLM_MODULE_NOOP;
+
+ /*
+ * '1' means "the rest of the string is a realm"
+ */
+ if (vp->vp_strvalue[0] != '1') return RLM_MODULE_NOOP;
+
+ realm = realm_find(vp->vp_strvalue + 1);
+ if (!realm) return RLM_MODULE_NOTFOUND;
+
+ if (!realm->coa_pool) {
+ RDEBUG2("CoA realm is LOCAL");
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Maybe add a Proxy-To-Realm attribute to the request.
+ */
+ RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n",
+ realm->name);
+ pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
+
+ return RLM_MODULE_UPDATED; /* try the next module */
+}
+#endif
+
+/* globally exported name */
+extern module_t rlm_realm;
+module_t rlm_realm = {
+ .magic = RLM_MODULE_INIT,
+ .name = "realm",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(struct rlm_realm_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_realm_recv_coa
+#endif
+ },
+};
+
diff --git a/src/modules/rlm_realm/trustrouter.c b/src/modules/rlm_realm/trustrouter.c
new file mode 100644
index 0000000..c62edea
--- /dev/null
+++ b/src/modules/rlm_realm/trustrouter.c
@@ -0,0 +1,715 @@
+/*
+ * 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 trustrouter.c
+ * @brief Integration with external trust router code
+ *
+ * @copyright 2014 Network RADIUS SARL
+ */
+#include <trust_router/tid.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/realms.h>
+
+#ifdef HAVE_TRUST_ROUTER_TR_DH_H
+#include "trustrouter.h"
+
+#include <trust_router/tr_dh.h>
+#include <ctype.h>
+
+struct resp_opaque {
+ REALM *orig_realm;
+ REALM *output_realm;
+ TID_RC result;
+ char err_msg[1024];
+ char *fr_realm_name;
+};
+
+/*
+ * This structure represents a rekey context. It is created once a new REALM is added to the REALM rbtree and it
+ * contains the values required to recreate the TIDC request that originated that REALM.
+ */
+struct rekey_ctx {
+ REALM *realm;
+ char const *realm_name;
+ char const *community;
+ char const *rprealm;
+ char const *trustrouter;
+ unsigned int port;
+ unsigned int times;
+ unsigned int failed;
+ fr_event_t *ev;
+};
+
+/* Thread, event list, and mutexes to protect access to the event list */
+static pthread_t rekeyer_thread_id;
+static fr_event_list_t *rekey_evl = NULL;
+static pthread_mutex_t evl_mutex;
+static pthread_mutexattr_t evl_mutex_attr;
+
+/* Mutex to control concurrent acceses to the realm tree */
+static pthread_mutex_t realm_tree_mutex;
+
+/* Mutexes to serialise TID queries for the same realm */
+#define REALM_MUTEX_MAX 16
+static pthread_mutex_t realm_mutex[REALM_MUTEX_MAX];
+
+/* Constant declarations */
+static uint MAX_FAILED_REKEYS = 5; // Max number of tolerable consecutive rekey errors
+static uint REKEY_ERROR_DELAY = 10; // Number of seconds we wait until we start a new rekey after a failure
+static uint REKEY_THRESHOLD = 60; // Number of seconds before the REALM expires to start a rekey
+
+/* Configuration parameters */
+static uint32_t realm_lifetime = 0; // Number of seconds the REALM can be used
+static bool rekey_enabled = false; // Is the rekey functionality enabled?
+
+/* Forward declarations */
+static void tr_response_func(TIDC_INSTANCE*, TID_REQ*, TID_RESP*, void*);
+static void _tr_do_rekey(void *);
+
+/* Copied from dict_hashname */
+#define FNV_MAGIC_INIT (0x811c9dc5)
+#define FNV_MAGIC_PRIME (0x01000193)
+
+static uint32_t realm_name_hash(const char* realm_name)
+{
+ uint32_t hash = FNV_MAGIC_INIT;
+ char const *p;
+
+ for (p = realm_name; *p != '\0'; p++) {
+ int c = *(unsigned char const *) p;
+ if (isalpha(c)) c = tolower(c);
+
+ hash *= FNV_MAGIC_PRIME;
+ hash ^= (uint32_t ) (c & 0xff);
+ }
+
+ return hash % REALM_MUTEX_MAX;
+}
+
+static void realm_lock(const char *realm_name)
+{
+ int index = realm_name_hash(realm_name);
+ DEBUG2("Locking realm %s using mutex %d", realm_name, index);
+ pthread_mutex_lock(&realm_mutex[index]);
+}
+
+static void realm_unlock(const char *realm_name)
+{
+ int index = realm_name_hash(realm_name);
+ DEBUG2("Unlocking realm %s using mutex %d", realm_name, index);
+ pthread_mutex_unlock(&realm_mutex[index]);
+}
+
+/*
+ * Builds a rekey_ctx context using the given parameters.
+ * Memory context is attached to the REALM object, whereas all the char* fields are copied.
+ */
+static struct rekey_ctx *build_rekey_ctx(REALM *realm, char const *realm_name, char const *community,
+ char const *rprealm, const char *trustrouter, int port)
+{
+ struct rekey_ctx *ctx = talloc_zero(realm, struct rekey_ctx);
+ ctx->realm = realm;
+ ctx->realm_name = talloc_strdup(ctx, realm_name);
+ ctx->community = talloc_strdup(ctx, community);
+ ctx->rprealm = talloc_strdup(ctx, rprealm);
+ ctx->trustrouter = talloc_strdup(ctx, trustrouter);
+ ctx->port = port;
+ ctx->times = 0;
+ ctx->ev = NULL;
+ return ctx;
+}
+
+/*
+ * Main function for the rekeyer thread, which implements the rekey event loop.
+ * A recursive lock is used to protect access to the event list, which might receive insertions from
+ * other threads (i.e. REQUESTS).
+ * If there are no rekey events to be executed, it sleeps for 1 second.
+ */
+void *rekeyer_thread(UNUSED void* args)
+{
+ struct timeval when;
+ int rv = 0;
+ while (true) {
+ gettimeofday(&when, NULL);
+ pthread_mutex_lock(&evl_mutex);
+ rv = fr_event_run(rekey_evl, &when);
+ // DEBUG2("REALMs to be rekeyed: %d. Next rekey event in %lu seconds",
+ // fr_event_list_num_elements(rekey_evl), when.tv_sec - time(NULL));
+ pthread_mutex_unlock(&evl_mutex);
+ if (!rv) sleep(1);
+ }
+ return NULL;
+}
+
+/*
+ * Sends a TIDC request and fills up the provided cookie with the response.
+ * Returns FALSE if a response cannot be obtained for some reason (e.g. cannot connect to the TR)
+ */
+static bool tidc_send_recv(const char *trustrouter, int port, const char *rprealm, const char *realm_name,
+ const char *community, struct resp_opaque *cookie)
+{
+ gss_ctx_id_t gssctx;
+ int conn = 0;
+ int rcode;
+ bool result = false;
+
+ /* Open TIDC connection */
+ DEBUG2("Opening TIDC connection to %s:%u for resolving realm %s", trustrouter, port, realm_name);
+ TIDC_INSTANCE *tidc = tidc_create();
+ if (!tidc) {
+ DEBUG2( "tr_init: Error creating global TIDC instance.\n");
+ goto cleanup;
+ }
+
+ if (!tidc_set_dh(tidc, tr_create_dh_params(NULL, 0))) {
+ DEBUG2( "tr_init: Error creating client DH params.\n");
+ goto cleanup;
+ }
+
+
+ conn = tidc_open_connection(tidc, (char *) trustrouter, port, &gssctx);
+ if (conn < 0) {
+ DEBUG2("Error in tidc_open_connection.");
+ goto cleanup;
+ }
+
+ /* Send TIDC request */
+ rcode = tidc_send_request(tidc, conn, gssctx, (char *) rprealm, (char *) realm_name,
+ (char *) community, &tr_response_func, cookie);
+ if (rcode < 0) {
+ DEBUG2("Error in tidc_send_request for %s, rc = %d.", realm_name, rcode);
+ goto cleanup;
+ }
+
+ result = true;
+cleanup:
+ tidc_destroy(tidc);
+ return result;
+}
+
+/*
+ * Gets the maximum expiration time of the realm's auth pool.
+ */
+static time_t get_realm_expiration(REALM const *realm)
+{
+ time_t expiration = 0;
+ for (int i = 0; i < realm->auth_pool->num_home_servers; i++) {
+ home_server_t *server = realm->auth_pool->servers[i];
+ if (server->expiration > expiration)
+ expiration = server->expiration;
+ }
+ return expiration;
+}
+
+/*
+ * Schedules a rekey event with the indicated context by inserting a new event in the list.
+ * It uses the evl_mutex to make sure no other thread accesses the event list at the same time.
+ */
+static int schedule_rekey(struct rekey_ctx *rekey_ctx)
+{
+ int rv = 0;
+ struct timeval when;
+ gettimeofday(&when, NULL);
+ pthread_mutex_lock(&evl_mutex);
+ /* If last attempt was a failure, schedule a rekey in REKEY_ERROR_DELAY seconds.
+ * Else, schedule the rekey for REKEY_THRESHOLD seconds before the actual REALM expiration.
+ */
+ if (rekey_ctx->failed)
+ when.tv_sec += REKEY_ERROR_DELAY;
+ else
+ when.tv_sec = get_realm_expiration(rekey_ctx->realm) - REKEY_THRESHOLD;
+
+ rv = fr_event_insert(rekey_evl, _tr_do_rekey, rekey_ctx, &when, &rekey_ctx->ev);
+ pthread_mutex_unlock(&evl_mutex);
+ DEBUG2("Scheduled a rekey for realm %s in %lu seconds", rekey_ctx->realm_name, when.tv_sec - time(NULL));
+ return rv;
+}
+
+/*
+ * Callback that performs the actual rekey of a REALM. It receives a rekey_ctx which is used to replicate the
+ * original TIDC query. If the request is sucessful, a new rekey is scheduled based on the expiration lifetime and
+ * the configured threshold (REKEY_THRESHOLD).
+ * When a failure is found, a new rekey is scheduled in a shorter period of time (REKEY_ERROR_DELAY).
+ */
+static void _tr_do_rekey(void *ctx){
+ struct rekey_ctx *rekey_ctx = (struct rekey_ctx *) ctx;
+ bool result;
+ struct resp_opaque cookie;
+
+ /* clear the cookie structure and copy values from the rekey context */
+ memset (&cookie, 0, sizeof(cookie));
+ cookie.fr_realm_name = (char*) rekey_ctx->realm->name;
+ cookie.orig_realm = rekey_ctx->realm;
+
+ DEBUG2("Rekeying realm %s for the %dth time", rekey_ctx->realm_name, ++rekey_ctx->times);
+
+ /* send the TIDC request and get the response. Use REALM mutext */
+ realm_lock(rekey_ctx->realm_name);
+ result = tidc_send_recv(rekey_ctx->trustrouter, rekey_ctx->port, rekey_ctx->rprealm,
+ rekey_ctx->realm_name, rekey_ctx->community, &cookie);
+ realm_unlock(rekey_ctx->realm_name);
+
+ /* If the rekey failed, schedule a new rekey in REKEY_ERROR_DELAY seconds, unless we have failed more
+ than MAX_FAILED_REKEYS times in a row. In that case, return without scheduling a rekey */
+ if (!result || cookie.result != TID_SUCCESS) {
+ if (++rekey_ctx->failed >= MAX_FAILED_REKEYS) {
+ DEBUG2("Reached the maximum number of failed rekeys (%d) for realm %s. Giving up.",
+ MAX_FAILED_REKEYS, rekey_ctx->realm_name);
+ talloc_free(rekey_ctx);
+ return;
+ }
+ DEBUG2("Rekey for realm %s failed for the %dth time.", rekey_ctx->realm_name, rekey_ctx->failed);
+ }
+ /* if rekey is successful, reset the failed counter */
+ else {
+ rekey_ctx->failed = 0;
+ }
+
+ /* schedule the new rekey */
+ if (!schedule_rekey(rekey_ctx)){
+ DEBUG2("Error scheduling rekey event for realm %s!", rekey_ctx->realm_name);
+ talloc_free(rekey_ctx);
+ }
+}
+
+bool tr_init(bool cnf_rekey_enabled, uint32_t cnf_realm_lifetime)
+{
+ int i = 0;
+ DEBUG2( "tr_init: Init Trust Router module.\n");
+
+ realm_lifetime = cnf_realm_lifetime;
+ rekey_enabled = cnf_rekey_enabled;
+
+ /* create the locks */
+ pthread_mutex_init(&realm_tree_mutex, NULL);
+ for (i=0; i<REALM_MUTEX_MAX; i++)
+ pthread_mutex_init(&realm_mutex[i], NULL);
+
+ /* If rekey is enabled, set up and create the rekeyer thread, event list and event mutex (recursive) */
+ if (rekey_enabled) {
+ rekey_evl = fr_event_list_create(NULL, NULL);
+ pthread_mutexattr_init(&evl_mutex_attr);
+ pthread_mutexattr_settype(&evl_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&evl_mutex, &evl_mutex_attr);
+ pthread_create(&rekeyer_thread_id, NULL, rekeyer_thread, NULL);
+ }
+
+ return true;
+}
+
+static fr_tls_server_conf_t *construct_tls(TIDC_INSTANCE *inst,
+ home_server_t *hs,
+ TID_SRVR_BLK *server)
+{
+ fr_tls_server_conf_t *tls;
+ unsigned char *key_buf = NULL;
+ ssize_t keylen = 0;
+ char *hexbuf = NULL;
+ DH *aaa_server_dh;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ const BIGNUM *dh_pubkey = NULL;
+#endif
+
+ tls = tls_server_conf_alloc(hs);
+ if (!tls) return NULL;
+
+ aaa_server_dh = tid_srvr_get_dh(server);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ DH_get0_key(aaa_server_dh, &dh_pubkey, NULL);
+ if (NULL == dh_pubkey) {
+ DEBUG2("DH error");
+ goto error;
+ }
+
+ keylen = tr_compute_dh_key(&key_buf, BN_dup(dh_pubkey),
+ tidc_get_dh(inst));
+#else
+ keylen = tr_compute_dh_key(&key_buf, aaa_server_dh->pub_key,
+ tidc_get_dh(inst));
+#endif
+ if (keylen <= 0) {
+ DEBUG2("DH error");
+ goto error;
+ }
+
+ hexbuf = talloc_size(tls, keylen*2 + 1);
+ if (!hexbuf) goto error;
+
+ tr_bin_to_hex(key_buf, keylen, hexbuf, 2*keylen + 1);
+
+ tls->psk_password = hexbuf;
+ tls->psk_identity = talloc_strdup(tls, tid_srvr_get_key_name(server)->buf);
+
+ tls->cipher_list = talloc_strdup(tls, "aPSK");
+ tls->fragment_size = 4200;
+ tls->ctx = tls_init_ctx(tls, 1, NULL, NULL);
+ if (!tls->ctx) goto error;
+
+ memset(key_buf, 0, keylen);
+ tr_dh_free(key_buf);
+ return tls;
+
+error:
+ if (key_buf) {
+ memset(key_buf, 0, keylen);
+ tr_dh_free(key_buf);
+ }
+ if (hexbuf) memset(hexbuf, 0, keylen*2);
+
+ if (tls) talloc_free(tls);
+ return NULL;
+}
+
+static char *build_pool_name(TALLOC_CTX *ctx, TID_RESP *resp)
+{
+ size_t index, sa_len, sl;
+ TID_SRVR_BLK *server;
+ char *pool_name = NULL;
+ char addr_buf[256];
+ const struct sockaddr *sa;
+ pool_name = talloc_strdup(ctx, "hp-");
+
+ tid_resp_servers_foreach(resp, server, index) {
+ tid_srvr_get_address(server, &sa, &sa_len);
+ if (0 != getnameinfo(sa, sa_len,
+ addr_buf, sizeof(addr_buf)-1,
+ NULL, 0, NI_NUMERICHOST)) {
+ DEBUG2("getnameinfo failed");
+ return NULL;
+ }
+
+ sl = strlen(addr_buf);
+ rad_assert(sl+2 <= sizeof(addr_buf));
+
+ addr_buf[sl] = '-';
+ addr_buf[sl+1] = '\0';
+
+ pool_name = talloc_strdup_append(pool_name, addr_buf);
+ }
+
+ return pool_name;
+}
+
+static home_server_t *srvr_blk_to_home_server(TALLOC_CTX *ctx,
+ TIDC_INSTANCE *inst,
+ TID_SRVR_BLK *blk,
+ char const *realm_name)
+{
+ home_server_t *hs = NULL;
+ const struct sockaddr *sa = NULL;
+ size_t sa_len = 0;
+ fr_ipaddr_t home_server_ip;
+ uint16_t port;
+ char nametemp[256];
+ time_t now = time(NULL);
+ struct timeval key_expiration;
+
+ rad_assert(blk != NULL);
+ tid_srvr_get_address(blk, &sa, &sa_len);
+ if (sa == NULL) {
+ DEBUG2("tid_srvr_get_address failed");
+ return NULL;
+ }
+
+ fr_sockaddr2ipaddr((struct sockaddr_storage *) sa, sa_len, &home_server_ip, &port);
+ if (0 != getnameinfo(sa, sa_len,
+ nametemp,
+ sizeof nametemp,
+ NULL, 0,
+ NI_NUMERICHOST)) {
+ DEBUG2("getnameinfo failed");
+ return NULL;
+ }
+
+ hs = talloc_zero(ctx, home_server_t);
+ if (!hs) return NULL;
+
+ /*
+ * All dynamic home servers are for authentication.
+ */
+ hs->type = HOME_TYPE_AUTH;
+ hs->ipaddr = home_server_ip;
+ hs->src_ipaddr.af = home_server_ip.af;
+ hs->log_name = talloc_asprintf(hs, "%s-for-%s", nametemp, realm_name);
+ hs->name = talloc_strdup(hs, nametemp);
+ hs->port = port;
+ hs->proto = IPPROTO_TCP;
+ hs->secret = talloc_strdup(hs, "radsec");
+ hs->response_window.tv_sec = 30;
+ hs->last_packet_recv = now;
+ /*
+ * We want sockets using these servers to close as soon as possible,
+ * to make sure that whenever a pool is replaced, sockets using old ones
+ * will not last long (hopefully less than 300s).
+ */
+ hs->limit.idle_timeout = 5;
+ /*
+ * Set the expiration of the server.
+ * If a realm_lifetime configuration parameter is provided (i.e. >0), use: now + realm_lifetime
+ * Else use the value from the TIDC response (if the accessor function is available) or now + 600
+ */
+#ifdef HAVE_TRUST_ROUTER_GET_KEY_EXP
+ tid_srvr_get_key_expiration(blk, &key_expiration);
+#else
+ key_expiration.tv_sec = now + 600;
+#endif
+ hs->expiration = realm_lifetime > 0 ? (now + realm_lifetime) : key_expiration.tv_sec;
+ hs->tls = construct_tls(inst, hs, blk);
+ if (!hs->tls) goto error;
+
+ realm_home_server_sanitize(hs, NULL);
+
+ return hs;
+error:
+ talloc_free(hs);
+ return NULL;
+}
+
+static home_pool_t *servers_to_pool(TALLOC_CTX *ctx,
+ TIDC_INSTANCE *inst,
+ TID_RESP *resp,
+ const char *realm_name)
+{
+ home_pool_t *pool = NULL;
+ size_t num_servers = 0, index;
+ TID_SRVR_BLK *server = NULL;
+
+ num_servers = tid_resp_get_num_servers(resp);
+
+ pool = talloc_zero_size(ctx, sizeof(*pool) + num_servers *sizeof(home_server_t *));
+ if (!pool) goto error;
+
+ pool->type = HOME_POOL_CLIENT_PORT_BALANCE;
+ pool->server_type = HOME_TYPE_AUTH;
+
+ pool->name = build_pool_name(pool, resp);
+ if (!pool->name) goto error;
+
+ pool->num_home_servers = num_servers;
+
+ tid_resp_servers_foreach(resp, server, index) {
+ home_server_t *hs;
+
+ hs = srvr_blk_to_home_server(pool, inst, server, realm_name);
+ if (!hs) goto error;
+ pool->servers[index] = hs;
+ }
+
+ return pool;
+
+error:
+ if (pool) talloc_free(pool);
+
+ return NULL;
+}
+
+static void tr_response_func( TIDC_INSTANCE *inst,
+ UNUSED TID_REQ *req, TID_RESP *resp,
+ void *cookie)
+{
+ struct resp_opaque *opaque = (struct resp_opaque *) cookie;
+ REALM *nr = opaque->orig_realm;
+
+ if (tid_resp_get_result(resp) != TID_SUCCESS) {
+ size_t err_msg_len;
+ opaque->result = tid_resp_get_result(resp);
+ memset(opaque->err_msg, 0, sizeof(opaque->err_msg));
+
+ if (tid_resp_get_err_msg(resp)) {
+ TR_NAME *err_msg = tid_resp_get_err_msg(resp);
+ err_msg_len = err_msg->len+1;
+ if (err_msg_len > sizeof(opaque->err_msg))
+ err_msg_len = sizeof(opaque->err_msg);
+ strlcpy(opaque->err_msg, err_msg->buf, err_msg_len);
+ }
+ return;
+ }
+
+ pthread_mutex_lock(&realm_tree_mutex);
+ if (!nr) {
+ nr = talloc_zero(NULL, REALM);
+ if (!nr) goto error;
+ nr->name = talloc_move(nr, &opaque->fr_realm_name);
+ nr->auth_pool = servers_to_pool(nr, inst, resp, nr->name);
+ if (!nr->auth_pool) {
+ ERROR("Unable to create pool for %s", nr->name);
+ goto error;
+ }
+ if (!realm_realm_add(nr, NULL)) goto error;
+
+ } else {
+ home_pool_t *old_pool = nr->auth_pool;
+ home_pool_t *new_pool;
+
+ new_pool = servers_to_pool(nr, inst, resp, opaque->fr_realm_name);
+ if (!new_pool) {
+ ERROR("Unable to recreate pool for %s", opaque->fr_realm_name);
+ goto error;
+ }
+ nr->auth_pool = new_pool;
+
+ /*
+ * Mark the old pool as "to be freed"
+ */
+ realm_pool_free(old_pool);
+ }
+
+ opaque->output_realm = nr;
+ pthread_mutex_unlock(&realm_tree_mutex);
+ return;
+
+error:
+ if (nr && !opaque->orig_realm) {
+ talloc_free(nr);
+ }
+ opaque->result = TID_ERROR;
+ snprintf(opaque->err_msg, sizeof(opaque->err_msg),
+ "There was an error creating the pool for %s", opaque->fr_realm_name);
+ pthread_mutex_unlock(&realm_tree_mutex);
+ return;
+}
+
+static bool update_required(REALM const *r)
+{
+ const home_pool_t *pool;
+ int i;
+ const home_server_t *server;
+ time_t now = time(NULL);
+
+ /*
+ * No pool. Not our realm.
+ */
+ if (!r->auth_pool) return false;
+
+ pool = r->auth_pool;
+
+ for (i = 0; i < pool->num_home_servers; i++) {
+ server = pool->servers[i];
+
+ /*
+ * The realm was loaded from the configuration
+ * files.
+ */
+ if (server->cs) return false;
+
+ /*
+ * These values don't make sense.
+ */
+ if ((server->last_packet_recv > (now + 5)) ||
+ (server->last_failed_open > (now + 5))) {
+ continue;
+ }
+
+ /*
+ * If home server is expired, update
+ */
+ if (now > server->expiration)
+ continue;
+ /*
+ * If we've opened in the last 10 minutes, then
+ * open rather than update.
+ */
+ if ((now - server->last_failed_open) > 600) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+REALM *tr_query_realm(REQUEST *request, char const *realm,
+ char const *community,
+ char const *rprealm,
+ char const *trustrouter,
+ unsigned int port)
+{
+ VALUE_PAIR *vp;
+ struct resp_opaque cookie;
+ bool rv = false;
+
+ if (!realm) return NULL;
+
+ if (!trustrouter || (strcmp(trustrouter, "none") == 0)) return NULL;
+
+ /* clear the cookie structure */
+ memset (&cookie, 0, sizeof(cookie));
+
+ /* See if the request overrides the community*/
+ vp = fr_pair_find_by_num(request->packet->vps, PW_UKERNA_TR_COI, VENDORPEC_UKERNA, TAG_ANY);
+ if (vp)
+ community = vp->vp_strvalue;
+ else pair_make_request("Trust-Router-COI", community, T_OP_SET);
+
+ /* Check if we already have a valid REALM and return it */
+ cookie.fr_realm_name = talloc_asprintf(NULL,
+ "%s%%%s",
+ community, realm);
+ cookie.orig_realm = cookie.output_realm = realm_find(cookie.fr_realm_name);
+ if (cookie.orig_realm && !update_required(cookie.orig_realm))
+ goto cleanup;
+
+ /* We use this lock for serializing TID requests for this realm */
+ realm_lock(realm);
+
+ /* Check again that the realm was not created while we were waiting to acquire the lock. */
+ cookie.orig_realm = cookie.output_realm = realm_find(cookie.fr_realm_name);
+ if (cookie.orig_realm && !update_required(cookie.orig_realm)){
+ realm_unlock(realm);
+ goto cleanup;
+ }
+
+ /* Perform the request/response exchange with the trust router server */
+ rv = tidc_send_recv(trustrouter, port, (char *) rprealm, (char *) realm, (char *)community, &cookie);
+ realm_unlock(realm);
+
+ /* If we weren't able to get a response from the trust router server, goto cleanup (hence return NULL realm) */
+ if (!rv) {
+ DEBUG2("Could not connect with Trust Router server for realm %s, rv = %d\n", realm, rv);
+ module_failure_msg(request, "Could not connect with Trust Router server for realm %s", realm);
+ goto cleanup;
+ }
+
+ /* If we got a response but it is an error one, include a Reply-Message and Error-Cause attributes */
+ if (cookie.result != TID_SUCCESS) {
+ DEBUG2("TID response is error, rc = %d: %s.\n", cookie.result,
+ cookie.err_msg?cookie.err_msg:"(NO ERROR TEXT)");
+ module_failure_msg(request, "TID response is error, rc = %d: %s.\n", cookie.result,
+ cookie.err_msg?cookie.err_msg:"(NO ERROR TEXT)");
+ if (cookie.err_msg)
+ pair_make_reply("Reply-Message", cookie.err_msg, T_OP_SET);
+ pair_make_reply("Error-Cause", "502", T_OP_SET); /*proxy unroutable*/
+ }
+ /* TIDC request was successful. If rekey is enabled, create a rekey event */
+ else if (rekey_enabled) {
+ struct rekey_ctx *rctx = build_rekey_ctx(cookie.output_realm, realm, community,
+ rprealm, trustrouter, port);
+ if (!schedule_rekey(rctx)){
+ talloc_free(rctx);
+ DEBUG2("Error scheduling rekey event for realm %s!", realm);
+ }
+ }
+
+cleanup:
+ if (cookie.fr_realm_name)
+ talloc_free(cookie.fr_realm_name);
+
+ return cookie.output_realm;
+}
+#endif /* HAVE_TRUST_ROUTER_TR_DH_H */
diff --git a/src/modules/rlm_realm/trustrouter.h b/src/modules/rlm_realm/trustrouter.h
new file mode 100644
index 0000000..f3aee90
--- /dev/null
+++ b/src/modules/rlm_realm/trustrouter.h
@@ -0,0 +1,38 @@
+/*
+ * 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 trustrouter.h
+ * @brief Headers for trust router code
+ *
+ * @copyright 2014 Network RADIUS SARL
+ */
+#ifndef TRUSTROUTER_INTEG_H
+#define TRUSTROUTER_INTEG_H
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+REALM *tr_query_realm(REQUEST *request, char const *realm,
+ char const *community,
+ char const *rprealm,
+ char const *trustrouter,
+ unsigned int port);
+
+bool tr_init(bool cnf_rekey_enabled, uint32_t cnf_realm_lifetime);
+
+#endif
diff --git a/src/modules/rlm_redis/.gitignore b/src/modules/rlm_redis/.gitignore
new file mode 100644
index 0000000..9e8fcfe
--- /dev/null
+++ b/src/modules/rlm_redis/.gitignore
@@ -0,0 +1,2 @@
+all.mk
+libfreeradius-redis.mk
diff --git a/src/modules/rlm_redis/README.md b/src/modules/rlm_redis/README.md
new file mode 100644
index 0000000..cc47d11
--- /dev/null
+++ b/src/modules/rlm_redis/README.md
@@ -0,0 +1,14 @@
+# rlm_redis
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Provides connectivity to single and clustered instances of Redis.
+This module exposes a string expansion that may be used to execute
+queries against Redis.
+
+Other related modules such as rlm_redis_ippool and rlm_rediswho
+provide additional functionality.
diff --git a/src/modules/rlm_redis/all.mk.in b/src/modules/rlm_redis/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_redis/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_redis/configure b/src/modules/rlm_redis/configure
new file mode 100755
index 0000000..fabc984
--- /dev/null
+++ b/src/modules/rlm_redis/configure
@@ -0,0 +1,4201 @@
+#! /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_redis.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_redis
+with_redis_include_dir
+with_redis_lib_dir
+with_redis_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_redis build without Redis database support
+ --with-redis-include-dir=DIR
+ Directory where the redis includes may be found
+ --with-redis-lib-dir=DIR
+ Directory where the redis libraries may be found
+ --with-redis-dir=DIR Base directory where redis is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_redis
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_redis was given.
+if test "${with_rlm_redis+set}" = set; then :
+ withval=$with_rlm_redis;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_redis" != xno; then
+
+
+
+redis_include_dir=
+
+# Check whether --with-redis-include-dir was given.
+if test "${with_redis_include_dir+set}" = set; then :
+ withval=$with_redis_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+redis_lib_dir=
+
+# Check whether --with-redis-lib-dir was given.
+if test "${with_redis_lib_dir+set}" = set; then :
+ withval=$with_redis_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-redis-dir was given.
+if test "${with_redis_dir+set}" = set; then :
+ withval=$with_redis_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac
+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
+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
+
+
+
+smart_try_dir="${redis_include_dir}"
+
+
+
+ac_safe=`echo "hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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}/hiredis/hiredis.h" >&5
+$as_echo_n "checking for ${_prefix}/hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h" >&5
+$as_echo_n "checking for hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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_hiredis_hiredis_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&2;}
+
+fail="$fail hiredis.h"
+
+fi
+
+
+smart_try_dir="$redis_lib_dir"
+
+
+sm_lib_safe=`echo "hiredis" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "redisConnect" | 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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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 redisConnect in -lhiredis" >&5
+$as_echo_n "checking for redisConnect in -lhiredis... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ { $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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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_hiredis_redisConnect" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&2;}
+
+fail="$fail libhiredis"
+
+fi
+
+
+ targetname=rlm_redis
+else
+ targetname=
+ echo \*\*\* module rlm_redis is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_redis to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_redis." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_redis." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_redis requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_redis requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_redis/configure.ac b/src/modules/rlm_redis/configure.ac
new file mode 100644
index 0000000..f5d56b1
--- /dev/null
+++ b/src/modules/rlm_redis/configure.ac
@@ -0,0 +1,102 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_redis.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_redis], [Redis database support])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-redis-include-dir=DIR
+redis_include_dir=
+AC_ARG_WITH(redis-include-dir,
+ [AS_HELP_STRING([--with-redis-include-dir=DIR],
+ [Directory where the redis includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-lib-dir=DIR
+redis_lib_dir=
+AC_ARG_WITH(redis-lib-dir,
+ [AS_HELP_STRING([--with-redis-lib-dir=DIR],
+ [Directory where the redis libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-dir=DIR
+AC_ARG_WITH(redis-dir,
+ [AS_HELP_STRING([--with-redis-dir=DIR],
+ [Base directory where redis is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for programs
+dnl ############################################################
+
+AC_PROG_CC
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="${redis_include_dir}"
+FR_SMART_CHECK_INCLUDE([hiredis/hiredis.h])
+if test "x$ac_cv_header_hiredis_hiredis_h" != "xyes"; then
+ AC_MSG_WARN([hiredis headers not found. Use --with-redis-include-dir=<path>.])
+ FR_MODULE_FAIL([hiredis.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+smart_try_dir="$redis_lib_dir"
+FR_SMART_CHECK_LIB(hiredis, redisConnect)
+if test "x$ac_cv_lib_hiredis_redisConnect" != "xyes"
+then
+ AC_MSG_WARN([hiredis libraries not found. Use --with-redis-lib-dir=<path>.])
+ FR_MODULE_FAIL([libhiredis])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_redis/rlm_redis.c b/src/modules/rlm_redis/rlm_redis.c
new file mode 100644
index 0000000..31bf5bd
--- /dev/null
+++ b/src/modules/rlm_redis/rlm_redis.c
@@ -0,0 +1,336 @@
+/*
+ * 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_redis.c
+ * @brief Driver for the REDIS noSQL key value stores.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2011 TekSavvy Solutions <gabe@teksavvy.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#include "rlm_redis.h"
+
+static const CONF_PARSER module_config[] = {
+ { "hostname", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, REDIS_INST, hostname), NULL },
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, REDIS_INST, hostname), NULL },
+ { "port", FR_CONF_OFFSET(PW_TYPE_SHORT, REDIS_INST, port), "6379" },
+ { "database", FR_CONF_OFFSET(PW_TYPE_INTEGER, REDIS_INST, database), "0" },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, REDIS_INST, password), NULL },
+ { "query_timeout", FR_CONF_OFFSET(PW_TYPE_SHORT, REDIS_INST, query_timeout), "5" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int _mod_conn_free(REDISSOCK *dissocket)
+{
+ if (dissocket->conn) {
+ redisFree(dissocket->conn);
+ dissocket->conn = NULL;
+ }
+
+ if (dissocket->reply) {
+ freeReplyObject(dissocket->reply);
+ dissocket->reply = NULL;
+ }
+
+ return 0;
+}
+
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ REDIS_INST *inst = instance;
+ REDISSOCK *dissocket = NULL;
+ redisContext *conn;
+ redisReply *reply = NULL;
+ char buffer[1024];
+ struct timeval tv;
+ tv.tv_sec = inst->query_timeout;
+ tv.tv_usec = 0;
+
+ conn = redisConnectWithTimeout(inst->hostname, inst->port, tv);
+ if (!conn) {
+ ERROR("rlm_redis (%s): Failed calling redisConnectWithTimeout('%s', %d, %d)",
+ inst->xlat_name, inst->hostname, inst->port, inst->query_timeout);
+ return NULL;
+ }
+
+#ifndef redisReplyReaderGetError
+#define redisReplyReaderGetError redisReaderGetError
+#endif
+
+ if (conn && conn->err) {
+ ERROR("rlm_redis (%s): Problems with redisConnectWithTimeout('%s', %d, %d), %s",
+ inst->xlat_name, inst->hostname, inst->port, inst->query_timeout, redisReplyReaderGetError(conn));
+ redisFree(conn);
+ return NULL;
+ }
+
+ if ( redisSetTimeout(conn, tv) == REDIS_ERR ) {
+ ERROR("rlm_redis (%s): redisSetTimeout('%s', %d) returned REDIS_ERR", inst->xlat_name, inst->hostname, inst->port);
+ redisFree(conn);
+ return NULL;
+ }
+
+ if (inst->password) {
+ snprintf(buffer, sizeof(buffer), "AUTH %s", inst->password);
+
+ reply = redisCommand(conn, buffer);
+ if (!reply) {
+ ERROR("rlm_redis (%s): Failed to run AUTH", inst->xlat_name);
+
+ do_close:
+ if (reply) freeReplyObject(reply);
+ redisFree(conn);
+ return NULL;
+ }
+
+
+ switch (reply->type) {
+ case REDIS_REPLY_STATUS:
+ if (strcmp(reply->str, "OK") != 0) {
+ ERROR("rlm_redis (%s): Failed authentication: reply %s",
+ inst->xlat_name, reply->str);
+ goto do_close;
+ }
+ break; /* else it's OK */
+
+ default:
+ ERROR("rlm_redis (%s): Unexpected reply to AUTH",
+ inst->xlat_name);
+ goto do_close;
+ }
+ }
+
+ if (inst->database) {
+ snprintf(buffer, sizeof(buffer), "SELECT %d", inst->database);
+
+ reply = redisCommand(conn, buffer);
+ if (!reply) {
+ ERROR("rlm_redis (%s): Failed to run SELECT",
+ inst->xlat_name);
+ goto do_close;
+ }
+
+ switch (reply->type) {
+ case REDIS_REPLY_STATUS:
+ if (strcmp(reply->str, "OK") != 0) {
+ ERROR("rlm_redis (%s): Failed SELECT %d: reply %s",
+ inst->xlat_name, inst->database,
+ reply->str);
+ goto do_close;
+ }
+ break; /* else it's OK */
+
+ default:
+ ERROR("rlm_redis (%s): Unexpected reply to SELECT",
+ inst->xlat_name);
+ goto do_close;
+ }
+ }
+
+ dissocket = talloc_zero(ctx, REDISSOCK);
+ dissocket->conn = conn;
+ talloc_set_destructor(dissocket, _mod_conn_free);
+
+ return dissocket;
+}
+
+static ssize_t redis_xlat(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ REDIS_INST *inst = instance;
+ REDISSOCK *dissocket;
+ size_t ret = 0;
+ char *buffer_ptr;
+ char buffer[21];
+
+ dissocket = fr_connection_get(inst->pool);
+ if (!dissocket) return -1;
+
+ /* Query failed for some reason, release socket and return */
+ if (rlm_redis_query(&dissocket, inst, fmt, request) < 0) {
+ goto release;
+ }
+
+ switch (dissocket->reply->type) {
+ case REDIS_REPLY_INTEGER:
+ buffer_ptr = buffer;
+ snprintf(buffer_ptr, sizeof(buffer), "%lld",
+ dissocket->reply->integer);
+
+ ret = strlen(buffer_ptr);
+ break;
+
+ case REDIS_REPLY_STATUS:
+ case REDIS_REPLY_STRING:
+ buffer_ptr = dissocket->reply->str;
+ ret = dissocket->reply->len;
+ break;
+
+ default:
+ buffer_ptr = NULL;
+ break;
+ }
+
+ if ((ret >= freespace) || (!buffer_ptr)) {
+ RDEBUG("rlm_redis (%s): Can't write result, insufficient space or unsupported result\n",
+ inst->xlat_name);
+ ret = -1;
+ goto release;
+ }
+
+ strlcpy(out, buffer_ptr, freespace);
+
+release:
+ rlm_redis_finish_query(dissocket);
+ fr_connection_release(inst->pool, dissocket);
+
+ return ret;
+}
+
+/*
+ * Only free memory we allocated. The strings allocated via
+ * cf_section_parse() do not need to be freed.
+ */
+static int mod_detach(void *instance)
+{
+ REDIS_INST *inst = instance;
+
+ fr_connection_pool_free(inst->pool);
+
+ return 0;
+}
+
+/*
+ * Query the redis database
+ */
+int rlm_redis_query(REDISSOCK **dissocket_p, REDIS_INST *inst,
+ char const *query, REQUEST *request)
+{
+ REDISSOCK *dissocket;
+ int argc;
+ char const *argv[MAX_REDIS_ARGS];
+ char argv_buf[MAX_QUERY_LEN];
+ struct timeval tv;
+ tv.tv_sec = inst->query_timeout;
+ tv.tv_usec = 0;
+
+ if (!query || !*query || !inst || !dissocket_p) {
+ return -1;
+ }
+
+ argc = rad_expand_xlat(request, query, MAX_REDIS_ARGS, argv, false,
+ sizeof(argv_buf), argv_buf);
+ if (argc <= 0)
+ return -1;
+
+ if (argc >= (MAX_REDIS_ARGS - 1)) {
+ RERROR("rlm_redis (%s): query has too many parameters; increase "
+ "MAX_REDIS_ARGS and recompile", inst->xlat_name);
+ return -1;
+ }
+
+ dissocket = *dissocket_p;
+
+ DEBUG2("rlm_redis (%s): executing the query: \"%s\"", inst->xlat_name, query);
+ dissocket->reply = redisCommandArgv(dissocket->conn, argc, argv, NULL);
+ if (!dissocket->reply) {
+ RERROR("%s", dissocket->conn->errstr);
+
+ dissocket = fr_connection_reconnect(inst->pool, dissocket);
+ if (!dissocket) {
+ error:
+ *dissocket_p = NULL;
+ return -1;
+ }
+
+ dissocket->reply = redisCommand(dissocket->conn, query, tv);
+ if (!dissocket->reply) {
+ RERROR("Failed after re-connect");
+ fr_connection_close(inst->pool, dissocket, NULL);
+ goto error;
+ }
+
+ *dissocket_p = dissocket;
+ }
+
+ if (dissocket->reply->type == REDIS_REPLY_ERROR) {
+ RERROR("Query failed, %s", query);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Clear the redis reply object if any
+ */
+int rlm_redis_finish_query(REDISSOCK *dissocket)
+{
+ if (!dissocket || !dissocket->reply) {
+ return -1;
+ }
+
+ freeReplyObject(dissocket->reply);
+ dissocket->reply = NULL;
+ return 0;
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ REDIS_INST *inst = instance;
+
+ INFO("rlm_redis: libhiredis version: %i.%i.%i", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
+
+ inst->xlat_name = cf_section_name2(conf);
+ if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf);
+
+ xlat_register(inst->xlat_name, redis_xlat, NULL, inst);
+
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ REDIS_INST *inst = instance;
+
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, NULL);
+ if (!inst->pool) {
+ return -1;
+ }
+
+ inst->redis_query = rlm_redis_query;
+ inst->redis_finish_query = rlm_redis_finish_query;
+
+ return 0;
+}
+
+extern module_t rlm_redis;
+module_t rlm_redis = {
+ .magic = RLM_MODULE_INIT,
+ .name = "redis",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(REDIS_INST),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach
+};
diff --git a/src/modules/rlm_redis/rlm_redis.h b/src/modules/rlm_redis/rlm_redis.h
new file mode 100644
index 0000000..4325fa9
--- /dev/null
+++ b/src/modules/rlm_redis/rlm_redis.h
@@ -0,0 +1,65 @@
+/*
+ * rlm_redis.h
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2011 TekSavvy Solutions <gabe@teksavvy.com>
+ */
+
+#ifndef RLM_REDIS_H
+#define RLM_REDIS_H
+
+RCSIDH(rlm_redis_h, "$Id$")
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#include <freeradius-devel/modpriv.h>
+#include <hiredis/hiredis.h>
+
+typedef struct redis_socket_t {
+ redisContext *conn;
+ redisReply *reply;
+} REDISSOCK;
+
+typedef struct rlm_redis_t REDIS_INST;
+
+typedef struct rlm_redis_t {
+ char const *xlat_name;
+
+ char const *hostname;
+ uint16_t port;
+ uint32_t database;
+ char const *password;
+ uint16_t query_timeout;
+ fr_connection_pool_t *pool;
+
+ int (*redis_query)(REDISSOCK **dissocket_p, REDIS_INST *inst, char const *query, REQUEST *request);
+ int (*redis_finish_query)(REDISSOCK *dissocket);
+} rlm_redis_t;
+
+#define MAX_QUERY_LEN 4096
+#define MAX_REDIS_ARGS 256
+
+int rlm_redis_query(REDISSOCK **dissocket_p, REDIS_INST *inst,
+ char const *query, REQUEST *request);
+int rlm_redis_finish_query(REDISSOCK *dissocket);
+
+#endif /* RLM_REDIS_H */
+
diff --git a/src/modules/rlm_rediswho/.gitignore b/src/modules/rlm_rediswho/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_rediswho/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_rediswho/README.md b/src/modules/rlm_rediswho/README.md
new file mode 100644
index 0000000..e940229
--- /dev/null
+++ b/src/modules/rlm_rediswho/README.md
@@ -0,0 +1,11 @@
+# rlm_rediswho
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Records which users are currently logged into the service. The
+file is used mainly for Simultaneous-Use checking to see who has
+current sessions.
diff --git a/src/modules/rlm_rediswho/all.mk.in b/src/modules/rlm_rediswho/all.mk.in
new file mode 100644
index 0000000..a9c1d38
--- /dev/null
+++ b/src/modules/rlm_rediswho/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I$(top_builddir)/src/modules/rlm_redis
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_rediswho/configure b/src/modules/rlm_rediswho/configure
new file mode 100755
index 0000000..af7b490
--- /dev/null
+++ b/src/modules/rlm_rediswho/configure
@@ -0,0 +1,4201 @@
+#! /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_rediswho.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_rediswho
+with_redis_include_dir
+with_redis_lib_dir
+with_redis_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_rediswho build without rlm_rediswho
+ --with-redis-include-dir=DIR
+ Directory where the redis includes may be found
+ --with-redis-lib-dir=DIR
+ Directory where the redis libraries may be found
+ --with-redis-dir=DIR Base directory where redis is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_rediswho
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_rediswho was given.
+if test "${with_rlm_rediswho+set}" = set; then :
+ withval=$with_rlm_rediswho;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_rediswho" != xno; then
+
+
+
+redis_include_dir=
+
+# Check whether --with-redis-include-dir was given.
+if test "${with_redis_include_dir+set}" = set; then :
+ withval=$with_redis_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+redis_lib_dir=
+
+# Check whether --with-redis-lib-dir was given.
+if test "${with_redis_lib_dir+set}" = set; then :
+ withval=$with_redis_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-redis-dir was given.
+if test "${with_redis_dir+set}" = set; then :
+ withval=$with_redis_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need redis-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac
+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
+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
+
+
+
+smart_try_dir="${redis_include_dir}"
+
+
+
+ac_safe=`echo "hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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}/hiredis/hiredis.h" >&5
+$as_echo_n "checking for ${_prefix}/hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h" >&5
+$as_echo_n "checking for hiredis/hiredis.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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 hiredis/hiredis.h in $try" >&5
+$as_echo_n "checking for hiredis/hiredis.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <hiredis/hiredis.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_hiredis_hiredis_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis headers not found. Use --with-redis-include-dir=<path>." >&2;}
+
+fail="$fail hiredis.h"
+
+fi
+
+
+smart_try_dir="$redis_lib_dir"
+
+
+sm_lib_safe=`echo "hiredis" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "redisConnect" | 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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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 redisConnect in -lhiredis" >&5
+$as_echo_n "checking for redisConnect in -lhiredis... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ { $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 redisConnect in -lhiredis in $try" >&5
+$as_echo_n "checking for redisConnect in -lhiredis in $try... " >&6; }
+ LIBS="-lhiredis $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char redisConnect();
+int
+main ()
+{
+redisConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lhiredis"
+ 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_hiredis_redisConnect" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: hiredis libraries not found. Use --with-redis-lib-dir=<path>." >&2;}
+
+fail="$fail libhiredis"
+
+fi
+
+
+ targetname=rlm_rediswho
+else
+ targetname=
+ echo \*\*\* module rlm_rediswho is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_rediswho to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_rediswho." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_rediswho." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_rediswho requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_rediswho requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_rediswho/configure.ac b/src/modules/rlm_rediswho/configure.ac
new file mode 100644
index 0000000..86c2712
--- /dev/null
+++ b/src/modules/rlm_rediswho/configure.ac
@@ -0,0 +1,102 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_rediswho.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_rediswho])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-redis-include-dir=DIR
+redis_include_dir=
+AC_ARG_WITH(redis-include-dir,
+ [AS_HELP_STRING([--with-redis-include-dir=DIR],
+ [Directory where the redis includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-lib-dir=DIR
+redis_lib_dir=
+AC_ARG_WITH(redis-lib-dir,
+ [AS_HELP_STRING([--with-redis-lib-dir=DIR],
+ [Directory where the redis libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-redis-dir=DIR
+AC_ARG_WITH(redis-dir,
+ [AS_HELP_STRING([--with-redis-dir=DIR],
+ [Base directory where redis is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need redis-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ redis_lib_dir="$withval/lib"
+ redis_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for programs
+dnl ############################################################
+
+AC_PROG_CC
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="${redis_include_dir}"
+FR_SMART_CHECK_INCLUDE([hiredis/hiredis.h])
+if test "x$ac_cv_header_hiredis_hiredis_h" != "xyes"; then
+ AC_MSG_WARN([hiredis headers not found. Use --with-redis-include-dir=<path>.])
+ FR_MODULE_FAIL([hiredis.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+smart_try_dir="$redis_lib_dir"
+FR_SMART_CHECK_LIB(hiredis, redisConnect)
+if test "x$ac_cv_lib_hiredis_redisConnect" != "xyes"
+then
+ AC_MSG_WARN([hiredis libraries not found. Use --with-redis-lib-dir=<path>.])
+ FR_MODULE_FAIL([libhiredis])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_rediswho/rlm_rediswho.c b/src/modules/rlm_rediswho/rlm_rediswho.c
new file mode 100644
index 0000000..11c3cf4
--- /dev/null
+++ b/src/modules/rlm_rediswho/rlm_rediswho.c
@@ -0,0 +1,247 @@
+/*
+ * 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_rediswho.c
+ * @brief Session tracking using redis.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2011 TekSavvy Solutions <gabe@teksavvy.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include <ctype.h>
+
+#include <rlm_redis.h>
+
+typedef struct rlm_rediswho_t {
+ char const *xlat_name;
+ CONF_SECTION *cs;
+
+ char const *redis_instance_name;
+ REDIS_INST *redis_inst;
+
+ /*
+ * expiry time in seconds if no updates are received for a user
+ */
+ int expiry_time;
+
+ /*
+ * How many session updates to keep track of per user
+ */
+ int trim_count;
+
+ /*
+ * These are used only for parsing. They aren't used at run-time.
+ */
+ char const *insert;
+ char const *trim;
+ char const *expire;
+
+} rlm_rediswho_t;
+
+static CONF_PARSER section_config[] = {
+ { "insert", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_rediswho_t, insert), NULL },
+ { "trim", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_rediswho_t, trim), NULL }, /* required only if trim_count > 0 */
+ { "expire", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_rediswho_t, expire), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static CONF_PARSER module_config[] = {
+ { "redis-instance-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_rediswho_t, redis_instance_name), NULL },
+ { "redis_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_rediswho_t, redis_instance_name), "redis" },
+
+ { "trim-count", FR_CONF_OFFSET(PW_TYPE_SIGNED | PW_TYPE_DEPRECATED, rlm_rediswho_t, trim_count), NULL },
+ { "trim_count", FR_CONF_OFFSET(PW_TYPE_SIGNED, rlm_rediswho_t, trim_count), "-1" },
+
+ /*
+ * These all smash the same variables, because we don't care about them right now.
+ * In 3.1, we should have a way of saying "parse a set of sub-sections according to a template"
+ */
+ { "Start", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), section_config },
+ { "Interim-Update", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), section_config },
+ { "Stop", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), section_config },
+
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Query the database executing a command with no result rows
+ */
+static int rediswho_command(char const *fmt, REDISSOCK **dissocket_p,
+ rlm_rediswho_t *inst, REQUEST *request)
+{
+ REDISSOCK *dissocket;
+ int result = 0;
+
+ if (!fmt) {
+ return 0;
+ }
+
+ if (inst->redis_inst->redis_query(dissocket_p, inst->redis_inst,
+ fmt, request) < 0) {
+
+ ERROR("rediswho_command: database query error in: '%s'", fmt);
+ return -1;
+
+ }
+ dissocket = *dissocket_p;
+
+ switch (dissocket->reply->type) {
+ case REDIS_REPLY_INTEGER:
+ DEBUG("rediswho_command: query response %lld\n",
+ dissocket->reply->integer);
+ if (dissocket->reply->integer > 0)
+ result = dissocket->reply->integer;
+ break;
+
+ case REDIS_REPLY_STATUS:
+ case REDIS_REPLY_STRING:
+ DEBUG("rediswho_command: query response %s\n",
+ dissocket->reply->str);
+ break;
+
+ default:
+ break;
+ }
+
+ (inst->redis_inst->redis_finish_query)(dissocket);
+
+ return result;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ module_instance_t *modinst;
+ rlm_rediswho_t *inst = instance;
+
+ inst->xlat_name = cf_section_name2(conf);
+
+ if (!inst->xlat_name)
+ inst->xlat_name = cf_section_name1(conf);
+
+ inst->cs = conf;
+
+ modinst = module_instantiate(cf_section_find("modules"),
+ inst->redis_instance_name);
+ if (!modinst) {
+ ERROR("rediswho: failed to find module instance \"%s\"",
+ inst->redis_instance_name);
+ return -1;
+ }
+
+ if (strcmp(modinst->entry->name, "rlm_redis") != 0) {
+ ERROR("rediswho: Module \"%s\""
+ " is not an instance of the redis module",
+ inst->redis_instance_name);
+ return -1;
+ }
+
+ inst->redis_inst = (REDIS_INST *) modinst->insthandle;
+
+ return 0;
+}
+
+static int mod_accounting_all(REDISSOCK **dissocket_p,
+ rlm_rediswho_t *inst, REQUEST *request,
+ char const *insert,
+ char const *trim,
+ char const *expire)
+{
+ int result;
+
+ result = rediswho_command(insert, dissocket_p, inst, request);
+ if (result < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Only trim if necessary */
+ if (inst->trim_count >= 0 && result > inst->trim_count) {
+ if (rediswho_command(trim, dissocket_p,
+ inst, request) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+ }
+
+ if (rediswho_command(expire, dissocket_p, inst, request) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void * instance, REQUEST * request)
+{
+ rlm_rcode_t rcode;
+ VALUE_PAIR * vp;
+ DICT_VALUE *dv;
+ CONF_SECTION *cs;
+ char const *insert, *trim, *expire;
+ rlm_rediswho_t *inst = (rlm_rediswho_t *) instance;
+ REDISSOCK *dissocket;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
+ if (!vp) {
+ RDEBUG("Could not find account status type in packet");
+ return RLM_MODULE_NOOP;
+ }
+
+ dv = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer);
+ if (!dv) {
+ RDEBUG("Unknown Acct-Status-Type %u", vp->vp_integer);
+ return RLM_MODULE_NOOP;
+ }
+
+ cs = cf_section_sub_find(inst->cs, dv->name);
+ if (!cs) {
+ RDEBUG("No subsection %s", dv->name);
+ return RLM_MODULE_NOOP;
+ }
+
+ dissocket = fr_connection_get(inst->redis_inst->pool);
+ if (!dissocket) return RLM_MODULE_FAIL;
+
+ insert = cf_pair_value(cf_pair_find(cs, "insert"));
+ trim = cf_pair_value(cf_pair_find(cs, "trim"));
+ expire = cf_pair_value(cf_pair_find(cs, "expire"));
+
+ rcode = mod_accounting_all(&dissocket, inst, request,
+ insert,
+ trim,
+ expire);
+
+ if (dissocket) fr_connection_release(inst->redis_inst->pool, dissocket);
+
+ return rcode;
+}
+
+extern module_t rlm_rediswho;
+module_t rlm_rediswho = {
+ .magic = RLM_MODULE_INIT,
+ .name = "rediswho",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_rediswho_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_ACCOUNTING] = mod_accounting
+ },
+};
diff --git a/src/modules/rlm_replicate/README.md b/src/modules/rlm_replicate/README.md
new file mode 100644
index 0000000..8563983
--- /dev/null
+++ b/src/modules/rlm_replicate/README.md
@@ -0,0 +1,10 @@
+# rlm_replicate
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Provide a way to make a copy of incoming packets and forward them
+to another server.
diff --git a/src/modules/rlm_replicate/all.mk b/src/modules/rlm_replicate/all.mk
new file mode 100644
index 0000000..d49dd26
--- /dev/null
+++ b/src/modules/rlm_replicate/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_replicate.a
+SOURCES := rlm_replicate.c
diff --git a/src/modules/rlm_replicate/rlm_replicate.c b/src/modules/rlm_replicate/rlm_replicate.c
new file mode 100644
index 0000000..cee26cc
--- /dev/null
+++ b/src/modules/rlm_replicate/rlm_replicate.c
@@ -0,0 +1,290 @@
+/*
+ * 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_replicate.c
+ * @brief Duplicate RADIUS requests.
+ *
+ * @copyright 2011-2013 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#ifdef WITH_PROXY
+static void cleanup(RADIUS_PACKET *packet)
+{
+ if (!packet) return;
+ if (packet->sockfd >= 0) {
+ close(packet->sockfd);
+ }
+
+ rad_free(&packet);
+}
+
+/** Copy packet to multiple servers
+ *
+ * Create a duplicate of the packet and send it to a list of realms
+ * defined by the presence of the Replicate-To-Realm VP in the control
+ * list of the current request.
+ *
+ * This is pretty hacky and is 100% fire and forget. If you're looking
+ * to forward authentication requests to multiple realms and process
+ * the responses, this function will not allow you to do that.
+ *
+ * @param[in] instance of this module.
+ * @param[in] request The current request.
+ * @param[in] list of attributes to copy to the duplicate packet.
+ * @param[in] code to write into the code field of the duplicate packet.
+ * @return RCODE fail on error, invalid if list does not exist, noop if no replications succeeded, else ok.
+ */
+static int replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, unsigned int code)
+{
+ int rcode = RLM_MODULE_NOOP;
+ VALUE_PAIR *vp, **vps;
+ vp_cursor_t cursor;
+ home_server_t *home;
+ REALM *realm;
+ home_pool_t *pool;
+ RADIUS_PACKET *packet = NULL;
+
+ /*
+ * Send as many packets as necessary to different
+ * destinations.
+ */
+ fr_cursor_init(&cursor, &request->config);
+ while ((vp = fr_cursor_next_by_num(&cursor, PW_REPLICATE_TO_REALM, 0, TAG_ANY))) {
+ realm = realm_find2(vp->vp_strvalue);
+ if (!realm) {
+ REDEBUG2("Cannot Replicate to unknown realm \"%s\"", vp->vp_strvalue);
+ continue;
+ }
+
+ /*
+ * We shouldn't really do this on every loop.
+ */
+ switch (request->packet->code) {
+ default:
+ REDEBUG2("Cannot replicate unknown packet code %d", request->packet->code);
+ cleanup(packet);
+ return RLM_MODULE_FAIL;
+
+ case PW_CODE_ACCESS_REQUEST:
+ pool = realm->auth_pool;
+ break;
+
+#ifdef WITH_ACCOUNTING
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ pool = realm->acct_pool;
+ break;
+#endif
+
+#ifdef WITH_COA
+ case PW_CODE_COA_REQUEST:
+ case PW_CODE_DISCONNECT_REQUEST:
+ pool = realm->coa_pool;
+ break;
+#endif
+ }
+
+ if (!pool) {
+ RWDEBUG2("Cancelling replication to Realm %s, as the realm is local", realm->name);
+ continue;
+ }
+
+ home = home_server_ldb(realm->name, pool, request);
+ if (!home) {
+ REDEBUG2("Failed to find live home server for realm %s", realm->name);
+ continue;
+ }
+
+#ifdef WITH_TCP
+ if (home->proto != IPPROTO_UDP) {
+ REDEBUG("The replicate module only does UDP - Cannot send to TCP home_server %s", home->name);
+ continue;
+ }
+#endif
+
+#ifdef WITH_TLS
+ if (home->tls) {
+ REDEBUG("The replicate module only does UDP - Cannot send to TLS home_server %s", home->name);
+ continue;
+ }
+#endif
+
+ /*
+ * For replication to multiple servers we re-use the packet
+ * we built here.
+ */
+ if (!packet) {
+ packet = rad_alloc(request, true);
+ if (!packet) {
+ return RLM_MODULE_FAIL;
+ }
+
+ packet->code = code;
+ packet->id = fr_rand() & 0xff;
+ packet->sockfd = fr_socket(&home->src_ipaddr, 0);
+ if (packet->sockfd < 0) {
+ REDEBUG("Failed opening socket: %s", fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto done;
+ }
+
+ vps = radius_list(request, list);
+ if (!vps) {
+ RWDEBUG("List '%s' doesn't exist for this packet",
+ fr_int2str(pair_lists, list, "<INVALID>"));
+ rcode = RLM_MODULE_INVALID;
+ goto done;
+ }
+
+ /*
+ * Don't assume the list actually contains any
+ * attributes.
+ */
+ if (*vps) {
+ packet->vps = fr_pair_list_copy(packet, *vps);
+ if (!packet->vps) {
+ rcode = RLM_MODULE_FAIL;
+ goto done;
+ }
+ }
+
+ /*
+ * For CHAP, create the CHAP-Challenge if
+ * it doesn't exist.
+ */
+ if ((code == PW_CODE_ACCESS_REQUEST) &&
+ (fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) != NULL) &&
+ (fr_pair_find_by_num(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL)) {
+ uint8_t *p;
+ vp = radius_pair_create(packet, &packet->vps, PW_CHAP_CHALLENGE, 0);
+ vp->length = AUTH_VECTOR_LEN;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
+ memcpy(p, request->packet->vector, AUTH_VECTOR_LEN);
+ }
+ } else {
+ size_t i;
+
+ for (i = 0; i < sizeof(packet->vector); i++) {
+ packet->vector[i] = fr_rand() & 0xff;
+ }
+
+ packet->id++;
+ TALLOC_FREE(packet->data);
+ packet->data_len = 0;
+ }
+
+ /*
+ * (Re)-Write these.
+ */
+ packet->dst_ipaddr = home->ipaddr;
+ packet->dst_port = home->port;
+ memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
+ packet->src_port = 0;
+
+ /*
+ * Encode, sign and then send the packet.
+ */
+ RDEBUG("Replicating list '%s' to Realm '%s'", fr_int2str(pair_lists, list, "<INVALID>"),
+ realm->name);
+ if (rad_send(packet, NULL, home->secret) < 0) {
+ REDEBUG("Failed replicating packet: %s", fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto done;
+ }
+
+ /*
+ * We've sent it to at least one destination.
+ */
+ rcode = RLM_MODULE_OK;
+ }
+
+ done:
+
+ cleanup(packet);
+ return rcode;
+}
+#else
+static rlm_rcode_t replicate_packet(UNUSED void *instance,
+ UNUSED REQUEST *request,
+ UNUSED pair_lists_t list,
+ UNUSED unsigned int code)
+{
+ RDEBUG("Replication is unsupported in this build");
+ return RLM_MODULE_FAIL;
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_preaccounting(void *instance, REQUEST *request)
+{
+ return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
+}
+
+#ifdef WITH_PROXY
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ return replicate_packet(instance, request, PAIR_LIST_PROXY_REQUEST, request->proxy->code);
+}
+#endif
+
+#ifdef WITH_COA
+static rlm_rcode_t CC_HINT(nonnull) mod_recv_coa(void *instance, REQUEST *request)
+{
+ return replicate_packet(instance, request, PAIR_LIST_REQUEST, request->packet->code);
+}
+#endif
+
+/*
+ * 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_replicate;
+module_t rlm_replicate = {
+ .magic = RLM_MODULE_INIT,
+ .name = "replicate",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_PREACCT] = mod_preaccounting,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+#endif
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa
+#endif
+ },
+};
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/README.md b/src/modules/rlm_rest/README.md
new file mode 100644
index 0000000..9d568a3
--- /dev/null
+++ b/src/modules/rlm_rest/README.md
@@ -0,0 +1,11 @@
+# rlm_rest
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Sends HTTP requests to remote servers and decodes the responses.
+
+Can also perform basic auth with user's credentials.
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..a0f8b0d
--- /dev/null
+++ b/src/modules/rlm_rest/configure
@@ -0,0 +1,5313 @@
+#! /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
+mod_ldflags
+mod_cflags
+targetname
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_rest
+echo
+
+
+# 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
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+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"
+
+fail="$fail libjson-c"
+
+ 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.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ 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;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$LIBCURL_CPPFLAGS $SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+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..a3263ba
--- /dev/null
+++ b/src/modules/rlm_rest/configure.ac
@@ -0,0 +1,155 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_rest.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_rest])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl ############################################################
+dnl # Check for curl
+dnl ############################################################
+
+LIBCURL_CHECK_CONFIG([], [7.19.1])
+
+if test "x$libcurl_cv_lib_version_ok" != "xyes"; then
+ FR_MODULE_FAIL([libcurl >= 7.19.2])
+elif test "x$libcurl_cv_lib_curl_usable" != "xyes"; then
+ FR_MODULE_FAIL([libcurl])
+else
+ if test x$libcurl_protocol_HTTP != xyes; then
+ FR_MODULE_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>.])
+ FR_MODULE_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"
+ FR_MODULE_FAIL([libjson-c])
+ 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
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$LIBCURL $SMART_LIBS"
+mod_cflags="$LIBCURL_CPPFLAGS $SMART_CPPFLAGS"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
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..035f557
--- /dev/null
+++ b/src/modules/rlm_rest/rest.c
@@ -0,0 +1,2689 @@
+/*
+ * 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;
+ rlm_rest_request_t *ctx = userdata;
+
+ 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 (ctx->state == READ_STATE_END || !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((uint8_t) *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((uint8_t) *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);
+
+#if CURL_AT_LEAST_VERSION(7,85,0)
+ SET_OPTION(CURLOPT_PROTOCOLS_STR, "http,https");
+#else
+# ifdef CURLOPT_PROTOCOLS
+ SET_OPTION(CURLOPT_PROTOCOLS, (CURLPROTO_HTTP | CURLPROTO_HTTPS));
+# endif
+#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 !CURL_AT_LEAST_VERSION(7,84,0)
+ if (section->tls_random_file) {
+ SET_OPTION(CURLOPT_RANDOM_FILE, section->tls_random_file);
+ }
+#endif
+
+ 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..cc0a0be
--- /dev/null
+++ b/src/modules/rlm_rest/rest.h
@@ -0,0 +1,328 @@
+/*
+ * 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;
+
+ bool body_encode; //!< Should the body data be URI encoded. Only applies
+ //!< to xlats.
+
+ 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
+
+ rlm_rest_section_t xlat; //!< Configuration specific to xlats
+
+#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..1942749
--- /dev/null
+++ b/src/modules/rlm_rest/rlm_rest.c
@@ -0,0 +1,1011 @@
+/*
+ * 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 },
+
+ /* Xlat specific */
+ { "body_uri_encode", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_rest_section_t, body_encode), "yes" },
+ 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, *request_body = NULL;
+ char const *p = fmt, *q;
+ char const *body;
+ http_method_t method;
+
+ /*
+ * Start with xlat "section" config.
+ * The provided string will then be parsed to populate URI etc.
+ */
+ rlm_rest_section_t section = inst->xlat;
+ *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((uint8_t) *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')) {
+ rlm_rest_handle_t *randle = handle;
+
+ /*
+ * As all input was escaped, this is already encoded.
+ * Un-escape if the body is to be sent as is.
+ */
+ if (section.body_encode) {
+ section.data = q;
+ } else {
+ request_body = curl_easy_unescape(randle->handle, q, strlen(q), NULL);
+ section.data = request_body;
+ }
+ section.body = HTTP_BODY_CUSTOM_LITERAL;
+ }
+
+ 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);
+ if (request_body) curl_free(request_body);
+
+ 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, char const *name)
+{
+ CONF_SECTION *cs;
+
+ 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, section_type_value[MOD_AUTHORIZE].section) < 0) ||
+ (parse_sub_section(conf, &inst->authenticate, section_type_value[MOD_AUTHENTICATE].section) < 0) ||
+ (parse_sub_section(conf, &inst->preacct, section_type_value[MOD_PREACCT].section) < 0) ||
+ (parse_sub_section(conf, &inst->accounting, section_type_value[MOD_ACCOUNTING].section) < 0) ||
+ (parse_sub_section(conf, &inst->pre_proxy, section_type_value[MOD_PRE_PROXY].section) < 0) ||
+ (parse_sub_section(conf, &inst->post_proxy, section_type_value[MOD_POST_PROXY].section) < 0) ||
+ (parse_sub_section(conf, &inst->xlat, "xlat") < 0) ||
+
+#ifdef WITH_COA
+ (parse_sub_section(conf, &inst->recv_coa, section_type_value[MOD_RECV_COA].section) < 0) ||
+#endif
+
+/* @todo add behaviour for checksimul */
+/* (parse_sub_section(conf, &inst->checksimul, MOD_SESSION) < 0) || */
+ (parse_sub_section(conf, &inst->post_auth, section_type_value[MOD_POST_AUTH].section) < 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
+ },
+};
diff --git a/src/modules/rlm_ruby/.gitignore b/src/modules/rlm_ruby/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_ruby/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_ruby/README.md b/src/modules/rlm_ruby/README.md
new file mode 100644
index 0000000..35ad129
--- /dev/null
+++ b/src/modules/rlm_ruby/README.md
@@ -0,0 +1,10 @@
+# rlm_ruby
+## Metadata
+<dl>
+ <dt>category</dt><dd>languages</dd>
+</dl>
+
+## Summary
+
+Allows the server to call a persistent, embedded Ruby script. This
+module should not be used - use `rlm_perl` or `rlm_python3` instead.
diff --git a/src/modules/rlm_ruby/all.mk.in b/src/modules/rlm_ruby/all.mk.in
new file mode 100644
index 0000000..03644b2
--- /dev/null
+++ b/src/modules/rlm_ruby/all.mk.in
@@ -0,0 +1,22 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TARGETNAME)" ""
+install: $(R)$(modconfdir)/ruby/example.rb
+
+$(R)$(modconfdir)/ruby: | $(R)$(modconfdir)
+ @echo INSTALL $(patsubst $(R)$(raddbdir)%,raddb%,$@)
+ @$(INSTALL) -d -m 750 $@
+
+$(R)$(modconfdir)/ruby/example.rb: src/modules/rlm_ruby/example.rb | $(R)$(modconfdir)/ruby
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 755 $< $(R)$(modconfdir)/ruby
+endif
diff --git a/src/modules/rlm_ruby/configure b/src/modules/rlm_ruby/configure
new file mode 100755
index 0000000..87f61d6
--- /dev/null
+++ b/src/modules/rlm_ruby/configure
@@ -0,0 +1,4638 @@
+#! /bin/sh
+# From configure.ac Revision: 1.9 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_ruby.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+ruby_headers
+mod_cflags
+mod_ldflags
+targetname
+RUBY_EXTRA_LIBS
+RUBY_SITE_PKG
+RUBY_LDFLAGS
+RUBY_CFLAGS
+AWK
+RUBY_VERSION
+GREP
+SED
+RUBY
+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_ruby
+with_ruby
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+RUBY'
+
+
+# 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_ruby build without support for embedded Ruby functions
+ --with-ruby=[PATH] absolute path to ruby executable
+
+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
+ RUBY Absolute path to ruby executable
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_ruby
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_ruby was given.
+if test "${with_rlm_ruby+set}" = set; then :
+ withval=$with_rlm_ruby;
+fi
+
+
+
+mod_cflags=
+mod_ldflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_ruby" != 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
+
+
+
+
+
+
+
+
+
+
+
+
+ if test -z "$RUBY"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ruby executable path has been provided" >&5
+$as_echo_n "checking whether ruby executable path has been provided... " >&6; }
+
+# Check whether --with-ruby was given.
+if test "${with_ruby+set}" = set; then :
+ withval=$with_ruby;
+ if test "$withval" != yes && test "$withval" != no; then :
+
+ RUBY="$withval"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
+$as_echo "$RUBY" >&6; }
+
+else
+
+ RUBY=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ if test "$withval" != no; then :
+
+ # Extract the first word of "ruby", so it can be a program name with args.
+set dummy ruby; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_RUBY+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $RUBY in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_RUBY="$RUBY" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_RUBY="$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
+
+ test -z "$ac_cv_path_RUBY" && ac_cv_path_RUBY="not-found"
+ ;;
+esac
+fi
+RUBY=$ac_cv_path_RUBY
+if test -n "$RUBY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
+$as_echo "$RUBY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ # Extract the first word of "ruby", so it can be a program name with args.
+set dummy ruby; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_RUBY+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $RUBY in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_RUBY="$RUBY" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="${PATH}:/usr/bin:/usr/local/bin"
+for as_dir in $as_dummy
+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_RUBY="$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
+
+ test -z "$ac_cv_path_RUBY" && ac_cv_path_RUBY="not-found"
+ ;;
+esac
+fi
+RUBY=$ac_cv_path_RUBY
+if test -n "$RUBY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY" >&5
+$as_echo "$RUBY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+
+fi
+
+
+
+
+
+
+
+if test -n "$RUBY"; then
+ AX_WITH_RUBY
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+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
+
+
+
+
+ if test -n "1.8"; then :
+
+
+
+
+ if test -n "$RUBY"; then :
+
+ ax_ruby_version="1.8"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ruby version" >&5
+$as_echo_n "checking for ruby version... " >&6; }
+
+ ruby_version=`$RUBY --version 2>&1 | $GREP "^ruby " | $SED -e 's/^.* \([0-9]*\.[0-9]*\.[0-9]*\) .*/\1/'`
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_version" >&5
+$as_echo "$ruby_version" >&6; }
+
+ RUBY_VERSION=$ruby_version
+
+
+
+
+
+ # Used to indicate true or false condition
+ ax_compare_version=false
+
+ # Convert the two version strings to be compared into a format that
+ # allows a simple string comparison. The end result is that a version
+ # string of the form 1.12.5-r617 will be converted to the form
+ # 0001001200050617. In other words, each number is zero padded to four
+ # digits, and non digits are removed.
+
+ ax_compare_version_A=`echo "$ax_ruby_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
+
+
+ ax_compare_version_B=`echo "$ruby_version" | sed -e 's/\([0-9]*\)/Z\1Z/g' \
+ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \
+ -e 's/[^0-9]//g'`
+
+
+ ax_compare_version=`echo "x$ax_compare_version_A
+x$ax_compare_version_B" | sed 's/^ *//' | sort | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"`
+
+
+
+ if test "$ax_compare_version" = "true" ; then
+
+ :
+
+
+ else
+ :
+
+
+ fi
+
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not find the ruby interpreter" >&5
+$as_echo "$as_me: WARNING: could not find the ruby interpreter" >&2;}
+
+
+fi
+
+fi
+
+ #
+ # Check if you have mkmf, else fail
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the mkmf Ruby package" >&5
+$as_echo_n "checking for the mkmf Ruby package... " >&6; }
+ ac_mkmf_result=`$RUBY -rmkmf -e ";" 2>&1`
+ if test -z "$ac_mkmf_result"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot import Ruby module \"mkmf\".
+Please check your Ruby installation. The error was:
+$ac_distutils_result" >&5
+$as_echo "$as_me: WARNING: cannot import Ruby module \"mkmf\".
+Please check your Ruby installation. The error was:
+$ac_distutils_result" >&2;}
+ fi
+
+ #
+ # Check for Ruby include path
+ #
+ if test -z "$RUBY_CFLAGS"; then
+ #
+ # Check for Ruby cflags
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby cflags" >&5
+$as_echo_n "checking for Ruby cflags... " >&6; }
+ if test -z "$RUBY_CFLAGS"; then
+ RUBY_CFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(CFLAGS))'`
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_CFLAGS" >&5
+$as_echo "$RUBY_CFLAGS" >&6; }
+
+ #
+ # Check for Ruby include path
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby include path" >&5
+$as_echo_n "checking for Ruby include path... " >&6; }
+ ruby_path=`$RUBY -rmkmf -e 'c = RbConfig::CONFIG; print c.has_key?(%q(rubyhdrdir)) ? \
+ c.fetch(%q(rubyhdrdir)) : c.fetch(%q(archdir))'`
+
+ ruby_arch=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(arch))'`
+
+ if test -n "${ruby_path}"; then
+ #
+ # For some reason ruby 1.9.1 on linux seems to put its
+ # config.h file in ${ruby_path}/${ruby_arch}/ruby/config.h
+ # Aside from the fact that it is WRONG to include your own
+ # config.h file, it means we can't use the headers unless we
+ # add both paths.
+ #
+ if test -d "${ruby_path}/${ruby_arch}"; then
+ ruby_path=" -I${ruby_path} -I${ruby_path}/${ruby_arch}"
+ else
+ ruby_path=" -I${ruby_path}"
+ fi
+ fi
+
+ RUBY_CFLAGS="$RUBY_CFLAGS $ruby_path"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ruby_path" >&5
+$as_echo "$ruby_path" >&6; }
+ fi
+
+
+
+ if test -z "$RUBY_LDFLAGS"; then
+ #
+ # Check for Ruby library path
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby library path" >&5
+$as_echo_n "checking for Ruby library path... " >&6; }
+ if test -z "$RUBY_LIBRARY_PATH"; then
+ RUBY_LIBRARY_PATH=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(libdir))'`
+ if test -n "${RUBY_LIBRARY_PATH}"; then
+ RUBY_LIBRARY_PATH=" -L$RUBY_LIBRARY_PATH"
+ fi
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LIBRARY_PATH" >&5
+$as_echo "$RUBY_LIBRARY_PATH" >&6; }
+
+ #
+ # Check for Ruby linking flags
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby linking flags" >&5
+$as_echo_n "checking for Ruby linking flags... " >&6; }
+
+ RUBY_LDFLAGS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(LIBRUBYARG_SHARED))'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_LDFLAGS" >&5
+$as_echo "$RUBY_LDFLAGS" >&6; }
+
+ RUBY_LDFLAGS="${RUBY_LIBRARY_PATH} ${RUBY_LDFLAGS}"
+ fi
+
+
+
+ #
+ # Check for site packages
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby site-packages path" >&5
+$as_echo_n "checking for Ruby site-packages path... " >&6; }
+ if test -z "$RUBY_SITE_PKG"; then
+ RUBY_SITE_PKG=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(sitearchdir))'`
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_SITE_PKG" >&5
+$as_echo "$RUBY_SITE_PKG" >&6; }
+
+
+ #
+ # libraries which must be linked in when embedding
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ruby extra libraries" >&5
+$as_echo_n "checking for Ruby extra libraries... " >&6; }
+ if test -z "$RUBY_EXTRA_LIBS"; then
+ RUBY_EXTRA_LIBS=`$RUBY -rmkmf -e 'print RbConfig::CONFIG.fetch(%q(SOLIBS))'`
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RUBY_EXTRA_LIBS" >&5
+$as_echo "$RUBY_EXTRA_LIBS" >&6; }
+
+
+ #
+ # linking flags needed when embedding
+ # (is it even needed for Ruby?)
+ #
+ # AC_MSG_CHECKING([for Ruby extra linking flags])
+ # if test -z "$RUBY_EXTRA_LIBS"; then
+ # RUBY_EXTRA_LIBS=`$RUBY -rmkmf -e 'print RubyConfig::CONFIG.fetch(%q(LINKFORSHARED))'`
+ # fi
+ # AC_MSG_RESULT([$RUBY_EXTRA_LIBS])
+ # AC_SUBST(RUBY_EXTRA_LIBS)
+
+ # this flags breaks ruby.h, and is sometimes defined by KDE m4 macros
+ CFLAGS="`echo "$CFLAGS" | sed -e 's/-std=iso9899:1990//g;'`"
+ #
+ # final check to see if everything compiles alright
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking consistency of all components of ruby development environment" >&5
+$as_echo_n "checking consistency of all components of ruby development environment... " >&6; }
+ 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
+
+ # save current global flags
+ ac_save_LIBS="$LIBS"
+ LIBS="$ac_save_LIBS $RUBY_LDFLAGS"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$ac_save_CFLAGS $RUBY_CFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ruby.h>
+int
+main ()
+{
+ruby_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ rubyexists=yes
+else
+ rubyexists=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rubyexists" >&5
+$as_echo "$rubyexists" >&6; }
+
+ if test ! "$rubyexists" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+ Could not link test program to Ruby. Maybe the main Ruby library has been
+ installed in some non-standard library path. If so, pass it to configure,
+ via the LDFLAGS environment variable.
+ Example: ./configure LDFLAGS=\"-L/usr/non-standard-path/ruby/lib\"
+ ============================================================================
+ You probably have to install the development version of the Ruby package
+ for your distribution. The exact name of this package varies among them.
+ ============================================================================
+ " >&5
+$as_echo "$as_me: WARNING:
+ Could not link test program to Ruby. Maybe the main Ruby library has been
+ installed in some non-standard library path. If so, pass it to configure,
+ via the LDFLAGS environment variable.
+ Example: ./configure LDFLAGS=\"-L/usr/non-standard-path/ruby/lib\"
+ ============================================================================
+ You probably have to install the development version of the Ruby package
+ for your distribution. The exact name of this package varies among them.
+ ============================================================================
+ " >&2;}
+ RUBY_VERSION=""
+ 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
+
+ # turn back to default flags
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ #
+ # all done!
+ #
+
+
+ if test -n "$RUBY_VERSION"; then
+ mod_cflags=$(echo "${RUBY_CFLAGS}" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*[ ]*//g')
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Sanitized cflags are \"${mod_cflags}\"" >&5
+$as_echo "$as_me: Sanitized cflags are \"${mod_cflags}\"" >&6;}
+
+ mod_ldflags="${RUBY_LDFLAGS} ${RUBY_EXTRA_LIBS}"
+ else
+
+fail="$fail ruby"
+
+ fi
+else
+
+fail="$fail ruby"
+
+fi
+
+
+ targetname=rlm_ruby
+else
+ targetname=
+ echo \*\*\* module rlm_ruby is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_ruby to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_ruby." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_ruby." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_ruby requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_ruby requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+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;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_ruby/configure.ac b/src/modules/rlm_ruby/configure.ac
new file mode 100644
index 0000000..aca8a3f
--- /dev/null
+++ b/src/modules/rlm_ruby/configure.ac
@@ -0,0 +1,40 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_ruby.c])
+AC_REVISION($Revision: 1.9 $)
+FR_INIT_MODULE([rlm_ruby], [support for embedded Ruby functions])
+
+mod_cflags=
+mod_ldflags=
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AX_WITH_PROG([RUBY],[ruby],[not-found],[${PATH}:/usr/bin:/usr/local/bin])
+
+if test -n "$RUBY"; then
+ AX_RUBY_DEVEL([1.8])
+
+ if test -n "$RUBY_VERSION"; then
+ mod_cflags=[$(echo "${RUBY_CFLAGS}" | sed 's/-I[ ]*/-isystem /g' | sed 's/-arch [^ ]*[ ]*//g')]
+
+ AC_MSG_NOTICE([Sanitized cflags are \"${mod_cflags}\"])
+
+ mod_ldflags="${RUBY_LDFLAGS} ${RUBY_EXTRA_LIBS}"
+ else
+ FR_MODULE_FAIL([ruby])
+ fi
+else
+ FR_MODULE_FAIL([ruby])
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+AC_SUBST(ruby_headers)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_ruby/example.rb b/src/modules/rlm_ruby/example.rb
new file mode 100644
index 0000000..169e059
--- /dev/null
+++ b/src/modules/rlm_ruby/example.rb
@@ -0,0 +1,25 @@
+#This is example radius.rb script
+module Radiusd
+ def Radiusd.instantiate(arg)
+ radlog(L_DBG,"[ruby]Running ruby instantiate")
+ p arg
+ return Radiusd::RLM_MODULE_OK
+ end
+ def Radiusd.authenticate(arg)
+ radlog(L_DBG,"[ruby]Running ruby authenticate")
+ p arg
+ return Radiusd::RLM_MODULE_NOOP
+ end
+ def Radiusd.authorize(arg)
+ radlog(L_DBG,"[ruby]Running ruby authorize")
+ p arg
+ #Here we return Cleartext-Password, which could have been retrieved from DB.
+ return [Radiusd::RLM_MODULE_UPDATED, [],[["Cleartext-Password","pass"]]]
+ end
+ def Radiusd.accounting(arg)
+ radlog(L_DBG,"[ruby]Running ruby accounting")
+ p arg
+ return Radiusd::RLM_MODULE_NOOP
+ end
+
+end
diff --git a/src/modules/rlm_ruby/rlm_ruby.c b/src/modules/rlm_ruby/rlm_ruby.c
new file mode 100644
index 0000000..ad2f15f
--- /dev/null
+++ b/src/modules/rlm_ruby/rlm_ruby.c
@@ -0,0 +1,481 @@
+/*
+ * 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_ruby.c
+ * @brief Translates requests between the server an a ruby interpreter.
+ *
+ * @note Maintainers note
+ * @note Please don't use this module, Matz ruby was never designed for embedding.
+ * @note This module leaks memory, and the ruby code installs signal handlers
+ * @note which interfere with normal operation of the server. It's all bad...
+ * @note mruby shows some promise, feel free to rewrite the module to use that.
+ * @note https://github.com/mruby/mruby
+ *
+ * @copyright 2008 Andriy Dmytrenko aka Antti, BuzhNET
+ */
+
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+/*
+ * Undefine any HAVE_* flags which may conflict
+ * ruby.h *REALLY* shouldn't #include its config.h file,
+ * but it does *sigh*.
+ */
+#undef HAVE_CRYPT
+
+#ifdef __clang__
+DIAG_OFF(disabled-macro-expansion)
+#endif
+#include <ruby.h>
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_ruby_t {
+#define RLM_RUBY_STRUCT(foo) unsigned long func_##foo
+
+ RLM_RUBY_STRUCT(instantiate);
+ RLM_RUBY_STRUCT(authorize);
+ RLM_RUBY_STRUCT(authenticate);
+ RLM_RUBY_STRUCT(preacct);
+ RLM_RUBY_STRUCT(accounting);
+ RLM_RUBY_STRUCT(checksimul);
+ RLM_RUBY_STRUCT(pre_proxy);
+ RLM_RUBY_STRUCT(post_proxy);
+ RLM_RUBY_STRUCT(post_auth);
+#ifdef WITH_COA
+ RLM_RUBY_STRUCT(recv_coa);
+ RLM_RUBY_STRUCT(send_coa);
+#endif
+ RLM_RUBY_STRUCT(detach);
+
+ char const *filename;
+ char const *module_name;
+ VALUE module;
+
+} rlm_ruby_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, struct rlm_ruby_t, filename), NULL },
+ { "module", FR_CONF_OFFSET(PW_TYPE_STRING, struct rlm_ruby_t, module_name), "Radiusd" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+/*
+ * radiusd Ruby functions
+ */
+
+/* radlog wrapper */
+
+static VALUE radlog_rb(UNUSED VALUE self, VALUE msg_type, VALUE rb_msg) {
+ int status;
+ char *msg;
+ status = FIX2INT(msg_type);
+ msg = StringValuePtr(rb_msg);
+ radlog(status, "%s", msg);
+ return Qnil;
+}
+
+/* Tuple to value pair conversion */
+
+static void add_vp_tuple(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vpp, VALUE rb_value,
+ char const *function_name) {
+ int i;
+ long outertuplesize;
+ VALUE_PAIR *vp;
+
+ /* If the Ruby function gave us nil for the tuple, then just return. */
+ if (NIL_P(rb_value)) {
+ return;
+ }
+
+ if (TYPE(rb_value) != T_ARRAY) {
+ REDEBUG("add_vp_tuple, %s: non-array passed", function_name);
+ return;
+ }
+
+ /* Get the array size. */
+ outertuplesize = RARRAY_LEN(rb_value);
+
+ for (i = 0; i < outertuplesize; i++) {
+ VALUE pTupleElement = rb_ary_entry(rb_value, i);
+
+ if ((pTupleElement != 0) &&
+ (TYPE(pTupleElement) == T_ARRAY)) {
+
+ /* Check if it's a pair */
+ long tuplesize;
+
+ if ((tuplesize = RARRAY_LEN(pTupleElement)) != 2) {
+ REDEBUG("%s: tuple element %i is a tuple "
+ " of size %li. must be 2\n", function_name,
+ i, tuplesize);
+ } else {
+ VALUE pString1, pString2;
+
+ pString1 = rb_ary_entry(pTupleElement, 0);
+ pString2 = rb_ary_entry(pTupleElement, 1);
+
+ if ((TYPE(pString1) == T_STRING) &&
+ (TYPE(pString2) == T_STRING)) {
+
+
+ char const *s1, *s2;
+
+ /* fr_pair_make() will convert and find any
+ * errors in the pair.
+ */
+
+ s1 = StringValuePtr(pString1);
+ s2 = StringValuePtr(pString2);
+
+ if ((s1 != NULL) && (s2 != NULL)) {
+ DEBUG("%s: %s = %s ",
+ function_name, s1, s2);
+
+ /* xxx Might need to support other T_OP */
+ vp = fr_pair_make(ctx, vpp, s1, s2, T_OP_EQ);
+ if (vp != NULL) {
+ DEBUG("%s: s1, s2 OK", function_name);
+ } else {
+ DEBUG("%s: s1, s2 FAILED", function_name);
+ }
+ } else {
+ REDEBUG("%s: string conv failed", function_name);
+ }
+
+ } else {
+ REDEBUG("%s: tuple element %d must be "
+ "(string, string)", function_name, i);
+ }
+ }
+ } else {
+ REDEBUG("%s: tuple element %d is not a tuple\n",
+ function_name, i);
+ }
+ }
+
+}
+
+/* This is the core Ruby function that the others wrap around.
+ * Pass the value-pair print strings in a tuple.
+ * xxx We're not checking the errors. If we have errors, what do we do?
+ */
+
+#define BUF_SIZE 1024
+static rlm_rcode_t CC_HINT(nonnull (4)) do_ruby(REQUEST *request, unsigned long func,
+ VALUE module, char const *function_name)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ vp_cursor_t cursor;
+
+ char buf[BUF_SIZE]; /* same size as vp_print buffer */
+
+ VALUE_PAIR *vp;
+ VALUE rb_request, rb_result, rb_reply_items, rb_config, rbString1, rbString2;
+
+ int n_tuple;
+ DEBUG("Calling ruby function %s which has id: %lu\n", function_name, func);
+
+ /* Return with "OK, continue" if the function is not defined.
+ * TODO: Should check with rb_respond_to each time, just because ruby can define function dynamicly?
+ */
+ if (func == 0) {
+ return rcode;
+ }
+
+ n_tuple = 0;
+ if (request) {
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ n_tuple++;
+ }
+ }
+
+ /*
+ Creating ruby array, that contains arrays of [name,value]
+ Maybe we should use hash instead? Can this names repeat?
+ */
+ rb_request = rb_ary_new2(n_tuple);
+
+ if (request) {
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ VALUE tmp = rb_ary_new2(2);
+
+ /* The name. logic from vp_prints, lib/print.c */
+ if (vp->da->flags.has_tag) {
+ snprintf(buf, BUF_SIZE, "%s:%d", vp->da->name, vp->tag);
+ } else {
+ strlcpy(buf, vp->da->name, sizeof(buf));
+ }
+ rbString1 = rb_str_new2(buf);
+ vp_prints_value(buf, sizeof (buf), vp, '"');
+ rbString2 = rb_str_new2(buf);
+
+ rb_ary_push(tmp, rbString1);
+ rb_ary_push(tmp, rbString2);
+ rb_ary_push(rb_request, tmp);
+ }
+ }
+
+ /* Calling corresponding ruby function, passing request and catching result */
+ rb_result = rb_funcall(module, func, 1, rb_request);
+
+ /*
+ * Checking result, it can be array of type [result,
+ * [array of reply pairs],[array of config pairs]],
+ * It can also be just a fixnum, which is a result itself.
+ */
+ if (TYPE(rb_result) == T_ARRAY) {
+ if (!FIXNUM_P(rb_ary_entry(rb_result, 0))) {
+ ERROR("First element of an array was not a FIXNUM (Which has to be a return_value)");
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ rcode = FIX2INT(rb_ary_entry(rb_result, 0));
+
+ /*
+ * Only process the results if we were passed a request.
+ */
+ if (request) {
+ rb_reply_items = rb_ary_entry(rb_result, 1);
+ rb_config = rb_ary_entry(rb_result, 2);
+
+ add_vp_tuple(request->reply, request, &request->reply->vps,
+ rb_reply_items, function_name);
+ add_vp_tuple(request, request, &request->config,
+ rb_config, function_name);
+ }
+ } else if (FIXNUM_P(rb_result)) {
+ rcode = FIX2INT(rb_result);
+ }
+
+finish:
+ return rcode;
+}
+
+static struct varlookup {
+ char const* name;
+ int value;
+} constants[] = {
+ { "L_DBG", L_DBG},
+ { "L_AUTH", L_AUTH},
+ { "L_INFO", L_INFO},
+ { "L_ERR", L_ERR},
+ { "L_PROXY", L_PROXY},
+ { "RLM_MODULE_REJECT", RLM_MODULE_REJECT},
+ { "RLM_MODULE_FAIL", RLM_MODULE_FAIL},
+ { "RLM_MODULE_OK", RLM_MODULE_OK},
+ { "RLM_MODULE_HANDLED", RLM_MODULE_HANDLED},
+ { "RLM_MODULE_INVALID", RLM_MODULE_INVALID},
+ { "RLM_MODULE_USERLOCK", RLM_MODULE_USERLOCK},
+ { "RLM_MODULE_NOTFOUND", RLM_MODULE_NOTFOUND},
+ { "RLM_MODULE_NOOP", RLM_MODULE_NOOP},
+ { "RLM_MODULE_UPDATED", RLM_MODULE_UPDATED},
+ { "RLM_MODULE_NUMCODES", RLM_MODULE_NUMCODES},
+ { NULL, 0},
+};
+
+/*
+ * Import a user module and load a function from it
+ */
+static int load_function(char const *f_name, unsigned long *func, VALUE module) {
+ if (!f_name) {
+ *func = 0;
+ } else {
+ *func = rb_intern(f_name);
+ /* rb_intern returns a symbol of a function, not a function itself
+ it can be aplied to any recipient,
+ so we should check it for our module recipient
+ */
+ if (!rb_respond_to(module, *func))
+ *func = 0;
+ }
+ DEBUG("load_function %s, result: %lu", f_name, *func);
+ 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(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_ruby_t *inst = instance;
+ VALUE module;
+
+ int idx;
+ int status;
+
+ /*
+ * Initialize Ruby interpreter. Fatal error if this fails.
+ */
+ ruby_init();
+ ruby_init_loadpath();
+ ruby_script("radiusd");
+
+ /* disabling GC, it will eat your memory, but at least it will be stable. */
+ rb_gc_disable();
+
+ /*
+ * Setup our 'radiusd' module.
+ */
+ module = inst->module = rb_define_module(inst->module_name);
+ if (!module) {
+ ERROR("Ruby rb_define_module failed");
+
+ return -1;
+ }
+
+ /*
+ * Load constants into module
+ */
+ for (idx = 0; constants[idx].name; idx++) {
+ rb_define_const(module, constants[idx].name, INT2NUM(constants[idx].value));
+ }
+
+ /*
+ * Expose some FreeRADIUS API functions as ruby functions
+ */
+ rb_define_module_function(module, "radlog", radlog_rb, 2);
+
+ DEBUG("Loading file %s...", inst->filename);
+ rb_load_protect(rb_str_new2(inst->filename), 0, &status);
+ if (status) {
+ ERROR("Error loading file %s status: %d", inst->filename, status);
+
+ return -1;
+ }
+ DEBUG("Loaded file %s", inst->filename);
+
+ /*
+ * Import user modules.
+ */
+#define RLM_RUBY_LOAD(foo) if (load_function(#foo, &inst->func_##foo, inst->module)==-1) { \
+ return -1; \
+ }
+
+ RLM_RUBY_LOAD(instantiate);
+ RLM_RUBY_LOAD(authenticate);
+ RLM_RUBY_LOAD(authorize);
+ RLM_RUBY_LOAD(preacct);
+ RLM_RUBY_LOAD(accounting);
+ RLM_RUBY_LOAD(checksimul);
+ RLM_RUBY_LOAD(pre_proxy);
+ RLM_RUBY_LOAD(post_proxy);
+ RLM_RUBY_LOAD(post_auth);
+#ifdef WITH_COA
+ RLM_RUBY_LOAD(recv_coa);
+ RLM_RUBY_LOAD(send_coa);
+#endif
+ RLM_RUBY_LOAD(detach);
+
+ /* Call the instantiate function. No request. Use the return value. */
+ return do_ruby(NULL, inst->func_instantiate, inst->module, "instantiate");
+}
+
+#define RLM_RUBY_FUNC(foo) static rlm_rcode_t CC_HINT(nonnull) mod_##foo(void *instance, REQUEST *request) \
+ { \
+ return do_ruby(request, \
+ ((struct rlm_ruby_t *)instance)->func_##foo,((struct rlm_ruby_t *)instance)->module, \
+ #foo); \
+ }
+
+RLM_RUBY_FUNC(authorize)
+RLM_RUBY_FUNC(authenticate)
+RLM_RUBY_FUNC(preacct)
+RLM_RUBY_FUNC(accounting)
+RLM_RUBY_FUNC(checksimul)
+RLM_RUBY_FUNC(pre_proxy)
+RLM_RUBY_FUNC(post_proxy)
+RLM_RUBY_FUNC(post_auth)
+#ifdef WITH_COA
+RLM_RUBY_FUNC(recv_coa)
+RLM_RUBY_FUNC(send_coa)
+#endif
+
+static int mod_detach(UNUSED void *instance)
+{
+ ruby_finalize();
+ ruby_cleanup(0);
+
+ 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_ruby;
+module_t rlm_ruby = {
+ .magic = RLM_MODULE_INIT,
+ .name = "ruby",
+ .type = RLM_TYPE_THREAD_UNSAFE, /* type, ok, let's be honest, MRI is not yet treadsafe */
+ .inst_size = sizeof(rlm_ruby_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_SESSION] = mod_checksimul,
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+ [MOD_POST_AUTH] = mod_post_auth,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_recv_coa,
+ [MOD_SEND_COA] = mod_send_coa
+#endif
+ },
+};
diff --git a/src/modules/rlm_securid/.gitignore b/src/modules/rlm_securid/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_securid/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_securid/README b/src/modules/rlm_securid/README
new file mode 100644
index 0000000..a34f374
--- /dev/null
+++ b/src/modules/rlm_securid/README
@@ -0,0 +1,34 @@
+ This module implements SecurID token checking. It should be listed
+in the "authenticate" section.
+
+ The module configuration is in the "securid" file. You will need to
+copy it by hand to the raddb/modules/directory.
+
+ There is a configure script, but you will most likely need to pass
+--with-securid-dir=<securid_path> argument.
+
+ The files it requires are acexport.h and libaceclnt.so which should be
+located in the include and lib folders beneath <secured_path>. EMC/RSA
+do not distribute these files on their public website. You will need to
+request the AuthSDK from your EMC/RSA representative.
+
+ Many people will wonder about the license issues involved in
+distributing this module. The short answer is that the source can be
+distributed, the binaries cannot be distributed. The explanation
+is given below.
+
+ This module falls under the GPLv2 license. The primary goal of this
+license is largely to ensure that you have access to the source code,
+which is included here. A secondary goal of this license is to ensure
+that binary distributions can be re-built from the existing source
+code. This is done by requiring binary distributions to offer source
+code for the GPLd binary, and to distribute ALL DEPENDENT LIBRARIES.
+
+ The RSA libraries are proprietary to RSA, and cannot be distributed.
+Therefore, any library (rlm_securid.a, rlm_securid.so, etc.) CANNOT be
+distributed by ANYONE.
+
+ The module is still useful, of course. The GPL restriction on
+distribution apply only on distribution to third parties. This means
+that building the module, and using it within your organization is
+allowed under the GPL.
diff --git a/src/modules/rlm_securid/README.md b/src/modules/rlm_securid/README.md
new file mode 100644
index 0000000..a173502
--- /dev/null
+++ b/src/modules/rlm_securid/README.md
@@ -0,0 +1,49 @@
+# rlm_securid
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Supports authentication against an RSA SecurID ACE instance.
+
+## Description
+
+This module implements SecurID token checking. It should be listed
+in the "authenticate" section.
+
+The module configuration is in the "securid" file. You will need
+to create a symlink from raddb/mods-enabled/securid to
+../mods-available/securid.
+
+There is a configure script, but you will most likely need to pass
+--with-securid-dir=<securid_path> argument.
+
+The files it requires are acexport.h and libaceclnt.so which
+should be located in the include and lib folders beneath
+<secured_path>. EMC/RSA do not distribute these files on their
+public website. You will need to request the AuthSDK from your
+EMC/RSA representative.
+
+Many people will wonder about the license issues involved in
+distributing this module. The short answer is that the source can
+be distributed, the binaries cannot be distributed. The
+explanation is given below.
+
+This module falls under the GPLv2 license. The primary goal of
+this license is largely to ensure that you have access to the
+source code, which is included here. A secondary goal of this
+license is to ensure that binary distributions can be re-built
+from the existing source code. This is done by requiring binary
+distributions to offer source code for the GPL'd binary, and to
+distribute ALL DEPENDENT LIBRARIES.
+
+The RSA libraries are proprietary to RSA, and cannot be
+distributed. Therefore, any library (rlm_securid.a,
+rlm_securid.so, etc.) CANNOT be distributed by ANYONE.
+
+The module is still useful, of course. The GPL restriction on
+distribution apply only on distribution to third parties. This
+means that building the module, and using it within your
+organization is allowed under the GPL.
diff --git a/src/modules/rlm_securid/all.mk.in b/src/modules/rlm_securid/all.mk.in
new file mode 100644
index 0000000..f261351
--- /dev/null
+++ b/src/modules/rlm_securid/all.mk.in
@@ -0,0 +1,18 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c mem.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
+
+ifneq "$(TARGETNAME)" ""
+install: $(R)$(raddbdir)/mods-available/securid
+
+$(R)$(raddbdir)/mods-available/securid: src/modules/rlm_securid/securid | $(R)$(raddbdir)/mods-available
+ @$(ECHO) INSTALL $(notdir $<)
+ @$(INSTALL) -m 640 $< $(R)$(raddbdir)/mods-available
+endif
diff --git a/src/modules/rlm_securid/configure b/src/modules/rlm_securid/configure
new file mode 100755
index 0000000..2752c98
--- /dev/null
+++ b/src/modules/rlm_securid/configure
@@ -0,0 +1,4200 @@
+#! /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_securid.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_securid
+with_rlm_securid_include_dir
+with_rlm_securid_lib_dir
+with_rlm_securid_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_securid build without rlm_securid
+ --with-rlm-securid-include-dir=DIR
+ Directory where the securid includes may be found
+ --with-rlm-securid-lib-dir=DIR
+ Directory where the securid libraries may be found
+ --with-rlm-securid-dir=DIR
+ Base directory where securid is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_securid
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_securid was given.
+if test "${with_rlm_securid+set}" = set; then :
+ withval=$with_rlm_securid;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_securid" != xno; then
+
+
+
+securid_include_dir=
+
+# Check whether --with-rlm-securid-include-dir was given.
+if test "${with_rlm_securid_include_dir+set}" = set; then :
+ withval=$with_rlm_securid_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-securid-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ securid_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+securid_lib_dir=
+
+# Check whether --with-rlm-securid-lib-dir was given.
+if test "${with_rlm_securid_lib_dir+set}" = set; then :
+ withval=$with_rlm_securid_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-securid-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ securid_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-rlm-securid-dir was given.
+if test "${with_rlm_securid_dir+set}" = set; then :
+ withval=$with_rlm_securid_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-securid-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ securid_lib_dir="$withval/lib"
+ securid_include_dir="$withval/inc"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir="$securid_include_dir"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "acexport.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 acexport.h in $try" >&5
+$as_echo_n "checking for acexport.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <acexport.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}/acexport.h" >&5
+$as_echo_n "checking for ${_prefix}/acexport.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <acexport.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 acexport.h" >&5
+$as_echo_n "checking for acexport.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <acexport.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 acexport.h in $try" >&5
+$as_echo_n "checking for acexport.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <acexport.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_acexport_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: securid headers not found. Use --with-rlm-securid-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: securid headers not found. Use --with-rlm-securid-include-dir=<path>." >&2;}
+
+fail="$fail acexport.h"
+
+fi
+
+
+smart_try_dir="$securid_lib_dir"
+
+
+sm_lib_safe=`echo "aceclnt" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SD_Init" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SD_Init in -laceclnt in $try" >&5
+$as_echo_n "checking for SD_Init in -laceclnt in $try... " >&6; }
+ LIBS="-laceclnt $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SD_Init();
+int
+main ()
+{
+SD_Init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-laceclnt"
+ 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 SD_Init in -laceclnt" >&5
+$as_echo_n "checking for SD_Init in -laceclnt... " >&6; }
+ LIBS="-laceclnt $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SD_Init();
+int
+main ()
+{
+SD_Init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-laceclnt"
+ { $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 SD_Init in -laceclnt in $try" >&5
+$as_echo_n "checking for SD_Init in -laceclnt in $try... " >&6; }
+ LIBS="-laceclnt $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SD_Init();
+int
+main ()
+{
+SD_Init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-laceclnt"
+ 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_aceclnt_SD_Init" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: securid libraries not found. Use --with-rlm-securid-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: securid libraries not found. Use --with-rlm-securid-lib-dir=<path>." >&2;}
+
+fail="$fail libaceclnt"
+
+fi
+
+
+ targetname=rlm_securid
+else
+ targetname=
+ echo \*\*\* module rlm_securid is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_securid to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_securid." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_securid." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_securid requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_securid requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_securid/configure.ac b/src/modules/rlm_securid/configure.ac
new file mode 100644
index 0000000..fc8f1d7
--- /dev/null
+++ b/src/modules/rlm_securid/configure.ac
@@ -0,0 +1,97 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_securid.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_securid])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-rlm-securid-include-dir=DIR
+securid_include_dir=
+AC_ARG_WITH(rlm-securid-include-dir,
+ [AS_HELP_STRING([--with-rlm-securid-include-dir=DIR],
+ [Directory where the securid includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-securid-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ securid_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-rlm-securid-lib-dir=DIR
+securid_lib_dir=
+AC_ARG_WITH(rlm-securid-lib-dir,
+ [AS_HELP_STRING([--with-rlm-securid-lib-dir=DIR],
+ [Directory where the securid libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-securid-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ securid_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-rlm-securid-dir=DIR
+AC_ARG_WITH(rlm-securid-dir,
+ [AS_HELP_STRING([--with-rlm-securid-dir=DIR],
+ [Base directory where securid is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-securid-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ securid_lib_dir="$withval/lib"
+ securid_include_dir="$withval/inc"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="$securid_include_dir"
+FR_SMART_CHECK_INCLUDE(acexport.h)
+if test "x$ac_cv_header_acexport_h" != "xyes"; then
+ AC_MSG_WARN([securid headers not found. Use --with-rlm-securid-include-dir=<path>.])
+ FR_MODULE_FAIL([acexport.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+dnl try to link to securid
+smart_try_dir="$securid_lib_dir"
+FR_SMART_CHECK_LIB(aceclnt, SD_Init)
+if test "x$ac_cv_lib_aceclnt_SD_Init" != "xyes"
+then
+ AC_MSG_WARN([securid libraries not found. Use --with-rlm-securid-lib-dir=<path>.])
+ FR_MODULE_FAIL([libaceclnt])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_securid/mem.c b/src/modules/rlm_securid/mem.c
new file mode 100644
index 0000000..6e262e8
--- /dev/null
+++ b/src/modules/rlm_securid/mem.c
@@ -0,0 +1,313 @@
+/*
+ * mem.c Session handling, mostly taken from src/modules/rlm_eap/mem.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2012 The FreeRADIUS server project
+ * Copyright 2012 Alan DeKok <aland@networkradius.com>
+ */
+
+#include <stdio.h>
+#include "rlm_securid.h"
+
+static void securid_sessionlist_clean_expired(rlm_securid_t *inst, REQUEST *request, time_t timestamp);
+
+static SECURID_SESSION* securid_sessionlist_delete(rlm_securid_t *inst,
+ SECURID_SESSION *session);
+
+SECURID_SESSION* securid_session_alloc(void)
+{
+ SECURID_SESSION *session;
+
+ session = rad_malloc(sizeof(SECURID_SESSION));
+ memset(session, 0, sizeof(SECURID_SESSION));
+
+ session->sdiHandle = SDI_HANDLE_NONE;
+
+ return session;
+}
+
+void securid_session_free(UNUSED rlm_securid_t *inst,REQUEST *request,
+ SECURID_SESSION *session)
+{
+ if (!session)
+ return;
+
+ RDEBUG2("Freeing session id=%d identity='%s' state='%s'",
+ session->session_id,SAFE_STR(session->identity),session->state);
+
+ if (session->identity) {
+ free(session->identity);
+ session->identity = NULL;
+ }
+ if (session->pin) {
+ free(session->pin);
+ session->pin = NULL;
+ }
+
+ if (session->sdiHandle != SDI_HANDLE_NONE) {
+ SD_Close(session->sdiHandle);
+ session->sdiHandle = SDI_HANDLE_NONE;
+ }
+
+ free(session);
+}
+
+
+void securid_sessionlist_free(rlm_securid_t *inst,REQUEST *request)
+{
+ SECURID_SESSION *node, *next;
+
+ pthread_mutex_lock(&(inst->session_mutex));
+
+ for (node = inst->session_head; node != NULL; node = next) {
+ next = node->next;
+ securid_session_free(inst,request,node);
+ }
+
+ inst->session_head = inst->session_tail = NULL;
+
+ pthread_mutex_unlock(&(inst->session_mutex));
+}
+
+
+
+/*
+ * Add a session to the set of active sessions.
+ *
+ * Since we're adding it to the list, we guess that this means
+ * the packet needs a State attribute. So add one.
+ */
+int securid_sessionlist_add(rlm_securid_t *inst,REQUEST *request, SECURID_SESSION *session)
+{
+ int status = 0;
+ VALUE_PAIR *state;
+
+ /*
+ * The time at which this request was made was the time
+ * at which it was received by the RADIUS server.
+ */
+ session->timestamp = request->timestamp;
+
+ session->src_ipaddr = request->packet->src_ipaddr;
+
+ /*
+ * Playing with a data structure shared among threads
+ * means that we need a lock, to avoid conflict.
+ */
+ pthread_mutex_lock(&(inst->session_mutex));
+
+ /*
+ * If we have a DoS attack, discard new sessions.
+ */
+ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) {
+ securid_sessionlist_clean_expired(inst, request, session->timestamp);
+ goto done;
+ }
+
+ if (session->session_id == 0) {
+ /* this is a NEW session (we are not inserting an updated session) */
+ inst->last_session_id++;
+ session->session_id = inst->last_session_id;
+ RDEBUG2("Creating a new session with id=%d\n",session->session_id);
+ }
+
+ memset(session->state, 0, sizeof(session->state));
+ snprintf(session->state,sizeof(session->state)-1,"FRR-CH %d|%d",session->session_id,session->trips+1);
+ RDEBUG2("Inserting session id=%d identity='%s' state='%s' to the session list",
+ session->session_id,SAFE_STR(session->identity),session->state);
+
+
+ /*
+ * Generate State, since we've been asked to add it to
+ * the list.
+ */
+ state = fr_pair_make(request->reply, &request->reply->vps, "State", NULL, T_OP_EQ);
+ if (!state) return -1;
+
+ fr_pair_value_memcpy(state, session->state, sizeof(session->state));
+
+ status = rbtree_insert(inst->session_tree, session);
+ if (status) {
+ /* tree insert SUCCESS */
+ /* insert the session to the linked list of sessions */
+ SECURID_SESSION *prev;
+
+ prev = inst->session_tail;
+ if (prev) {
+ /* insert to the tail of the list */
+ prev->next = session;
+ session->prev = prev;
+ session->next = NULL;
+ inst->session_tail = session;
+ } else {
+ /* 1st time */
+ inst->session_head = inst->session_tail = session;
+ session->next = session->prev = NULL;
+ }
+ }
+
+ /*
+ * Now that we've finished mucking with the list,
+ * unlock it.
+ */
+ done:
+ pthread_mutex_unlock(&(inst->session_mutex));
+
+ if (!status) {
+ fr_pair_list_free(&state);
+ ERROR("rlm_securid: Failed to store session");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Find existing session if any which matches the State variable in current AccessRequest
+ * Then, release the session from the list, and return it to
+ * the caller.
+ *
+ */
+SECURID_SESSION *securid_sessionlist_find(rlm_securid_t *inst, REQUEST *request)
+{
+ VALUE_PAIR *state;
+ SECURID_SESSION* session;
+ SECURID_SESSION mySession;
+
+ /* clean expired sessions if any */
+ pthread_mutex_lock(&(inst->session_mutex));
+ securid_sessionlist_clean_expired(inst, request, request->timestamp);
+ pthread_mutex_unlock(&(inst->session_mutex));
+
+ /*
+ * We key the sessions off of the 'state' attribute
+ */
+ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (!state) {
+ return NULL;
+ }
+
+ if (state->vp_length != SECURID_STATE_LEN) {
+ ERROR("rlm_securid: Invalid State variable. length=%d", (int) state->vp_length);
+ return NULL;
+ }
+
+ memset(&mySession,0,sizeof(mySession));
+ mySession.src_ipaddr = request->packet->src_ipaddr;
+ memcpy(mySession.state, state->vp_strvalue, sizeof(mySession.state));
+
+ /*
+ * Playing with a data structure shared among threads
+ * means that we need a lock, to avoid conflict.
+ */
+ pthread_mutex_lock(&(inst->session_mutex));
+ session = securid_sessionlist_delete(inst, &mySession);
+ pthread_mutex_unlock(&(inst->session_mutex));
+
+ /*
+ * Might not have been there.
+ */
+ if (!session) {
+ ERROR("rlm_securid: No SECURID session matching the State variable");
+ return NULL;
+ }
+
+ RDEBUG2("Session found identity='%s' state='%s', released from the list",
+ SAFE_STR(session->identity),session->state);
+ if (session->trips >= inst->max_trips_per_session) {
+ RDEBUG2("More than %d authentication packets for this SECURID session. Aborted.",inst->max_trips_per_session);
+ securid_session_free(inst,request,session);
+ return NULL;
+ }
+ session->trips++;
+
+ return session;
+}
+
+
+/************ private functions *************/
+static SECURID_SESSION *securid_sessionlist_delete(rlm_securid_t *inst, SECURID_SESSION *session)
+{
+ rbnode_t *node;
+
+ node = rbtree_find(inst->session_tree, session);
+ if (!node) return NULL;
+
+ session = rbtree_node2data(inst->session_tree, node);
+
+ /*
+ * Delete old session from the tree.
+ */
+ rbtree_delete(inst->session_tree, node);
+
+ /*
+ * And unsplice it from the linked list.
+ */
+ if (session->prev) {
+ session->prev->next = session->next;
+ } else {
+ inst->session_head = session->next;
+ }
+ if (session->next) {
+ session->next->prev = session->prev;
+ } else {
+ inst->session_tail = session->prev;
+ }
+ session->prev = session->next = NULL;
+
+ return session;
+}
+
+
+static void securid_sessionlist_clean_expired(rlm_securid_t *inst, REQUEST *request, time_t timestamp)
+{
+ int num_sessions;
+ SECURID_SESSION *session;
+
+ num_sessions = rbtree_num_elements(inst->session_tree);
+ RDEBUG2("There are %d sessions in the tree\n",num_sessions);
+
+ /*
+ * Delete old sessions from the list
+ *
+ */
+ while((session = inst->session_head)) {
+ if ((timestamp - session->timestamp) > inst->timer_limit) {
+ rbnode_t *node;
+ node = rbtree_find(inst->session_tree, session);
+ rad_assert(node != NULL);
+ rbtree_delete(inst->session_tree, node);
+
+ /*
+ * session == inst->session_head
+ */
+ inst->session_head = session->next;
+ if (session->next) {
+ session->next->prev = NULL;
+ } else {
+ inst->session_head = NULL;
+ inst->session_tail = NULL;
+ }
+
+ RDEBUG2("Cleaning expired session: identity='%s' state='%s'\n",
+ SAFE_STR(session->identity),session->state);
+ securid_session_free(inst,request,session);
+ } else {
+ /* no need to check all sessions since they are sorted by age */
+ break;
+ }
+ }
+}
diff --git a/src/modules/rlm_securid/rlm_securid.c b/src/modules/rlm_securid/rlm_securid.c
new file mode 100644
index 0000000..ddb9bba
--- /dev/null
+++ b/src/modules/rlm_securid/rlm_securid.c
@@ -0,0 +1,563 @@
+/*
+ * 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_securid.c
+ * @brief Supports auth against SecurID servers using OTP h/w tokens.
+ *
+ * Supports "next-token code" and "new-pin" modes.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ * @copyright 2012 Alan DeKok <aland@networkradius.com>
+ */
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <ctype.h>
+
+#include "rlm_securid.h"
+
+typedef enum {
+ RC_SECURID_AUTH_SUCCESS = 0,
+ RC_SECURID_AUTH_FAILURE = -3,
+ RC_SECURID_AUTH_ACCESS_DENIED_FAILURE = -4,
+ RC_SECURID_AUTH_INVALID_SERVER_FAILURE = -5,
+ RC_SECURID_AUTH_CHALLENGE = -17
+} SECURID_AUTH_RC;
+
+
+static const CONF_PARSER module_config[] = {
+ { "timer_expire", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, timer_limit), "600" },
+ { "max_sessions", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_sessions), "2048" },
+ { "max_trips_per_session", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_trips_per_session), NULL },
+ { "max_round_trips", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_securid_t, max_trips_per_session), "6" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static SD_CHAR empty_pin[] = "";
+
+/* comparison function to find session in the tree */
+static int securid_session_cmp(void const *a, void const *b)
+{
+ int rcode;
+ SECURID_SESSION const *one = a;
+ SECURID_SESSION const *two = b;
+
+ rad_assert(one != NULL);
+ rad_assert(two != NULL);
+
+ rcode = fr_ipaddr_cmp(&one->src_ipaddr, &two->src_ipaddr);
+ if (rcode != 0) return rcode;
+
+ return memcmp(one->state, two->state, sizeof(one->state));
+}
+
+
+static SECURID_AUTH_RC securidAuth(void *instance, REQUEST *request,
+ char const *username,
+ char const *passcode,
+ char *replyMsgBuffer, size_t replyMsgBufferSize)
+{
+ rlm_securid_t *inst = (rlm_securid_t *) instance;
+ int acm_ret;
+ SD_PIN pin_params;
+ char new_pin[10];
+ char format[30];
+ SECURID_SESSION *securid_session = NULL;
+ int rc = -1;
+
+ SD_CHAR *securid_user, *securid_pass;
+
+ if (!username) {
+ ERROR("SecurID username is NULL");
+ return RC_SECURID_AUTH_FAILURE;
+ }
+
+ if (!passcode) {
+ ERROR("SecurID passcode is NULL for %s user", username);
+ return RC_SECURID_AUTH_FAILURE;
+ }
+
+ memcpy(&securid_user, &username, sizeof(securid_user));
+ memcpy(&securid_pass, &passcode, sizeof(securid_pass));
+
+ *replyMsgBuffer = '\0';
+
+ securid_session = securid_sessionlist_find(inst, request);
+ if (!securid_session) {
+ /* securid session not found */
+ SDI_HANDLE sdiHandle = SDI_HANDLE_NONE;
+
+ acm_ret = SD_Init(&sdiHandle);
+ if (acm_ret != ACM_OK) {
+ ERROR("Cannot communicate with the ACE/Server");
+ return -1;
+ }
+
+ acm_ret = SD_Lock(sdiHandle, securid_user);
+ if (acm_ret != ACM_OK) {
+ ERROR("SecurID: Access denied. Name [%s] lock failed", username);
+ return -2;
+ }
+
+ acm_ret = SD_Check(sdiHandle, securid_pass, securid_user);
+ switch (acm_ret) {
+ case ACM_OK:
+ /* we are in now */
+ RDEBUG("SecurID authentication successful for %s", username);
+ SD_Close(sdiHandle);
+
+ return RC_SECURID_AUTH_SUCCESS;
+
+ case ACM_ACCESS_DENIED:
+ /* not this time */
+ RDEBUG("SecurID Access denied for %s", username);
+ SD_Close(sdiHandle);
+ return RC_SECURID_AUTH_ACCESS_DENIED_FAILURE;
+
+ case ACM_INVALID_SERVER:
+ ERROR("SecurID: Invalid ACE server");
+ return RC_SECURID_AUTH_INVALID_SERVER_FAILURE;
+
+ case ACM_NEW_PIN_REQUIRED:
+ RDEBUG2("SecurID new pin required for %s", username);
+
+ /* create a new session */
+ securid_session = securid_session_alloc();
+ securid_session->sdiHandle = sdiHandle; /* save ACE handle for future use */
+ securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
+ securid_session->identity = strdup(username);
+
+ /* Get PIN requirements */
+ (void) AceGetPinParams(sdiHandle, &pin_params);
+
+ /* If a system-generated PIN is required */
+ if (pin_params.Selectable == CANNOT_CHOOSE_PIN) {
+ /* Prompt user to accept a system generated PIN */
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nAre you prepared to accept a new system-generated PIN [y/n]?");
+ securid_session->securidSessionState = NEW_PIN_SYSTEM_ACCEPT_STATE;
+
+ } else if (pin_params.Selectable == USER_SELECTABLE) { //may be returned by AM 6.x servers.
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nPress 'y' to generate a new PIN\r\nOR\r\n'n'to enter a new PIN yourself [y/n]");
+ securid_session->securidSessionState = NEW_PIN_USER_SELECT_STATE;
+
+ } else {
+ if (pin_params.Alphanumeric) {
+ strcpy(format, "alphanumeric characters");
+ } else {
+ strcpy(format, "digits");
+ }
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+ pin_params.Min, pin_params.Max, format);
+ }
+
+ /* insert new session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+
+ return RC_SECURID_AUTH_CHALLENGE;
+
+ case ACM_NEXT_CODE_REQUIRED:
+ RDEBUG2("Next securid token code required for %s",
+ username);
+
+ /* create a new session */
+ securid_session = securid_session_alloc();
+ securid_session->sdiHandle = sdiHandle;
+ securid_session->securidSessionState = NEXT_CODE_REQUIRED_STATE;
+ securid_session->identity = strdup(username);
+
+ /* insert new session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+
+ strlcpy(replyMsgBuffer, "\r\nPlease Enter the Next Code from Your Token:", replyMsgBufferSize);
+ return RC_SECURID_AUTH_CHALLENGE;
+
+ default:
+ ERROR("SecurID: Unexpected error from ACE/Agent API acm_ret=%d", acm_ret);
+ securid_session_free(inst, request, securid_session);
+ return RC_SECURID_AUTH_FAILURE;
+
+
+ }
+ } else {
+ /* existing session found */
+ RDEBUG("Continuing previous session found for user [%s]", username);
+
+ /* continue previous session */
+ switch (securid_session->securidSessionState) {
+ case NEXT_CODE_REQUIRED_STATE:
+ DEBUG2("Securid NEXT_CODE_REQUIRED_STATE: User [%s]", username);
+ /* next token code mode */
+
+ acm_ret = SD_Next(securid_session->sdiHandle, securid_pass);
+ if (acm_ret == ACM_OK) {
+ INFO("Next SecurID token accepted for [%s].", securid_session->identity);
+ rc = RC_SECURID_AUTH_SUCCESS;
+
+ } else {
+ INFO("SecurID: Next token rejected for [%s].", securid_session->identity);
+ rc = RC_SECURID_AUTH_FAILURE;
+ }
+
+ /* deallocate session */
+ securid_session_free(inst, request, securid_session);
+ return rc;
+
+ case NEW_PIN_REQUIRED_STATE:
+ RDEBUG2("SecurID NEW_PIN_REQUIRED_STATE for %s",
+ username);
+
+ /* save the previous pin */
+ if (securid_session->pin) {
+ free(securid_session->pin);
+ securid_session->pin = NULL;
+ }
+ securid_session->pin = strdup(passcode);
+
+ strlcpy(replyMsgBuffer, "\r\n Please re-enter new PIN:", replyMsgBufferSize);
+
+ /* set next state */
+ securid_session->securidSessionState = NEW_PIN_USER_CONFIRM_STATE;
+
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+ return RC_SECURID_AUTH_CHALLENGE;
+
+ case NEW_PIN_USER_CONFIRM_STATE:
+ RDEBUG2("SecurID NEW_PIN_USER_CONFIRM_STATE: User [%s]", username);
+ /* compare previous pin and current pin */
+ if (!securid_session->pin || strcmp(securid_session->pin, passcode)) {
+ RDEBUG2("Pin confirmation failed. Pins do not match [%s] and [%s]",
+ SAFE_STR(securid_session->pin), securid_pass);
+ /* pins do not match */
+
+ /* challenge the user again */
+ AceGetPinParams(securid_session->sdiHandle, &pin_params);
+ if (pin_params.Alphanumeric) {
+ strcpy(format, "alphanumeric characters");
+ } else {
+ strcpy(format, "digits");
+ }
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Pins do not match--Please try again.\r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+ pin_params.Min, pin_params.Max, format);
+
+ securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
+
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+ rc = RC_SECURID_AUTH_CHALLENGE;
+
+ } else {
+ /* pins match */
+ RDEBUG2("Pin confirmation succeeded. Pins match");
+ acm_ret = SD_Pin(securid_session->sdiHandle, securid_pass);
+ if (acm_ret == ACM_NEW_PIN_ACCEPTED) {
+ RDEBUG("New SecurID pin accepted for %s.", securid_session->identity);
+
+ securid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE;
+
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+
+ rc = RC_SECURID_AUTH_CHALLENGE;
+ strlcpy(replyMsgBuffer, " \r\n\r\nWait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:", replyMsgBufferSize);
+ } else {
+ RDEBUG("SecurID: New SecurID pin rejected for %s.", securid_session->identity);
+ SD_Pin(securid_session->sdiHandle, &empty_pin[0]); /* cancel PIN */
+
+
+ rc = RC_SECURID_AUTH_FAILURE;
+
+ /* deallocate session */
+ securid_session_free(inst, request, securid_session);
+ }
+ }
+ return rc;
+ case NEW_PIN_AUTH_VALIDATE_STATE:
+ acm_ret = SD_Check(securid_session->sdiHandle, securid_pass, securid_user);
+ if (acm_ret == ACM_OK) {
+ RDEBUG("New SecurID passcode accepted for %s.",
+ securid_session->identity);
+ rc = RC_SECURID_AUTH_SUCCESS;
+
+ } else {
+ INFO("SecurID: New passcode rejected for [%s].", securid_session->identity);
+ rc = RC_SECURID_AUTH_FAILURE;
+ }
+
+ /* deallocate session */
+ securid_session_free(inst, request, securid_session);
+
+ return rc;
+ case NEW_PIN_SYSTEM_ACCEPT_STATE:
+ if (!strcmp(passcode, "y")) {
+ AceGetSystemPin(securid_session->sdiHandle, new_pin);
+
+ /* Save the PIN for the next session
+ * continuation */
+ if (securid_session->pin) {
+ free(securid_session->pin);
+ securid_session->pin = NULL;
+ }
+ securid_session->pin = strdup(new_pin);
+
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
+ new_pin);
+ securid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
+
+ /* insert the updated session in the
+ * session list */
+ securid_sessionlist_add(inst, request, securid_session);
+
+ rc = RC_SECURID_AUTH_CHALLENGE;
+
+ } else {
+ SD_Pin(securid_session->sdiHandle, &empty_pin[0]); //Cancel new PIN
+
+ /* deallocate session */
+ securid_session_free(inst, request,
+ securid_session);
+
+ rc = RC_SECURID_AUTH_FAILURE;
+ }
+
+ return rc;
+
+ case NEW_PIN_SYSTEM_CONFIRM_STATE:
+ acm_ret = SD_Pin(securid_session->sdiHandle, (SD_CHAR*)securid_session->pin);
+ if (acm_ret == ACM_NEW_PIN_ACCEPTED) {
+ strlcpy(replyMsgBuffer, " \r\n\r\nPin Accepted. Wait for the code on your card to change, then enter new PIN and TokenCode\r\n\r\nEnter PASSCODE:", replyMsgBufferSize);
+ securid_session->securidSessionState = NEW_PIN_AUTH_VALIDATE_STATE;
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request, securid_session);
+ rc = RC_SECURID_AUTH_CHALLENGE;
+
+ } else {
+ SD_Pin(securid_session->sdiHandle, &empty_pin[0]); //Cancel new PIN
+ strlcpy(replyMsgBuffer, " \r\n\r\nPin Rejected. Wait for the code on your card to change, then try again.\r\n\r\nEnter PASSCODE:", replyMsgBufferSize);
+ /* deallocate session */
+ securid_session_free(inst, request,
+ securid_session);
+ rc = RC_SECURID_AUTH_FAILURE;
+ }
+
+ return rc;
+
+ /* USER_SELECTABLE state should be implemented to preserve compatibility with AM 6.x servers, which can return this state */
+ case NEW_PIN_USER_SELECT_STATE:
+ if (!strcmp(passcode, "y")) {
+ /* User has opted for a system-generated PIN */
+ AceGetSystemPin(securid_session->sdiHandle, new_pin);
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ "\r\nYour new PIN is: %s\r\nDo you accept this [y/n]?",
+ new_pin);
+ securid_session->securidSessionState = NEW_PIN_SYSTEM_CONFIRM_STATE;
+
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request,
+ securid_session);
+ rc = RC_SECURID_AUTH_CHALLENGE;
+
+ } else {
+ /* User has opted for a user-defined PIN */
+ AceGetPinParams(securid_session->sdiHandle,
+ &pin_params);
+ if (pin_params.Alphanumeric) {
+ strcpy(format, "alphanumeric characters");
+ } else {
+ strcpy(format, "digits");
+ }
+
+ snprintf(replyMsgBuffer, replyMsgBufferSize,
+ " \r\n Enter your new PIN of %d to %d %s, \r\n or\r\n <Ctrl-D> to cancel the New PIN procedure:",
+ pin_params.Min, pin_params.Max, format);
+ securid_session->securidSessionState = NEW_PIN_REQUIRED_STATE;
+
+ /* insert the updated session in the session list */
+ securid_sessionlist_add(inst, request,
+ securid_session);
+ rc = RC_SECURID_AUTH_CHALLENGE;
+ }
+
+ return rc;
+
+ default:
+ ERROR("rlm_securid: Invalid session state %d for user [%s]",
+ securid_session->securidSessionState,
+ username);
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+/******************************************/
+static int mod_detach(void *instance)
+{
+ rlm_securid_t *inst = (rlm_securid_t *) instance;
+
+ /* delete session tree */
+ if (inst->session_tree) {
+ rbtree_free(inst->session_tree);
+ inst->session_tree = NULL;
+ }
+
+ pthread_mutex_destroy(&(inst->session_mutex));
+
+ return 0;
+}
+
+
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_securid_t *inst = instance;
+
+ /*
+ * Lookup sessions in the tree. We don't free them in
+ * the tree, as that's taken care of elsewhere...
+ */
+ inst->session_tree = rbtree_create(NULL, securid_session_cmp, NULL, 0);
+ if (!inst->session_tree) {
+ ERROR("rlm_securid: Cannot initialize session tree");
+ return -1;
+ }
+
+ pthread_mutex_init(&(inst->session_mutex), NULL);
+ return 0;
+}
+
+
+/*
+ * Authenticate the user via one of any well-known password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ int rcode;
+ rlm_securid_t *inst = instance;
+ char buffer[MAX_STRING_LEN]="";
+ char const *username=NULL, *password=NULL;
+ VALUE_PAIR *vp;
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
+ */
+ if (!request->username) {
+ AUTH("rlm_securid: Attribute \"User-Name\" is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (!request->password) {
+ RAUTH("Attribute \"Password\" is required for authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * Clear-text passwords are the only ones we support.
+ */
+ if (request->password->da->attr != PW_USER_PASSWORD) {
+ RAUTH("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->da->name);
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * The user MUST supply a non-zero-length password.
+ */
+ if (request->password->vp_length == 0) {
+ REDEBUG("Password should not be empty");
+ return RLM_MODULE_INVALID;
+ }
+
+ /*
+ * shortcuts
+ */
+ username = request->username->vp_strvalue;
+ password = request->password->vp_strvalue;
+
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("Login attempt with password \"%s\"", password);
+ } else {
+ RDEBUG("Login attempt with password");
+ }
+
+ rcode = securidAuth(inst, request, username, password,
+ buffer, sizeof(buffer));
+
+ switch (rcode) {
+ case RC_SECURID_AUTH_SUCCESS:
+ rcode = RLM_MODULE_OK;
+ break;
+
+ case RC_SECURID_AUTH_CHALLENGE:
+ /* reply with Access-challenge message code (11) */
+
+ /* Generate Prompt attribute */
+ vp = fr_pair_afrom_num(request->reply, PW_PROMPT, 0);
+
+ rad_assert(vp != NULL);
+ vp->vp_integer = 0; /* no echo */
+ fr_pair_add(&request->reply->vps, vp);
+
+ /* Mark the packet as a Acceess-Challenge Packet */
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ RDEBUG("Sending Access-Challenge");
+ rcode = RLM_MODULE_HANDLED;
+ break;
+
+ case RC_SECURID_AUTH_FAILURE:
+ case RC_SECURID_AUTH_ACCESS_DENIED_FAILURE:
+ case RC_SECURID_AUTH_INVALID_SERVER_FAILURE:
+ default:
+ rcode = RLM_MODULE_REJECT;
+ break;
+ }
+
+ if (*buffer) pair_make_reply("Reply-Message", buffer, T_OP_EQ);
+
+ return rcode;
+}
+
+
+/*
+ * 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_securid;
+module_t rlm_securid = {
+ .magic = RLM_MODULE_INIT,
+ .name = "securid",
+ .type = RLM_TYPE_HUP_SAFE,
+ .inst_size = sizeof(rlm_securid_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate
+ },
+};
diff --git a/src/modules/rlm_securid/rlm_securid.h b/src/modules/rlm_securid/rlm_securid.h
new file mode 100644
index 0000000..82ed77e
--- /dev/null
+++ b/src/modules/rlm_securid/rlm_securid.h
@@ -0,0 +1,93 @@
+#ifndef _RLM_SECURID_H
+#define _RLM_SECURID_H
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include "acexport.h"
+
+#define SAFE_STR(s) s==NULL?"EMPTY":s
+
+typedef enum {
+ INITIAL_STATE = 0,
+ NEXT_CODE_REQUIRED_STATE = 100,
+ NEW_PIN_REQUIRED_STATE = 200,
+ NEW_PIN_USER_CONFIRM_STATE = 201,
+ NEW_PIN_AUTH_VALIDATE_STATE = 202,
+ NEW_PIN_SYSTEM_ACCEPT_STATE = 203,
+ NEW_PIN_SYSTEM_CONFIRM_STATE = 204,
+ NEW_PIN_USER_SELECT_STATE = 205,
+} SECURID_SESSION_STATE;
+
+/*
+ * SECURID_SESSION is used to identify existing securID sessions
+ * to continue Next-Token code and New-Pin conversations with a client
+ *
+ * next = pointer to next
+ * state = state attribute from the reply we sent
+ * state_len = length of data in the state attribute.
+ * src_ipaddr = client which sent us the RADIUS request containing
+ * this SecurID conversation.
+ * timestamp = timestamp when this handler was last used.
+ * trips = number of trips
+ * identity = Identity of the user
+ * request = RADIUS request data structure
+ */
+
+#define SECURID_STATE_LEN 32
+typedef struct _securid_session_t {
+ struct _securid_session_t *prev, *next;
+ SDI_HANDLE sdiHandle;
+ SECURID_SESSION_STATE securidSessionState;
+
+ char state[SECURID_STATE_LEN];
+
+ fr_ipaddr_t src_ipaddr;
+ time_t timestamp;
+ unsigned int session_id;
+ uint32_t trips;
+
+ char *pin; /* previous pin if user entered it during NEW-PIN mode process */
+ char *identity; /* save user's identity name for future use */
+
+} SECURID_SESSION;
+
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ * sessions = remembered sessions, in a tree for speed.
+ * mutex = ensure only one thread is updating the sessions list
+ */
+typedef struct rlm_securid_t {
+ pthread_mutex_t session_mutex;
+ rbtree_t* session_tree;
+ SECURID_SESSION *session_head, *session_tail;
+
+ unsigned int last_session_id;
+
+ /*
+ * Configuration items.
+ */
+ uint32_t timer_limit;
+ uint32_t max_sessions;
+ uint32_t max_trips_per_session;
+} rlm_securid_t;
+
+/* Memory Management */
+SECURID_SESSION* securid_session_alloc(void);
+void securid_session_free(rlm_securid_t *inst, REQUEST *request,SECURID_SESSION *session)
+ CC_HINT(nonnull);
+
+void securid_sessionlist_free(rlm_securid_t *inst,REQUEST *request) CC_HINT(nonnull);
+
+int securid_sessionlist_add(rlm_securid_t *inst, REQUEST *request, SECURID_SESSION *session)
+ CC_HINT(nonnull);
+SECURID_SESSION *securid_sessionlist_find(rlm_securid_t *inst, REQUEST *request) CC_HINT(nonnull);
+
+
+#endif
diff --git a/src/modules/rlm_securid/securid b/src/modules/rlm_securid/securid
new file mode 100644
index 0000000..c848267
--- /dev/null
+++ b/src/modules/rlm_securid/securid
@@ -0,0 +1,19 @@
+#
+# This is the configuration for the "securid" module.
+#
+
+securid {
+ # How long the module waits before expiring a session.
+ #
+ timer_expire = 600
+
+ # The sessions are tracked internally. This configuration
+ # item limits the total number of allowed sessions.
+ #
+ max_sessions = 2048
+
+ # How many round trips are allowed before the authentication
+ # is forced to fail.
+ #
+ max_round_trips = 6
+}
diff --git a/src/modules/rlm_smsotp/.gitignore b/src/modules/rlm_smsotp/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_smsotp/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_smsotp/README.md b/src/modules/rlm_smsotp/README.md
new file mode 100644
index 0000000..491fda3
--- /dev/null
+++ b/src/modules/rlm_smsotp/README.md
@@ -0,0 +1,11 @@
+# rlm_smsotp
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Extends FreeRADIUS with a socket interface to create and validate
+one-time passwords. For example this can be used in certain
+circumstances to perform 2FA using SMS messages.
diff --git a/src/modules/rlm_smsotp/all.mk.in b/src/modules/rlm_smsotp/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_smsotp/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_smsotp/config.h.in b/src/modules/rlm_smsotp/config.h.in
new file mode 100644
index 0000000..f3758b3
--- /dev/null
+++ b/src/modules/rlm_smsotp/config.h.in
@@ -0,0 +1,34 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/src/modules/rlm_smsotp/configure b/src/modules/rlm_smsotp/configure
new file mode 100755
index 0000000..cb684e0
--- /dev/null
+++ b/src/modules/rlm_smsotp/configure
@@ -0,0 +1,4552 @@
+#! /bin/sh
+# From configure.ac Revision: 0.1 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_smsotp.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_smsotp
+'
+ 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_smsotp build without rlm_smsotp
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_smsotp
+echo
+
+
+# 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_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $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
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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; } && { ac_try='./conftest$ac_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 :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ 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_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ 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. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_smsotp was given.
+if test "${with_rlm_smsotp+set}" = set; then :
+ withval=$with_rlm_smsotp;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_smsotp" != 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
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/un.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_un_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_UN_H 1
+_ACEOF
+
+fi
+
+done
+
+if test "$ac_cv_header_sys_un_h" != "yes"; then
+
+fail="$fail sys/un.h"
+
+fi
+
+
+ targetname=rlm_smsotp
+else
+ targetname=
+ echo \*\*\* module rlm_smsotp is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_smsotp to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_smsotp." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_smsotp." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_smsotp requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_smsotp requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_smsotp/configure.ac b/src/modules/rlm_smsotp/configure.ac
new file mode 100644
index 0000000..f5dea59
--- /dev/null
+++ b/src/modules/rlm_smsotp/configure.ac
@@ -0,0 +1,24 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_smsotp.c])
+AC_REVISION($Revision: 0.1 $)
+FR_INIT_MODULE([rlm_smsotp])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_CHECK_HEADERS(sys/un.h)
+if test "$ac_cv_header_sys_un_h" != "yes"; then
+ FR_MODULE_FAIL([sys/un.h])
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_smsotp/rlm_smsotp.c b/src/modules/rlm_smsotp/rlm_smsotp.c
new file mode 100644
index 0000000..409ff0b
--- /dev/null
+++ b/src/modules/rlm_smsotp/rlm_smsotp.c
@@ -0,0 +1,344 @@
+/*
+ * 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_smsotp.c
+ * @brief Supports OTP authentication using SMS.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2009 Siemens AG, Holger Wolff holger.wolff@siemens.com
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <sys/un.h>
+
+typedef struct rlm_smsotp_t {
+ char const *socket;
+ char const *challenge;
+ char const *authtype;
+ fr_connection_pool_t *pool;
+} rlm_smsotp_t;
+
+static const CONF_PARSER module_config[] = {
+ { "socket", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, socket), "/var/run/smsotp_socket" },
+ { "challenge_message", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, challenge), "Enter Mobile PIN" },
+ { "challenge_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_smsotp_t, authtype), "smsotp-reply" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int _mod_conn_free(int *fdp)
+{
+ close(*fdp);
+ return 0;
+}
+
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ int fd;
+ struct sockaddr_un sa;
+ rlm_smsotp_t *inst = instance;
+ socklen_t socklen = sizeof(sa);
+ int *fdp;
+
+ sa.sun_family = AF_UNIX;
+ strlcpy(sa.sun_path, inst->socket, sizeof(sa.sun_path));
+
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ ERROR("Failed opening SMSOTP file %s: %s",
+ inst->socket, fr_syserror(errno));
+ return NULL;
+ }
+
+ if (connect(fd, (struct sockaddr *) &sa, socklen) < -1) {
+ close(fd);
+ ERROR("Failed connecting to SMSOTP file %s: %s",
+ inst->socket, fr_syserror(errno));
+ return NULL;
+ }
+
+ fdp = talloc_zero(ctx, int);
+ talloc_set_destructor(fdp, _mod_conn_free);
+ *fdp = fd;
+
+ return fdp;
+}
+
+/*
+ * Full read with logging, and close on failure.
+ * Returns nread on success, 0 on EOF, -1 on other failures.
+ */
+static size_t read_all(int *fdp, char *buf, size_t len)
+{
+ ssize_t n;
+ size_t total = 0;
+
+ fd_set fds;
+ struct timeval tv;
+ int retval;
+
+ FD_ZERO(&fds);
+ FD_SET(*fdp, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ while (total < len) {
+ n = read(*fdp, &buf[total], len - total);
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ return -1;
+ }
+
+ /*
+ * Socket was closed. Don't try to re-open it.
+ */
+ if (n == 0) return 0;
+ total += n;
+
+ /*
+ * Check if there's more data. If not, return
+ * now.
+ */
+ retval = select(1, &fds, NULL, NULL, &tv);
+ if (!retval) {
+ buf[total]= '\0';
+ break;
+ }
+ }
+
+ return total;
+}
+
+
+/*
+ * Write all of the data, taking care of EINTR, etc.
+ */
+static int write_all(int *fdp, char const *buf, size_t len)
+{
+ size_t left = len;
+ ssize_t n;
+
+ while (left) {
+ n = write(*fdp, &buf[len - left], left);
+ if (n < 0) {
+ if ((errno == EINTR) || (errno == EPIPE)) {
+ continue;
+ }
+ return -1;
+ }
+ left -= n;
+ }
+
+ 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_smsotp_t *inst = instance;
+ struct sockaddr_un sa;
+ if (strlen(inst->socket) > (sizeof(sa.sun_path) - 1)) {
+ cf_log_err_cs(conf, "Socket filename is too long");
+ return -1;
+ }
+
+ /*
+ * Initialize the socket pool.
+ */
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, NULL);
+ if (!inst->pool) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Authenticate the user with the given password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_smsotp_t *inst = instance;
+ VALUE_PAIR *state;
+ int bufsize;
+ int *fdp;
+ rlm_rcode_t rcode = RLM_MODULE_FAIL;
+ char buffer[1000];
+ char output[1000];
+
+ fdp = fr_connection_get(inst->pool);
+ if (!fdp) return RLM_MODULE_FAIL;
+
+ /* Get greeting */
+ bufsize = read_all(fdp, buffer, sizeof(buffer));
+ if (bufsize == 0) {
+ REDEBUG("No data available from socket - other end closed the connection");
+ goto done;
+ }
+ if (bufsize < 0) {
+ REDEBUG("Failed reading from socket: %s", fr_syserror(errno));
+ goto done;
+ }
+
+ /*
+ * Look for the 'state' attribute.
+ */
+#define WRITE_ALL(_a,_b,_c) if (write_all(_a,_b,_c) < 0) goto done;
+ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (state) {
+ RDEBUG("Found reply to access challenge");
+
+ /* send username */
+ snprintf(output, sizeof(output), "check otp for %s\n",
+ request->username->vp_strvalue);
+ WRITE_ALL(fdp, output, strlen(output));
+
+ (void) read_all(fdp, buffer, sizeof(buffer));
+
+ /* send password */
+ snprintf(output, sizeof(output), "user otp is %s\n",
+ request->password->vp_strvalue);
+ WRITE_ALL(fdp, output, strlen(output));
+
+ (void) read_all(fdp, buffer, sizeof(buffer));
+
+ /* set uuid */
+ snprintf(output, sizeof(output), "otp id is %s\n",
+ state->vp_strvalue);
+ WRITE_ALL(fdp, output, strlen(output));
+
+ (void) read_all(fdp, buffer, sizeof(buffer));
+
+ /* now check the otp */
+ WRITE_ALL(fdp, "get check result\n", 17);
+
+ (void) read_all(fdp, buffer, sizeof(buffer));
+
+ /* end the sesssion */
+ WRITE_ALL(fdp, "quit\n", 5);
+
+ RDEBUG("answer is %s", buffer);
+ if (strcmp(buffer,"OK") == 0) {
+ rcode = RLM_MODULE_OK;
+ }
+
+ goto done;
+ }
+
+ RDEBUG("Generating OTP");
+
+ /* set username */
+ snprintf(output, sizeof(output), "generate otp for %s\n",
+ request->username->vp_strvalue);
+ WRITE_ALL(fdp, output, strlen(output));
+
+ (void) read_all(fdp, buffer, sizeof(buffer));
+
+ /* end the sesssion */
+ WRITE_ALL(fdp, "quit\n", 5);
+
+ RDEBUG("Unique ID is %s", buffer);
+
+ /* check the return string */
+ if (strcmp(buffer,"FAILED") == 0) { /* smsotp script returns a error */
+ goto done;
+ }
+
+ /*
+ * Create the challenge, and add it to the reply.
+ */
+
+ pair_make_reply("Reply-Message", inst->challenge, T_OP_EQ);
+ pair_make_reply("State", buffer, T_OP_EQ);
+
+ /*
+ * Mark the packet as an Access-Challenge packet.
+ *
+ * The server will take care of sending it to the user.
+ */
+ request->reply->code = PW_CODE_ACCESS_CHALLENGE;
+ DEBUG("rlm_smsotp: Sending Access-Challenge");
+
+ rcode = RLM_MODULE_HANDLED;
+
+done:
+ fr_connection_release(inst->pool, fdp);
+ return rcode;
+}
+
+/*
+ * 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)
+{
+ VALUE_PAIR *state;
+ rlm_smsotp_t *inst = instance;
+
+ /*
+ * Look for the 'state' attribute.
+ */
+ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY);
+ if (state != NULL) {
+ DEBUG("rlm_smsotp: Found reply to access challenge (AUTZ), Adding Auth-Type '%s'",inst->authtype);
+
+ fr_pair_delete_by_num(&request->config, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */
+ pair_make_config("Auth-Type", inst->authtype, T_OP_SET);
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * 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_smsotp;
+module_t rlm_smsotp = {
+ .magic = RLM_MODULE_INIT,
+ .name = "smsotp",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_smsotp_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_smsotp/smsotpd.pl b/src/modules/rlm_smsotp/smsotpd.pl
new file mode 100644
index 0000000..9fed0f7
--- /dev/null
+++ b/src/modules/rlm_smsotp/smsotpd.pl
@@ -0,0 +1,238 @@
+#!/usr/bin/perl -w
+
+# Copyright 2012 Thomas Glanzmann <thomas@glanzmann.de>
+# based on POE: Cookbook - UNIX Servers example server writen by James March
+
+use strict;
+use warnings FATAL => 'all';
+
+use POE;
+use POE::Wheel::SocketFactory;
+use POE::Wheel::ReadWrite;
+
+# If e-mail is specified, an e-mail will be send to the user.
+# If mobile is specified, an SMS will be send to the user.
+
+my %users = (
+ 'Administrator' => { email => 'devnull@binary.net', mobile => '49176xxx' },
+);
+
+my $otp_lifetime = 600;
+
+my $sipgateurl = 'https://login:password@samurai.sipgate.net/RPC2';
+
+my %tokens;
+my %sessions;
+
+my $OKAY = "OK\0\n";
+my $FAILED = "FAILED\0\n";
+
+Server::spawn('/var/run/smsotp_socket');
+$poe_kernel->run();
+exit 0;
+
+package Server;
+use POE::Session;
+use Socket;
+
+sub
+spawn
+{
+ my $rendezvous = shift;
+ POE::Session->create(
+ inline_states => {
+ _start => \&server_started,
+ got_client => \&server_accepted,
+ got_error => \&server_error,
+ },
+ heap => {rendezvous => $rendezvous,},
+ );
+}
+
+sub
+server_started
+{
+ my ($kernel, $heap) = @_[KERNEL, HEAP];
+ unlink $heap->{rendezvous} if -e $heap->{rendezvous};
+ $heap->{server} = POE::Wheel::SocketFactory->new(
+ SocketDomain => PF_UNIX,
+ BindAddress => $heap->{rendezvous},
+ SuccessEvent => 'got_client',
+ FailureEvent => 'got_error',
+ );
+}
+
+sub
+server_error
+{
+ my ($heap, $syscall, $errno, $error) = @_[HEAP, ARG0 .. ARG2];
+ $error = "Normal disconnection." unless $errno;
+ warn "Server socket encountered $syscall error $errno: $error\n";
+ delete $heap->{server};
+}
+
+sub
+server_accepted
+{
+ my $client_socket = $_[ARG0];
+ ServerSession::spawn($client_socket);
+}
+
+package ServerSession;
+use POE::Session;
+use Mail::Mailer;
+use Frontier::Client;
+
+sub
+spawn
+{
+ my $socket = shift;
+ POE::Session->create(
+ inline_states => {
+ _start => \&server_session_start,
+ got_client_input => \&server_session_input,
+ got_client_error => \&server_session_error,
+ },
+ args => [$socket],
+ );
+}
+
+sub
+server_session_start
+{
+ my ($heap, $socket) = @_[HEAP, ARG0];
+ $heap->{client} = POE::Wheel::ReadWrite->new(
+ Handle => $socket,
+ InputEvent => 'got_client_input',
+ ErrorEvent => 'got_client_error',
+ );
+
+ $heap->{client}->put("HELLO\0\n");
+}
+
+sub
+send_email
+{
+ my %args = @_;
+
+ my $mailer = Mail::Mailer->new('sendmail');
+ $mailer->open({
+ From => 'otp@glanzmann.de',
+ To => $args{to},
+ Subject => "One time password",
+ });
+ print $mailer $args{otp};
+ $mailer->close();
+}
+
+sub
+send_sms
+{
+ my %args = @_;
+
+ my $xmlrpc_client = Frontier::Client->new('url' => $sipgateurl);
+ my $xmlrpc_result = $xmlrpc_client->call("samurai.ClientIdentify", {
+ ClientName => 'sipgateAPI-sms.pl',
+ ClientVersion => '1.0',
+ ClientVendor => 'indigo networks GmbH'
+ });
+
+ if ($xmlrpc_result->{'StatusCode'} != 200) {
+ return; # catch error
+ }
+
+ $xmlrpc_result = $xmlrpc_client->call("samurai.SessionInitiate", {RemoteUri => "sip:$args{to}\@sipgate.net", TOS => "text", Content => $args{otp}});
+
+ if ($xmlrpc_result->{'StatusCode'} != 200) {
+ return; # catch error
+ }
+}
+
+sub
+reply_ok
+{
+ my $session = shift || die;
+
+ return 0 unless exists($sessions{$session}->{user});
+ return 0 unless exists($sessions{$session}->{otp});
+ return 0 unless exists($sessions{$session}->{id});
+
+ return 0 unless exists($tokens{$sessions{$session}->{user}}->{id});
+ return 0 unless exists($tokens{$sessions{$session}->{user}}->{otp});
+ return 0 unless exists($tokens{$sessions{$session}->{user}}->{time});
+
+ return 0 unless ($sessions{$session}->{otp} eq $tokens{$sessions{$session}->{user}}->{otp});
+ return 0 unless ($sessions{$session}->{id} eq $tokens{$sessions{$session}->{user}}->{id});
+
+ return 0 unless ((time() - $tokens{$sessions{$session}->{user}}->{time}) < $otp_lifetime);
+
+ return 1;
+}
+
+sub
+server_session_input
+{
+ my ($session, $heap, $input) = @_[SESSION, HEAP, ARG0];
+
+ if ($input =~ /^generate otp for ([\w\d]+)/) {
+ my $user = $1;
+
+ if (exists($users{$user})) {
+ $tokens{$user}->{id} = int(1 + rand(9999999999));
+ $tokens{$user}->{otp} = sprintf("%05d", int(1 + rand(99999)));
+ $tokens{$user}->{time} = time;
+
+ if (exists($users{$user}->{email})) {
+ send_email(to => $users{$user}->{email}, otp => $tokens{$user}->{otp});
+ }
+
+ if (exists($users{$user}->{mobile})) {
+ send_sms(to => $users{$user}->{mobile}, otp => $tokens{$user}->{otp});
+ }
+ $heap->{client}->put($tokens{$user}->{id} . "\0\n");
+
+ } else {
+ $heap->{client}->put($FAILED);
+ }
+
+ } elsif ($input =~ /^check otp for ([\w\d]+)/) {
+ $sessions{$session}->{user} = $1;
+ $heap->{client}->put($OKAY);
+
+ } elsif ($input =~ /^user otp is ([\w\d]+)/) {
+ $sessions{$session}->{otp} = $1;
+ $heap->{client}->put($OKAY);
+
+ } elsif ($input =~ /^otp id is ([\w\d_-]+)/) {
+ $sessions{$session}->{id} = $1;
+ $heap->{client}->put($OKAY);
+
+ } elsif ($input =~ /^get check result/) {
+ if (reply_ok($session)) {
+ $heap->{client}->put($OKAY);
+ } else {
+ $heap->{client}->put($FAILED);
+ }
+
+ delete($tokens{$sessions{$session}->{user}});
+
+ delete ($sessions{$session});
+
+ } elsif ($input =~ /^quit/) {
+ $heap->{client}->put($OKAY);
+ delete ($sessions{$session});
+ delete $heap->{client};
+
+ } else {
+ $heap->{client}->put($FAILED);
+ }
+}
+
+sub
+server_session_error
+{
+ my ($heap, $syscall, $errno, $error) = @_[HEAP, ARG0 .. ARG2];
+ $error = "Normal disconnection." unless $errno;
+ warn "Server session encountered $syscall error $errno: $error\n";
+ delete $heap->{client};
+}
diff --git a/src/modules/rlm_soh/README.md b/src/modules/rlm_soh/README.md
new file mode 100644
index 0000000..464c4ce
--- /dev/null
+++ b/src/modules/rlm_soh/README.md
@@ -0,0 +1,10 @@
+# rlm_soh
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Implements support for Microsoft's Statement of Health (SoH)
+protocol, which can run inside of PEAP or DHCP.
diff --git a/src/modules/rlm_soh/all.mk b/src/modules/rlm_soh/all.mk
new file mode 100644
index 0000000..a86a2a8
--- /dev/null
+++ b/src/modules/rlm_soh/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_soh.a
+SOURCES := rlm_soh.c
diff --git a/src/modules/rlm_soh/rlm_soh.c b/src/modules/rlm_soh/rlm_soh.c
new file mode 100644
index 0000000..11ab67b
--- /dev/null
+++ b/src/modules/rlm_soh/rlm_soh.c
@@ -0,0 +1,226 @@
+/*
+ * 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_soh.c
+ * @brief Decodes Microsoft's Statement of Health sub-protocol.
+ *
+ * @copyright 2010 Phil Mayers <p.mayers@imperial.ac.uk>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/dhcp.h>
+#include <freeradius-devel/soh.h>
+
+
+typedef struct rlm_soh_t {
+ char const *xlat_name;
+ bool dhcp;
+} rlm_soh_t;
+
+
+/*
+ * Not sure how to make this useful yet...
+ */
+static ssize_t soh_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen) {
+
+ VALUE_PAIR* vp[6];
+ char const *osname;
+
+ /*
+ * There will be no point unless SoH-Supported = yes
+ */
+ vp[0] = fr_pair_find_by_num(request->packet->vps, PW_SOH_SUPPORTED, 0, TAG_ANY);
+ if (!vp[0])
+ return 0;
+
+
+ if (strncasecmp(fmt, "OS", 2) == 0) {
+ /* OS vendor */
+ vp[0] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_OS_VENDOR, 0, TAG_ANY);
+ vp[1] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_OS_VERSION, 0, TAG_ANY);
+ vp[2] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_OS_RELEASE, 0, TAG_ANY);
+ vp[3] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_OS_BUILD, 0, TAG_ANY);
+ vp[4] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_SP_VERSION, 0, TAG_ANY);
+ vp[5] = fr_pair_find_by_num(request->packet->vps, PW_SOH_MS_MACHINE_SP_RELEASE, 0, TAG_ANY);
+
+ if (vp[0] && vp[0]->vp_integer == VENDORPEC_MICROSOFT) {
+ if (!vp[1]) {
+ snprintf(out, outlen, "Windows unknown");
+ } else {
+ switch (vp[1]->vp_integer) {
+ case 7:
+ osname = "7";
+ break;
+
+ case 6:
+ osname = "Vista";
+ break;
+
+ case 5:
+ osname = "XP";
+ break;
+
+ default:
+ osname = "Other";
+ break;
+ }
+ snprintf(out, outlen, "Windows %s %d.%d.%d sp %d.%d", osname, vp[1]->vp_integer,
+ vp[2] ? vp[2]->vp_integer : 0,
+ vp[3] ? vp[3]->vp_integer : 0,
+ vp[4] ? vp[4]->vp_integer : 0,
+ vp[5] ? vp[5]->vp_integer : 0
+ );
+ }
+ return strlen(out);
+ }
+ }
+
+ return 0;
+}
+
+
+static const CONF_PARSER module_config[] = {
+ /*
+ * Do SoH over DHCP?
+ */
+ { "dhcp", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_soh_t, dhcp), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ char const *name;
+ rlm_soh_t *inst = instance;
+
+ name = cf_section_name2(conf);
+ if (!name) name = cf_section_name1(conf);
+ inst->xlat_name = name;
+ if (!inst->xlat_name) return -1;
+
+ xlat_register(inst->xlat_name, soh_xlat, NULL, inst);
+
+ return 0;
+}
+
+#ifdef WITH_DHCP
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ int rcode;
+ VALUE_PAIR *vp;
+ rlm_soh_t *inst = instance;
+
+ if (!inst->dhcp) return RLM_MODULE_NOOP;
+
+ vp = fr_pair_find_by_num(request->packet->vps, 43, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
+ /*
+ * vendor-specific options contain
+ *
+ * vendor opt 220/0xdc - SoH payload, or null byte to probe, or string
+ * "NAP" to indicate server-side support for SoH in OFFERs
+ *
+ * vendor opt 222/0xde - SoH correlation ID as utf-16 string, yuck...
+ */
+ uint8_t vopt, vlen;
+ uint8_t const *data;
+
+ data = vp->vp_octets;
+ while (data < vp->vp_octets + vp->vp_length) {
+ vopt = *data++;
+ vlen = *data++;
+ switch (vopt) {
+ case 220:
+ if (vlen <= 1) {
+ uint8_t *p;
+
+ RDEBUG("SoH adding NAP marker to DHCP reply");
+ /* client probe; send "NAP" in the reply */
+ vp = fr_pair_afrom_num(request->reply, 43, DHCP_MAGIC_VENDOR);
+ vp->vp_length = 5;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
+
+ p[0] = 220;
+ p[1] = 3;
+ p[4] = 'N';
+ p[3] = 'A';
+ p[2] = 'P';
+
+ fr_pair_add(&request->reply->vps, vp);
+
+ } else {
+ RDEBUG("SoH decoding NAP from DHCP request");
+ /* SoH payload */
+ rcode = soh_verify(request, data, vlen);
+ if (rcode < 0) {
+ return RLM_MODULE_FAIL;
+ }
+ }
+ break;
+
+ default:
+ /* nothing to do */
+ break;
+ }
+ data += vlen;
+ }
+ return RLM_MODULE_OK;
+ }
+ return RLM_MODULE_NOOP;
+}
+#endif
+
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void * instance, REQUEST *request)
+{
+ VALUE_PAIR *vp;
+ int rv;
+
+ /* try to find the MS-SoH payload */
+ vp = fr_pair_find_by_num(request->packet->vps, 55, VENDORPEC_MICROSOFT, TAG_ANY);
+ if (!vp) {
+ RDEBUG("SoH radius VP not found");
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG("SoH radius VP found");
+ /* decode it */
+ rv = soh_verify(request, vp->vp_octets, vp->vp_length);
+ if (rv < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ return RLM_MODULE_OK;
+}
+
+extern module_t rlm_soh;
+module_t rlm_soh = {
+ .magic = RLM_MODULE_INIT,
+ .name = "soh",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_soh_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_DHCP
+ [MOD_POST_AUTH] = mod_post_auth
+#endif
+ },
+};
diff --git a/src/modules/rlm_sometimes/README.md b/src/modules/rlm_sometimes/README.md
new file mode 100644
index 0000000..358fbc0
--- /dev/null
+++ b/src/modules/rlm_sometimes/README.md
@@ -0,0 +1,13 @@
+# rlm_sometimes
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Is a hashing and distribution protocol, that will sometimes return
+one code or another depending on the input value configured.
+
+For load balancing it's recommended to use the load-balance {}
+section instead.
diff --git a/src/modules/rlm_sometimes/all.mk b/src/modules/rlm_sometimes/all.mk
new file mode 100644
index 0000000..1518b13
--- /dev/null
+++ b/src/modules/rlm_sometimes/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_sometimes.a
+SOURCES := rlm_sometimes.c
diff --git a/src/modules/rlm_sometimes/rlm_sometimes.c b/src/modules/rlm_sometimes/rlm_sometimes.c
new file mode 100644
index 0000000..1aa71b9
--- /dev/null
+++ b/src/modules/rlm_sometimes/rlm_sometimes.c
@@ -0,0 +1,191 @@
+/*
+ * 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_sometimes.c
+ * @brief Switches between retuning different return codes.
+ *
+ * @copyright 2012 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * The instance data for rlm_sometimes is the list of fake values we are
+ * going to return.
+ */
+typedef struct rlm_sometimes_t {
+ char const *rcode_str;
+ rlm_rcode_t rcode;
+ uint32_t start;
+ uint32_t end;
+ char const *key;
+ DICT_ATTR const *da;
+} rlm_sometimes_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "rcode", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sometimes_t, rcode_str), "fail" },
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sometimes_t, key), "User-Name" },
+ { "start", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sometimes_t, start), "0" },
+ { "end", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sometimes_t, end), "127" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_sometimes_t *inst = instance;
+
+ /*
+ * Convert the rcode string to an int, and get rid of it
+ */
+ inst->rcode = fr_str2int(mod_rcode_table, inst->rcode_str, RLM_MODULE_UNKNOWN);
+ if (inst->rcode == RLM_MODULE_UNKNOWN) {
+ cf_log_err_cs(conf, "Unknown module return code '%s'", inst->rcode_str);
+ return -1;
+ }
+
+ inst->da = dict_attrbyname(inst->key);
+ rad_assert(inst->da);
+
+ return 0;
+}
+
+/*
+ * A lie! It always returns!
+ */
+static rlm_rcode_t sometimes_return(void *instance, RADIUS_PACKET *packet, RADIUS_PACKET *reply)
+{
+ uint32_t hash;
+ uint32_t value;
+ rlm_sometimes_t *inst = instance;
+ VALUE_PAIR *vp;
+
+ /*
+ * Set it to NOOP and the module will always do nothing
+ */
+ if (inst->rcode == RLM_MODULE_NOOP) return inst->rcode;
+
+ /*
+ * Hash based on the given key. Usually User-Name.
+ */
+ vp = fr_pair_find_by_da(packet->vps, inst->da, TAG_ANY);
+ if (!vp) return RLM_MODULE_NOOP;
+
+ hash = fr_hash(&vp->data, vp->vp_length);
+ hash &= 0xff; /* ensure it's 0..255 */
+ value = hash;
+
+ /*
+ * Ranges are INCLUSIVE.
+ * [start,end] returns "rcode"
+ * Everything else returns "noop"
+ */
+ if (value < inst->start) return RLM_MODULE_NOOP;
+ if (value > inst->end) return RLM_MODULE_NOOP;
+
+ /*
+ * If we're returning "handled", then set the packet
+ * code in the reply, so that the server responds.
+ */
+ if ((inst->rcode == RLM_MODULE_HANDLED) && reply) {
+ switch (packet->code) {
+ case PW_CODE_ACCESS_REQUEST:
+ reply->code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ reply->code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ case PW_CODE_COA_REQUEST:
+ reply->code = PW_CODE_COA_ACK;
+ break;
+
+ case PW_CODE_DISCONNECT_REQUEST:
+ reply->code = PW_CODE_DISCONNECT_ACK;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return inst->rcode;
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_sometimes_packet(void *instance, REQUEST *request)
+{
+ return sometimes_return(instance, request->packet, request->reply);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_sometimes_reply(void *instance, REQUEST *request)
+{
+ return sometimes_return(instance, request->reply, NULL);
+}
+
+#ifdef WITH_PROXY
+static rlm_rcode_t CC_HINT(nonnull) mod_pre_proxy(void *instance, REQUEST *request)
+{
+ if (!request->proxy) return RLM_MODULE_NOOP;
+
+ return sometimes_return(instance, request->proxy, request->proxy_reply);
+}
+
+static rlm_rcode_t CC_HINT(nonnull) mod_post_proxy(void *instance, REQUEST *request)
+{
+ if (!request->proxy_reply) return RLM_MODULE_NOOP;
+
+ return sometimes_return(instance, request->proxy_reply, NULL);
+}
+#endif
+
+extern module_t rlm_sometimes;
+module_t rlm_sometimes = {
+ .magic = RLM_MODULE_INIT,
+ .name = "sometimes",
+ .type = RLM_TYPE_HUP_SAFE, /* needed for radmin */
+ .inst_size = sizeof(rlm_sometimes_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_sometimes_packet,
+ [MOD_AUTHORIZE] = mod_sometimes_packet,
+ [MOD_PREACCT] = mod_sometimes_packet,
+ [MOD_ACCOUNTING] = mod_sometimes_packet,
+#ifdef WITH_PROXY
+ [MOD_PRE_PROXY] = mod_pre_proxy,
+ [MOD_POST_PROXY] = mod_post_proxy,
+#endif
+ [MOD_POST_AUTH] = mod_sometimes_reply,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_sometimes_packet,
+ [MOD_SEND_COA] = mod_sometimes_reply,
+#endif
+ },
+};
diff --git a/src/modules/rlm_sql/.gitignore b/src/modules/rlm_sql/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql/README.md b/src/modules/rlm_sql/README.md
new file mode 100644
index 0000000..4c5d14c
--- /dev/null
+++ b/src/modules/rlm_sql/README.md
@@ -0,0 +1,19 @@
+# rlm_sql
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Provides an abstraction over multiple SQL backends, via database specific drivers.
+
+Supports the following operations:
+
+- Bulk client load
+- Livingston style users file - allows attributes and group
+ information to be stored in an SQL directory
+- Group membership checks
+- Authentication records
+- Accounting records
+- Simultaneous use checks
diff --git a/src/modules/rlm_sql/all.mk.in b/src/modules/rlm_sql/all.mk.in
new file mode 100644
index 0000000..a86bd3f
--- /dev/null
+++ b/src/modules/rlm_sql/all.mk.in
@@ -0,0 +1,12 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+SUBMAKEFILES := $(TARGETNAME).mk \
+ $(wildcard ${top_srcdir}/src/modules/rlm_sql/drivers/rlm_sql_*/all.mk)
+
+rlm_sql_CFLAGS := @mod_cflags@
+rlm_sql_LDLIBS := @mod_ldflags@
+endif
+
+
+
diff --git a/src/modules/rlm_sql/configure b/src/modules/rlm_sql/configure
new file mode 100755
index 0000000..ce623fb
--- /dev/null
+++ b/src/modules/rlm_sql/configure
@@ -0,0 +1,3980 @@
+#! /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_sql.c"
+enable_option_checking=no
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+subdirs
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_sql
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+ac_subdirs_all='$mysubdirs'
+
+# 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_sql build without support for SQL databases
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql was given.
+if test "${with_rlm_sql+set}" = set; then :
+ withval=$with_rlm_sql;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql" != 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
+
+
+mysubdirs=
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `find ./drivers -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ mysubdirs="$mysubdirs $bar"
+ done
+else
+ for foo in `cat stable`; do
+ mysubdirs="$mysubdirs ./drivers/$foo"
+ done
+fi
+
+ln -s ../../../install-sh install-sh
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+
+subdirs="$subdirs $mysubdirs"
+
+rm install-sh
+
+
+ targetname=rlm_sql
+else
+ targetname=
+ echo \*\*\* module rlm_sql is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+ # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+ # so they do not pile up.
+ ac_sub_configure_args=
+ ac_prev=
+ eval "set x $ac_configure_args"
+ shift
+ for ac_arg
+ do
+ if test -n "$ac_prev"; then
+ ac_prev=
+ continue
+ fi
+ case $ac_arg in
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
+ | --c=*)
+ ;;
+ --config-cache | -C)
+ ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ ;;
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ ;;
+ --disable-option-checking)
+ ;;
+ *)
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+ esac
+ done
+
+ # Always prepend --prefix to ensure using the same prefix
+ # in subdir configurations.
+ ac_arg="--prefix=$prefix"
+ case $ac_arg in
+ *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+ # Pass --silent
+ if test "$silent" = yes; then
+ ac_sub_configure_args="--silent $ac_sub_configure_args"
+ fi
+
+ # Always prepend --disable-option-checking to silence warnings, since
+ # different subdirs can have different --enable and --with options.
+ ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+ ac_popdir=`pwd`
+ for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+ # Do not complain, so a configure script can configure whichever
+ # parts of a large source tree are present.
+ test -d "$srcdir/$ac_dir" || continue
+
+ ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+ $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+ $as_echo "$ac_msg" >&6
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ cd "$ac_dir"
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ ac_sub_configure=$ac_srcdir/configure.gnu
+ elif test -f "$ac_srcdir/configure"; then
+ ac_sub_configure=$ac_srcdir/configure
+ elif test -f "$ac_srcdir/configure.in"; then
+ # This should be Cygnus configure.
+ ac_sub_configure=$ac_aux_dir/configure
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+ ac_sub_configure=
+ fi
+
+ # The recursion is here.
+ if test -n "$ac_sub_configure"; then
+ # Make the cache file name correct relative to the subdirectory.
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+ *) # Relative name.
+ ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+ # The eval makes quoting arguments work.
+ eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+ as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+ fi
+
+ cd "$ac_popdir"
+ done
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/configure.ac b/src/modules/rlm_sql/configure.ac
new file mode 100644
index 0000000..bb1003c
--- /dev/null
+++ b/src/modules/rlm_sql/configure.ac
@@ -0,0 +1,41 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql], [support for SQL databases])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+
+mysubdirs=
+if test "x$EXPERIMENTAL" = "xyes"; then
+ for foo in `find ./drivers -name configure -print`; do
+ bar=`echo $foo | sed 's%/configure$%%g'`
+ mysubdirs="$mysubdirs $bar"
+ done
+else
+ for foo in `cat stable`; do
+ mysubdirs="$mysubdirs ./drivers/$foo"
+ done
+fi
+
+dnl # don't ask... this is done to avoid autoconf stupidities.
+ln -s ../../../install-sh install-sh
+
+AC_CONFIG_SUBDIRS($mysubdirs)
+rm install-sh
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/README.md b/src/modules/rlm_sql/drivers/rlm_sql_db2/README.md
new file mode 100644
index 0000000..582f5e2
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_db2
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for IBM DB2.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_db2/all.mk.in
new file mode 100644
index 0000000..cf54d69
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @sql_ibmdb2_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @sql_ibmdb2_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/configure b/src/modules/rlm_sql/drivers/rlm_sql_db2/configure
new file mode 100755
index 0000000..0c36ba8
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/configure
@@ -0,0 +1,4191 @@
+#! /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_sql_db2.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+sql_ibmdb2_cflags
+sql_ibmdb2_ldflags
+targetname
+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_sql_db2
+with_ibmdb2_include_dir
+with_ibmdb2_lib_dir
+with_ibmdb2_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_db2 build without rlm_sql_db2
+ --with-ibmdb2-include-dir=DIR
+ Directory where the IBM-DB2 includes may be found
+ --with-ibmdb2-lib-dir=DIR
+ Directory where the IBM-DB2 libraries may be found
+ --with-ibmdb2-dir=DIR Base directory where IBM-DB2 is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_db2
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_db2 was given.
+if test "${with_rlm_sql_db2+set}" = set; then :
+ withval=$with_rlm_sql_db2;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_db2" != xno; then
+
+
+ibmdb2_include_dir=
+
+# Check whether --with-ibmdb2-include-dir was given.
+if test "${with_ibmdb2_include_dir+set}" = set; then :
+ withval=$with_ibmdb2_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ibmdb2-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+ibmdb2_lib_dir=
+
+# Check whether --with-ibmdb2-lib-dir was given.
+if test "${with_ibmdb2_lib_dir+set}" = set; then :
+ withval=$with_ibmdb2_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ibmdb2-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-ibmdb2-dir was given.
+if test "${with_ibmdb2_dir+set}" = set; then :
+ withval=$with_ibmdb2_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ibmdb2-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_lib_dir="$withval/lib"
+ ibmdb2_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$ibmdb2_lib_dir /usr/local/db2/lib /usr/IBMdb2/V7.1/lib"
+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
+
+
+
+
+sm_lib_safe=`echo "db2" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SQLConnect" | 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 SQLConnect in -ldb2 in $try" >&5
+$as_echo_n "checking for SQLConnect in -ldb2 in $try... " >&6; }
+ LIBS="-ldb2 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ldb2"
+ 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 SQLConnect in -ldb2" >&5
+$as_echo_n "checking for SQLConnect in -ldb2... " >&6; }
+ LIBS="-ldb2 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ldb2"
+ { $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 SQLConnect in -ldb2 in $try" >&5
+$as_echo_n "checking for SQLConnect in -ldb2 in $try... " >&6; }
+ LIBS="-ldb2 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-ldb2"
+ 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_db2_SQLConnect" != xyes; then
+
+fail="$fail libdb2"
+
+fi
+
+smart_try_dir="$ibmdb2_include_dir /usr/local/db2/include /usr/IBMdb2/V7.1/include"
+
+
+ac_safe=`echo "sqlcli.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 sqlcli.h in $try" >&5
+$as_echo_n "checking for sqlcli.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlcli.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}/sqlcli.h" >&5
+$as_echo_n "checking for ${_prefix}/sqlcli.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlcli.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 sqlcli.h" >&5
+$as_echo_n "checking for sqlcli.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlcli.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 sqlcli.h in $try" >&5
+$as_echo_n "checking for sqlcli.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlcli.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_sqlcli_h" != xyes; then
+
+fail="$fail sqlcli.h"
+
+fi
+
+
+ targetname=rlm_sql_db2
+else
+ targetname=
+ echo \*\*\* module rlm_sql_db2 is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_db2 to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_db2." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_db2." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_db2 requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_db2 requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+sql_ibmdb2_ldflags="$SMART_LIBS"
+sql_ibmdb2_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_db2/configure.ac
new file mode 100644
index 0000000..0d94ee9
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/configure.ac
@@ -0,0 +1,83 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_db2.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_db2])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-ibmdb2-include-dir
+ibmdb2_include_dir=
+AC_ARG_WITH(ibmdb2-include-dir,
+ [AS_HELP_STRING([--with-ibmdb2-include-dir=DIR],
+ [Directory where the IBM-DB2 includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ibmdb2-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-ibmdb2-lib-dir
+ibmdb2_lib_dir=
+AC_ARG_WITH(ibmdb2-lib-dir,
+ [AS_HELP_STRING([--with-ibmdb2-lib-dir=DIR],
+ [Directory where the IBM-DB2 libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ibmdb2-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-ibmdb2-dir
+AC_ARG_WITH(ibmdb2-dir,
+ [AS_HELP_STRING([--with-ibmdb2-dir=DIR],
+ [Base directory where IBM-DB2 is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ibmdb2-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ibmdb2_lib_dir="$withval/lib"
+ ibmdb2_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl Check for SQLConnect in -ldb2
+smart_try_dir="$ibmdb2_lib_dir /usr/local/db2/lib /usr/IBMdb2/V7.1/lib"
+FR_SMART_CHECK_LIB(db2, SQLConnect)
+if test "x$ac_cv_lib_db2_SQLConnect" != xyes; then
+ FR_MODULE_FAIL([libdb2])
+fi
+
+dnl Check for sqlcli.h
+smart_try_dir="$ibmdb2_include_dir /usr/local/db2/include /usr/IBMdb2/V7.1/include"
+FR_SMART_CHECK_INCLUDE(sqlcli.h)
+if test "x$ac_cv_header_sqlcli_h" != xyes; then
+ FR_MODULE_FAIL([sqlcli.h])
+fi
+
+FR_MODULE_END_TESTS
+
+sql_ibmdb2_ldflags="$SMART_LIBS"
+sql_ibmdb2_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(sql_ibmdb2_ldflags)
+AC_SUBST(sql_ibmdb2_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c b/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c
new file mode 100644
index 0000000..01d1710
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c
@@ -0,0 +1,271 @@
+/*
+ * sql_db2.c IBM DB2 rlm_sql driver
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Mike Machado <mike@innercite.com>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ * Copyright 2001 Joerg Wendland <wendland@scan-plus.de>
+ */
+
+/*
+ * Modification of rlm_sql_db2 to handle IBM DB2 UDB V7
+ * by Joerg Wendland <wendland@scan-plus.de>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <sqlcli.h>
+
+#include "rlm_sql.h"
+
+typedef struct rlm_sql_conn {
+ SQLHANDLE dbc_handle;
+ SQLHANDLE env_handle;
+ SQLHANDLE stmt;
+} rlm_sql_db2_conn_t;
+
+static int _sql_socket_destructor(rlm_sql_db2_conn_t *conn)
+{
+ DEBUG2("rlm_sql_db2: Socket destructor called, closing socket");
+
+ if (conn->stmt) {
+ SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
+ conn->stmt = 0;
+ }
+
+ if (conn->dbc_handle) {
+ SQLDisconnect(conn->dbc_handle);
+ SQLFreeHandle(SQL_HANDLE_DBC, conn->dbc_handle);
+ conn->dbc_handle = 0;
+ }
+
+ if (conn->env_handle) {
+ SQLFreeHandle(SQL_HANDLE_ENV, conn->env_handle);
+ conn->env_handle = 0;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ SQLRETURN retval;
+ rlm_sql_db2_conn_t *conn;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ /* Allocate handles */
+ SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->env_handle));
+ SQLAllocHandle(SQL_HANDLE_DBC, conn->env_handle, &(conn->dbc_handle));
+
+ /*
+ * The db2 API doesn't qualify arguments as const even when they should be.
+ */
+ {
+ SQLCHAR *server, *login, *password;
+
+ memcpy(&server, &config->sql_server, sizeof(server));
+ memcpy(&login, &config->sql_login, sizeof(login));
+ memcpy(&password, &config->sql_password, sizeof(password));
+
+ retval = SQLConnect(conn->dbc_handle,
+ server, SQL_NTS,
+ login, SQL_NTS,
+ password, SQL_NTS);
+ }
+
+ if (retval != SQL_SUCCESS) {
+ ERROR("could not connect to DB2 server %s", config->sql_server);
+
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ SQLRETURN retval;
+ rlm_sql_db2_conn_t *conn;
+
+ conn = handle->conn;
+
+ /* allocate handle for statement */
+ SQLAllocHandle(SQL_HANDLE_STMT, conn->dbc_handle, &(conn->stmt));
+
+ /* execute query */
+ {
+ SQLCHAR *db2_query;
+ memcpy(&db2_query, &query, sizeof(query));
+
+ retval = SQLExecDirect(conn->stmt, db2_query, SQL_NTS);
+ if (retval != SQL_SUCCESS) {
+ SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
+ conn->stmt = 0;
+
+ /* XXX Check if retval means we should return RLM_SQL_RECONNECT */
+ ERROR("Could not execute statement \"%s\"", query);
+ return RLM_SQL_ERROR;
+ }
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ return sql_query(handle, config, query);
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ SQLSMALLINT c;
+ rlm_sql_db2_conn_t *conn;
+
+ conn = handle->conn;
+ SQLNumResultCols(conn->stmt, &c);
+ return c;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ int c, i;
+ SQLINTEGER len, slen;
+ rlm_sql_row_t retval;
+ rlm_sql_db2_conn_t *conn;
+
+ conn = handle->conn;
+
+ c = sql_num_fields(handle, config);
+ retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
+ memset(retval, 0, c*sizeof(char*)+1);
+
+ /* advance cursor */
+ if (SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
+ handle->row = NULL;
+ for (i = 0; i < c; i++) free(retval[i]);
+ free(retval);
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ for (i = 0; i < c; i++) {
+ /* get column length */
+ SQLColAttribute(conn->stmt, i+1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &len);
+
+ retval[i] = rad_malloc(len+1);
+
+ /* get the actual column */
+ SQLGetData(conn->stmt, i + 1, SQL_C_CHAR, retval[i], len+1, &slen);
+ if(slen == SQL_NULL_DATA) {
+ retval[i][0] = '\0';
+ }
+ }
+
+ handle->row = retval;
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_db2_conn_t *conn;
+ conn = handle->conn;
+
+ if (conn->stmt) {
+ SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
+ conn->stmt = 0;
+ }
+
+ return RLM_SQL_OK;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ char state[6];
+ char errbuff[1024];
+ SQLINTEGER err;
+ SQLSMALLINT rl;
+ rlm_sql_db2_conn_t *conn = handle->conn;
+
+ rad_assert(conn);
+ rad_assert(outlen > 0);
+
+ errbuff[0] = '\0';
+ SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) state, &err,
+ (SQLCHAR *) errbuff, sizeof(errbuff), &rl);
+ if (errbuff[0] == '\0') return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = talloc_asprintf(ctx, "%s: %s", state, errbuff);
+
+ return 1;
+}
+
+static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_finish_query(handle, config);
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ SQLINTEGER c;
+ rlm_sql_db2_conn_t *conn = handle->conn;
+
+ SQLRowCount(conn->stmt, &c);
+
+ return c;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_db2;
+rlm_sql_module_t rlm_sql_db2 = {
+ .name = "rlm_sql_db2",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/README.md b/src/modules/rlm_sql/drivers/rlm_sql_firebird/README.md
new file mode 100644
index 0000000..245bee9
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_firebird
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for Firebird.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_firebird/all.mk.in
new file mode 100644
index 0000000..1982697
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c sql_fbapi.c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure b/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure
new file mode 100755
index 0000000..d7baa6a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure
@@ -0,0 +1,4192 @@
+#! /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_sql_firebird.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_firebird
+with_firebird_include_dir
+with_firebird_lib_dir
+with_firebird_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_firebird
+ build without rlm_sql_firebird
+ --with-firebird-include-dir=DIR
+ Directory where the firebird includes may be found
+ --with-firebird-lib-dir=DIR
+ Directory where the firebird libraries may be found
+ --with-firebird-dir=DIR Base directory where firebird is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_firebird
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_firebird was given.
+if test "${with_rlm_sql_firebird+set}" = set; then :
+ withval=$with_rlm_sql_firebird;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_firebird" != xno; then
+
+
+firebird_include_dir=
+
+# Check whether --with-firebird-include-dir was given.
+if test "${with_firebird_include_dir+set}" = set; then :
+ withval=$with_firebird_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need firebird-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+firebird_lib_dir=
+
+# Check whether --with-firebird-lib-dir was given.
+if test "${with_firebird_lib_dir+set}" = set; then :
+ withval=$with_firebird_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need firebird-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-firebird-dir was given.
+if test "${with_firebird_dir+set}" = set; then :
+ withval=$with_firebird_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need firebird-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_lib_dir="$withval/lib"
+ firebird_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$firebird_lib_dir /usr/lib/firebird2/lib /usr/local/firebird/lib"
+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
+
+
+
+
+sm_lib_safe=`echo "fbclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "isc_attach_database" | 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 isc_attach_database in -lfbclient in $try" >&5
+$as_echo_n "checking for isc_attach_database in -lfbclient in $try... " >&6; }
+ LIBS="-lfbclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char isc_attach_database();
+int
+main ()
+{
+isc_attach_database()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lfbclient"
+ 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 isc_attach_database in -lfbclient" >&5
+$as_echo_n "checking for isc_attach_database in -lfbclient... " >&6; }
+ LIBS="-lfbclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char isc_attach_database();
+int
+main ()
+{
+isc_attach_database()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lfbclient"
+ { $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 isc_attach_database in -lfbclient in $try" >&5
+$as_echo_n "checking for isc_attach_database in -lfbclient in $try... " >&6; }
+ LIBS="-lfbclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char isc_attach_database();
+int
+main ()
+{
+isc_attach_database()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lfbclient"
+ 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_fbclient_isc_attach_database" != xyes; then
+
+fail="$fail libfbclient"
+
+fi
+
+smart_try_dir="$firebird_include_dir /usr/lib/firebird2/include /usr/local/firebird/include"
+
+
+ac_safe=`echo "ibase.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 ibase.h in $try" >&5
+$as_echo_n "checking for ibase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ibase.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}/ibase.h" >&5
+$as_echo_n "checking for ${_prefix}/ibase.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ibase.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 ibase.h" >&5
+$as_echo_n "checking for ibase.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ibase.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 ibase.h in $try" >&5
+$as_echo_n "checking for ibase.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ibase.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_ibase_h" != xyes; then
+
+fail="$fail ibase.h"
+
+fi
+
+
+ targetname=rlm_sql_firebird
+else
+ targetname=
+ echo \*\*\* module rlm_sql_firebird is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_firebird to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_firebird." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_firebird." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_firebird requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_firebird requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure.ac
new file mode 100644
index 0000000..5aa7b4b
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/configure.ac
@@ -0,0 +1,83 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_firebird.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_firebird])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-firebird-include-dir
+firebird_include_dir=
+AC_ARG_WITH(firebird-include-dir,
+ [AS_HELP_STRING([--with-firebird-include-dir=DIR],
+ [Directory where the firebird includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need firebird-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-firebird-lib-dir
+firebird_lib_dir=
+AC_ARG_WITH(firebird-lib-dir,
+ [AS_HELP_STRING([--with-firebird-lib-dir=DIR],
+ [Directory where the firebird libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need firebird-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-firebird-dir
+AC_ARG_WITH(firebird-dir,
+ [AS_HELP_STRING([--with-firebird-dir=DIR],
+ [Base directory where firebird is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need firebird-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ firebird_lib_dir="$withval/lib"
+ firebird_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl Check for isc_attach_database in -lfbclient
+smart_try_dir="$firebird_lib_dir /usr/lib/firebird2/lib /usr/local/firebird/lib"
+FR_SMART_CHECK_LIB(fbclient, isc_attach_database)
+if test "x$ac_cv_lib_fbclient_isc_attach_database" != xyes; then
+ FR_MODULE_FAIL([libfbclient])
+fi
+
+dnl Check for ibase.h
+smart_try_dir="$firebird_include_dir /usr/lib/firebird2/include /usr/local/firebird/include"
+FR_SMART_CHECK_INCLUDE(ibase.h)
+if test "x$ac_cv_header_ibase_h" != xyes; then
+ FR_MODULE_FAIL([ibase.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c b/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c
new file mode 100644
index 0000000..49bcf73
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c
@@ -0,0 +1,298 @@
+/*
+ * sql_firebird.c Part of Firebird rlm_sql driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2006 The FreeRADIUS server project
+ * Copyright 2006 Vitaly Bodzhgua <vitaly@eastera.net>
+ */
+
+RCSID("$Id$")
+
+#include "sql_fbapi.h"
+#include <freeradius-devel/rad_assert.h>
+
+
+/* Forward declarations */
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+static int _sql_socket_destructor(rlm_sql_firebird_conn_t *conn)
+{
+ int i;
+
+ DEBUG2("rlm_sql_firebird: socket destructor called, closing socket");
+
+ fb_commit(conn);
+ if (conn->dbh) {
+ fb_free_statement(conn);
+ isc_detach_database(conn->status, &(conn->dbh));
+
+ if (fb_error(conn)) {
+ WARN("rlm_sql_firebird: Got error "
+ "when closing socket: %s", conn->error);
+ }
+ }
+
+#ifdef _PTHREAD_H
+ pthread_mutex_destroy (&conn->mut);
+#endif
+
+ for (i = 0; i < conn->row_fcount; i++) free(conn->row[i]);
+
+ free(conn->row);
+ free(conn->row_sizes);
+ fb_free_sqlda(conn->sqlda_out);
+
+ free(conn->sqlda_out);
+ free(conn->tpb);
+ free(conn->dpb);
+
+ return 0;
+}
+
+/** Establish connection to the db
+ *
+ */
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_firebird_conn_t *conn;
+
+ long res;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_firebird_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ res = fb_init_socket(conn);
+ if (res) return RLM_SQL_ERROR;
+
+ if (fb_connect(conn, config)) {
+ ERROR("rlm_sql_firebird: Connection failed: %s", conn->error);
+
+ return RLM_SQL_RECONNECT;
+ }
+
+ return 0;
+}
+
+/** Issue a non-SELECT query (ie: update/delete/insert) to the database.
+ *
+ */
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_firebird_conn_t *conn = handle->conn;
+
+ int deadlock = 0;
+
+#ifdef _PTHREAD_H
+ pthread_mutex_lock(&conn->mut);
+#endif
+
+ try_again:
+ /*
+ * Try again query when deadlock, beacuse in any case it
+ * will be retried.
+ */
+ if (fb_sql_query(conn, query)) {
+ /* but may be lost for short sessions */
+ if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
+ !deadlock) {
+ DEBUG("conn_id deadlock. Retry query %s", query);
+
+ /*
+ * @todo For non READ_COMMITED transactions put
+ * rollback here
+ * fb_rollback(conn);
+ */
+ deadlock = 1;
+ goto try_again;
+ }
+
+ ERROR("conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
+ (long int) conn->sql_code, conn->error, query);
+
+ if (conn->sql_code == DOWN_SQL_CODE) {
+ reconnect:
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
+ return RLM_SQL_RECONNECT;
+ }
+
+ /* Free problem query */
+ if (fb_rollback(conn)) {
+ //assume the network is down if rollback had failed
+ ERROR("Fail to rollback transaction after previous error: %s", conn->error);
+
+ goto reconnect;
+ }
+ // conn->in_use=0;
+ fail:
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
+ return RLM_SQL_ERROR;
+ }
+
+ if (conn->statement_type != isc_info_sql_stmt_select) {
+ if (fb_commit(conn)) goto fail;
+ }
+
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
+ return 0;
+}
+
+/** Issue a select query to the database.
+ *
+ */
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ return sql_query(handle, config, query);
+}
+
+/** Returns number of columns from query.
+ *
+ */
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ return ((rlm_sql_firebird_conn_t *) handle->conn)->sqlda_out->sqld;
+}
+
+/** Returns number of rows in query.
+ *
+ */
+static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_affected_rows(handle, config);
+}
+
+/** Returns an individual row.
+ *
+ */
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_firebird_conn_t *conn = handle->conn;
+ int res;
+
+ handle->row = NULL;
+
+ if (conn->statement_type != isc_info_sql_stmt_exec_procedure) {
+ res = fb_fetch(conn);
+ if (res == 100) {
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ if (res) {
+ ERROR("rlm_sql_firebird. Fetch problem: %s", conn->error);
+
+ return RLM_SQL_ERROR;
+ }
+ } else {
+ conn->statement_type = 0;
+ }
+
+ fb_store_row(conn);
+
+ handle->row = conn->row;
+
+ return 0;
+}
+
+/** End the select query, such as freeing memory or result.
+ *
+ */
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_firebird_conn_t *conn = (rlm_sql_firebird_conn_t *) handle->conn;
+
+ fb_commit(conn);
+ fb_close_cursor(conn);
+
+ return 0;
+}
+
+/** End the query
+ *
+ */
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ sql_free_result(handle, config);
+
+ return 0;
+}
+
+/** Frees memory allocated for a result set.
+ *
+ */
+static sql_rcode_t sql_free_result(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_firebird_conn_t *conn = handle->conn;
+
+ rad_assert(conn);
+ rad_assert(outlen > 0);
+
+ if (!conn->error) return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = conn->error;
+
+ return 1;
+}
+
+/** Return the number of rows affected by the query (update, or insert)
+ *
+ */
+static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ return fb_affected_rows(handle->conn);
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_firebird;
+rlm_sql_module_t rlm_sql_firebird = {
+ .name = "rlm_sql_firebird",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.c b/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.c
new file mode 100644
index 0000000..b217a78
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.c
@@ -0,0 +1,578 @@
+/*
+ * sql_fbapi.c Part of Firebird rlm_sql driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2006 The FreeRADIUS server project
+ * Copyright 2006 Vitaly Bodzhgua <vitaly@eastera.net>
+ */
+
+RCSID("$Id$")
+
+#include "sql_fbapi.h"
+
+#include <stdarg.h>
+
+static void fb_set_tpb(rlm_sql_firebird_conn_t *conn, int count, ...)
+{
+ int i;
+ va_list arg;
+
+ va_start(arg, count);
+ conn->tpb = malloc(count);
+
+ for (i = 0; i < count; i++) {
+ conn->tpb[i] = (char) va_arg(arg, int);
+ }
+
+ conn->tpb_len = count;
+
+ va_end(arg);
+}
+
+
+static void fb_dpb_add_str(char **dpb, char name, char const *value)
+{
+ int l;
+
+ if (!value) {
+ return;
+ }
+
+ l = strlen(value);
+
+ *(*dpb)++= name;
+ *(*dpb)++= (char) l;
+
+ memmove(*dpb, value, l);
+
+ *dpb += l;
+}
+
+static void fb_set_sqlda(XSQLDA *sqlda) {
+ int i;
+
+ for (i = 0; i < sqlda->sqld; i++) {
+ if ((sqlda->sqlvar[i].sqltype & ~1) == SQL_VARYING) {
+ sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short));
+ } else {
+ sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);
+ }
+
+ if (sqlda->sqlvar[i].sqltype & 1) {
+ sqlda->sqlvar[i].sqlind = (short*)calloc(sizeof(short), 1);
+ } else {
+ sqlda->sqlvar[i].sqlind = 0;
+ }
+ }
+}
+
+DIAG_OFF(deprecated-declarations)
+int fb_error(rlm_sql_firebird_conn_t *conn)
+{
+ ISC_SCHAR error[2048]; /* Only 1024 bytes should be written to this, but were playing it extra safe */
+ ISC_STATUS *pstatus;
+
+ conn->sql_code = 0;
+
+ /*
+ * Free any previous errors.
+ */
+ TALLOC_FREE(conn->error);
+
+ /*
+ * Check if the status array contains an error
+ */
+ if (IS_ISC_ERROR(conn->status)) {
+ conn->sql_code = isc_sqlcode(conn->status);
+
+ /*
+ * pstatus is a pointer into the status array which is
+ * advanced by isc_interprete. It's initialised to the
+ * first element of the status array.
+ */
+ pstatus = &conn->status[0];
+
+ /*
+ * It's deprecated because the size of the buffer isn't
+ * passed and this isn't safe. But as were passing a very
+ * large buffer it's unlikely this will be an issue, and
+ * allows us to maintain compatibility with the interbase
+ * API.
+ */
+ isc_interprete(&error[0], &pstatus);
+ conn->error = talloc_typed_asprintf(conn, "%s. ", &error[0]);
+
+ while (isc_interprete(&error[0], &pstatus)) {
+ conn->error = talloc_asprintf_append(conn->error, "%s. ", &error[0]);
+ }
+
+ memset(&conn->status, 0, sizeof(conn->status));
+ }
+
+ return conn->sql_code;
+}
+DIAG_ON(deprecated-declarations)
+
+void fb_free_sqlda(XSQLDA *sqlda)
+{
+ int i;
+ for (i = 0; i < sqlda->sqld; i++) {
+ free(sqlda->sqlvar[i].sqldata);
+ free(sqlda->sqlvar[i].sqlind);
+ }
+ sqlda->sqld = 0;
+}
+
+
+
+//Macro for NULLs check
+#define IS_NULL(x) (x->sqltype & 1) && (*x->sqlind < 0)
+
+//Structure to manage a SQL_VARYING Firebird's data types
+typedef struct vary_fb {
+ short vary_length;
+ char vary_string[1];
+} VARY;
+
+//function fb_store_row based on fiebird's apifull example
+void fb_store_row(rlm_sql_firebird_conn_t *conn)
+{
+ int dtype;
+ struct tm times;
+ ISC_QUAD bid;
+ int i;
+ XSQLVAR *var;
+ VARY * vary;
+
+ /* assumed: id, username, attribute, value, op */
+ if (conn->row_fcount<conn->sqlda_out->sqld) {
+ i = conn->row_fcount;
+ conn->row_fcount = conn->sqlda_out->sqld;
+ conn->row = (char **) realloc(conn->row, conn->row_fcount * sizeof(char *));
+ conn->row_sizes = (int *) realloc(conn->row_sizes, conn->row_fcount * sizeof(int));
+
+ while( i <conn->row_fcount) {
+ conn->row[i] = 0;
+ conn->row_sizes[i++] = 0;
+ }
+ }
+
+ for (i = 0, var = conn->sqlda_out->sqlvar; i < conn->sqlda_out->sqld; var++, i++) {
+ /*
+ * Initial buffer size to store field's data is 256 bytes
+ */
+ if (conn->row_sizes[i]<256) {
+ conn->row[i] = (char *) realloc(conn->row[i], 256);
+ conn->row_sizes[i] = 256;
+ }
+
+ if (IS_NULL(var)) {
+ strcpy(conn->row[i], "NULL");
+ continue;
+ }
+
+ dtype = var->sqltype & ~1;
+
+ switch (dtype) {
+ case SQL_TEXT:
+ if (conn->row_sizes[i]<= var->sqllen) {
+ conn->row_sizes[i] = var->sqllen + 1;
+ conn->row[i] = realloc(conn->row[i],
+ conn->row_sizes[i]);
+ }
+
+ memmove(conn->row[i], var->sqldata, var->sqllen);
+ conn->row[i][var->sqllen] = 0;
+ break;
+
+ case SQL_VARYING:
+ vary = (VARY*) var->sqldata;
+ if (conn->row_sizes[i] <= vary->vary_length) {
+ conn->row_sizes[i] = vary->vary_length + 1;
+ conn->row[i] = realloc(conn->row[i],
+ conn->row_sizes[i]);
+ }
+ memmove(conn->row[i], vary->vary_string, vary->vary_length);
+ conn->row[i][vary->vary_length] = 0;
+ break;
+
+ case SQL_FLOAT:
+ snprintf(conn->row[i], conn->row_sizes[i], "%15g",
+ *(float ISC_FAR *) (var->sqldata));
+ break;
+
+ case SQL_SHORT:
+ case SQL_LONG:
+ case SQL_INT64:
+ {
+ ISC_INT64 value = 0;
+ short field_width = 0;
+ short dscale = 0;
+ char *p;
+ p = conn->row[i];
+
+ switch (dtype) {
+ case SQL_SHORT:
+ value = (ISC_INT64) *(short *)var->sqldata;
+ field_width = 6;
+ break;
+
+ case SQL_LONG:
+ value = (ISC_INT64) *(int *)var->sqldata;
+ field_width = 11;
+ break;
+
+ case SQL_INT64:
+ value = (ISC_INT64) *(ISC_INT64 *)var->sqldata;
+ field_width = 21;
+ break;
+ }
+ dscale = var->sqlscale;
+
+ if (dscale < 0) {
+ ISC_INT64 tens;
+ short j;
+
+ tens = 1;
+ for (j = 0; j > dscale; j--) {
+ tens *= 10;
+ }
+
+ if (value >= 0) {
+ sprintf(p, "%*lld.%0*lld",
+ field_width - 1 + dscale,
+ (ISC_INT64) value / tens,
+ -dscale,
+ (ISC_INT64) value % tens);
+ } else if ((value / tens) != 0) {
+ sprintf (p, "%*lld.%0*lld",
+ field_width - 1 + dscale,
+ (ISC_INT64) (value / tens),
+ -dscale,
+ (ISC_INT64) -(value % tens));
+ } else {
+ sprintf(p, "%*s.%0*lld", field_width - 1 + dscale,
+ "-0", -dscale, (ISC_INT64) - (value % tens));
+ }
+ } else if (dscale) {
+ sprintf(p, "%*lld%0*d", field_width,
+ (ISC_INT64) value, dscale, 0);
+ } else {
+ sprintf(p, "%*lld", field_width,
+ (ISC_INT64) value);
+ }
+ }
+ break;
+
+ case SQL_D_FLOAT:
+ case SQL_DOUBLE:
+ snprintf(conn->row[i], conn->row_sizes[i], "%24f",
+ *(double ISC_FAR *) (var->sqldata));
+ break;
+
+ case SQL_TIMESTAMP:
+ isc_decode_timestamp((ISC_TIMESTAMP ISC_FAR *)var->sqldata, &times);
+ snprintf(conn->row[i], conn->row_sizes[i], "%04d-%02d-%02d %02d:%02d:%02d.%04d",
+ times.tm_year + 1900,
+ times.tm_mon + 1,
+ times.tm_mday,
+ times.tm_hour,
+ times.tm_min,
+ times.tm_sec,
+ ((ISC_TIMESTAMP *)var->sqldata)->timestamp_time % 10000);
+ break;
+
+ case SQL_TYPE_DATE:
+ isc_decode_sql_date((ISC_DATE ISC_FAR *)var->sqldata, &times);
+ snprintf(conn->row[i], conn->row_sizes[i], "%04d-%02d-%02d",
+ times.tm_year + 1900,
+ times.tm_mon + 1,
+ times.tm_mday);
+ break;
+
+ case SQL_TYPE_TIME:
+ isc_decode_sql_time((ISC_TIME ISC_FAR *)var->sqldata, &times);
+ snprintf(conn->row[i], conn->row_sizes[i], "%02d:%02d:%02d.%04d",
+ times.tm_hour,
+ times.tm_min,
+ times.tm_sec,
+ (*((ISC_TIME *)var->sqldata)) % 10000);
+ break;
+
+ case SQL_BLOB:
+ case SQL_ARRAY:
+ /* Print the blob id on blobs or arrays */
+ bid = *(ISC_QUAD ISC_FAR *) var->sqldata;
+ snprintf(conn->row[i], conn->row_sizes[i], "%08" ISC_LONG_FMT "x:%08" ISC_LONG_FMT "x",
+ bid.gds_quad_high, bid.gds_quad_low);
+ break;
+ }
+ }
+}
+
+int fb_init_socket(rlm_sql_firebird_conn_t *conn)
+{
+ memset(conn, 0, sizeof(*conn));
+ conn->sqlda_out = (XSQLDA ISC_FAR *) calloc(XSQLDA_LENGTH (5), 1);
+ conn->sqlda_out->sqln = 5;
+ conn->sqlda_out->version = SQLDA_VERSION1;
+ conn->sql_dialect = 3;
+#ifdef _PTHREAD_H
+ pthread_mutex_init (&conn->mut, NULL);
+ DEBUG("Init mutex %p\n", &conn->mut);
+#endif
+
+ /*
+ * Set tpb to read_committed/wait/no_rec_version
+ */
+ fb_set_tpb(conn, 5, isc_tpb_version3, isc_tpb_wait, isc_tpb_write,
+ isc_tpb_read_committed, isc_tpb_no_rec_version);
+ if (!conn->tpb) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int fb_connect(rlm_sql_firebird_conn_t * conn, rlm_sql_config_t *config)
+{
+ char *p;
+ char *database;
+
+ conn->dpb_len = 4;
+ if (config->sql_login) {
+ conn->dpb_len+= strlen(config->sql_login) + 2;
+ }
+
+ if (config->sql_password) {
+ conn->dpb_len += strlen(config->sql_password) + 2;
+ }
+
+ conn->dpb = (char *) malloc(conn->dpb_len);
+ p = conn->dpb;
+
+ *conn->dpb++= isc_dpb_version1;
+ *conn->dpb++= isc_dpb_num_buffers;
+ *conn->dpb++= 1;
+ *conn->dpb++= 90;
+
+ fb_dpb_add_str(&conn->dpb, isc_dpb_user_name, config->sql_login);
+ fb_dpb_add_str(&conn->dpb, isc_dpb_password, config->sql_password);
+
+ conn->dpb = p;
+
+ /*
+ * Check if database and server in the form of server:database.
+ * If config->sql_server contains ':', then config->sql_db
+ * parameter ignored.
+ */
+ if (strchr(config->sql_server, ':')) {
+ database = strdup(config->sql_server);
+ } else {
+ /*
+ * Make database and server to be in the form
+ * of server:database
+ */
+ int ls = strlen(config->sql_server);
+ int ld = strlen(config->sql_db);
+ database = (char *) calloc(ls + ld + 2, 1);
+ strcpy(database, config->sql_server);
+ database[ls] = ':';
+ memmove(database + ls + 1, config->sql_db, ld);
+ }
+ isc_attach_database(conn->status, 0, database, &conn->dbh,
+ conn->dpb_len, conn->dpb);
+ free(database);
+
+ return fb_error(conn);
+}
+
+
+int fb_fetch(rlm_sql_firebird_conn_t *conn)
+{
+ long fetch_stat;
+ if (conn->statement_type!= isc_info_sql_stmt_select) {
+ return 100;
+ }
+
+ fetch_stat = isc_dsql_fetch(conn->status, &conn->stmt,
+ SQL_DIALECT_V6, conn->sqlda_out);
+ if (fetch_stat) {
+ if (fetch_stat!= 100L) {
+ fb_error(conn);
+ } else {
+ conn->sql_code = 0;
+ }
+ }
+
+ return fetch_stat;
+}
+
+static int fb_prepare(rlm_sql_firebird_conn_t *conn, char const *query)
+{
+ static char stmt_info[] = { isc_info_sql_stmt_type };
+ char info_buffer[128];
+ short l;
+
+ if (!conn->trh) {
+ isc_start_transaction(conn->status, &conn->trh, 1, &conn->dbh,
+ conn->tpb_len, conn->tpb);
+ if (!conn->trh) {
+ return -4;
+ }
+ }
+
+ fb_free_statement(conn);
+ if (!conn->stmt) {
+ isc_dsql_allocate_statement(conn->status, &conn->dbh,
+ &conn->stmt);
+ if (!conn->stmt) {
+ return -1;
+ }
+ }
+
+ fb_free_sqlda(conn->sqlda_out);
+ isc_dsql_prepare(conn->status, &conn->trh, &conn->stmt, 0, query,
+ conn->sql_dialect, conn->sqlda_out);
+ if (IS_ISC_ERROR(conn->status)) {
+ return -2;
+ }
+
+ if (conn->sqlda_out->sqln<conn->sqlda_out->sqld) {
+ conn->sqlda_out->sqln = conn->sqlda_out->sqld;
+ conn->sqlda_out = (XSQLDA ISC_FAR *) realloc(conn->sqlda_out,
+ XSQLDA_LENGTH(conn->sqlda_out->sqld));
+ isc_dsql_describe(conn->status, &conn->stmt, SQL_DIALECT_V6,
+ conn->sqlda_out);
+
+ if (IS_ISC_ERROR(conn->status)) {
+ return -3;
+ }
+ }
+ /*
+ * Get statement type
+ */
+ isc_dsql_sql_info(conn->status, &conn->stmt, sizeof(stmt_info),
+ stmt_info, sizeof(info_buffer), info_buffer);
+ if (IS_ISC_ERROR(conn->status)) return -4;
+
+ l = (short) isc_vax_integer((char ISC_FAR *) info_buffer + 1, 2);
+ conn->statement_type = isc_vax_integer((char ISC_FAR *) info_buffer + 3,
+ l);
+
+ if (conn->sqlda_out->sqld) {
+ fb_set_sqlda(conn->sqlda_out); //set out sqlda
+ }
+
+ return 0;
+}
+
+
+int fb_sql_query(rlm_sql_firebird_conn_t *conn, char const *query) {
+ if (fb_prepare(conn, query)) {
+ return fb_error(conn);
+ }
+
+ switch (conn->statement_type) {
+ case isc_info_sql_stmt_exec_procedure:
+ isc_dsql_execute2(conn->status, &conn->trh, &conn->stmt,
+ SQL_DIALECT_V6, 0, conn->sqlda_out);
+ break;
+
+ default:
+ isc_dsql_execute(conn->status, &conn->trh, &conn->stmt,
+ SQL_DIALECT_V6, 0);
+ break;
+ }
+ return fb_error(conn);
+}
+
+int fb_affected_rows(rlm_sql_firebird_conn_t *conn) {
+ static char count_info[] = {isc_info_sql_records};
+ char info_buffer[128];
+ char *p ;
+ int affected_rows = -1;
+
+ if (!conn->stmt) return -1;
+
+ isc_dsql_sql_info(conn->status, &conn->stmt,
+ sizeof (count_info), count_info,
+ sizeof (info_buffer), info_buffer);
+
+ if (IS_ISC_ERROR(conn->status)) {
+ return fb_error(conn);
+ }
+
+ p = info_buffer + 3;
+ while (*p != isc_info_end) {
+ p++;
+ short len = (short)isc_vax_integer(p, 2);
+ p += 2;
+
+ affected_rows = isc_vax_integer(p, len);
+ if (affected_rows > 0) {
+ break;
+ }
+ p += len;
+ }
+ return affected_rows;
+}
+
+int fb_close_cursor(rlm_sql_firebird_conn_t *conn) {
+ isc_dsql_free_statement(conn->status, &conn->stmt, DSQL_close);
+
+ return fb_error(conn);
+}
+
+void fb_free_statement(rlm_sql_firebird_conn_t *conn) {
+ if (conn->stmt) {
+ isc_dsql_free_statement(conn->status, &conn->stmt, DSQL_drop);
+ conn->stmt = 0;
+ }
+}
+
+int fb_rollback(rlm_sql_firebird_conn_t *conn) {
+ conn->sql_code = 0;
+ if (conn->trh) {
+ isc_rollback_transaction(conn->status, &conn->trh);
+// conn->in_use = 0;
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
+
+ if (IS_ISC_ERROR(conn->status)) {
+ return fb_error(conn);
+ }
+ }
+ return conn->sql_code;
+}
+
+int fb_commit(rlm_sql_firebird_conn_t *conn) {
+ conn->sql_code = 0;
+ if (conn->trh) {
+ isc_commit_transaction (conn->status, &conn->trh);
+ if (IS_ISC_ERROR(conn->status)) {
+ fb_error(conn);
+ ERROR("Fail to commit. Error: %s. Try to rollback.", conn->error);
+ return fb_rollback(conn);
+ }
+ }
+// conn->in_use = 0;
+#ifdef _PTHREAD_H
+ pthread_mutex_unlock(&conn->mut);
+#endif
+ return conn->sql_code;
+}
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.h b/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.h
new file mode 100644
index 0000000..f3e272c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/sql_fbapi.h
@@ -0,0 +1,91 @@
+/*
+ * sql_fbapi.h Part of Firebird rlm_sql driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2006 The FreeRADIUS server project
+ * Copyright 2006 Vitaly Bodzhgua <vitaly@eastera.net>
+ */
+
+
+#ifndef _SQL_FBAPI_H_
+#define _SQL_FBAPI_H_
+
+RCSIDH(sql_fbapi_h, "$Id$")
+
+#include <stdlib.h>
+#include <string.h>
+#include <ibase.h>
+
+#include <freeradius-devel/radiusd.h>
+#include "rlm_sql.h"
+
+#define IS_ISC_ERROR(status) ((status[0] == 1) && (status[1] > 0))
+
+#define DEADLOCK_SQL_CODE -913
+#define DOWN_SQL_CODE -902
+
+#if defined(_LP64) || defined(__LP64__) || defined(__arch64__)
+#define ISC_LONG_FMT "d"
+#define ISC_ULONG_FMT "u"
+#else
+#define ISC_LONG_FMT "l"
+#define ISC_ULONG_FMT "ul"
+#endif
+
+typedef struct rlm_sql_firebird_conn {
+ isc_db_handle dbh;
+ isc_stmt_handle stmt;
+ isc_tr_handle trh;
+
+ ISC_STATUS status[20]; //!< Magic interbase status code array (holds multiple error codes used
+ //!< to construct more detailed error messages.
+
+ ISC_LONG sql_code;
+ XSQLDA *sqlda_out;
+ int sql_dialect;
+ int statement_type;
+ char *tpb;
+ int tpb_len;
+ char *dpb;
+ int dpb_len;
+ char *error;
+
+ rlm_sql_row_t row;
+ int *row_sizes;
+ int row_fcount;
+
+#ifdef _PTHREAD_H
+ pthread_mutex_t mut;
+#endif
+} rlm_sql_firebird_conn_t;
+
+
+int fb_free_result(rlm_sql_firebird_conn_t *conn);
+int fb_error(rlm_sql_firebird_conn_t *conn);
+int fb_init_socket(rlm_sql_firebird_conn_t *conn);
+int fb_connect(rlm_sql_firebird_conn_t *conn, rlm_sql_config_t *config);
+int fb_disconnect(rlm_sql_firebird_conn_t *conn);
+int fb_sql_query(rlm_sql_firebird_conn_t *conn, char const *query);
+int fb_affected_rows(rlm_sql_firebird_conn_t *conn);
+int fb_fetch(rlm_sql_firebird_conn_t *conn);
+void fb_free_sqlda(XSQLDA *sqlda);
+void fb_free_statement(rlm_sql_firebird_conn_t *conn);
+int fb_close_cursor(rlm_sql_firebird_conn_t *conn);
+int fb_rollback(rlm_sql_firebird_conn_t *conn);
+int fb_commit(rlm_sql_firebird_conn_t *conn);
+void fb_store_row(rlm_sql_firebird_conn_t *conn);
+
+#endif
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/.gitignore b/src/modules/rlm_sql/drivers/rlm_sql_freetds/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/README.md b/src/modules/rlm_sql/drivers/rlm_sql_freetds/README.md
new file mode 100644
index 0000000..de47a9a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_freetds
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver implementing the TDS protocol used by Sybase and MSSQL.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_freetds/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure b/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure
new file mode 100755
index 0000000..35a00f9
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure
@@ -0,0 +1,4200 @@
+#! /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_sql_freetds.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_freetds
+with_freetds_include_dir
+with_freetds_lib_dir
+with_freetds_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_freetds
+ build without rlm_sql_freetds
+ --with-freetds-include-dir=DIR
+ Directory where the freetds includes may be found
+ --with-freetds-lib-dir=DIR
+ Directory where the freetds libraries may be found
+ --with-freetds-dir=DIR Base directory where freetds is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_freetds
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_freetds was given.
+if test "${with_rlm_sql_freetds+set}" = set; then :
+ withval=$with_rlm_sql_freetds;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_freetds" != xno; then
+
+
+
+freetds_include_dir=
+
+# Check whether --with-freetds-include-dir was given.
+if test "${with_freetds_include_dir+set}" = set; then :
+ withval=$with_freetds_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need freetds-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+freetds_lib_dir=
+
+# Check whether --with-freetds-lib-dir was given.
+if test "${with_freetds_lib_dir+set}" = set; then :
+ withval=$with_freetds_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need freetds-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-freetds-dir was given.
+if test "${with_freetds_dir+set}" = set; then :
+ withval=$with_freetds_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need freetds-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_lib_dir="$withval/lib"
+ freetds_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir="$freetds_include_dir"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "ctpublic.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 ctpublic.h in $try" >&5
+$as_echo_n "checking for ctpublic.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ctpublic.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}/ctpublic.h" >&5
+$as_echo_n "checking for ${_prefix}/ctpublic.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ctpublic.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 ctpublic.h" >&5
+$as_echo_n "checking for ctpublic.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ctpublic.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 ctpublic.h in $try" >&5
+$as_echo_n "checking for ctpublic.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ctpublic.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_ctpublic_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: freetds headers not found. Use --with-freetds-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: freetds headers not found. Use --with-freetds-include-dir=<path>." >&2;}
+
+fail="$fail ctpublic.h"
+
+fi
+
+
+smart_try_dir="$freetds_lib_dir"
+
+
+sm_lib_safe=`echo "ct" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ct_command" | 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 ct_command in -lct in $try" >&5
+$as_echo_n "checking for ct_command in -lct in $try... " >&6; }
+ LIBS="-lct $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ct_command();
+int
+main ()
+{
+ct_command()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lct"
+ 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 ct_command in -lct" >&5
+$as_echo_n "checking for ct_command in -lct... " >&6; }
+ LIBS="-lct $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ct_command();
+int
+main ()
+{
+ct_command()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lct"
+ { $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 ct_command in -lct in $try" >&5
+$as_echo_n "checking for ct_command in -lct in $try... " >&6; }
+ LIBS="-lct $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ct_command();
+int
+main ()
+{
+ct_command()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lct"
+ 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_ct_ct_command" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: freetds libraries not found. Use --with-freetds-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: freetds libraries not found. Use --with-freetds-lib-dir=<path>." >&2;}
+
+fail="$fail libct"
+
+fi
+
+
+ targetname=rlm_sql_freetds
+else
+ targetname=
+ echo \*\*\* module rlm_sql_freetds is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_freetds to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_freetds." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_freetds." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_freetds requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_freetds requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure.ac
new file mode 100644
index 0000000..60970d5
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/configure.ac
@@ -0,0 +1,97 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_freetds.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_freetds])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-freetds-include-dir=DIR
+freetds_include_dir=
+AC_ARG_WITH(freetds-include-dir,
+ [AS_HELP_STRING([--with-freetds-include-dir=DIR],
+ [Directory where the freetds includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need freetds-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-freetds-lib-dir=DIR
+freetds_lib_dir=
+AC_ARG_WITH(freetds-lib-dir,
+ [AS_HELP_STRING([--with-freetds-lib-dir=DIR],
+ [Directory where the freetds libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need freetds-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-freetds-dir=DIR
+AC_ARG_WITH(freetds-dir,
+ [AS_HELP_STRING([--with-freetds-dir=DIR],
+ [Base directory where freetds is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need freetds-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ freetds_lib_dir="$withval/lib"
+ freetds_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="$freetds_include_dir"
+FR_SMART_CHECK_INCLUDE(ctpublic.h)
+if test "x$ac_cv_header_ctpublic_h" != "xyes"; then
+ AC_MSG_WARN([freetds headers not found. Use --with-freetds-include-dir=<path>.])
+ FR_MODULE_FAIL([ctpublic.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+dnl try to link to freetds
+smart_try_dir="$freetds_lib_dir"
+FR_SMART_CHECK_LIB(ct, ct_command)
+if test "x$ac_cv_lib_ct_ct_command" != "xyes"
+then
+ AC_MSG_WARN([freetds libraries not found. Use --with-freetds-lib-dir=<path>.])
+ FR_MODULE_FAIL([libct])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c b/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c
new file mode 100644
index 0000000..a5c3b93
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c
@@ -0,0 +1,773 @@
+ /*
+ * 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_sql.c
+ * @brief Implements FreeTDS rlm_sql driver.
+ *
+ * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Mattias Sjostrom <mattias@nogui.se>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <ctpublic.h>
+
+#include "rlm_sql.h"
+
+typedef struct rlm_sql_freetds_conn {
+ CS_CONTEXT *context; //!< Structure FreeTDS uses to avoid creating globals.
+ CS_CONNECTION *db; //!< Handle specifying a single connection to the database.
+ CS_COMMAND *command; //!< A prepared statement.
+ char **results; //!< Result strings from statement execution.
+ char *error; //!< The last error string created by one of the call backs.
+ bool established; //!< Set to false once the connection has been properly established.
+ CS_INT rows_affected; //!< Rows affected by last INSERT / UPDATE / DELETE.
+} rlm_sql_freetds_conn_t;
+
+#define MAX_DATASTR_LEN 256
+
+/** Client-Library error handler
+ *
+ * Callback for any errors raised by the Client-Library. Will overwrite any previous errors associated
+ * with a connection.
+ *
+ * @param context The FreeTDS library context.
+ * @param conn DB connection handle.
+ * @param emsgp Pointer to the error structure.
+ * @return CS_CUCCEED
+ */
+static CS_RETCODE CS_PUBLIC clientmsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_CLIENTMSG *emsgp)
+{
+ rlm_sql_freetds_conn_t *this = NULL;
+ int len = 0;
+
+ /*
+ * Not actually an error, but the client wanted to tell us something...
+ */
+ if (emsgp->severity == CS_SV_INFORM) {
+ INFO("rlm_sql_freetds: %s", emsgp->msgstring);
+
+ return CS_SUCCEED;
+ }
+
+ if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
+ ERROR("rlm_sql_freetds: failed retrieving context userdata");
+
+ return CS_SUCCEED;
+ }
+
+ if (this->error) TALLOC_FREE(this->error);
+
+ this->error = talloc_typed_asprintf(this, "client error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+ (long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
+ (long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
+ emsgp->msgstring);
+
+ if (emsgp->osstringlen > 0) {
+ this->error = talloc_asprintf_append(this->error, ". os error: number(%ld): %s",
+ (long)emsgp->osnumber, emsgp->osstring);
+ }
+
+ return CS_SUCCEED;
+}
+
+/** Client error handler
+ *
+ * Callback for any errors raised by the client. Will overwrite any previous errors associated
+ * with a connection.
+ *
+ * @param context The FreeTDS library context.
+ * @param emsgp Pointer to the error structure.
+ * @return CS_SUCCEED
+ */
+static CS_RETCODE CS_PUBLIC csmsg_callback(CS_CONTEXT *context, CS_CLIENTMSG *emsgp)
+{
+ rlm_sql_freetds_conn_t *this = NULL;
+ int len = 0;
+
+ /*
+ * Not actually an error, but the client wanted to tell us something...
+ */
+ if (emsgp->severity == CS_SV_INFORM) {
+ INFO("rlm_sql_freetds: %s", emsgp->msgstring);
+
+ return CS_SUCCEED;
+ }
+
+ if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
+ ERROR("rlm_sql_freetds: failed retrieving context userdata");
+
+ return CS_SUCCEED;
+ }
+
+ if (this->error) TALLOC_FREE(this->error);
+
+ this->error = talloc_typed_asprintf(this, "cs error: severity(%ld), number(%ld), origin(%ld), layer(%ld): %s",
+ (long)CS_SEVERITY(emsgp->severity), (long)CS_NUMBER(emsgp->msgnumber),
+ (long)CS_ORIGIN(emsgp->msgnumber), (long)CS_LAYER(emsgp->msgnumber),
+ emsgp->msgstring);
+
+ if (emsgp->osstringlen > 0) {
+ this->error = talloc_asprintf_append(this->error, ". os error: number(%ld): %s",
+ (long)emsgp->osnumber, emsgp->osstring);
+ }
+
+ return CS_SUCCEED;
+}
+
+/** Server error handler
+ *
+ * Callback for any messages sent back from the server.
+ *
+ * There's no standard categorisation of messages sent back from the server, so we don't know they're errors,
+ * the only thing we can do is write them to the long as informational messages.
+ *
+ * @param context The FreeTDS library context.
+ * @param conn DB connection handle.
+ * @param msgp Pointer to the error structure.
+ * @return CS_SUCCEED
+ */
+static CS_RETCODE CS_PUBLIC servermsg_callback(CS_CONTEXT *context, UNUSED CS_CONNECTION *conn, CS_SERVERMSG *msgp)
+{
+ rlm_sql_freetds_conn_t *this = NULL;
+ int len = 0;
+
+ if ((cs_config(context, CS_GET, CS_USERDATA, &this, sizeof(this), &len) != CS_SUCCEED) || !this) {
+ ERROR("rlm_sql_freetds: failed retrieving context userdata");
+
+ return CS_SUCCEED;
+ }
+
+ /*
+ * Because apparently there are no standard severity levels *brilliant*
+ */
+ if (this->established) {
+ INFO("rlm_sql_freetds: server msg from \"%s\": severity(%ld), number(%ld), origin(%ld), "
+ "layer(%ld), procedure \"%s\": %s",
+ (msgp->svrnlen > 0) ? msgp->svrname : "unknown",
+ (long)msgp->msgnumber, (long)msgp->severity, (long)msgp->state, (long)msgp->line,
+ (msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
+ } else {
+ if (this->error) TALLOC_FREE(this->error);
+
+ this->error = talloc_typed_asprintf(this, "Server msg from \"%s\": severity(%ld), number(%ld), "
+ "origin(%ld), layer(%ld), procedure \"%s\": %s",
+ (msgp->svrnlen > 0) ? msgp->svrname : "unknown",
+ (long)msgp->msgnumber, (long)msgp->severity, (long)msgp->state,
+ (long)msgp->line,
+ (msgp->proclen > 0) ? msgp->proc : "none", msgp->text);
+ }
+
+ return CS_SUCCEED;
+}
+
+/*************************************************************************
+ *
+ * Function: sql_query
+ *
+ * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
+ * the database.
+ *
+ *************************************************************************/
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ CS_RETCODE results_ret;
+ CS_INT result_type;
+
+ /*
+ * Reset rows_affected in case the query fails.
+ * Prevents accidentally returning the rows_affected from a previous query.
+ */
+ conn->rows_affected = -1;
+
+ if (ct_cmd_alloc(conn->db, &conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: Unable to allocate command structure (ct_cmd_alloc())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ if (ct_command(conn->command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: Unable to initialise command structure (ct_command())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ if (ct_send(conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: Unable to send command (ct_send())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * We'll make three calls to ct_results, first to get a success indicator, secondly to get a
+ * done indicator, and thirdly to get a "nothing left to handle" status.
+ */
+
+ /*
+ * First call to ct_results, we need returncode CS_SUCCEED and result_type CS_CMD_SUCCEED.
+ */
+ if ((results_ret = ct_results(conn->command, &result_type)) == CS_SUCCEED) {
+ if (result_type != CS_CMD_SUCCEED) {
+ if (result_type == CS_ROW_RESULT) {
+ ERROR("rlm_sql_freetds: sql_query processed a query returning rows. "
+ "Use sql_select_query instead!");
+ }
+ ERROR("rlm_sql_freetds: Result failure or unexpected result type from query");
+
+ return RLM_SQL_ERROR;
+ }
+ } else {
+ switch (results_ret) {
+ case CS_FAIL: /* Serious failure, freetds requires us to cancel and maybe even close db */
+ ERROR("rlm_sql_freetds: Failure retrieving query results");
+
+ if (ct_cancel(NULL, conn->command, CS_CANCEL_ALL) == CS_FAIL) {
+ INFO("rlm_sql_freetds: Cleaning up");
+
+ return RLM_SQL_RECONNECT;
+ }
+ conn->command = NULL;
+
+ return RLM_SQL_ERROR;
+ default:
+ ERROR("rlm_sql_freetds: Unexpected return value from ct_results()");
+
+ return RLM_SQL_ERROR;
+ }
+ }
+
+ /*
+ * Retrieve the number of rows affected - the later calls
+ * to ct_results end up resetting the underlying counter so we
+ * no longer have access to this.
+ */
+ if (ct_res_info(conn->command, CS_ROW_COUNT, &conn->rows_affected, CS_UNUSED, NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: error retrieving row count");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Second call to ct_results, we need returncode CS_SUCCEED
+ * and result_type CS_CMD_DONE.
+ */
+ if ((results_ret = ct_results(conn->command, &result_type)) == CS_SUCCEED) {
+ if (result_type != CS_CMD_DONE) {
+ ERROR("rlm_sql_freetds: Result failure or unexpected result type from query");
+
+ return RLM_SQL_ERROR;
+ }
+ } else {
+ switch (results_ret) {
+ case CS_FAIL: /* Serious failure, freetds requires us to cancel and maybe even close db */
+ ERROR("rlm_sql_freetds: Failure retrieving query results");
+ if (ct_cancel(NULL, conn->command, CS_CANCEL_ALL) == CS_FAIL) return RLM_SQL_RECONNECT;
+
+ conn->command = NULL;
+ return RLM_SQL_ERROR;
+
+ default:
+ ERROR("rlm_sql_freetds: Unexpected return value from ct_results()");
+
+ return RLM_SQL_ERROR;
+ }
+ }
+
+ /*
+ * Third call to ct_results, we need returncode CS_END_RESULTS result_type will be ignored.
+ */
+ results_ret = ct_results(conn->command, &result_type);
+ switch (results_ret) {
+ case CS_FAIL: /* Serious failure, freetds requires us to cancel and maybe even close db */
+ ERROR("rlm_sql_freetds: Failure retrieving query results");
+ if (ct_cancel(NULL, conn->command, CS_CANCEL_ALL) == CS_FAIL) return RLM_SQL_RECONNECT;
+ conn->command = NULL;
+
+ return RLM_SQL_ERROR;
+
+ case CS_END_RESULTS: /* This is where we want to end up */
+ break;
+
+ default:
+ ERROR("rlm_sql_freetds: Unexpected return value from ct_results()");
+
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+/*************************************************************************
+ *
+ * Function: sql_num_fields
+ *
+ * Purpose: database specific num_fields function. Returns number
+ * of columns from query
+ *
+ *************************************************************************/
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+ int num = 0;
+
+ if (ct_res_info(conn->command, CS_NUMDATA, (CS_INT *)&num, CS_UNUSED, NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: Error retrieving column count");
+
+ return RLM_SQL_ERROR;
+ }
+
+ return num;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ rad_assert(conn && conn->db);
+ rad_assert(outlen > 0);
+
+ if (!conn->error) return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = conn->error;
+
+ return 1;
+}
+
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
+ if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: freeing command structure failed");
+
+ return RLM_SQL_ERROR;
+ }
+ conn->command = NULL;
+
+ TALLOC_FREE(conn->results);
+
+ return RLM_SQL_OK;
+
+}
+
+/** Execute a query when we expected a result set
+ *
+ * @note Only the first row from queries returning several rows will be returned by this function,
+ * consecutive rows will be discarded.
+ *
+ */
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ CS_RETCODE results_ret;
+ CS_INT result_type;
+ CS_DATAFMT descriptor;
+
+ int colcount,i;
+ char **rowdata;
+
+ if (!conn->db) {
+ ERROR("rlm_sql_freetds: socket not connected");
+
+ return RLM_SQL_ERROR;
+ }
+
+ if (ct_cmd_alloc(conn->db, &conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to allocate command structure (ct_cmd_alloc())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ if (ct_command(conn->command, CS_LANG_CMD, query, CS_NULLTERM, CS_UNUSED) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to initiate command structure (ct_command()");
+
+ return RLM_SQL_ERROR;
+ }
+
+ if (ct_send(conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to send command (ct_send())");
+ return RLM_SQL_ERROR;
+ }
+
+ results_ret = ct_results(conn->command, &result_type);
+ switch (results_ret) {
+ case CS_SUCCEED:
+ switch (result_type) {
+ case CS_ROW_RESULT:
+
+ /*
+ * Set up a target buffer for the results data, and associate the buffer with the results,
+ * but the actual fetching takes place in sql_fetch_row.
+ * The layer above MUST call sql_fetch_row and/or sql_finish_select_query
+ * or this socket will be unusable and may cause segfaults
+ * if reused later on.
+ */
+
+ /*
+ * Set up the DATAFMT structure that describes our target array
+ * and tells freetds what we want future ct_fetch calls to do.
+ */
+ descriptor.datatype = CS_CHAR_TYPE; /* The target buffer is a string */
+ descriptor.format = CS_FMT_NULLTERM; /* Null termination please */
+ descriptor.maxlength = MAX_DATASTR_LEN; /* The string arrays are this large */
+ descriptor.count = 1; /* Fetch one row of data */
+ descriptor.locale = NULL; /* Don't do NLS stuff */
+
+ colcount = sql_num_fields(handle, config); /* Get number of elements in row result */
+
+ rowdata = talloc_zero_array(conn, char *, colcount + 1); /* Space for pointers */
+ rowdata[colcount] = NULL;
+
+ for (i = 0; i < colcount; i++) {
+ /* Space to hold the result data */
+ rowdata[i] = talloc_array(rowdata, char, MAX_DATASTR_LEN + 1);
+
+ /* Associate the target buffer with the data */
+ if (ct_bind(conn->command, i + 1, &descriptor, rowdata[i], NULL, NULL) != CS_SUCCEED) {
+ talloc_free(rowdata);
+
+ ERROR("rlm_sql_freetds: ct_bind() failed)");
+
+ return RLM_SQL_ERROR;
+ }
+
+ }
+
+ rowdata[i] = NULL; /* Terminate the array */
+ conn->results = rowdata;
+ break;
+
+ case CS_CMD_SUCCEED:
+ case CS_CMD_DONE:
+ ERROR("rlm_sql_freetds: query returned no data");
+ break;
+
+ default:
+
+ ERROR("rlm_sql_freetds: unexpected result type from query");
+ sql_finish_select_query(handle, config);
+
+ return RLM_SQL_ERROR;
+ }
+ break;
+
+ case CS_FAIL:
+
+ /*
+ * Serious failure, freetds requires us to cancel the results and maybe even close the db.
+ */
+
+ ERROR("rlm_sql_freetds: failure retrieving query results");
+
+ if (ct_cancel(NULL, conn->command, CS_CANCEL_ALL) == CS_FAIL) {
+ ERROR("rlm_sql_freetds: cleaning up");
+
+ return RLM_SQL_RECONNECT;
+ }
+ conn->command = NULL;
+
+ return RLM_SQL_ERROR;
+
+ default:
+ ERROR("rlm_sql_freetds: unexpected return value from ct_results()");
+
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ return (conn->rows_affected);
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+ CS_INT ret, count;
+
+ handle->row = NULL;
+
+ ret = ct_fetch(conn->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count);
+ switch (ret) {
+ case CS_FAIL:
+ /*
+ * Serious failure, freetds requires us to cancel the results and maybe even close the db.
+ */
+ ERROR("rlm_sql_freetds: failure fetching row data");
+ if (ct_cancel(NULL, conn->command, CS_CANCEL_ALL) == CS_FAIL) {
+ ERROR("rlm_sql_freetds: cleaning up");
+ } else {
+ conn->command = NULL;
+ }
+
+ return RLM_SQL_RECONNECT;
+
+ case CS_END_DATA:
+ return RLM_SQL_NO_MORE_ROWS;
+
+ case CS_SUCCEED:
+ handle->row = conn->results;
+
+ return RLM_SQL_OK;
+
+ case CS_ROW_FAIL:
+ ERROR("rlm_sql_freetds: recoverable failure fetching row data");
+
+ return RLM_SQL_RECONNECT;
+
+ default:
+ ERROR("rlm_sql_freetds: unexpected returncode from ct_fetch");
+
+ return RLM_SQL_ERROR;
+ }
+}
+
+static sql_rcode_t sql_free_result(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+
+ /*
+ * Not implemented, never called from rlm_sql anyway result buffer is freed in the
+ * finish_query functions.
+ */
+ return RLM_SQL_OK;
+
+}
+
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn = handle->conn;
+
+ ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
+ if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: freeing command structure failed");
+
+ return RLM_SQL_ERROR;
+ }
+ conn->command = NULL;
+ conn->rows_affected = -1;
+
+ return RLM_SQL_OK;
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_num_rows(handle, config);
+}
+
+
+static int _sql_socket_destructor(rlm_sql_freetds_conn_t *conn)
+{
+ DEBUG2("rlm_sql_freetds: socket destructor called, closing socket");
+
+ if (conn->command) {
+ ct_cancel(NULL, conn->command, CS_CANCEL_ALL);
+ if (ct_cmd_drop(conn->command) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: freeing command structure failed");
+
+ return RLM_SQL_ERROR;
+ }
+ }
+
+ if (conn->db) {
+ /*
+ * We first try gracefully closing the connection (which informs the server)
+ * Then if that fails we force the connection closure.
+ *
+ * Sybase docs says this may fail because of pending results, but we
+ * should not have any pending results at this point, so something else must
+ * of gone wrong.
+ */
+ if (ct_close(conn->db, CS_UNUSED) != CS_SUCCEED) {
+ ct_close(conn->db, CS_FORCE_CLOSE);
+ }
+
+ ct_con_drop(conn->db);
+ }
+
+ if (conn->context) {
+ ct_exit(conn->context, CS_UNUSED);
+ cs_ctx_drop(conn->context);
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_freetds_conn_t *conn;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_freetds_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ /*
+ * Allocate a CS context structure. This should really only be done once, but because of
+ * the db pooling design of rlm_sql, we'll have to go with one context per db
+ */
+ if (cs_ctx_alloc(CS_VERSION_100, &conn->context) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to allocate CS context structure (cs_ctx_alloc())");
+
+ goto error;
+ }
+
+ /*
+ * Initialize ctlib
+ */
+ if (ct_init(conn->context, CS_VERSION_100) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to initialize Client-Library");
+
+ goto error;
+ }
+
+ /*
+ * Install callback functions for error-handling
+ */
+ if (cs_config(conn->context, CS_SET, CS_MESSAGE_CB, (CS_VOID *)csmsg_callback, CS_UNUSED, NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to install CS Library error callback");
+
+ goto error;
+ }
+
+ if (cs_config(conn->context, CS_SET, CS_USERDATA,
+ (CS_VOID *)&handle->conn, sizeof(handle->conn), NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to set userdata pointer");
+
+ goto error;
+ }
+
+ if (ct_callback(conn->context, NULL, CS_SET, CS_CLIENTMSG_CB, (CS_VOID *)clientmsg_callback) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to install client message callback");
+
+ goto error;
+ }
+
+ if (ct_callback(conn->context, NULL, CS_SET, CS_SERVERMSG_CB, (CS_VOID *)servermsg_callback) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to install server message callback");
+
+ goto error;
+ }
+
+ /*
+ * Allocate a ctlib db structure
+ */
+ if (ct_con_alloc(conn->context, &conn->db) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to allocate db structure");
+
+ goto error;
+ }
+
+ /*
+ * Set User and Password properties for the db
+ */
+ {
+ CS_VOID *login, *password;
+ CS_CHAR *server;
+ char database[128];
+
+ memcpy(&login, &config->sql_login, sizeof(login));
+ if (ct_con_props(conn->db, CS_SET, CS_USERNAME, login, strlen(config->sql_login), NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to set username for db");
+
+ goto error;
+ }
+
+ memcpy(&password, &config->sql_password, sizeof(password));
+ if (ct_con_props(conn->db, CS_SET, CS_PASSWORD,
+ password, strlen(config->sql_password), NULL) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to set password for db");
+
+ goto error;
+ }
+
+ /*
+ * Connect to the database
+ */
+ memcpy(&server, &config->sql_server, sizeof(server));
+ if (ct_connect(conn->db, server, strlen(config->sql_server)) != CS_SUCCEED) {
+ ERROR("rlm_sql_freetds: unable to establish db to symbolic servername %s",
+ config->sql_server);
+
+ goto error;
+ }
+
+ /*
+ * There doesn't appear to be a way to set the database with the API, so use an
+ * sql statement when we first open the connection.
+ */
+ snprintf(database, sizeof(database), "USE %s;", config->sql_db);
+ if (sql_query(handle, config, database) != RLM_SQL_OK) {
+ goto error;
+ }
+
+ sql_finish_query(handle, config);
+ }
+
+ return RLM_SQL_OK;
+
+error:
+ if (conn->context) {
+ sql_log_entry_t error;
+
+ if (sql_error(NULL, &error, 1, handle, config) > 0) ERROR("rlm_sql_freetds: %s", error.msg);
+ }
+
+ return RLM_SQL_ERROR;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_freetds;
+rlm_sql_module_t rlm_sql_freetds = {
+ .name = "rlm_sql_freetds",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/.gitignore b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/README.md b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/README.md
new file mode 100644
index 0000000..7ef3a02
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_iodbc
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for the iODBC connector library.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure
new file mode 100755
index 0000000..0fb563c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure
@@ -0,0 +1,4191 @@
+#! /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_sql_iodbc.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_iodbc
+with_iodbc_include_dir
+with_iodbc_lib_dir
+with_iodbc_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_iodbc build without rlm_sql_iodbc
+ --with-iodbc-include-dir=DIR
+ Directory where the Iodbc includes may be found
+ --with-iodbc-lib-dir=DIR
+ Directory where the Iodbc libraries may be found
+ --with-iodbc-dir=DIR Base directory where Iodbc is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_iodbc
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_iodbc was given.
+if test "${with_rlm_sql_iodbc+set}" = set; then :
+ withval=$with_rlm_sql_iodbc;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_iodbc" != xno; then
+
+
+iodbc_include_dir=
+
+# Check whether --with-iodbc-include-dir was given.
+if test "${with_iodbc_include_dir+set}" = set; then :
+ withval=$with_iodbc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need iodbc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+iodbc_lib_dir=
+
+# Check whether --with-iodbc-lib-dir was given.
+if test "${with_iodbc_lib_dir+set}" = set; then :
+ withval=$with_iodbc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need iodbc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-iodbc-dir was given.
+if test "${with_iodbc_dir+set}" = set; then :
+ withval=$with_iodbc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need iodbc-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_lib_dir="$withval/lib"
+ iodbc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$iodbc_lib_dir /usr/lib /usr/lib/iodbc /usr/local/lib/iodbc /usr/local/iodbc/lib/iodbc"
+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
+
+
+
+
+sm_lib_safe=`echo "iodbc" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SQLConnect" | 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 SQLConnect in -liodbc in $try" >&5
+$as_echo_n "checking for SQLConnect in -liodbc in $try... " >&6; }
+ LIBS="-liodbc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-liodbc"
+ 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 SQLConnect in -liodbc" >&5
+$as_echo_n "checking for SQLConnect in -liodbc... " >&6; }
+ LIBS="-liodbc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-liodbc"
+ { $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 SQLConnect in -liodbc in $try" >&5
+$as_echo_n "checking for SQLConnect in -liodbc in $try... " >&6; }
+ LIBS="-liodbc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-liodbc"
+ 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_iodbc_SQLConnect" != xyes; then
+
+fail="$fail libiodbc"
+
+fi
+
+smart_try_dir="$iodbc_include_dir /usr/include /usr/include/iodbc /usr/local/iodbc/include"
+
+
+ac_safe=`echo "isql.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 isql.h in $try" >&5
+$as_echo_n "checking for isql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <isql.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}/isql.h" >&5
+$as_echo_n "checking for ${_prefix}/isql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <isql.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 isql.h" >&5
+$as_echo_n "checking for isql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <isql.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 isql.h in $try" >&5
+$as_echo_n "checking for isql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <isql.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_isql_h" != xyes; then
+
+fail="$fail isql.h"
+
+fi
+
+
+ targetname=rlm_sql_iodbc
+else
+ targetname=
+ echo \*\*\* module rlm_sql_iodbc is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_iodbc to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_iodbc." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_iodbc." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_iodbc requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_iodbc requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure.ac
new file mode 100644
index 0000000..d96216a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/configure.ac
@@ -0,0 +1,83 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_iodbc.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_iodbc])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-iodbc-include-dir
+iodbc_include_dir=
+AC_ARG_WITH(iodbc-include-dir,
+ [AS_HELP_STRING([--with-iodbc-include-dir=DIR],
+ [Directory where the Iodbc includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need iodbc-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-iodbc-lib-dir
+iodbc_lib_dir=
+AC_ARG_WITH(iodbc-lib-dir,
+ [AS_HELP_STRING([--with-iodbc-lib-dir=DIR],
+ [Directory where the Iodbc libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need iodbc-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-iodbc-dir
+AC_ARG_WITH(iodbc-dir,
+ [AS_HELP_STRING([--with-iodbc-dir=DIR],
+ [Base directory where Iodbc is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need iodbc-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ iodbc_lib_dir="$withval/lib"
+ iodbc_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl Check for SQLConnect in -liodbc
+smart_try_dir="$iodbc_lib_dir /usr/lib /usr/lib/iodbc /usr/local/lib/iodbc /usr/local/iodbc/lib/iodbc"
+FR_SMART_CHECK_LIB(iodbc, SQLConnect)
+if test "x$ac_cv_lib_iodbc_SQLConnect" != xyes; then
+ FR_MODULE_FAIL([libiodbc])
+fi
+
+dnl Check for isql.h
+smart_try_dir="$iodbc_include_dir /usr/include /usr/include/iodbc /usr/local/iodbc/include"
+FR_SMART_CHECK_INCLUDE(isql.h)
+if test "x$ac_cv_header_isql_h" != xyes; then
+ FR_MODULE_FAIL([isql.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_iodbc/rlm_sql_iodbc.c b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/rlm_sql_iodbc.c
new file mode 100644
index 0000000..d87444d
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_iodbc/rlm_sql_iodbc.c
@@ -0,0 +1,295 @@
+/*
+ * sql_iodbc.c iODBC support for FreeRadius
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Jeff Carneal <jeff@apex.net>
+ */
+
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <isql.h>
+#include <isqlext.h>
+#include <sqltypes.h>
+
+#include "rlm_sql.h"
+
+#define IODBC_MAX_ERROR_LEN 256
+
+typedef struct rlm_sql_iodbc_conn {
+ HENV env_handle;
+ HDBC dbc_handle;
+ HSTMT stmt;
+ int id;
+
+ rlm_sql_row_t row;
+
+ struct sql_socket *next;
+
+ void *conn;
+} rlm_sql_iodbc_conn_t;
+
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config);
+static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+static int _sql_socket_destructor(rlm_sql_iodbc_conn_t *conn)
+{
+ DEBUG2("rlm_sql_iodbc: Socket destructor called, closing socket");
+
+ if (conn->stmt) SQLFreeStmt(conn->stmt, SQL_DROP);
+
+ if (conn->dbc_handle) {
+ SQLDisconnect(conn->dbc_handle);
+ SQLFreeConnect(conn->dbc_handle);
+ }
+
+ if (conn->env_handle) SQLFreeEnv(conn->env_handle);
+
+ return 0;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+
+ rlm_sql_iodbc_conn_t *conn;
+ SQLRETURN rcode;
+ sql_log_entry_t entry;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_iodbc_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ rcode = SQLAllocEnv(&conn->env_handle);
+ if (!SQL_SUCCEEDED(rcode)) {
+ ERROR("rlm_sql_iodbc: SQLAllocEnv failed");
+ if (sql_error(NULL, &entry, 1, handle, config) > 0) ERROR("rlm_sql_iodbc: %s", entry.msg);
+
+ return RLM_SQL_ERROR;
+ }
+
+ rcode = SQLAllocConnect(conn->env_handle,
+ &conn->dbc_handle);
+ if (!SQL_SUCCEEDED(rcode)) {
+ ERROR("rlm_sql_iodbc: SQLAllocConnect failed");
+ if (sql_error(NULL, &entry, 1, handle, config) > 0) ERROR("rlm_sql_iodbc: %s", entry.msg);
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * The iodbc API doesn't qualify arguments as const even when they should be.
+ */
+ {
+ SQLCHAR *server, *login, *password;
+
+ memcpy(&server, &config->sql_server, sizeof(server));
+ memcpy(&login, &config->sql_login, sizeof(login));
+ memcpy(&password, &config->sql_password, sizeof(password));
+
+ rcode = SQLConnect(conn->dbc_handle, server, SQL_NTS, login, SQL_NTS, password, SQL_NTS);
+ }
+ if (!SQL_SUCCEEDED(rcode)) {
+ ERROR("rlm_sql_iodbc: SQLConnectfailed");
+ if (sql_error(NULL, &entry, 1, handle, config) > 0) ERROR("rlm_sql_iodbc: %s", entry.msg);
+
+ return RLM_SQL_ERROR;
+ }
+
+ return 0;
+}
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+ SQLRETURN rcode;
+
+ rcode = SQLAllocStmt(conn->dbc_handle, &conn->stmt);
+ if (!SQL_SUCCEEDED(rcode)) return RLM_SQL_ERROR;
+
+ if (!conn->dbc_handle) {
+ ERROR("rlm_sql_iodbc: Socket not connected");
+ return RLM_SQL_ERROR;
+ }
+
+ {
+ SQLCHAR *statement;
+
+ memcpy(&statement, &query, sizeof(statement));
+ rcode = SQLExecDirect(conn->stmt, statement, SQL_NTS);
+ }
+
+ if (!SQL_SUCCEEDED(rcode)) return RLM_SQL_ERROR;
+
+ return 0;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ int numfields = 0;
+ int i = 0;
+ char **row = NULL;
+ long len = 0;
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+
+ if (sql_query(handle, config, query) < 0) return RLM_SQL_ERROR;
+
+ numfields = sql_num_fields(handle, config);
+
+ row = (char **) rad_malloc(sizeof(char *) * (numfields+1));
+ memset(row, 0, (sizeof(char *) * (numfields)));
+ row[numfields] = NULL;
+
+ for(i=1; i<=numfields; i++) {
+ SQLColAttributes(conn->stmt, ((SQLUSMALLINT) i), SQL_COLUMN_LENGTH, NULL, 0, NULL, &len);
+ len++;
+
+ /*
+ * Allocate space for each column
+ */
+ row[i - 1] = rad_malloc((size_t) len);
+
+ /*
+ * This makes me feel dirty, but, according to Microsoft, it works.
+ * Any ODBC datatype can be converted to a 'char *' according to
+ * the following:
+ *
+ * http://msdn.microsoft.com/library/psdk/dasdk/odap4o4z.htm
+ */
+ SQLBindCol(conn->stmt, i, SQL_C_CHAR, (SQLCHAR *)row[i-1], len, 0);
+ }
+
+ conn->row = row;
+
+ return 0;
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+
+ SQLSMALLINT count=0;
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+
+ SQLNumResultCols(conn->stmt, &count);
+
+ return (int)count;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ SQLRETURN rc;
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+
+ handle->row = NULL;
+
+ rc = SQLFetch(conn->stmt);
+ if (rc == SQL_NO_DATA_FOUND) return RLM_SQL_NO_MORE_ROWS;
+
+ /* XXX Check rc for database down, if so, return RLM_SQL_RECONNECT */
+
+ handle->row = conn->row;
+ return 0;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ int i = 0;
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+
+ for (i = 0; i < sql_num_fields(handle, config); i++) free(conn->row[i]);
+ free(conn->row);
+ conn->row = NULL;
+
+ SQLFreeStmt(conn->stmt, SQL_DROP);
+ conn->stmt = NULL;
+
+ return 0;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+ SQLINTEGER errornum = 0;
+ SQLSMALLINT length = 0;
+ SQLCHAR state[256] = "";
+ SQLCHAR errbuff[IODBC_MAX_ERROR_LEN];
+
+ rad_assert(outlen > 0);
+
+ errbuff[0] = '\0';
+ SQLError(conn->env_handle, conn->dbc_handle, conn->stmt,
+ state, &errornum, errbuff, IODBC_MAX_ERROR_LEN, &length);
+ if (errbuff[0] == '\0') return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = talloc_asprintf(ctx, "%s: %s", state, errbuff);
+
+ return 1;
+}
+
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_free_result(handle, config);
+}
+
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_free_result(handle, config);
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ long count;
+ rlm_sql_iodbc_conn_t *conn = handle->conn;
+
+ SQLRowCount(conn->stmt, &count);
+ return (int)count;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_iodbc;
+rlm_sql_module_t rlm_sql_iodbc = {
+ .name = "rlm_sql_iodbc",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mongo/README.md b/src/modules/rlm_sql/drivers/rlm_sql_mongo/README.md
new file mode 100644
index 0000000..36b15fd
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mongo/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_mongo
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for MongoDB.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mongo/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_mongo/all.mk.in
new file mode 100644
index 0000000..49b7d04
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mongo/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mongoc_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mongoc_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure b/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure
new file mode 100755
index 0000000..378fc31
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure
@@ -0,0 +1,4075 @@
+#! /bin/sh
+# From configure.ac Revision: 1.10 .
+# 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_sql_mongo.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mongoc_ldflags
+mongoc_cflags
+targetname
+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_sql_mongo
+with_mongoc_lib_dir
+with_mongoc_include_dir
+with_bson_lib_dir
+with_bson_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_mongo build without rlm_sql_mongo
+ --with-mongoc-lib-dir Path of libmongoc libraries
+ --with-mongoc-include-dir
+ Path of libmongoc includes
+ --with-bson-lib-dir Path of libbson libraries
+ --with-bson-include-dir Path of libbson includes
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_mongo
+echo
+
+
+# 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_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ 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. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_mongo was given.
+if test "${with_rlm_sql_mongo+set}" = set; then :
+ withval=$with_rlm_sql_mongo;
+fi
+
+
+
+mongoc_ldflags=
+mongoc_cflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_mongo" != xno; then
+
+
+
+# Check whether --with-mongoc_lib_dir was given.
+if test "${with_mongoc_lib_dir+set}" = set; then :
+ withval=$with_mongoc_lib_dir; mongoc_lib_dir="$withval"
+else
+ mongoc_lib_dir=""
+fi
+
+
+
+# Check whether --with-mongoc_include_dir was given.
+if test "${with_mongoc_include_dir+set}" = set; then :
+ withval=$with_mongoc_include_dir; mongoc_include_dir="$withval"
+else
+ mongoc_include_dir=""
+fi
+
+
+
+# Check whether --with-bson_lib_dir was given.
+if test "${with_bson_lib_dir+set}" = set; then :
+ withval=$with_bson_lib_dir; bson_lib_dir="$withval"
+else
+ bson_lib_dir=""
+fi
+
+
+
+# Check whether --with-bson_include_dir was given.
+if test "${with_bson_include_dir+set}" = set; then :
+ withval=$with_bson_include_dir; bson_include_dir="$withval"
+else
+ bson_include_dir=""
+fi
+
+
+
+CFLAGS_PRE="$CFLAGS"
+if test x$bson_include_dir != x ; then
+ bson_cflags="-isystem ${bson_include_dir}"
+else
+ bson_cflags="-isystem /usr/include/libbson-1.0"
+fi
+CFLAGS="$CFLAGS ${bson_cflags}"
+
+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_fn_c_check_header_compile "$LINENO" "bson/bson.h" "ac_cv_header_bson_bson_h" "#include <bson/bson.h>
+"
+if test "x$ac_cv_header_bson_bson_h" = xyes; then :
+
+fi
+
+
+CFLAGS="$CFLAGS_PRE"
+
+if test "x$ac_cv_header_bson_bson_h" != "xyes"; then
+
+fail="$fail bson/bson.h"
+
+fi
+
+
+LDFLAGS_PRE="$LDFLAGS"
+if test x$bson_lib_dir != x ; then
+ bson_ldflags="-L${bson_lib_dir} -lbson-1.0"
+else
+ bson_ldflags="-L/usr/lib -lbson-1.0"
+fi
+LDFLAGS="$LDFLAGS ${bson_ldflags}"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bson_iter_init_find in -lbson-1.0" >&5
+$as_echo_n "checking for bson_iter_init_find in -lbson-1.0... " >&6; }
+if ${ac_cv_lib_bson_1_0__bson_iter_init_find_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbson-1.0 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char bson_iter_init_find ();
+int
+main ()
+{
+return bson_iter_init_find ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bson_1_0__bson_iter_init_find_=yes
+else
+ ac_cv_lib_bson_1_0__bson_iter_init_find_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bson_1_0__bson_iter_init_find_" >&5
+$as_echo "$ac_cv_lib_bson_1_0__bson_iter_init_find_" >&6; }
+if test "x$ac_cv_lib_bson_1_0__bson_iter_init_find_" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBSON_1_0 1
+_ACEOF
+
+ LIBS="-lbson-1.0 $LIBS"
+
+fi
+
+LDFLAGS="$LDFLAGS_PRE"
+
+if test "x$ac_cv_lib_bson_1_0__bson_iter_init_find_" != "xyes"; then
+
+fail="$fail libbson"
+
+fi
+
+
+CFLAGS_PRE="$CFLAGS"
+if test x$mongoc_include_dir != x ; then
+ mongoc_cflags="-isystem ${mongoc_include_dir} ${bson_cflags}"
+else
+ mongoc_cflags="-isystem /usr/include/libmongoc-1.0 ${bson_cflags}"
+fi
+CFLAGS="$CFLAGS ${mongoc_cflags}"
+
+ac_fn_c_check_header_compile "$LINENO" "mongoc.h" "ac_cv_header_mongoc_h" "#include <mongoc.h>
+"
+if test "x$ac_cv_header_mongoc_h" = xyes; then :
+
+fi
+
+
+CFLAGS="$CFLAGS_PRE"
+
+if test "x$ac_cv_header_mongoc_h" != "xyes"; then
+
+fail="$fail mongoc.h"
+
+fi
+
+
+LDFLAGS_PRE="$LDFLAGS"
+if test x$mongoc_lib_dir != x ; then
+ mongoc_ldflags="-L${mongoc_lib_dir} -lmongoc-1.0 ${bson_ldflags}"
+else
+ mongoc_ldflags="-L/usr/lib -lmongoc-1.0 ${bson_ldflags}"
+fi
+LDFLAGS="$LDFLAGS ${mongoc_ldflags}"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mongoc_init in -lmongoc-1.0" >&5
+$as_echo_n "checking for mongoc_init in -lmongoc-1.0... " >&6; }
+if ${ac_cv_lib_mongoc_1_0__mongoc_init_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmongoc-1.0 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mongoc_init ();
+int
+main ()
+{
+return mongoc_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_mongoc_1_0__mongoc_init_=yes
+else
+ ac_cv_lib_mongoc_1_0__mongoc_init_=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mongoc_1_0__mongoc_init_" >&5
+$as_echo "$ac_cv_lib_mongoc_1_0__mongoc_init_" >&6; }
+if test "x$ac_cv_lib_mongoc_1_0__mongoc_init_" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBMONGOC_1_0 1
+_ACEOF
+
+ LIBS="-lmongoc-1.0 $LIBS"
+
+fi
+
+LDFLAGS="$LDFLAGS_PRE"
+
+if test "x$ac_cv_lib_mongoc_1_0__mongoc_init_" != "xyes"; then
+
+fail="$fail libmongoc-1.0"
+
+fi
+
+
+ targetname=rlm_sql_mongo
+else
+ targetname=
+ echo \*\*\* module rlm_sql_mongo is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_mongo to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_mongo." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_mongo." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_mongo requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_mongo requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure.ac
new file mode 100644
index 0000000..b9756a9
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mongo/configure.ac
@@ -0,0 +1,118 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_mongo.c])
+AC_REVISION($Revision: 1.10 $)
+FR_INIT_MODULE([rlm_sql_mongo])
+
+mongoc_ldflags=
+mongoc_cflags=
+
+FR_MODULE_START_TESTS
+
+AC_ARG_WITH(mongoc_lib_dir,
+ [AS_HELP_STRING([--with-mongoc-lib-dir],
+ [Path of libmongoc libraries])],
+ [ mongoc_lib_dir="$withval" ],
+ [ mongoc_lib_dir="" ])
+
+AC_ARG_WITH(mongoc_include_dir,
+ [AS_HELP_STRING([--with-mongoc-include-dir],
+ [Path of libmongoc includes])],
+ [ mongoc_include_dir="$withval" ],
+ [ mongoc_include_dir="" ])
+
+AC_ARG_WITH(bson_lib_dir,
+ [AS_HELP_STRING([--with-bson-lib-dir],
+ [Path of libbson libraries])],
+ [ bson_lib_dir="$withval" ],
+ [ bson_lib_dir="" ])
+
+AC_ARG_WITH(bson_include_dir,
+ [AS_HELP_STRING([--with-bson-include-dir],
+ [Path of libbson includes])],
+ [ bson_include_dir="$withval" ],
+ [ bson_include_dir="" ])
+
+dnl ######################################################
+dnl # Check for header files of Bson Libraries
+dnl ######################################################
+
+CFLAGS_PRE="$CFLAGS"
+if test x$bson_include_dir != x ; then
+ bson_cflags="-isystem ${bson_include_dir}"
+else
+ bson_cflags="-isystem /usr/include/libbson-1.0"
+fi
+CFLAGS="$CFLAGS ${bson_cflags}"
+
+AC_CHECK_HEADER([bson/bson.h], [], [], [#include <bson/bson.h>])
+CFLAGS="$CFLAGS_PRE"
+
+if test "x$ac_cv_header_bson_bson_h" != "xyes"; then
+ FR_MODULE_FAIL([bson/bson.h])
+fi
+
+dnl ######################################################
+dnl # Check for libraries of Bson
+dnl ######################################################
+
+LDFLAGS_PRE="$LDFLAGS"
+if test x$bson_lib_dir != x ; then
+ bson_ldflags="-L${bson_lib_dir} -lbson-1.0"
+else
+ bson_ldflags="-L/usr/lib -lbson-1.0"
+fi
+LDFLAGS="$LDFLAGS ${bson_ldflags}"
+
+AC_CHECK_LIB(bson-1.0, [ bson_iter_init_find ], [], [])
+LDFLAGS="$LDFLAGS_PRE"
+
+if test "x$ac_cv_lib_bson_1_0__bson_iter_init_find_" != "xyes"; then
+ FR_MODULE_FAIL([libbson])
+fi
+
+dnl ######################################################
+dnl # Check for header files of MongoC Libraries
+dnl ######################################################
+
+CFLAGS_PRE="$CFLAGS"
+if test x$mongoc_include_dir != x ; then
+ mongoc_cflags="-isystem ${mongoc_include_dir} ${bson_cflags}"
+else
+ mongoc_cflags="-isystem /usr/include/libmongoc-1.0 ${bson_cflags}"
+fi
+CFLAGS="$CFLAGS ${mongoc_cflags}"
+
+AC_CHECK_HEADER([mongoc.h], [], [], [#include <mongoc.h>])
+CFLAGS="$CFLAGS_PRE"
+
+if test "x$ac_cv_header_mongoc_h" != "xyes"; then
+ FR_MODULE_FAIL([mongoc.h])
+fi
+
+dnl ######################################################
+dnl # Check for libraries of MongoC
+dnl ######################################################
+
+LDFLAGS_PRE="$LDFLAGS"
+if test x$mongoc_lib_dir != x ; then
+ mongoc_ldflags="-L${mongoc_lib_dir} -lmongoc-1.0 ${bson_ldflags}"
+else
+ mongoc_ldflags="-L/usr/lib -lmongoc-1.0 ${bson_ldflags}"
+fi
+LDFLAGS="$LDFLAGS ${mongoc_ldflags}"
+
+AC_CHECK_LIB(mongoc-1.0, [ mongoc_init ], [], [])
+LDFLAGS="$LDFLAGS_PRE"
+
+if test "x$ac_cv_lib_mongoc_1_0__mongoc_init_" != "xyes"; then
+ FR_MODULE_FAIL([libmongoc-1.0])
+fi
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mongoc_cflags)
+AC_SUBST(mongoc_ldflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mongo/rlm_sql_mongo.c b/src/modules/rlm_sql/drivers/rlm_sql_mongo/rlm_sql_mongo.c
new file mode 100644
index 0000000..f40f18a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mongo/rlm_sql_mongo.c
@@ -0,0 +1,884 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_sql_mongo.c
+ * @brief Mongo driver.
+ *
+ * @copyright 2019 Network RADIUS SARL
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <mongoc.h>
+
+#include "rlm_sql.h"
+
+#define MAX_ROWS (64)
+
+typedef struct rlm_sql_mongo_config {
+ char *appname; /* what we tell Mongo we are */
+ mongoc_ssl_opt_t tls;
+ mongoc_client_pool_t *pool;
+} rlm_sql_mongo_config_t;
+
+typedef struct rlm_sql_mongo_conn {
+ rlm_sql_mongo_config_t *driver;
+ bson_t *result;
+ bson_error_t error;
+ int cur_row;
+ int num_fields; //!< number of columns
+ int affected_rows; //!< only for writes
+
+ int num_rows; //!< for selects
+ bson_t **bson_row; //!< copy of selected document
+
+ char **row; //!< really fields, i.e. columns
+} rlm_sql_mongo_conn_t;
+
+static CONF_PARSER tls_config[] = {
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mongo_config_t, tls.pem_file), NULL },
+ { "certificate_password", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_mongo_config_t, tls.pem_pwd), NULL },
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mongo_config_t, tls.ca_file), NULL },
+ { "ca_dir", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mongo_config_t, tls.ca_dir), NULL },
+ { "crl_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mongo_config_t, tls.crl_file), NULL },
+ { "weak_cert_validation", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mongo_config_t, tls.weak_cert_validation), NULL },
+ { "allow_invalid_hostname", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mongo_config_t, tls.allow_invalid_hostname), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER driver_config[] = {
+ { "appname", PW_TYPE_STRING, offsetof(rlm_sql_mongo_config_t, appname), NULL, NULL},
+
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * This is only accessed fromt the main server thread, so it
+ * doesn't need locks.
+ */
+static int use_count = 0;
+
+#define BSON_DESTROY(_x) do { if (_x) { bson_destroy(_x); _x = NULL; }} while (0)
+
+static int _sql_destructor(rlm_sql_mongo_config_t *driver)
+{
+ if (driver->pool) {
+ mongoc_client_pool_destroy(driver->pool);
+ driver->pool = NULL;
+ }
+
+ use_count--;
+ if (use_count == 0) {
+ mongoc_cleanup();
+ }
+
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_config_t *driver;
+ mongoc_uri_t *uri;
+ bson_error_t error;
+
+ MEM(driver = config->driver = talloc_zero(config, rlm_sql_mongo_config_t));
+ if (cf_section_parse(conf, driver, driver_config) < 0) {
+ return -1;
+ }
+
+ /*
+ * Initialize the C library if necessary.
+ */
+ if (use_count == 0) {
+ mongoc_init();
+ }
+ use_count++;
+
+ uri = mongoc_uri_new_with_error(config->sql_server, &error);
+ if (!uri) {
+ ERROR("Failed to parse server URI string '%s': %s",
+ config->sql_server, error.message);
+ return -1;
+ }
+
+ driver->pool = mongoc_client_pool_new(uri);
+ mongoc_client_pool_set_error_api(driver->pool, 2);
+
+ if (driver->tls.ca_dir || driver->tls.ca_file) {
+ mongoc_client_pool_set_ssl_opts(driver->pool, &driver->tls);
+ }
+
+ mongoc_uri_destroy(uri);
+ talloc_set_destructor(driver, _sql_destructor);
+
+ return 0;
+}
+
+static void sql_conn_free(rlm_sql_mongo_conn_t *conn)
+{
+ if (conn->bson_row) {
+ int i;
+
+ for (i = 0; i < conn->num_rows; i++) {
+ BSON_DESTROY(conn->bson_row[i]);
+ }
+
+ TALLOC_FREE(conn->bson_row);
+ conn->result = NULL; /* reference to conn->bson_row[0] */
+ }
+ conn->num_rows = 0;
+
+ BSON_DESTROY(conn->result);
+ TALLOC_FREE(conn->row);
+ conn->num_fields = 0;
+}
+
+static int _sql_socket_destructor(rlm_sql_mongo_conn_t *conn)
+{
+ DEBUG2("rlm_sql_mongo: Socket destructor called, closing socket.");
+ sql_conn_free(conn);
+ return 0;
+}
+
+static int CC_HINT(nonnull) sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_mongo_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ conn->driver = config->driver;
+
+ DEBUG2("rlm_sql_mongo: Socket initialized.");
+ return 0;
+}
+
+/*
+ * Only return the number of columns if there's an actual result.
+ */
+static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+
+ return conn->num_fields;
+}
+
+static int sql_affected_rows(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+
+ return conn->affected_rows;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+
+ sql_conn_free(conn);
+
+ return 0;
+}
+
+
+static CC_HINT(nonnull) sql_rcode_t sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config,
+ char const *query)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+ char const *p, *q;
+ char *str, *r, *end;
+ bool aggregate = false;
+ bool findandmodify = false;
+ bool find = false;
+ bool insert = false;
+ char *ptr;
+ mongoc_client_t *client;
+ bson_t *bson = NULL;
+ bool rcode;
+ bson_iter_t iter;
+ mongoc_collection_t *collection;
+ bson_t *bson_query, *bson_update, *bson_sort, *bson_fields;
+ char name[256];
+ char command[256];
+
+ conn->affected_rows = 0;
+ conn->cur_row = 0;
+
+ client = NULL;
+ collection = NULL;
+ bson_query = bson_update = bson_sort = bson_fields = NULL;
+
+ /*
+ * Ensure that we use whatever results come back now not
+ * whatever was left over from before. Also, if the
+ * query / connection fails, that there is less to clean up.
+ */
+ BSON_DESTROY(conn->result);
+
+ /*
+ * See what kind of query it is. Aggregate queries
+ * require a different API, so they are handled differently.
+ *
+ * The query string is "db.COLLECTION.COMMAND( ... json ... )
+ *
+ * We parse the string to see what's up.
+ */
+ p = query;
+ while (isspace((uint8_t) *p)) p++;
+
+ if (strncmp(p, "db.", 3) != 0) {
+ ERROR("rlm_sql_mongo: Invalid query - must start with 'db.'");
+ return RLM_SQL_QUERY_INVALID;
+ }
+ p += 3;
+
+ /*
+ * Get the collection name.
+ */
+ ptr = name;
+ while (*p) {
+ /*
+ * Stop if we hit the next delimiter, and skip
+ * it.
+ */
+ if (*p == '.') {
+ *ptr = '\0';
+ p++;
+ break;
+ }
+
+ if ((size_t) (ptr - name) >= sizeof(name)) {
+ ERROR("rlm_sql_mongo: Invalid query - collection name is too long");
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ *(ptr++) = *(p++);
+ }
+
+ /*
+ * Get the command name. There's no real need to copy it
+ * here, but it's fine.
+ */
+ ptr = command;
+ while (*p) {
+ /*
+ * Allow whitespace after the command name, and
+ * before the bracket.
+ */
+ if (isspace((uint8_t) *p)) {
+ *ptr = '\0';
+ while (*p && isspace((uint8_t) *p)) p++;
+
+ if (*p != '(') {
+ ERROR("rlm_sql_mongo: Invalid query - no starting '('");
+ return RLM_SQL_QUERY_INVALID;
+ }
+ }
+
+ /*
+ * Stop if we hit the brace holding the json, and
+ * skip it.
+ */
+ if (*p == '(') {
+ *ptr = '\0';
+ p++;
+ break;
+ }
+
+ if ((size_t) (ptr - command) >= sizeof(command)) {
+ ERROR("rlm_sql_mongo: Invalid query - command name is too long");
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ *(ptr++) = *(p++);
+ }
+
+ /*
+ * Look for the ending ')'.
+ */
+ q = strrchr(p, ')');
+ if (!q) {
+ ERROR("rlm_sql_mongo: Invalid query - no ending ')'");
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ if (q[1] != '\0') {
+ ERROR("rlm_sql_mongo: Invalid query - Unexpected text after ')'");
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ if (strcasecmp(command, "findOne") == 0) {
+ find = true;
+
+ } else if (strcasecmp(command, "findAndModify") == 0) {
+ findandmodify = true;
+
+ } else if (strcasecmp(command, "aggregate") == 0) {
+ aggregate = true;
+
+ } else if (strcasecmp(command, "insert") == 0) {
+ insert = true;
+
+ } else {
+ ERROR("rlm_sql_mongo: Invalid query - Unknown / unsupported Mongo command '%s'",
+ command);
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ /*
+ * Take a second pass over the query, moving single quotes to double quotes.
+ */
+ str = talloc_strndup(NULL, p, (size_t) (q - p));
+ end = str + (q - p);
+ for (r = str; r < end; r++) {
+ if (*r == '\'') *r = '"';
+ }
+
+ /*
+ * <whew> p && q now enclose the json blob.
+ */
+ bson = bson_new_from_json((uint8_t const *) str, q - p, &conn->error);
+ talloc_free(str);
+ if (!bson) {
+ ERROR("rlm_sql_mongo: Invalid query - json is malfomed - %s",
+ conn->error.message);
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ /*
+ * Get the client connection, run the command, and return
+ * the connection to the pool.
+ *
+ * Note that MongoC has it's own thread-safe thread pool
+ * connection handling.
+ *
+ * The total number of clients that can be created from
+ * this pool is limited by the URI option “maxPoolSize”,
+ * default 100. If this number of clients has been
+ * created and all are in use, the "pop" call will block
+ * until another thread has done a "push".
+ */
+ client = mongoc_client_pool_pop(conn->driver->pool);
+ collection = mongoc_client_get_collection(client, config->sql_db, name);
+
+ if (findandmodify) {
+ bson_t bson_reply;
+ bson_value_t const *value;
+ bson_iter_t child;
+ bool upsert, remove, update;
+ uint8_t const *document;
+ uint32_t document_len;
+
+ upsert = remove = update = false;
+
+ /*
+ * Parse the various fields.
+ */
+ if (bson_iter_init_find(&iter, bson, "query")) {
+ if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
+ DEBUG("rlm_sql_mongo: 'query' does not hold a document.");
+ goto error;
+ }
+
+ bson_iter_document(&iter, &document_len, &document);
+ bson_query = bson_new_from_data(document, document_len);
+ if (!bson_query) {
+ DEBUG("rlm_sql_mongo: Failed parsing 'query'");
+ goto error;
+ }
+ } else {
+ DEBUG("rlm_sql_mongo: No 'query' subdocument found.");
+ goto error;
+ }
+
+ if (bson_iter_init_find(&iter, bson, "update")) {
+ if (!(BSON_ITER_HOLDS_DOCUMENT(&iter) || BSON_ITER_HOLDS_ARRAY(&iter))) {
+ DEBUG("rlm_sql_mongo: 'update' does not hold a document or array.");
+ goto error;
+ }
+
+ if (BSON_ITER_HOLDS_DOCUMENT(&iter)) {
+ bson_iter_document(&iter, &document_len, &document);
+ } else {
+ bson_iter_array(&iter, &document_len, &document);
+ }
+
+ bson_update = bson_new_from_data(document, document_len);
+
+ if (!bson_update) {
+ DEBUG("rlm_sql_mongo: Failed parsing 'update'");
+ goto error;
+ }
+
+ update = true;
+ }
+
+ if (bson_iter_init_find(&iter, bson, "sort")) {
+ if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
+ DEBUG("rlm_sql_mongo: 'sort' does not hold a document.");
+ goto error;
+ }
+
+ bson_iter_document(&iter, &document_len, &document);
+ bson_sort = bson_new_from_data(document, document_len);
+
+ if (!bson_sort) {
+ DEBUG("rlm_sql_mongo: Failed parsing 'sort'");
+ goto error;
+ }
+ }
+
+ if (bson_iter_init_find(&iter, bson, "fields")) {
+ if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
+ DEBUG("rlm_sql_mongo: 'fields' does not hold a document.");
+ goto error;
+ }
+
+ bson_iter_document(&iter, &document_len, &document);
+ bson_fields = bson_new_from_data(document, document_len);
+
+ if (!bson_fields) {
+ DEBUG("rlm_sql_mongo: Failed parsing 'fields'");
+ goto error;
+ }
+ }
+
+ if (bson_iter_init_find(&iter, bson, "upsert")) {
+ if (!BSON_ITER_HOLDS_BOOL(&iter)) {
+ DEBUG("rlm_sql_mongo: 'upsert' does not hold a boolean.");
+ goto error;
+ }
+
+ upsert = bson_iter_as_bool(&iter);
+ }
+
+ if (bson_iter_init_find(&iter, bson, "remove")) {
+ if (!BSON_ITER_HOLDS_BOOL(&iter)) {
+ DEBUG("rlm_sql_mongo: 'remove' does not hold a boolean.");
+ goto error;
+ }
+
+ remove = bson_iter_as_bool(&iter);
+ }
+
+ if (!update && !remove) {
+ WARN("rlm_sql_mongo: 'findAndModify' requires 'update' or 'remove'. Query will likely fail");
+ }
+
+ rcode = mongoc_collection_find_and_modify(collection, bson_query,
+ bson_sort, bson_update, bson_fields,
+ remove, upsert,
+ true, &bson_reply,
+ &conn->error);
+ BSON_DESTROY(bson_query);
+ BSON_DESTROY(bson_update);
+ BSON_DESTROY(bson_sort);
+ BSON_DESTROY(bson_fields);
+
+ /*
+ * See just what the heck was returned.
+ */
+ if (rad_debug_lvl >= 3) {
+ str = bson_as_canonical_extended_json (&bson_reply, NULL);
+ if (str) {
+ DEBUG3("bson reply: %s\n", str);
+ bson_free(str);
+ }
+ }
+
+ /*
+ * If we've removed something, we've affected a
+ * row.
+ */
+ if (remove) {
+ conn->affected_rows = 1;
+ goto done_reply;
+ }
+
+ /*
+ * Retrieve the number of affected documents
+ */
+ if (bson_iter_init_find(&iter, &bson_reply, "lastErrorObject") &&
+ BSON_ITER_HOLDS_DOCUMENT(&iter) &&
+ bson_iter_recurse(&iter, &child) &&
+ bson_iter_find(&child, "n") &&
+ BSON_ITER_HOLDS_INT32(&child)) {
+ value = bson_iter_value(&child);
+ conn->affected_rows = value->value.v_int32;
+ DEBUG3("Query updated %u documents", value->value.v_int32);
+ }
+
+ if (!conn->affected_rows) {
+ WARN("rlm_sql_mongo: No document updated for query.");
+ }
+
+ if (!bson_iter_init_find(&iter, &bson_reply, "value")) {
+ DEBUG3("reply has no 'value'");
+ goto done_reply;
+ }
+
+ /*
+ * The actual result is in the "value" of the
+ * reply. It should be a document.
+ */
+ if (!BSON_ITER_HOLDS_DOCUMENT(&iter)) {
+ DEBUG3("reply 'value' is not a document");
+ goto done_reply;
+ }
+
+ /*
+ * If the query returns a scalar, the scalar is
+ * in "value.value". The top-level "value"
+ * document also contains copies of the other
+ * fields used by the query, and we don't care
+ * about those other fields.
+ */
+ if (!bson_iter_recurse(&iter, &child) ||
+ !bson_iter_find(&child, "value")) {
+ DEBUG3("reply has no 'value.value'");
+ goto done_reply;
+ }
+
+ /*
+ * "value.value" should hold something tangible.
+ */
+ if (!BSON_ITER_HOLDS_UTF8(&child) &&
+ !BSON_ITER_HOLDS_INT32(&child) &&
+ !BSON_ITER_HOLDS_TIMESTAMP(&child) &&
+ !BSON_ITER_HOLDS_INT64(&child)) {
+ DEBUG3("reply has 'value.value' is not utf8 / int32 / int64 / timestamp");
+ goto done_reply;
+ }
+
+ /*
+ * Finally, grab the value.
+ */
+ value = bson_iter_value(&child);
+ if (!value) {
+ DEBUG3("reply has 'value.value', but it cannot be parsed");
+ goto done_reply;
+ }
+
+ /*
+ * Synthesize a new result from the scalar value.
+ *
+ * This work is done so that fetch_row() has a
+ * consistent type of result to work with.
+ */
+ conn->result = bson_new();
+ (void) bson_append_value(conn->result, "scalar", 6, value);
+
+ done_reply:
+ bson_destroy(&bson_reply);
+
+ } else if (insert) {
+ if (!mongoc_collection_insert(collection, MONGOC_INSERT_NONE, bson, NULL, &conn->error)) {
+ goto print_error;
+ }
+
+ bson_destroy(bson);
+ mongoc_client_pool_push(conn->driver->pool, client);
+ mongoc_collection_destroy(collection);
+ conn->num_fields = 0;
+
+ return RLM_SQL_OK;
+
+ } else {
+ mongoc_cursor_t *cursor;
+ bson_t const *doc;
+
+ /*
+ * findOne versus aggregate. For findOne, we
+ * limit the results to (drumroll) one.
+ */
+ if (find) {
+ bson_t *opts = BCON_NEW("limit", BCON_INT64 (1));
+ cursor = mongoc_collection_find_with_opts(collection, bson, opts, NULL);
+ bson_destroy(opts);
+
+ } else {
+ rad_assert(aggregate == true);
+ cursor = mongoc_collection_aggregate(collection, MONGOC_QUERY_NONE, bson, NULL, NULL);
+ }
+
+ conn->num_rows = 0;
+ conn->bson_row = talloc_zero_array(conn, bson_t *, MAX_ROWS);
+
+ /*
+ * Copy the documents.
+ */
+ while (mongoc_cursor_next(cursor, &doc)) {
+ conn->bson_row[conn->num_rows] = bson_copy(doc);
+
+ if (rad_debug_lvl >= 3) {
+ str = bson_as_canonical_extended_json (doc, NULL);
+ if (str) {
+ DEBUG3("rlm_sql_mongo got result into row %d: %s", conn->num_rows, str);
+ bson_free(str);
+ }
+ }
+
+ conn->num_rows++;
+ if (conn->num_rows >= MAX_ROWS) break;
+ }
+
+ if (mongoc_cursor_error(cursor, &conn->error)) {
+ DEBUG("rlm_sql_mongo: Failed running query: %s",
+ conn->error.message);
+ rcode = false;
+ } else {
+ rcode = true;
+ }
+
+ mongoc_cursor_destroy(cursor);
+
+ /*
+ * As a hack to simplify the later code.
+ */
+ conn->result = conn->bson_row[0];
+ }
+
+ mongoc_client_pool_push(conn->driver->pool, client);
+ client = NULL;
+ mongoc_collection_destroy(collection);
+ collection = NULL;
+
+ if (!conn->result) {
+ DEBUG("rlm_sql_mongo: Query got no result");
+ BSON_DESTROY(bson);
+ (void) sql_free_result(handle, config);
+ return RLM_SQL_OK;
+ }
+
+ if (!rcode) {
+ print_error:
+ DEBUG("rlm_sql_mongo: Failed running command: %s",
+ conn->error.message);
+
+ error:
+ if (client) mongoc_client_pool_push(conn->driver->pool, client);
+ if (collection) mongoc_collection_destroy(collection);
+ BSON_DESTROY(bson);
+ BSON_DESTROY(bson_query);
+ BSON_DESTROY(bson_update);
+ BSON_DESTROY(bson_sort);
+ BSON_DESTROY(bson_fields);
+ (void) sql_free_result(handle, config);
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * No more need for this.
+ */
+ BSON_DESTROY(bson);
+
+ /*
+ * Count the number of fields in the first row. This is
+ * the number of fields that each row must have.
+ */
+ conn->num_fields = 0;
+ if (!bson_iter_init(&iter, conn->result)) goto error;
+
+ while (bson_iter_next(&iter)) {
+ conn->num_fields++;
+ }
+
+ /*
+ * And let sql_fetch_row do the actual work of parsing the bson.
+ */
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char const *query)
+{
+ return sql_query(handle, config, query);
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+ int i, num_fields;
+ bson_t *bson;
+ bson_iter_t iter;
+
+ handle->row = NULL;
+
+ if (conn->num_rows) {
+ DEBUG("getting result from row %d = %p", conn->cur_row,
+ conn->bson_row[conn->cur_row]);
+ bson = conn->bson_row[conn->cur_row++];
+ } else {
+ bson = conn->result;
+ }
+
+ TALLOC_FREE(conn->row);
+
+ if (!bson) {
+ DEBUG("No more rows");
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ if (!bson_iter_init(&iter, bson)) return RLM_SQL_NO_MORE_ROWS;
+
+ /*
+ * Find the number of fields in this row.
+ */
+ num_fields = 0;
+ while (bson_iter_next(&iter)) {
+ num_fields++;
+ }
+
+ if (!bson_iter_init(&iter, bson)) return RLM_SQL_NO_MORE_ROWS;
+
+ /*
+ * If this row has a different number of columns than the
+ * first one, all bets are off. Stop processing the
+ * result.
+ */
+ if (num_fields != conn->num_fields) return RLM_SQL_NO_MORE_ROWS;
+
+ conn->row = talloc_zero_array(conn, char *, conn->num_fields + 1);
+
+ if (!bson_iter_init(&iter, bson)) return RLM_SQL_NO_MORE_ROWS;
+
+ /*
+ * We have to call this to get the FIRST element.
+ */
+ if (!bson_iter_next(&iter)) return RLM_SQL_OK;
+
+ for (i = 0; i < conn->num_fields; i++) {
+ bson_value_t const *value;
+
+ if (conn->row[i]) TALLOC_FREE(conn->row[i]);
+
+ DEBUG3("rlm_sql_mongo: key '%s' at field %d", bson_iter_key(&iter), i);
+
+ value = bson_iter_value(&iter);
+ if (!value) {
+ DEBUG("rlm_sql_mongo: Iteration returned no value at field %d", i);
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ switch (value->value_type) {
+ case BSON_TYPE_INT32:
+ conn->row[i] = talloc_asprintf(conn->row, "%u", value->value.v_int32);
+ break;
+
+ case BSON_TYPE_INT64:
+ conn->row[i] = talloc_asprintf(conn->row, "%" PRIu64, value->value.v_int64);
+ break;
+
+ /*
+ * In milliseconds, as a 64-bit number.
+ */
+ case BSON_TYPE_TIMESTAMP:
+ conn->row[i] = talloc_asprintf(conn->row, "%" PRIu64, value->value.v_datetime / 1000);
+ break;
+
+ case BSON_TYPE_UTF8:
+ conn->row[i] = talloc_asprintf(conn->row, "%.*s", value->value.v_utf8.len, value->value.v_utf8.str);
+ break;
+
+ default:
+ conn->row[i] = talloc_asprintf(conn->row, "??? unknown bson type %u ???", value->value_type);
+ break;
+ }
+
+ handle->row = conn->row;
+
+ if (!bson_iter_next(&iter)) break;
+ }
+
+ return RLM_SQL_OK;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mongo_conn_t *conn = handle->conn;
+
+ rad_assert(outlen > 0);
+
+ out[0].type = L_ERR;
+ out[0].msg = talloc_asprintf(ctx, "%u.%u: %s", conn->error.domain, conn->error.code, conn->error.message);
+ return 1;
+}
+
+/*
+ * Escape strings. Note that we escape things for json: " and \, and 0x00
+ * We also escape single quotes, as they're used in the queries.
+ */
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
+{
+ char *p, *end;
+ char const *q;
+
+ end = out + outlen;
+ p = out;
+ q = in;
+
+ while (*q) {
+ if ((*q == '\'') || (*q == '"') || (*q == '\\')) {
+ if ((end - p) <= 2) break;
+
+ *(p++) = '\\';
+
+ } else {
+ if ((end - p) <= 1) break;
+ }
+
+ *(p++) = *(q++);
+ }
+
+ *(p++) = '\0';
+
+ return p - out;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_mongo;
+rlm_sql_module_t rlm_sql_mongo = {
+ .name = "rlm_sql_mongo",
+ .mod_instantiate = mod_instantiate,
+ .sql_socket_init = sql_socket_init,
+ .sql_finish_query = sql_free_result,
+ .sql_finish_select_query = sql_free_result,
+ .sql_num_fields = sql_num_fields,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_error = sql_error,
+ .sql_escape_func = sql_escape_func
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/.gitignore b/src/modules/rlm_sql/drivers/rlm_sql_mysql/.gitignore
new file mode 100644
index 0000000..589d7ff
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/.gitignore
@@ -0,0 +1,2 @@
+all.mk
+config.h
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/README.md b/src/modules/rlm_sql/drivers/rlm_sql_mysql/README.md
new file mode 100644
index 0000000..acee972
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_mysql
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for MySQL.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_mysql/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/config.h.in b/src/modules/rlm_sql/drivers/rlm_sql_mysql/config.h.in
new file mode 100644
index 0000000..e19bf08
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/config.h.in
@@ -0,0 +1,7 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if you have <mysql.h> */
+#undef HAVE_MYSQL_H
+
+/* Define if you have <mysql/mysql.h> */
+#undef HAVE_MYSQL_MYSQL_H
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/configure b/src/modules/rlm_sql/drivers/rlm_sql_mysql/configure
new file mode 100755
index 0000000..b2f4f9d
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/configure
@@ -0,0 +1,4789 @@
+#! /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_sql_mysql.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+MYSQL_CONFIG
+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_sql_mysql
+with_mysql_include_dir
+with_mysql_lib_dir
+with_mysql_dir
+with_threads
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_mysql build without rlm_sql_mysql
+ --with-mysql-include-dir=DIR
+ Directory where the mysql includes may be found
+ --with-mysql-lib-dir=DIR
+ Directory where the mysql libraries may be found
+ --with-mysql-dir=DIR Base directory where mysql is installed
+ --with-threads use threads, if available. (default=yes)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_mysql
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_mysql was given.
+if test "${with_rlm_sql_mysql+set}" = set; then :
+ withval=$with_rlm_sql_mysql;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_mysql" != xno; then
+
+
+
+mysql_include_dir=
+
+# Check whether --with-mysql-include-dir was given.
+if test "${with_mysql_include_dir+set}" = set; then :
+ withval=$with_mysql_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need mysql-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+mysql_lib_dir=
+
+# Check whether --with-mysql-lib-dir was given.
+if test "${with_mysql_lib_dir+set}" = set; then :
+ withval=$with_mysql_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need mysql-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-mysql-dir was given.
+if test "${with_mysql_dir+set}" = set; then :
+ withval=$with_mysql_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need mysql-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_lib_dir="$withval/lib"
+ mysql_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+mysql_with_threads=yes
+
+# Check whether --with-threads was given.
+if test "${with_threads+set}" = set; then :
+ withval=$with_threads; case "$withval" in
+ no)
+ mysql_with_threads=no
+
+if echo "$fr_features" | grep -q "+threads+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without threads" >> config.report.tmp
+ fr_features="$fr_features +threads+"
+fi
+
+ ;;
+ *)
+ ;;
+ esac
+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
+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
+
+# Extract the first word of "mysql_config", so it can be a program name with args.
+set dummy mysql_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_prog_MYSQL_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MYSQL_CONFIG"; then
+ ac_cv_prog_MYSQL_CONFIG="$MYSQL_CONFIG" # 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_MYSQL_CONFIG="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_MYSQL_CONFIG" && ac_cv_prog_MYSQL_CONFIG="no"
+fi
+fi
+MYSQL_CONFIG=$ac_cv_prog_MYSQL_CONFIG
+if test -n "$MYSQL_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_CONFIG" >&5
+$as_echo "$MYSQL_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test "x$MYSQL_CONFIG" = "xyes"; then
+ mysql_libs="$(mysql_config --libs_r)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient_r (using mysql_config)" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient_r (using mysql_config)... " >&6; }
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mysql_init ();
+int
+main ()
+{
+return mysql_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ have_libmysqlclient_r=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient_r" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ have_a_libmysqlclient='yes'
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+
+ if test "x$have_a_libmysqlclient" != "xyes"; then
+ mysql_libs="$(mysql_config --libs)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient (using mysql_config)" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient (using mysql_config)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mysql_init ();
+int
+main ()
+{
+return mysql_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ have_libmysqlclient=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ have_a_libmysqlclient=yes
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+fi
+
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql /usr/local/lib/mysql /usr/local/mysql/lib/mysql"
+
+
+sm_lib_safe=`echo "mysqlclient_r" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "mysql_init" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient_r in $try" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient_r in $try... " >&6; }
+ LIBS="-lmysqlclient_r $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient_r"
+ 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 mysql_init in -lmysqlclient_r" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient_r... " >&6; }
+ LIBS="-lmysqlclient_r $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient_r"
+ { $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 mysql_init in -lmysqlclient_r in $try" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient_r in $try... " >&6; }
+ LIBS="-lmysqlclient_r $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient_r"
+ 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_mysqlclient_r_mysql_init" = "xyes"; then
+ have_a_libmysqlclient='yes'
+ fi
+fi
+
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql /usr/local/lib/mysql /usr/local/mysql/lib/mysql"
+
+
+sm_lib_safe=`echo "mysqlclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "mysql_init" | sed 'y%./+-%__p_%'`
+
+old_LIBS="$LIBS"
+old_CPPFLAGS="$CPPFLAGS"
+smart_lib=
+smart_ldflags=
+smart_lib_dir=
+
+if test "x$smart_try_dir" != "x"; then
+ for try in $smart_try_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient in $try" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient in $try... " >&6; }
+ LIBS="-lmysqlclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient"
+ 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 mysql_init in -lmysqlclient" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; }
+ LIBS="-lmysqlclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient"
+ { $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 mysql_init in -lmysqlclient in $try" >&5
+$as_echo_n "checking for mysql_init in -lmysqlclient in $try... " >&6; }
+ LIBS="-lmysqlclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char mysql_init();
+int
+main ()
+{
+mysql_init()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lmysqlclient"
+ 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_mysqlclient_mysql_init" = "xyes"; then
+ have_a_libmysqlclient='yes'
+ fi
+fi
+
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ mysql_libs="$(mariadb_config --libs)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmariadb (using mariadb_config)" >&5
+$as_echo_n "checking for mysql_init in -lmariadb (using mariadb_config)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mysql_init ();
+int
+main ()
+{
+return mysql_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ have_libmysqlclient=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ have_a_libmysqlclient=yes
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+fi
+
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MySQL libraries not found. Use --with-mysql-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: MySQL libraries not found. Use --with-mysql-lib-dir=<path>." >&2;}
+
+fail="$fail libmysqlclient || libmysqlclient_r"
+
+fi
+
+
+if test "x$MYSQL_CONFIG" = "xyes"; then
+ mod_cflags="$(mysql_config --cflags)"
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $mod_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql.h (using mysql_config --cflags)" >&5
+$as_echo_n "checking for mysql.h (using mysql_config --cflags)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <mysql.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_mysql_h=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "x$have_mysql_h" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_MYSQL_H /**/" >>confdefs.h
+
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ mod_cflags="$(mysql_config --include)"
+ CFLAGS="$old_CFLAGS $mod_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql.h (using mysql_config --include)" >&5
+$as_echo_n "checking for mysql.h (using mysql_config --include)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <mysql.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_mysql_h=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "x$have_mysql_h" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_MYSQL_H /**/" >>confdefs.h
+
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+ CFLAGS="$old_CFLAGS"
+fi
+
+# MariaDB
+if test "x$have_mysql_h" != "xyes"; then
+ mod_cflags="$(mariadb_config --cflags)"
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $mod_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql.h (using mariadb_config --cflags)" >&5
+$as_echo_n "checking for mysql.h (using mariadb_config --cflags)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <mysql.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_mysql_h=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "x$have_mysql_h" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_MYSQL_H /**/" >>confdefs.h
+
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ mod_cflags="$(mariadb_config --include)"
+ CFLAGS="$old_CFLAGS $mod_cflags"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql.h (using mariadb_config --include)" >&5
+$as_echo_n "checking for mysql.h (using mariadb_config --include)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <mysql.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ have_mysql_h=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test "x$have_mysql_h" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_MYSQL_H /**/" >>confdefs.h
+
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$have_mysql_h" != "xyes"; then
+ smart_try_dir="$mysql_include_dir /usr/local/include /usr/local/mysql/include"
+
+
+ac_safe=`echo "mysql/mysql.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 mysql/mysql.h in $try" >&5
+$as_echo_n "checking for mysql/mysql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <mysql/mysql.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}/mysql/mysql.h" >&5
+$as_echo_n "checking for ${_prefix}/mysql/mysql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <mysql/mysql.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 mysql/mysql.h" >&5
+$as_echo_n "checking for mysql/mysql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <mysql/mysql.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 mysql/mysql.h in $try" >&5
+$as_echo_n "checking for mysql/mysql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <mysql/mysql.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_mysql_mysql_h" = "xyes"; then
+
+$as_echo "#define HAVE_MYSQL_MYSQL_H /**/" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: MySQL headers not found. Use --with-mysql-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: MySQL headers not found. Use --with-mysql-include-dir=<path>." >&2;}
+
+fail="$fail mysql.h"
+
+ fi
+fi
+
+
+ targetname=rlm_sql_mysql
+else
+ targetname=
+ echo \*\*\* module rlm_sql_mysql is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_mysql to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_mysql." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_mysql." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_mysql requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_mysql requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_sql/drivers/rlm_sql_mysql/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_mysql/configure.ac
new file mode 100644
index 0000000..d36aecb
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/configure.ac
@@ -0,0 +1,265 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_mysql.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_mysql])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-mysql-include-dir=DIR
+mysql_include_dir=
+AC_ARG_WITH(mysql-include-dir,
+ [AS_HELP_STRING([--with-mysql-include-dir=DIR],
+ [Directory where the mysql includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need mysql-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-mysql-lib-dir=DIR
+mysql_lib_dir=
+AC_ARG_WITH(mysql-lib-dir,
+ [AS_HELP_STRING([--with-mysql-lib-dir=DIR],
+ [Directory where the mysql libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need mysql-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-mysql-dir=DIR
+AC_ARG_WITH(mysql-dir,
+ [AS_HELP_STRING([--with-mysql-dir=DIR],
+ [Base directory where mysql is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need mysql-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ mysql_lib_dir="$withval/lib"
+ mysql_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl extra argument: --with-threads
+mysql_with_threads=yes
+AC_ARG_WITH(threads,
+ [AS_HELP_STRING([--with-threads],
+ [use threads, if available. (default=yes)])],
+ [case "$withval" in
+ no)
+ mysql_with_threads=no
+ FR_MODULE_FEATURE([threads], [without threads])
+ ;;
+ *)
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for programs
+dnl ############################################################
+
+AC_PROG_CC
+AC_CHECK_PROG(MYSQL_CONFIG, mysql_config, yes, no)
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+dnl # Older versions of mysqlclient packages had two variants libmysqlclient
+dnl # and libmysqlclient_r. libmysqlclient_r is the threadsafe variant that
+dnl # is per-connection threadsafe. If that is available on the system it
+dnl # should be used in preference to libmysqlclient.
+dnl # More recent versions >~ 5.6 have stopped including libmyqlclient_r
+dnl # however (as libmysqlclient is now threadsafe), so we should fall back
+dnl # to libmysqlclient if it is the only one available on the system.
+
+dnl # Use linker arguments from mysql_config if available, then fallback
+dnl # to hunting around if we can't find the client library.
+if test "x$MYSQL_CONFIG" = "xyes"; then
+ mysql_libs="$(mysql_config --libs_r)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ dnl # First check for libmysqlclient_r
+ AC_MSG_CHECKING([for mysql_init in -lmysqlclient_r (using mysql_config)])
+ AC_TRY_LINK_FUNC([mysql_init], [have_libmysqlclient_r=yes])
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient_r" = "xyes"; then
+ AC_MSG_RESULT(yes)
+
+ have_a_libmysqlclient='yes'
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+
+ dnl # If that's not available check for libmysqlclient
+ if test "x$have_a_libmysqlclient" != "xyes"; then
+ mysql_libs="$(mysql_config --libs)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ AC_MSG_CHECKING([for mysql_init in -lmysqlclient (using mysql_config)])
+ AC_TRY_LINK_FUNC([mysql_init], [have_libmysqlclient=yes])
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient" = "xyes"; then
+ AC_MSG_RESULT(yes)
+
+ have_a_libmysqlclient=yes
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+fi
+
+dnl # Check for libmysqlclient_r
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql /usr/local/lib/mysql /usr/local/mysql/lib/mysql"
+ FR_SMART_CHECK_LIB(mysqlclient_r, mysql_init)
+ if test "x$ac_cv_lib_mysqlclient_r_mysql_init" = "xyes"; then
+ have_a_libmysqlclient='yes'
+ fi
+fi
+
+dnl # Check for libmysqlclient
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ smart_try_dir="$mysql_lib_dir /usr/lib /usr/lib/mysql /usr/local/lib/mysql /usr/local/mysql/lib/mysql"
+ FR_SMART_CHECK_LIB(mysqlclient, mysql_init)
+ if test "x$ac_cv_lib_mysqlclient_mysql_init" = "xyes"; then
+ have_a_libmysqlclient='yes'
+ fi
+fi
+
+dnl # Check for MariaDB
+dnl # If that's not available check for libmariadb
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ mysql_libs="$(mariadb_config --libs)"
+ old_LIBS="$LIBS"
+ LIBS="$mysql_libs $LIBS"
+
+ AC_MSG_CHECKING([for mysql_init in -lmariadb (using mariadb_config)])
+ AC_TRY_LINK_FUNC([mysql_init], [have_libmysqlclient=yes])
+
+ LIBS="$old_LIBS"
+ if test "x$have_libmysqlclient" = "xyes"; then
+ AC_MSG_RESULT(yes)
+
+ have_a_libmysqlclient=yes
+ SMART_LIBS="$mysql_libs $SMART_LIBS"
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+
+if test "x$have_a_libmysqlclient" != "xyes"; then
+ AC_MSG_WARN([MySQL libraries not found. Use --with-mysql-lib-dir=<path>.])
+ FR_MODULE_FAIL([libmysqlclient || libmysqlclient_r])
+fi
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+if test "x$MYSQL_CONFIG" = "xyes"; then
+ mod_cflags="$(mysql_config --cflags)"
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $mod_cflags"
+ AC_MSG_CHECKING([for mysql.h (using mysql_config --cflags)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <mysql.h>]], [[int a = 1;]])],[have_mysql_h=yes],[])
+ if test "x$have_mysql_h" = "xyes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ AC_MSG_RESULT(no)
+
+ mod_cflags="$(mysql_config --include)"
+ CFLAGS="$old_CFLAGS $mod_cflags"
+ AC_MSG_CHECKING([for mysql.h (using mysql_config --include)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <mysql.h>]], [[int a = 1;]])],[have_mysql_h=yes],[])
+ if test "x$have_mysql_h" = "xyes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+ CFLAGS="$old_CFLAGS"
+fi
+
+# MariaDB
+if test "x$have_mysql_h" != "xyes"; then
+ mod_cflags="$(mariadb_config --cflags)"
+ old_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $mod_cflags"
+ AC_MSG_CHECKING([for mysql.h (using mariadb_config --cflags)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <mysql.h>]], [[int a = 1;]])],[have_mysql_h=yes],[])
+ if test "x$have_mysql_h" = "xyes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ AC_MSG_RESULT(no)
+
+ mod_cflags="$(mariadb_config --include)"
+ CFLAGS="$old_CFLAGS $mod_cflags"
+ AC_MSG_CHECKING([for mysql.h (using mariadb_config --include)])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <mysql.h>]], [[int a = 1;]])],[have_mysql_h=yes],[])
+ if test "x$have_mysql_h" = "xyes"; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MYSQL_H, [], [Define if you have <mysql.h>])
+ SMART_CPPFLAGS="$SMART_CPPFLAGS $mod_cflags"
+ else
+ AC_MSG_RESULT(no)
+ fi
+ fi
+ CFLAGS="$old_CFLAGS"
+fi
+
+if test "x$have_mysql_h" != "xyes"; then
+ smart_try_dir="$mysql_include_dir /usr/local/include /usr/local/mysql/include"
+ FR_SMART_CHECK_INCLUDE(mysql/mysql.h)
+ if test "x$ac_cv_header_mysql_mysql_h" = "xyes"; then
+ AC_DEFINE(HAVE_MYSQL_MYSQL_H, [], [Define if you have <mysql/mysql.h>])
+ else
+ AC_MSG_WARN([MySQL headers not found. Use --with-mysql-include-dir=<path>.])
+ FR_MODULE_FAIL([mysql.h])
+ fi
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c b/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c
new file mode 100644
index 0000000..78d1b8f
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c
@@ -0,0 +1,858 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file rlm_sql_mysql.c
+ * @brief MySQL driver.
+ *
+ * @copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000-2007,2015 The FreeRADIUS server project
+ * @copyright 2000 Mike Machado <mike@innercite.com>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef HAVE_MYSQL_MYSQL_H
+# include <mysql/mysql_version.h>
+# include <mysql/errmsg.h>
+# include <mysql/mysql.h>
+# include <mysql/mysqld_error.h>
+#elif defined(HAVE_MYSQL_H)
+# include <mysql_version.h>
+# include <errmsg.h>
+# include <mysql.h>
+# include <mysqld_error.h>
+#endif
+
+#if (MYSQL_VERSION_ID >= 50555) && (MYSQL_VERSION_ID < 50600)
+# define HAVE_TLS_OPTIONS 1
+# define HAVE_CRL_OPTIONS 0
+# define HAVE_TLS_VERIFY_OPTIONS 0
+#elif (MYSQL_VERSION_ID >= 50636) && (MYSQL_VERSION_ID < 50700)
+# define HAVE_TLS_OPTIONS 1
+# define HAVE_CRL_OPTIONS 1
+# define HAVE_TLS_VERIFY_OPTIONS 0
+#elif MYSQL_VERSION_ID >= 50700
+# define HAVE_TLS_OPTIONS 1
+# define HAVE_CRL_OPTIONS 1
+# define HAVE_TLS_VERIFY_OPTIONS 1
+#endif
+
+#include "rlm_sql.h"
+
+static int mysql_instance_count = 0;
+
+typedef enum {
+ SERVER_WARNINGS_AUTO = 0,
+ SERVER_WARNINGS_YES,
+ SERVER_WARNINGS_NO
+} rlm_sql_mysql_warnings;
+
+static const FR_NAME_NUMBER server_warnings_table[] = {
+ { "auto", SERVER_WARNINGS_AUTO },
+ { "yes", SERVER_WARNINGS_YES },
+ { "no", SERVER_WARNINGS_NO },
+ { NULL, 0 }
+};
+
+typedef struct rlm_sql_mysql_conn {
+ MYSQL db;
+ MYSQL *sock;
+ MYSQL_RES *result;
+} rlm_sql_mysql_conn_t;
+
+typedef struct rlm_sql_mysql_config {
+ char const *tls_ca_file; //!< Path to the CA used to validate the server's certificate.
+ char const *tls_ca_path; //!< Directory containing CAs that may be used to validate the
+ //!< servers certificate.
+ char const *tls_certificate_file; //!< Public certificate we present to the server.
+ char const *tls_private_key_file; //!< Private key for the certificate we present to the server.
+
+ char const *tls_crl_file; //!< Public certificate we present to the server.
+ char const *tls_crl_path; //!< Private key for the certificate we present to the server.
+
+ char const *tls_cipher; //!< Colon separated list of TLS ciphers for TLS <= 1.2.
+
+ bool tls_required; //!< Require that the connection is encrypted.
+ bool tls_check_cert; //!< Verify there's a trust relationship between the server's
+ ///< cert and one of the CAs we have configured.
+ bool tls_check_cert_cn; //!< Verify that the CN in the server cert matches the host
+ ///< we passed to mysql_real_connect().
+
+ char const *warnings_str; //!< Whether we always query the server for additional warnings.
+ rlm_sql_mysql_warnings warnings; //!< mysql_warning_count() doesn't
+ //!< appear to work with NDB cluster
+} rlm_sql_mysql_config_t;
+
+static CONF_PARSER tls_config[] = {
+ { "ca_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_ca_file), NULL },
+ { "ca_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_ca_path), NULL },
+ { "certificate_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_certificate_file), NULL },
+ { "private_key_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_private_key_file), NULL },
+
+#if HAVE_CRL_OPTIONS
+ { "crl_file", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_crl_file), NULL },
+ { "crl_path", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_sql_mysql_config_t, tls_crl_path), NULL },
+#endif
+ /*
+ * MySQL Specific TLS attributes
+ */
+ { "cipher", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_mysql_config_t, tls_cipher), NULL },
+
+ /*
+ * The closest thing we have to these options in other modules is
+ * in rlm_rest. rlm_ldap has its own bizarre option set.
+ *
+ * There, the options can be toggled independently, here they can't
+ * but for consistency we break them out anyway, and warn if the user
+ * has provided an invalid list of flags.
+ */
+#if HAVE_TLS_OPTIONS
+ { "tls_required", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_required), "no" },
+# if HAVE_TLS_VERIFY_OPTIONS
+ { "check_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_check_cert), "no" },
+ { "check_cert_cn", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_mysql_config_t, tls_check_cert_cn), "no" },
+# endif
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER driver_config[] = {
+ { "tls", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) tls_config },
+
+ { "warnings", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_mysql_config_t, warnings_str), "auto" },
+ CONF_PARSER_TERMINATOR
+};
+
+/* Prototypes */
+static sql_rcode_t sql_free_result(rlm_sql_handle_t*, rlm_sql_config_t*);
+
+static int _sql_socket_destructor(rlm_sql_mysql_conn_t *conn)
+{
+ DEBUG2("rlm_sql_mysql: Socket destructor called, closing socket");
+
+ if (conn->sock){
+ mysql_close(conn->sock);
+ }
+
+ return 0;
+}
+
+static int _mod_destructor(UNUSED rlm_sql_mysql_config_t *driver)
+{
+ if (--mysql_instance_count == 0) mysql_library_end();
+
+#if HAVE_TLS_VERIFY_OPTIONS
+ if (driver->tls_check_cert && !driver->tls_required) {
+ WARN("Implicitly setting tls_required = yes, as tls_check_cert = yes");
+ driver->tls_required = true;
+ }
+ if (driver->tls_check_cert_cn) {
+ if (!driver->tls_required) {
+ WARN("Implicitly setting tls_required = yes, as check_cert_cn = yes");
+ driver->tls_required = true;
+ }
+
+ if (!driver->tls_check_cert) {
+ WARN("Implicitly setting check_cert = yes, as check_cert_cn = yes");
+ driver->tls_check_cert = true;
+ }
+ }
+#endif
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_config_t *driver;
+ int warnings;
+
+ static bool version_done = false;
+
+ if (!version_done) {
+ version_done = true;
+
+ INFO("rlm_sql_mysql: libmysql version: %s", mysql_get_client_info());
+ }
+
+ if (mysql_instance_count == 0) {
+ if (mysql_library_init(0, NULL, NULL)) {
+ ERROR("rlm_sql_mysql: libmysql initialisation failed");
+
+ return -1;
+ }
+ }
+ mysql_instance_count++;
+
+ MEM(driver = config->driver = talloc_zero(config, rlm_sql_mysql_config_t));
+ talloc_set_destructor(driver, _mod_destructor);
+
+ if (cf_section_parse(conf, driver, driver_config) < 0) {
+ return -1;
+ }
+
+ warnings = fr_str2int(server_warnings_table, driver->warnings_str, -1);
+ if (warnings < 0) {
+ ERROR("rlm_sql_mysql: Invalid warnings value \"%s\", must be yes, no, or auto", driver->warnings_str);
+ return -1;
+ }
+ driver->warnings = (rlm_sql_mysql_warnings)warnings;
+
+ return 0;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn;
+ rlm_sql_mysql_config_t *driver = config->driver;
+ unsigned long sql_flags;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_mysql_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ DEBUG("rlm_sql_mysql: Starting connect to MySQL server");
+
+ mysql_init(&(conn->db));
+
+ /*
+ * If any of the TLS options are set, configure TLS
+ *
+ * According to MySQL docs this function always returns 0, so we won't
+ * know if ssl setup succeeded until mysql_real_connect is called below.
+ */
+ if (driver->tls_ca_file || driver->tls_ca_path ||
+ driver->tls_certificate_file || driver->tls_private_key_file) {
+ mysql_ssl_set(&(conn->db), driver->tls_private_key_file, driver->tls_certificate_file,
+ driver->tls_ca_file, driver->tls_ca_path, driver->tls_cipher);
+ }
+
+#if HAVE_TLS_OPTIONS
+ {
+ enum mysql_option ssl_mysql_opt;
+ unsigned int ssl_mysql_arg;
+ bool ssl_mode_isset = false;
+
+# if defined(MARIADB_VERSION_ID) || defined(MARIADB_BASE_VERSION)
+# if HAVE_TLS_VERIFY_OPTIONS
+ if (driver->tls_required || driver->tls_check_cert || driver->tls_check_cert_cn) {
+# else
+ if (driver->tls_required) {
+# endif
+ ssl_mode_isset = true;
+# if defined(MARIADB_VERSION_ID) || defined(MARIADB_BASE_VERSION)
+ /**
+ * For MariaDB, It should be true as can be seen in
+ * https://github.com/MariaDB/server/blob/mariadb-5.5.68/sql-common/client.c#L4338
+ */
+ ssl_mysql_arg = true;
+#else
+ ssl_mysql_arg = SSL_MODE_REQUIRED;
+#endif
+ ssl_mysql_opt = MYSQL_OPT_SSL_VERIFY_SERVER_CERT;
+ }
+# else
+ ssl_mysql_opt = MYSQL_OPT_SSL_MODE;
+
+ if (driver->tls_required) {
+ ssl_mysql_arg = SSL_MODE_REQUIRED;
+ ssl_mode_isset = true;
+ }
+# if HAVE_TLS_VERIFY_OPTIONS
+ if (driver->tls_check_cert) {
+ ssl_mysql_arg = SSL_MODE_VERIFY_CA;
+ ssl_mode_isset = true;
+ }
+ if (driver->tls_check_cert_cn) {
+ ssl_mysql_arg = SSL_MODE_VERIFY_IDENTITY;
+ ssl_mode_isset = true;
+ }
+# endif /* MARIADB_VERSION_ID */
+# endif
+
+ if (ssl_mode_isset) mysql_options(&(conn->db), ssl_mysql_opt, &ssl_mysql_arg);
+ }
+#endif
+
+#if HAVE_CRL_OPTIONS
+ if (driver->tls_crl_file) mysql_options(&(conn->db), MYSQL_OPT_SSL_CRL, driver->tls_crl_file);
+ if (driver->tls_crl_path) mysql_options(&(conn->db), MYSQL_OPT_SSL_CRLPATH, driver->tls_crl_path);
+#endif
+
+ mysql_options(&(conn->db), MYSQL_READ_DEFAULT_GROUP, "freeradius");
+
+ /*
+ * We need to know about connection errors, and are capable
+ * of reconnecting automatically.
+ */
+#if MYSQL_VERSION_ID >= 50013
+ {
+ int reconnect = 0;
+ mysql_options(&(conn->db), MYSQL_OPT_RECONNECT, &reconnect);
+ }
+#endif
+
+#if (MYSQL_VERSION_ID >= 50000)
+ if (config->query_timeout) {
+ unsigned int connect_timeout = config->query_timeout;
+ unsigned int read_timeout = config->query_timeout;
+ unsigned int write_timeout = config->query_timeout;
+
+ /*
+ * The timeout in seconds for each attempt to read from the server.
+ * There are retries if necessary, so the total effective timeout
+ * value is three times the option value.
+ */
+ if (config->query_timeout >= 3) read_timeout /= 3;
+
+ /*
+ * The timeout in seconds for each attempt to write to the server.
+ * There is a retry if necessary, so the total effective timeout
+ * value is two times the option value.
+ */
+ if (config->query_timeout >= 2) write_timeout /= 2;
+
+ /*
+ * Connect timeout is actually connect timeout (according to the
+ * docs) there are no automatic retries.
+ */
+ mysql_options(&(conn->db), MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
+ mysql_options(&(conn->db), MYSQL_OPT_READ_TIMEOUT, &read_timeout);
+ mysql_options(&(conn->db), MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
+ }
+#endif
+
+#if (MYSQL_VERSION_ID >= 40100)
+ sql_flags = CLIENT_MULTI_RESULTS | CLIENT_FOUND_ROWS;
+#else
+ sql_flags = CLIENT_FOUND_ROWS;
+#endif
+
+#ifdef CLIENT_MULTI_STATEMENTS
+ sql_flags |= CLIENT_MULTI_STATEMENTS;
+#endif
+ conn->sock = mysql_real_connect(&(conn->db),
+ config->sql_server,
+ config->sql_login,
+ config->sql_password,
+ config->sql_db,
+ config->sql_port,
+ NULL,
+ sql_flags);
+ if (!conn->sock) {
+ ERROR("rlm_sql_mysql: Couldn't connect to MySQL server %s@%s:%s", config->sql_login,
+ config->sql_server, config->sql_db);
+ ERROR("rlm_sql_mysql: MySQL error: %s", mysql_error(&conn->db));
+
+ conn->sock = NULL;
+ return RLM_SQL_ERROR;
+ }
+
+ DEBUG2("rlm_sql_mysql: Connected to database '%s' on %s, server version %s, protocol version %i",
+ config->sql_db, mysql_get_host_info(conn->sock),
+ mysql_get_server_info(conn->sock), mysql_get_proto_info(conn->sock));
+
+ return RLM_SQL_OK;
+}
+
+/** Analyse the last error that occurred on the socket, and determine an action
+ *
+ * @param server Socket from which to extract the server error. May be NULL.
+ * @param client_errno Error from the client.
+ * @return an action for rlm_sql to take.
+ */
+static sql_rcode_t sql_check_error(MYSQL *server, int client_errno)
+{
+ int sql_errno = 0;
+
+ /*
+ * The client and server error numbers are in the
+ * same numberspace.
+ */
+ if (server) sql_errno = mysql_errno(server);
+ if ((sql_errno == 0) && (client_errno != 0)) sql_errno = client_errno;
+
+ if (sql_errno > 0) switch (sql_errno) {
+ case CR_SERVER_GONE_ERROR:
+ case CR_SERVER_LOST:
+ case -1:
+ return RLM_SQL_RECONNECT;
+
+ case CR_OUT_OF_MEMORY:
+ case CR_COMMANDS_OUT_OF_SYNC:
+ case CR_UNKNOWN_ERROR:
+ default:
+ return RLM_SQL_ERROR;
+
+ /*
+ * Constraints errors that signify a duplicate, or that we might
+ * want to try an alternative query.
+ *
+ * Error constants not found in the 3.23/4.0/4.1 manual page
+ * are checked for.
+ * Other error constants should always be available.
+ */
+ case ER_DUP_UNIQUE: /* Can't write, because of unique constraint, to table '%s'. */
+ case ER_DUP_KEY: /* Can't write; duplicate key in table '%s' */
+
+ case ER_DUP_ENTRY: /* Duplicate entry '%s' for key %d. */
+ case ER_NO_REFERENCED_ROW: /* Cannot add or update a child row: a foreign key constraint fails */
+ case ER_ROW_IS_REFERENCED: /* Cannot delete or update a parent row: a foreign key constraint fails */
+#ifdef ER_FOREIGN_DUPLICATE_KEY
+ case ER_FOREIGN_DUPLICATE_KEY: /* Upholding foreign key constraints for table '%s', entry '%s', key %d would lead to a duplicate entry. */
+#endif
+#ifdef ER_DUP_ENTRY_WITH_KEY_NAME
+ case ER_DUP_ENTRY_WITH_KEY_NAME: /* Duplicate entry '%s' for key '%s' */
+#endif
+#ifdef ER_NO_REFERENCED_ROW_2
+ case ER_NO_REFERENCED_ROW_2:
+#endif
+#ifdef ER_ROW_IS_REFERENCED_2
+ case ER_ROW_IS_REFERENCED_2:
+#endif
+ return RLM_SQL_ALT_QUERY;
+
+ /*
+ * Constraints errors that signify an invalid query
+ * that can never succeed.
+ */
+ case ER_BAD_NULL_ERROR: /* Column '%s' cannot be null */
+ case ER_NON_UNIQ_ERROR: /* Column '%s' in %s is ambiguous */
+ return RLM_SQL_QUERY_INVALID;
+
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+ sql_rcode_t rcode;
+ char const *info;
+
+ if (!conn->sock) {
+ ERROR("rlm_sql_mysql: Socket not connected");
+ return RLM_SQL_RECONNECT;
+ }
+
+ mysql_query(conn->sock, query);
+ rcode = sql_check_error(conn->sock, 0);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
+ }
+
+ /* Only returns non-null string for INSERTS */
+ info = mysql_info(conn->sock);
+ if (info) DEBUG2("rlm_sql_mysql: %s", info);
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_store_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+ sql_rcode_t rcode;
+ int ret;
+
+ if (!conn->sock) {
+ ERROR("rlm_sql_mysql: Socket not connected");
+ return RLM_SQL_RECONNECT;
+ }
+
+retry_store_result:
+ conn->result = mysql_store_result(conn->sock);
+ if (!conn->result) {
+ rcode = sql_check_error(conn->sock, 0);
+ if (rcode != RLM_SQL_OK) return rcode;
+#if (MYSQL_VERSION_ID >= 40100)
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
+ /* there are more results */
+ goto retry_store_result;
+ } else if (ret > 0) return sql_check_error(NULL, ret);
+ /* ret == -1 signals no more results */
+#endif
+ }
+ return RLM_SQL_OK;
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ int num = 0;
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+#if MYSQL_VERSION_ID >= 32224
+ /*
+ * Count takes a connection handle
+ */
+ if (!(num = mysql_field_count(conn->sock))) {
+#else
+ /*
+ * Fields takes a result struct
+ */
+ if (!(num = mysql_num_fields(conn->result))) {
+#endif
+ return -1;
+ }
+ return num;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ sql_rcode_t rcode;
+
+ rcode = sql_query(handle, config, query);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
+ }
+
+ rcode = sql_store_result(handle, config);
+ if (rcode != RLM_SQL_OK) {
+ return rcode;
+ }
+
+ /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
+ * this cannot return an error. Perhaps just to complain if no
+ * fields are found?
+ */
+ sql_num_fields(handle, config);
+
+ return rcode;
+}
+
+static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+ if (conn->result) {
+ return mysql_num_rows(conn->result);
+ }
+
+ return 0;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+ sql_rcode_t rcode;
+ MYSQL_ROW row;
+ int ret;
+ unsigned int num_fields, i;
+ unsigned long *field_lens;
+
+ /*
+ * Check pointer before de-referencing it.
+ */
+ if (!conn->result) {
+ return RLM_SQL_RECONNECT;
+ }
+
+ TALLOC_FREE(handle->row); /* Clear previous row set */
+
+retry_fetch_row:
+ row = mysql_fetch_row(conn->result);
+ if (!row) {
+ rcode = sql_check_error(conn->sock, 0);
+ if (rcode != RLM_SQL_OK) return rcode;
+
+#if (MYSQL_VERSION_ID >= 40100)
+ sql_free_result(handle, config);
+
+ ret = mysql_next_result(conn->sock);
+ if (ret == 0) {
+ /* there are more results */
+ if ((sql_store_result(handle, config) == 0) && (conn->result != NULL)) {
+ goto retry_fetch_row;
+ }
+ } else if (ret > 0) return sql_check_error(NULL, ret);
+ /* If ret is -1 then there are no more rows */
+#endif
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ num_fields = mysql_num_fields(conn->result);
+ if (!num_fields) return RLM_SQL_NO_MORE_ROWS;
+
+ field_lens = mysql_fetch_lengths(conn->result);
+
+ MEM(handle->row = talloc_zero_array(handle, char *, num_fields + 1));
+ for (i = 0; i < num_fields; i++) {
+ MEM(handle->row[i] = talloc_bstrndup(handle->row, row[i], field_lens[i]));
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+ if (conn->result) {
+ mysql_free_result(conn->result);
+ conn->result = NULL;
+ }
+ TALLOC_FREE(handle->row);
+
+ return RLM_SQL_OK;
+}
+
+/** Retrieves any warnings associated with the last query
+ *
+ * MySQL stores a limited number of warnings associated with the last query
+ * executed. These can be very useful in diagnosing issues, or in some cases
+ * working around bugs in MySQL which causes it to return the wrong error.
+ *
+ * @note Caller should free any memory allocated in ctx (talloc_free_children()).
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array or -1 on error.
+ */
+static size_t sql_warnings(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ unsigned int num_fields;
+ size_t i = 0;
+
+ if (outlen == 0) return 0;
+
+ /*
+ * Retrieve any warnings associated with the previous query
+ * that were left lingering on the server.
+ */
+ if (mysql_query(conn->sock, "SHOW WARNINGS") != 0) return -1;
+ result = mysql_store_result(conn->sock);
+ if (!result) return -1;
+
+ /*
+ * Fields should be [0] = Level, [1] = Code, [2] = Message
+ */
+ num_fields = mysql_field_count(conn->sock);
+ if (num_fields < 3) {
+ WARN("rlm_sql_mysql: Failed retrieving warnings, expected 3 fields got %u", num_fields);
+ mysql_free_result(result);
+
+ return -1;
+ }
+
+ while ((row = mysql_fetch_row(result))) {
+ char *msg = NULL;
+ log_type_t type;
+
+ /*
+ * Translate the MySQL log level into our internal
+ * log levels, so they get colourised correctly.
+ */
+ if (strcasecmp(row[0], "warning") == 0) type = L_WARN;
+ else if (strcasecmp(row[0], "note") == 0) type = L_DBG;
+ else type = L_ERR;
+
+ msg = talloc_asprintf(ctx, "%s: %s", row[1], row[2]);
+ out[i].type = type;
+ out[i].msg = msg;
+ if (++i == outlen) break;
+ }
+
+ mysql_free_result(result);
+
+ return i;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller should free any memory allocated in ctx (talloc_free_children()).
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+ rlm_sql_mysql_config_t *driver = config->driver;
+ char const *error;
+ size_t i = 0;
+
+ rad_assert(conn && conn->sock);
+ rad_assert(outlen > 0);
+
+ error = mysql_error(conn->sock);
+
+ /*
+ * Grab the error now in case it gets cleared on the next operation.
+ */
+ if (error && (error[0] != '\0')) {
+ error = talloc_asprintf(ctx, "ERROR %u (%s): %s", mysql_errno(conn->sock), error,
+ mysql_sqlstate(conn->sock));
+ }
+
+ /*
+ * Don't attempt to get errors from the server, if the last error
+ * was that the server was unavailable.
+ */
+ if ((outlen > 1) && (sql_check_error(conn->sock, 0) != RLM_SQL_RECONNECT)) {
+ size_t ret;
+ unsigned int msgs;
+
+ switch (driver->warnings) {
+ case SERVER_WARNINGS_AUTO:
+ /*
+ * Check to see if any warnings can be retrieved from the server.
+ */
+ msgs = mysql_warning_count(conn->sock);
+ if (msgs == 0) {
+ DEBUG3("rlm_sql_mysql: No additional diagnostic info on server");
+ break;
+ }
+
+ /* FALL-THROUGH */
+ case SERVER_WARNINGS_YES:
+ ret = sql_warnings(ctx, out, outlen - 1, handle, config);
+ if (ret > 0) i += ret;
+ break;
+
+ case SERVER_WARNINGS_NO:
+ break;
+
+ default:
+ rad_assert(0);
+ }
+ }
+
+ if (error) {
+ out[i].type = L_ERR;
+ out[i].msg = error;
+ }
+ i++;
+
+ return i;
+}
+
+/** Finish query
+ *
+ * As a single SQL statement may return multiple results
+ * sets, (for example stored procedures) it is necessary to check
+ * whether more results exist and process them in turn if so.
+ *
+ */
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+#if (MYSQL_VERSION_ID >= 40100)
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+ int ret;
+ MYSQL_RES *result;
+
+ /*
+ * If there's no result associated with the
+ * connection handle, assume the first result in the
+ * result set hasn't been retrieved.
+ *
+ * MySQL docs says there's no performance penalty for
+ * calling mysql_store_result for queries which don't
+ * return results.
+ */
+ if (conn->result == NULL) {
+ result = mysql_store_result(conn->sock);
+ if (result) mysql_free_result(result);
+ /*
+ * ...otherwise call sql_free_result to free an
+ * already stored result.
+ */
+ } else {
+ sql_free_result(handle, config); /* sql_free_result sets conn->result to NULL */
+ }
+
+ /*
+ * Drain any other results associated with the handle
+ *
+ * mysql_next_result advances the result cursor so that
+ * the next call to mysql_store_result will retrieve
+ * the next result from the server.
+ *
+ * Unfortunately this really does appear to be the
+ * only way to return the handle to a consistent state.
+ */
+ while (((ret = mysql_next_result(conn->sock)) == 0) &&
+ (result = mysql_store_result(conn->sock))) {
+ mysql_free_result(result);
+ }
+ if (ret > 0) return sql_check_error(NULL, ret);
+#endif
+ return RLM_SQL_OK;
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+ return mysql_affected_rows(conn->sock);
+}
+
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
+{
+ size_t inlen;
+ rlm_sql_handle_t *handle = talloc_get_type_abort(arg, rlm_sql_handle_t);
+ rlm_sql_mysql_conn_t *conn = handle->conn;
+
+ /* Check for potential buffer overflow */
+ inlen = strlen(in);
+ if ((inlen * 2 + 1) > outlen) return 0;
+ /* Prevent integer overflow */
+ if ((inlen * 2 + 1) <= inlen) return 0;
+
+ return mysql_real_escape_string(conn->sock, out, in, inlen);
+}
+
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_mysql;
+rlm_sql_module_t rlm_sql_mysql = {
+ .name = "rlm_sql_mysql",
+ .flags = RLM_SQL_RCODE_FLAGS_ALT_QUERY,
+ .mod_instantiate = mod_instantiate,
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_store_result = sql_store_result,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_query,
+ .sql_escape_func = sql_escape_func
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_null/README.md b/src/modules/rlm_sql/drivers/rlm_sql_null/README.md
new file mode 100644
index 0000000..bf9046d
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_null/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_null
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+Dummy SQL driver for logging SQL queries to disk, but not executing them.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_null/all.mk b/src/modules/rlm_sql/drivers/rlm_sql_null/all.mk
new file mode 100644
index 0000000..e61f913
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_null/all.mk
@@ -0,0 +1,4 @@
+TARGET = rlm_sql_null.a
+SOURCES = rlm_sql_null.c
+
+SRC_CFLAGS = -I${top_srcdir}/src/modules/rlm_sql
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c b/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c
new file mode 100644
index 0000000..8f3a8f0
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c
@@ -0,0 +1,120 @@
+/*
+ * sql_null.c SQL Module
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2012 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+
+#include "rlm_sql.h"
+
+
+/* Prototypes */
+static sql_rcode_t sql_free_result(rlm_sql_handle_t*, rlm_sql_config_t*);
+
+static const void *fake = "fake";
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ memcpy(&handle->conn, &fake, sizeof(handle->conn));
+ return 0;
+}
+
+static sql_rcode_t sql_query(UNUSED rlm_sql_handle_t * handle,
+ UNUSED rlm_sql_config_t *config, UNUSED char const *query)
+{
+ return 0;
+}
+
+static int sql_num_fields(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+static sql_rcode_t sql_select_query(UNUSED rlm_sql_handle_t *handle,
+ UNUSED rlm_sql_config_t *config, UNUSED char const *query)
+{
+ if (rad_debug_lvl >= L_DBG_LVL_1) {
+ radlog(L_DBG | L_WARN, "The 'rlm_sql_null' driver CANNOT be used for SELECTS.");
+ radlog(L_DBG | L_WARN, "Please update the 'sql' module configuration to use a real database.");
+ radlog(L_DBG | L_WARN, "Set 'driver = ...' to the database you want to use.");
+ }
+
+ return 0;
+}
+
+static int sql_num_rows(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ handle->row = NULL;
+
+ return RLM_SQL_NO_MORE_ROWS;
+}
+
+static sql_rcode_t sql_free_result(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+/** Stub function for retrieving errors, should not be called
+ *
+ */
+static size_t sql_error(UNUSED TALLOC_CTX *ctx, UNUSED sql_log_entry_t out[], UNUSED size_t outlen,
+ UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+static sql_rcode_t sql_finish_select_query(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 0;
+}
+
+static int sql_affected_rows(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ return 1;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_null;
+rlm_sql_module_t rlm_sql_null = {
+ .name = "rlm_sql_null",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query,
+ .sql_affected_rows = sql_affected_rows
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/README.md b/src/modules/rlm_sql/drivers/rlm_sql_oracle/README.md
new file mode 100644
index 0000000..00a4a93
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_oracle
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for Oracle. Must be built manually against the instaclient libraries.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_oracle/all.mk.in
new file mode 100644
index 0000000..4638b39
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/all.mk.in
@@ -0,0 +1,14 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+
+# Comment this out if you're experiencing build errors
+SRC_CFLAGS += -Wno-strict-prototypes
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure b/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure
new file mode 100755
index 0000000..4fa63c3
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure
@@ -0,0 +1,4160 @@
+#! /bin/sh
+# From configure.ac Revision: 1.10 .
+# 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_sql_oracle.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_oracle
+with_oracle_include_dir
+with_oracle_lib_dir
+with_oracle_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_oracle
+ build without rlm_sql_oracle
+ --with-oracle-include-dir=DIR
+ Directory where the oracle includes may be found
+ --with-oracle-lib-dir=DIR
+ Directory where the oracle libraries may be found
+ --with-oracle-dir=DIR Base directory where oracle is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_oracle
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_oracle was given.
+if test "${with_rlm_sql_oracle+set}" = set; then :
+ withval=$with_rlm_sql_oracle;
+fi
+
+
+
+oracle_supported_versions="19 18 12 11 10 9"
+mod_ldflags=
+mod_cflags=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_oracle" != xno; then
+
+
+
+oracle_include_dir=
+
+# Check whether --with-oracle-include-dir was given.
+if test "${with_oracle_include_dir+set}" = set; then :
+ withval=$with_oracle_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need oracle-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+oracle_lib_dir=
+
+# Check whether --with-oracle-lib-dir was given.
+if test "${with_oracle_lib_dir+set}" = set; then :
+ withval=$with_oracle_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need oracle-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-oracle-dir was given.
+if test "${with_oracle_dir+set}" = set; then :
+ withval=$with_oracle_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need oracle-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval/lib"
+ oracle_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+smart_try_dir="$oracle_include_dir /usr/local/instaclient/include"
+
+if test "x$ORACLE_HOME" != "x"; then
+ smart_try_dir="${smart_try_dir} ${ORACLE_HOME}/include"
+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
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "oci.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 oci.h in $try" >&5
+$as_echo_n "checking for oci.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <oci.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}/oci.h" >&5
+$as_echo_n "checking for ${_prefix}/oci.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <oci.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 oci.h" >&5
+$as_echo_n "checking for oci.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <oci.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 oci.h in $try" >&5
+$as_echo_n "checking for oci.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <oci.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_oci_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME." >&5
+$as_echo "$as_me: WARNING: oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME." >&2;}
+
+fail="$fail oci.h"
+
+fi
+
+
+old_LIBS="$LIBS"
+
+if test "x$oracle_lib_dir" != "x" ; then
+ lib_path="${oracle_lib_dir} "
+elif test "x$ORACLE_HOME" != "x" ; then
+ lib_path="${ORACLE_HOME}/lib "
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Oracle supported versions: ${oracle_supported_versions}" >&5
+$as_echo "$as_me: WARNING: Oracle supported versions: ${oracle_supported_versions}" >&2;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Oracle version >= 12 needs -laio" >&5
+$as_echo "$as_me: WARNING: Oracle version >= 12 needs -laio" >&2;}
+
+for path in $lib_path "/usr/local/instaclient/lib" "" "/opt/lib"; do
+ for oracle_version in ${oracle_supported_versions} ""; do
+ if test "$path" != ""; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version} in $path" >&5
+$as_echo_n "checking for OCIInitialize in nnz${oracle_version} in $path... " >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIInitialize in nnz${oracle_version}" >&5
+$as_echo_n "checking for OCIInitialize in nnz${oracle_version}... " >&6; }
+ fi
+
+ LIBS="$old_LIBS -L$path -Wl,-rpath,$path -lclntsh -lnnz${oracle_version}"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <oci.h>
+
+ static OCIEnv *p_env;
+ static OCIError *p_err;
+ static OCISvcCtx *p_svc;
+ static OCIStmt *p_sql;
+ static OCIDefine *p_dfn = (OCIDefine *) 0;
+ static OCIBind *p_bnd = (OCIBind *) 0;
+
+int
+main ()
+{
+
+ int p_bvi;
+ char p_sli[20];
+ int rc;
+ char errbuf[100];
+ int errcode;
+
+ rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
+ (dvoid * (*)(dvoid *, size_t)) 0,
+ (dvoid * (*)(dvoid *, dvoid *, size_t))0,
+ (void (*)(dvoid *, dvoid *)) 0 );
+
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ mod_ldflags="$LIBS"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "x$mod_ldflags" != "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ done
+
+ if test "x$mod_ldflags" != "x"; then
+ break
+ fi
+done
+
+LIBS="$old_LIBS"
+
+if test "x$mod_ldflags" = "x"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME." >&5
+$as_echo "$as_me: WARNING: oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME." >&2;}
+
+fail="$fail libclntsh libnnz(9-12)"
+
+fi
+
+
+ targetname=rlm_sql_oracle
+else
+ targetname=
+ echo \*\*\* module rlm_sql_oracle is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_oracle to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_oracle." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_oracle." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_oracle requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_oracle requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure.ac
new file mode 100644
index 0000000..f31b7d2
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/configure.ac
@@ -0,0 +1,153 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_oracle.c])
+AC_REVISION($Revision: 1.10 $)
+FR_INIT_MODULE([rlm_sql_oracle])
+
+oracle_supported_versions="19 18 12 11 10 9"
+mod_ldflags=
+mod_cflags=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-oracle-include-dir=DIR
+oracle_include_dir=
+AC_ARG_WITH(oracle-include-dir,
+ [AS_HELP_STRING([--with-oracle-include-dir=DIR],
+ [Directory where the oracle includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-oracle-lib-dir=DIR
+oracle_lib_dir=
+AC_ARG_WITH(oracle-lib-dir,
+ [AS_HELP_STRING([--with-oracle-lib-dir=DIR],
+ [Directory where the oracle libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-oracle-dir=DIR
+AC_ARG_WITH(oracle-dir,
+ [AS_HELP_STRING([--with-oracle-dir=DIR],
+ [Base directory where oracle is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need oracle-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ oracle_lib_dir="$withval/lib"
+ oracle_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="$oracle_include_dir /usr/local/instaclient/include"
+
+if test "x$ORACLE_HOME" != "x"; then
+ smart_try_dir="${smart_try_dir} ${ORACLE_HOME}/include"
+fi
+
+FR_SMART_CHECK_INCLUDE(oci.h)
+if test "x$ac_cv_header_oci_h" != "xyes"; then
+ AC_MSG_WARN([oracle headers not found. Use --with-oracle-include-dir=<path> or set ORACLE_HOME.])
+ FR_MODULE_FAIL([oci.h])
+fi
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+old_LIBS="$LIBS"
+
+if test "x$oracle_lib_dir" != "x" ; then
+ lib_path="${oracle_lib_dir} "
+elif test "x$ORACLE_HOME" != "x" ; then
+ lib_path="${ORACLE_HOME}/lib "
+fi
+
+AC_MSG_WARN([Oracle supported versions: ${oracle_supported_versions}])
+AC_MSG_WARN([Oracle version >= 12 needs -laio])
+
+for path in $lib_path "/usr/local/instaclient/lib" "" "/opt/lib"; do
+ for oracle_version in ${oracle_supported_versions} ""; do
+ if test "$path" != ""; then
+ AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version} in $path])
+ else
+ AC_MSG_CHECKING([for OCIInitialize in nnz${oracle_version}])
+ fi
+
+ LIBS="$old_LIBS -L$path -Wl,-rpath,$path -lclntsh -lnnz${oracle_version}"
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <oci.h>
+
+ static OCIEnv *p_env;
+ static OCIError *p_err;
+ static OCISvcCtx *p_svc;
+ static OCIStmt *p_sql;
+ static OCIDefine *p_dfn = (OCIDefine *) 0;
+ static OCIBind *p_bnd = (OCIBind *) 0;
+ ]], [[
+ int p_bvi;
+ char p_sli[20];
+ int rc;
+ char errbuf[100];
+ int errcode;
+
+ rc = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, /* Initialize OCI */
+ (dvoid * (*)(dvoid *, size_t)) 0,
+ (dvoid * (*)(dvoid *, dvoid *, size_t))0,
+ (void (*)(dvoid *, dvoid *)) 0 );
+
+ ]])],[mod_ldflags="$LIBS"],[])
+ if test "x$mod_ldflags" != "x"; then
+ AC_MSG_RESULT(yes)
+ break
+ fi
+ AC_MSG_RESULT(no)
+ done
+
+ if test "x$mod_ldflags" != "x"; then
+ break
+ fi
+done
+
+LIBS="$old_LIBS"
+
+if test "x$mod_ldflags" = "x"; then
+ AC_MSG_WARN([oracle libraries not found. Use --with-oracle-lib-dir=<path> or set ORACLE_HOME.])
+ FR_MODULE_FAIL([libclntsh libnnz(9-12)])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_cflags="$SMART_CPPFLAGS"
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c b/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c
new file mode 100644
index 0000000..9fe8a19
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c
@@ -0,0 +1,482 @@
+/*
+ * sql_oracle.c Oracle (OCI) routines for rlm_sql
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 David Kerry <davidk@snti.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+/*
+ * There are typos in the Oracle Instaclient where the definition controlling prototype
+ * format is _STDC_ (not __STDC__).
+ *
+ * There are still cases where the oracle headers do not declare ANSI C function types
+ * but this at least cuts down the errors.
+ *
+ * -Wno-strict-prototypes does the rest.
+ */
+DIAG_OFF(unused-macros)
+#if defined(__STDC__) && __STDC__
+# define _STDC_
+#endif
+
+#include <oci.h>
+DIAG_ON(unused-macros)
+
+#include "rlm_sql.h"
+
+typedef struct rlm_sql_oracle_conn_t {
+ OCIEnv *env;
+ OCIStmt *query;
+ OCIError *error;
+ OCISvcCtx *ctx;
+ sb2 *ind;
+ char **row;
+ int id;
+ int col_count; //!< Number of columns associated with the result set
+ struct timeval tv;
+} rlm_sql_oracle_conn_t;
+
+#define MAX_DATASTR_LEN 64
+
+/** Write the last Oracle error out to a buffer
+ *
+ * @param out Where to write the error (should be at least 512 bytes).
+ * @param outlen The length of the error buffer.
+ * @param handle sql handle.
+ * @param config Instance config.
+ * @return 0 on success, -1 if there was no error.
+ */
+static int sql_prints_error(char *out, size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ sb4 errcode = 0;
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ rad_assert(conn);
+
+ out[0] = '\0';
+
+ OCIErrorGet((dvoid *) conn->error, 1, (OraText *) NULL, &errcode, (OraText *) out,
+ outlen, OCI_HTYPE_ERROR);
+ if (!errcode) return -1;
+
+ return 0;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ char errbuff[512];
+ int ret;
+
+ rad_assert(outlen > 0);
+
+ ret = sql_prints_error(errbuff, sizeof(errbuff), handle, config);
+ if (ret < 0) return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = talloc_strdup(ctx, errbuff);
+
+ return 1;
+}
+
+static int sql_check_error(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ char errbuff[512];
+
+ if (sql_prints_error(errbuff, sizeof(errbuff), handle, config) < 0) goto unknown;
+
+ if (strstr(errbuff, "ORA-03113") || strstr(errbuff, "ORA-03114")) {
+ ERROR("rlm_sql_oracle: OCI_SERVER_NOT_CONNECTED");
+ return RLM_SQL_RECONNECT;
+ }
+
+unknown:
+ ERROR("rlm_sql_oracle: OCI_SERVER_NORMAL");
+ return -1;
+}
+
+static int _sql_socket_destructor(rlm_sql_oracle_conn_t *conn)
+{
+ if (conn->ctx) OCILogoff(conn->ctx, conn->error);
+ if (conn->query) OCIHandleFree((dvoid *)conn->query, OCI_HTYPE_STMT);
+ if (conn->error) OCIHandleFree((dvoid *)conn->error, OCI_HTYPE_ERROR);
+ if (conn->env) OCIHandleFree((dvoid *)conn->env, OCI_HTYPE_ENV);
+
+ return 0;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ char errbuff[512];
+
+ rlm_sql_oracle_conn_t *conn;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_oracle_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ /*
+ * Initialises the oracle environment
+ */
+ if (OCIEnvCreate(&conn->env, OCI_DEFAULT | OCI_THREADED, NULL, NULL, NULL, NULL, 0, NULL)) {
+ ERROR("rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Allocates an error handle
+ */
+ if (OCIHandleAlloc((dvoid *)conn->env, (dvoid **)&conn->error, OCI_HTYPE_ERROR, 0, NULL)) {
+ ERROR("rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Allocate handles for select and update queries
+ */
+ if (OCIHandleAlloc((dvoid *)conn->env, (dvoid **)&conn->query, OCI_HTYPE_STMT, 0, NULL)) {
+ ERROR("rlm_sql_oracle: Couldn't init Oracle query handles: %s",
+ (sql_prints_error(errbuff, sizeof(errbuff), handle, config) == 0) ? errbuff : "unknown");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Login to the oracle server
+ */
+ if (OCILogon(conn->env, conn->error, &conn->ctx,
+ (OraText const *)config->sql_login, strlen(config->sql_login),
+ (OraText const *)config->sql_password, strlen(config->sql_password),
+ (OraText const *)config->sql_db, strlen(config->sql_db))) {
+ ERROR("rlm_sql_oracle: Oracle logon failed: '%s'",
+ (sql_prints_error(errbuff, sizeof(errbuff), handle, config) == 0) ? errbuff : "unknown");
+
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ int count;
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ /* get the number of columns in the select list */
+ if (OCIAttrGet((dvoid *)conn->query, OCI_HTYPE_STMT, (dvoid *)&count, NULL, OCI_ATTR_PARAM_COUNT,
+ conn->error)) return -1;
+
+ return count;
+}
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ int status;
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ OraText *oracle_query;
+
+ memcpy(&oracle_query, &query, sizeof(oracle_query));
+
+ if (!conn->ctx) {
+ ERROR("rlm_sql_oracle: Socket not connected");
+
+ return RLM_SQL_RECONNECT;
+ }
+
+ if (OCIStmtPrepare(conn->query, conn->error, oracle_query, strlen(query),
+ OCI_NTV_SYNTAX, OCI_DEFAULT)) {
+ ERROR("rlm_sql_oracle: prepare failed in sql_query");
+
+ return RLM_SQL_ERROR;
+ }
+
+ status = OCIStmtExecute(conn->ctx, conn->query, conn->error, 1, 0,
+ NULL, NULL, OCI_COMMIT_ON_SUCCESS);
+
+ if (status == OCI_SUCCESS) return RLM_SQL_OK;
+ if (status == OCI_ERROR) {
+ ERROR("rlm_sql_oracle: execute query failed in sql_query");
+
+ return sql_check_error(handle, config);
+ }
+
+ return RLM_SQL_ERROR;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ int status;
+ char **row;
+
+ int i;
+ OCIParam *param;
+ OCIDefine *define;
+
+ ub2 dtype;
+ ub2 dsize;
+
+ sb2 *ind;
+
+ OraText *oracle_query;
+
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ memcpy(&oracle_query, &query, sizeof(oracle_query));
+
+ if (OCIStmtPrepare(conn->query, conn->error, oracle_query, strlen(query), OCI_NTV_SYNTAX,
+ OCI_DEFAULT)) {
+ ERROR("rlm_sql_oracle: prepare failed in sql_select_query");
+
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Retrieve a single row
+ */
+ status = OCIStmtExecute(conn->ctx, conn->query, conn->error, 0, 0, NULL, NULL, OCI_DEFAULT);
+ if (status == OCI_NO_DATA) return RLM_SQL_OK;
+ if (status != OCI_SUCCESS) {
+ ERROR("rlm_sql_oracle: query failed in sql_select_query");
+
+ return sql_check_error(handle, config);
+ }
+
+ /*
+ * We only need to do this once per result set, because
+ * the number of columns won't change.
+ */
+ if (conn->col_count == 0) {
+ conn->col_count = sql_num_fields(handle, config);
+
+ if (conn->col_count == 0) return RLM_SQL_ERROR;
+ }
+
+ MEM(row = talloc_zero_array(conn, char*, conn->col_count + 1));
+ MEM(ind = talloc_zero_array(row, sb2, conn->col_count + 1));
+
+ for (i = 0; i < conn->col_count; i++) {
+ status = OCIParamGet(conn->query, OCI_HTYPE_STMT, conn->error, (dvoid **)&param, i + 1);
+ if (status != OCI_SUCCESS) {
+ ERROR("rlm_sql_oracle: OCIParamGet() failed in sql_select_query");
+
+ goto error;
+ }
+
+ status = OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM, (dvoid*)&dtype, NULL, OCI_ATTR_DATA_TYPE,
+ conn->error);
+ if (status != OCI_SUCCESS) {
+ ERROR("rlm_sql_oracle: OCIAttrGet() failed in sql_select_query");
+
+ goto error;
+ }
+
+ dsize = MAX_DATASTR_LEN;
+
+ /*
+ * Use the retrieved length of dname to allocate an output buffer, and then define the output
+ * variable (but only for char/string type columns).
+ */
+ switch (dtype) {
+#ifdef SQLT_AFC
+ case SQLT_AFC: /* ansii fixed char */
+#endif
+#ifdef SQLT_AFV
+ case SQLT_AFV: /* ansii var char */
+#endif
+ case SQLT_VCS: /* var char */
+ case SQLT_CHR: /* char */
+ case SQLT_STR: /* string */
+ status = OCIAttrGet((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&dsize, NULL,
+ OCI_ATTR_DATA_SIZE, conn->error);
+ if (status != OCI_SUCCESS) {
+ ERROR("rlm_sql_oracle: OCIAttrGet() failed in sql_select_query");
+
+ goto error;
+ }
+
+ MEM(row[i] = talloc_zero_array(row, char, dsize + 1));
+
+ break;
+ case SQLT_DAT:
+ case SQLT_INT:
+ case SQLT_UIN:
+ case SQLT_FLT:
+ case SQLT_PDN:
+ case SQLT_BIN:
+ case SQLT_NUM:
+ MEM(row[i] = talloc_zero_array(row, char, dsize + 1));
+
+ break;
+ default:
+ dsize = 0;
+ row[i] = NULL;
+ break;
+ }
+
+ ind[i] = 0;
+
+ /*
+ * Grab the actual row value and write it to the buffer we allocated.
+ */
+ status = OCIDefineByPos(conn->query, &define, conn->error, i + 1, (ub1 *)row[i], dsize + 1, SQLT_STR,
+ (dvoid *)&ind[i], NULL, NULL, OCI_DEFAULT);
+
+ if (status != OCI_SUCCESS) {
+ ERROR("rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query");
+ goto error;
+ }
+ }
+
+ conn->row = row;
+ conn->ind = ind;
+
+ return RLM_SQL_OK;
+
+ error:
+ talloc_free(row);
+
+ return RLM_SQL_ERROR;
+}
+
+static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+ ub4 rows = 0;
+ ub4 size = sizeof(ub4);
+
+ OCIAttrGet((CONST dvoid *)conn->query, OCI_HTYPE_STMT, (dvoid *)&rows, &size, OCI_ATTR_ROW_COUNT, conn->error);
+
+ return rows;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ int status;
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ if (!conn->ctx) {
+ ERROR("rlm_sql_oracle: Socket not connected");
+
+ return RLM_SQL_RECONNECT;
+ }
+
+ handle->row = NULL;
+
+ status = OCIStmtFetch(conn->query, conn->error, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
+ if (status == OCI_SUCCESS) {
+ handle->row = conn->row;
+
+ return RLM_SQL_OK;
+ }
+
+ if (status == OCI_NO_DATA) {
+ handle->row = 0;
+
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ if (status == OCI_ERROR) {
+ ERROR("rlm_sql_oracle: fetch failed in sql_fetch_row");
+ return sql_check_error(handle, config);
+ }
+
+ return RLM_SQL_ERROR;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ /* Cancel the cursor first */
+ (void) OCIStmtFetch(conn->query, conn->error, 0, OCI_FETCH_NEXT, OCI_DEFAULT);
+
+ TALLOC_FREE(conn->row);
+ conn->ind = NULL; /* ind is a child of row */
+ conn->col_count = 0;
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ if (OCIStmtRelease(conn->query, conn->error, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS ) {
+ ERROR("OCI release failed in sql_finish_query");
+ return RLM_SQL_ERROR;
+ }
+
+ return 0;
+}
+
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_oracle_conn_t *conn = handle->conn;
+
+ TALLOC_FREE(conn->row);
+ conn->ind = NULL; /* ind is a child of row */
+ conn->col_count = 0;
+
+ if (OCIStmtRelease (conn->query, conn->error, NULL, 0, OCI_DEFAULT) != OCI_SUCCESS ) {
+ ERROR("OCI release failed in sql_finish_query");
+ return RLM_SQL_ERROR;
+ }
+
+ return 0;
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_num_rows(handle, config);
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_oracle;
+rlm_sql_module_t rlm_sql_oracle = {
+ .name = "rlm_sql_oracle",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/.gitignore b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/README.md b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/README.md
new file mode 100644
index 0000000..0225ebf
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_postgresql
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for PostgreSQL.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/config.h.in b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/config.h.in
new file mode 100644
index 0000000..066224d
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/config.h.in
@@ -0,0 +1,16 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Whether the PGRES_COPY_BOTH constant is defined */
+#undef HAVE_PGRES_COPY_BOTH
+
+/* Whether the PGRES_SINGLE_TUPLE constant is defined */
+#undef HAVE_PGRES_SINGLE_TUPLE
+
+/* Whether the PGRES_PIPELINE_SYNC constant is defined */
+#undef HAVE_PGRES_PIPELINE_SYNC
+
+/* Define to 1 if you have the `PQinitOpenSSL' function. */
+#undef HAVE_PQINITOPENSSL
+
+/* Define to 1 if you have the `PQinitSSL' function. */
+#undef HAVE_PQINITSSL
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure
new file mode 100755
index 0000000..c22d654
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure
@@ -0,0 +1,4473 @@
+#! /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_sql_postgresql.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_postgresql
+with_rlm_sql_postgresql_lib_dir
+with_rlm_sql_postgresql_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_postgresql
+ build without rlm_sql_postgresql
+ -with-rlm-sql-postgresql-lib-dir=DIR
+ Directory for PostgreSQL library files
+ -with-rlm-sql-postgresql-include-dir=DIR
+ Directory for PostgreSQL include files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_postgresql
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_postgresql was given.
+if test "${with_rlm_sql_postgresql+set}" = set; then :
+ withval=$with_rlm_sql_postgresql;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_postgresql" != 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
+
+
+rlm_sql_postgresql_lib_dir=
+
+# Check whether --with-rlm-sql-postgresql-lib-dir was given.
+if test "${with_rlm_sql_postgresql_lib_dir+set}" = set; then :
+ withval=$with_rlm_sql_postgresql_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-sql-postgresql-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_sql_postgresql_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+rlm_sql_postgresql_include_dir=
+
+# Check whether --with-rlm-sql-postgresql-include-dir was given.
+if test "${with_rlm_sql_postgresql_include_dir+set}" = set; then :
+ withval=$with_rlm_sql_postgresql_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-sql-postgresql-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_sql_postgresql_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$rlm_sql_postgresql_include_dir /usr/include/postgresql /usr/local/pgsql/include /usr/include/pgsql"
+
+
+
+ac_safe=`echo "libpq-fe.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 libpq-fe.h in $try" >&5
+$as_echo_n "checking for libpq-fe.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libpq-fe.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}/libpq-fe.h" >&5
+$as_echo_n "checking for ${_prefix}/libpq-fe.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libpq-fe.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 libpq-fe.h" >&5
+$as_echo_n "checking for libpq-fe.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libpq-fe.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 libpq-fe.h in $try" >&5
+$as_echo_n "checking for libpq-fe.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <libpq-fe.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_libpqmfe_h" != "xyes"; then
+
+fail="$fail libpq-fe.h"
+
+else
+ CPPFLAGS="$SMART_CPPFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PGRES_SINGLE_TUPLE" >&5
+$as_echo_n "checking for PGRES_SINGLE_TUPLE... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libpq-fe.h>
+int
+main ()
+{
+
+ if (PGRES_SINGLE_TUPLE) return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_PGRES_SINGLE_TUPLE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PGRES_COPY_BOTH" >&5
+$as_echo_n "checking for PGRES_COPY_BOTH... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libpq-fe.h>
+int
+main ()
+{
+
+ if (PGRES_COPY_BOTH) return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_PGRES_COPY_BOTH 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PGRES_PIPELINE_SYNC" >&5
+$as_echo_n "checking for PGRES_PIPELINE_SYNC... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <libpq-fe.h>
+int
+main ()
+{
+
+ if (PGRES_PIPELINE_SYNC) return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+
+$as_echo "#define HAVE_PGRES_PIPELINE_SYNC 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+smart_try_dir="$rlm_sql_postgresql_lib_dir /usr/lib /usr/local/pgsql/lib"
+
+
+sm_lib_safe=`echo "pq" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "PQconnectdb" | 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 PQconnectdb in -lpq in $try" >&5
+$as_echo_n "checking for PQconnectdb in -lpq in $try... " >&6; }
+ LIBS="-lpq $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char PQconnectdb();
+int
+main ()
+{
+PQconnectdb()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpq"
+ 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 PQconnectdb in -lpq" >&5
+$as_echo_n "checking for PQconnectdb in -lpq... " >&6; }
+ LIBS="-lpq $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char PQconnectdb();
+int
+main ()
+{
+PQconnectdb()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpq"
+ { $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 PQconnectdb in -lpq in $try" >&5
+$as_echo_n "checking for PQconnectdb in -lpq in $try... " >&6; }
+ LIBS="-lpq $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char PQconnectdb();
+int
+main ()
+{
+PQconnectdb()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lpq"
+ 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_pq_PQconnectdb" != "xyes"; then
+
+fail="$fail libpq"
+
+fi
+
+for ac_func in \
+ PQinitOpenSSL \
+ PQinitSSL \
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+ targetname=rlm_sql_postgresql
+else
+ targetname=
+ echo \*\*\* module rlm_sql_postgresql is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_postgresql to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_postgresql." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_postgresql." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_postgresql requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_postgresql requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_sql/drivers/rlm_sql_postgresql/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure.ac
new file mode 100644
index 0000000..46587e4
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/configure.ac
@@ -0,0 +1,119 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_postgresql.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_postgresql])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+
+dnl extra argument: --with-rlm-sql-postgresql-lib-dir
+rlm_sql_postgresql_lib_dir=
+AC_ARG_WITH(rlm-sql-postgresql-lib-dir,
+ [AS_HELP_STRING([-with-rlm-sql-postgresql-lib-dir=DIR],
+ [Directory for PostgreSQL library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-sql-postgresql-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_sql_postgresql_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-rlm-sql-postgresql-include-dir
+rlm_sql_postgresql_include_dir=
+AC_ARG_WITH(rlm-sql-postgresql-include-dir,
+ [AS_HELP_STRING([-with-rlm-sql-postgresql-include-dir=DIR],
+ [Directory for PostgreSQL include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-sql-postgresql-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_sql_postgresql_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir="$rlm_sql_postgresql_include_dir /usr/include/postgresql /usr/local/pgsql/include /usr/include/pgsql"
+FR_SMART_CHECK_INCLUDE(libpq-fe.h)
+if test "x$ac_cv_header_libpqmfe_h" != "xyes"; then
+ FR_MODULE_FAIL([libpq-fe.h])
+else
+ CPPFLAGS="$SMART_CPPFLAGS"
+ AC_MSG_CHECKING([for PGRES_SINGLE_TUPLE])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include <libpq-fe.h>], [[
+ if (PGRES_SINGLE_TUPLE) return 0;
+ return 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_PGRES_SINGLE_TUPLE], [1],
+ [Whether the PGRES_SINGLE_TUPLE constant is defined])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+
+ AC_MSG_CHECKING([for PGRES_COPY_BOTH])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include <libpq-fe.h>], [[
+ if (PGRES_COPY_BOTH) return 0;
+ return 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_PGRES_COPY_BOTH], [1],
+ [Whether the PGRES_COPY_BOTH constant is defined])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+
+ AC_MSG_CHECKING([for PGRES_PIPELINE_SYNC])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include <libpq-fe.h>], [[
+ if (PGRES_PIPELINE_SYNC) return 0;
+ return 1;
+ ]])],
+ [
+ AC_DEFINE([HAVE_PGRES_PIPELINE_SYNC], [1],
+ [Whether the PGRES_PIPELINE_SYNC constant is defined])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+fi
+
+smart_try_dir="$rlm_sql_postgresql_lib_dir /usr/lib /usr/local/pgsql/lib"
+FR_SMART_CHECK_LIB(pq, PQconnectdb)
+if test "x$ac_cv_lib_pq_PQconnectdb" != "xyes"; then
+ FR_MODULE_FAIL([libpq])
+fi
+
+AC_CHECK_FUNCS(\
+ PQinitOpenSSL \
+ PQinitSSL \
+)
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c
new file mode 100644
index 0000000..c88d8b0
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c
@@ -0,0 +1,610 @@
+/*
+ * sql_postgresql.c Postgresql rlm_sql driver
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Mike Machado <mike@innercite.com>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+/*
+ * April 2001:
+ *
+ * Use blocking queries and delete unused functions. In
+ * rlm_sql_postgresql replace all functions that are not really used
+ * with the not_implemented function.
+ *
+ * Add a new field to the rlm_sql_postgres_conn_t struct to store the
+ * number of rows affected by a query because the sql module calls
+ * finish_query before it retrieves the number of affected rows from the
+ * driver
+ *
+ * Bernhard Herzog <bh@intevation.de>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/stat.h>
+
+#include <libpq-fe.h>
+#include <postgres_ext.h>
+
+#include "config.h"
+#include "rlm_sql.h"
+#include "sql_postgresql.h"
+
+#ifndef NAMEDATALEN
+# define NAMEDATALEN 64
+#endif
+
+typedef struct rlm_sql_postgres_config {
+ char const *db_string;
+ bool send_application_name;
+ char const *application_name;
+} rlm_sql_postgres_config_t;
+
+typedef struct rlm_sql_postgres_conn {
+ PGconn *db;
+ PGresult *result;
+ int cur_row;
+ int num_fields;
+ int affected_rows;
+ char **row;
+} rlm_sql_postgres_conn_t;
+
+static const CONF_PARSER driver_config[] = {
+ { "send_application_name", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_postgres_config_t, send_application_name), "no" },
+ { "application_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_postgres_config_t, application_name), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
+{
+#if defined(HAVE_OPENSSL_CRYPTO_H) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
+ static bool ssl_init = false;
+#endif
+
+ rlm_sql_postgres_config_t *driver;
+ char buffer[NAMEDATALEN];
+ char const *application_name = NULL;
+ char *db_string;
+
+#if defined(HAVE_OPENSSL_CRYPTO_H) && (defined(HAVE_PQINITOPENSSL) || defined(HAVE_PQINITSSL))
+ if (!ssl_init) {
+# ifdef HAVE_PQINITOPENSSL
+ PQinitOpenSSL(0, 0);
+# else
+ PQinitSSL(0);
+# endif
+ ssl_init = true;
+ }
+#endif
+
+ MEM(driver = config->driver = talloc_zero(config, rlm_sql_postgres_config_t));
+ if (cf_section_parse(conf, driver, driver_config) < 0) {
+ return -1;
+ }
+
+ /*
+ * Allow the user to set their own, or disable it
+ */
+ if (driver->send_application_name) {
+ if (driver->application_name && *driver->application_name) {
+ application_name = driver->application_name;
+ } else {
+ CONF_SECTION *cs;
+ char const *name;
+
+ cs = cf_item_parent(cf_section_to_item(conf));
+
+ name = cf_section_name2(cs);
+ if (!name) name = cf_section_name1(cs);
+
+ snprintf(buffer, sizeof(buffer),
+ "FreeRADIUS " RADIUSD_VERSION_STRING " - %s (%s)", main_config.name, name);
+
+ application_name = buffer;
+ }
+ }
+
+ /*
+ * Old style database name
+ *
+ * Append options if they were set in the config
+ */
+ if (!strchr(config->sql_db, '=')) {
+ db_string = talloc_typed_asprintf(driver, "dbname='%s'", config->sql_db);
+
+ if (config->sql_server[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " host='%s'", config->sql_server);
+ }
+
+ if (config->sql_port) {
+ db_string = talloc_asprintf_append(db_string, " port=%i", config->sql_port);
+ }
+
+ if (config->sql_login[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " user='%s'", config->sql_login);
+ }
+
+ if (config->sql_password[0] != '\0') {
+ db_string = talloc_asprintf_append(db_string, " password='%s'", config->sql_password);
+ }
+
+ if (config->query_timeout) {
+ db_string = talloc_asprintf_append(db_string, " connect_timeout=%d", config->query_timeout);
+ }
+
+ if (driver->send_application_name) {
+ db_string = talloc_asprintf_append(db_string, " application_name='%s'", application_name);
+ }
+
+ /*
+ * New style parameter string
+ *
+ * Only append options when not already present
+ */
+ } else {
+ db_string = talloc_typed_strdup(driver, config->sql_db);
+
+ if ((config->sql_server[0] != '\0') && !strstr(db_string, "host=")) {
+ db_string = talloc_asprintf_append(db_string, " host='%s'", config->sql_server);
+ }
+
+ if (config->sql_port && !strstr(db_string, "port=")) {
+ db_string = talloc_asprintf_append(db_string, " port=%i", config->sql_port);
+ }
+
+ if ((config->sql_login[0] != '\0') && !strstr(db_string, "user=")) {
+ db_string = talloc_asprintf_append(db_string, " user='%s'", config->sql_login);
+ }
+
+ if ((config->sql_password[0] != '\0') && !strstr(db_string, "password=")) {
+ db_string = talloc_asprintf_append(db_string, " password='%s'", config->sql_password);
+ }
+
+ if ((config->query_timeout) && !strstr(db_string, "connect_timeout=")) {
+ db_string = talloc_asprintf_append(db_string, " connect_timeout=%d", config->query_timeout);
+ }
+
+ if (driver->send_application_name && !strstr(db_string, "application_name=")) {
+ db_string = talloc_asprintf_append(db_string, " application_name='%s'", application_name);
+ }
+ }
+ driver->db_string = db_string;
+
+ return 0;
+}
+
+/** Return the number of affected rows of the result as an int instead of the string that postgresql provides
+ *
+ */
+static int affected_rows(PGresult * result)
+{
+ return atoi(PQcmdTuples(result));
+}
+
+/** Free the row of the current result that's stored in the conn struct
+ *
+ */
+static void free_result_row(rlm_sql_postgres_conn_t *conn)
+{
+ TALLOC_FREE(conn->row);
+ conn->num_fields = 0;
+}
+
+#if defined(PG_DIAG_SQLSTATE) && defined(PG_DIAG_MESSAGE_PRIMARY)
+static sql_rcode_t sql_classify_error(PGresult const *result)
+{
+ int i;
+
+ char *errorcode;
+ char *errormsg;
+
+ /*
+ * Check the error code to see if we should reconnect or not
+ * Error Code table taken from:
+ * http://www.postgresql.org/docs/8.1/interactive/errcodes-appendix.html
+ */
+ errorcode = PQresultErrorField(result, PG_DIAG_SQLSTATE);
+ errormsg = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
+ if (!errorcode) {
+ ERROR("rlm_sql_postgresql: Error occurred, but unable to retrieve error code");
+ return RLM_SQL_ERROR;
+ }
+
+ /* SUCCESSFUL COMPLETION */
+ if (strcmp("00000", errorcode) == 0) {
+ return RLM_SQL_OK;
+ }
+
+ /* WARNING */
+ if (strcmp("01000", errorcode) == 0) {
+ WARN("%s", errormsg);
+ return RLM_SQL_OK;
+ }
+
+ /* UNIQUE VIOLATION */
+ if (strcmp("23505", errorcode) == 0) {
+ return RLM_SQL_ALT_QUERY;
+ }
+
+ /* others */
+ for (i = 0; errorcodes[i].errorcode != NULL; i++) {
+ if (strcmp(errorcodes[i].errorcode, errorcode) == 0) {
+ ERROR("rlm_sql_postgresql: %s: %s", errorcode, errorcodes[i].meaning);
+
+ return (errorcodes[i].reconnect == true) ?
+ RLM_SQL_RECONNECT :
+ RLM_SQL_ERROR;
+ }
+ }
+
+ ERROR("rlm_sql_postgresql: Can't classify: %s", errorcode);
+ return RLM_SQL_ERROR;
+}
+# else
+static sql_rcode_t sql_classify_error(UNUSED PGresult const *result)
+{
+ ERROR("rlm_sql_postgresql: Error occurred, no more information available, rebuild with newer libpq");
+ return RLM_SQL_ERROR;
+}
+#endif
+
+static int _sql_socket_destructor(rlm_sql_postgres_conn_t *conn)
+{
+ DEBUG2("rlm_sql_postgresql: Socket destructor called, closing socket");
+
+ if (!conn->db) return 0;
+
+ /* PQfinish also frees the memory used by the PGconn structure */
+ PQfinish(conn->db);
+
+ return 0;
+}
+
+static int CC_HINT(nonnull) sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_config_t *driver = config->driver;
+ rlm_sql_postgres_conn_t *conn;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_postgres_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ DEBUG2("rlm_sql_postgresql: Connecting using parameters: %s", driver->db_string);
+ conn->db = PQconnectdb(driver->db_string);
+ if (!conn->db) {
+ ERROR("rlm_sql_postgresql: Connection failed: Out of memory");
+ return -1;
+ }
+ if (PQstatus(conn->db) != CONNECTION_OK) {
+ ERROR("rlm_sql_postgresql: Connection failed: %s", PQerrorMessage(conn->db));
+ PQfinish(conn->db);
+ conn->db = NULL;
+ return -1;
+ }
+
+ DEBUG2("Connected to database '%s' on '%s' server version %i, protocol version %i, backend PID %i ",
+ PQdb(conn->db), PQhost(conn->db), PQserverVersion(conn->db), PQprotocolVersion(conn->db),
+ PQbackendPID(conn->db));
+
+ return 0;
+}
+
+static CC_HINT(nonnull) sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config,
+ char const *query)
+{
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+ struct timeval start;
+ int sockfd;
+ ExecStatusType status;
+ int numfields = 0;
+ PGresult *tmp_result;
+
+ if (!conn->db) {
+ ERROR("rlm_sql_postgresql: Socket not connected");
+ return RLM_SQL_RECONNECT;
+ }
+
+ sockfd = PQsocket(conn->db);
+ if (sockfd < 0) {
+ ERROR("rlm_sql_postgresql: Unable to obtain socket: %s", PQerrorMessage(conn->db));
+ return RLM_SQL_RECONNECT;
+ }
+
+ if (!PQsendQuery(conn->db, query)) {
+ ERROR("rlm_sql_postgresql: Failed to send query: %s", PQerrorMessage(conn->db));
+ return RLM_SQL_RECONNECT;
+ }
+
+ /*
+ * We try to avoid blocking by waiting until the driver indicates that
+ * the result is ready or our timeout expires
+ */
+ gettimeofday(&start, NULL);
+ while (PQisBusy(conn->db)) {
+ int r;
+ fd_set read_fd;
+ struct timeval when, elapsed, wake;
+
+ FD_ZERO(&read_fd);
+ FD_SET(sockfd, &read_fd);
+
+ if (config->query_timeout) {
+ gettimeofday(&when, NULL);
+ rad_tv_sub(&when, &start, &elapsed);
+ if (elapsed.tv_sec >= config->query_timeout) goto too_long;
+
+ when.tv_sec = config->query_timeout;
+ when.tv_usec = 0;
+ rad_tv_sub(&when, &elapsed, &wake);
+ }
+
+ r = select(sockfd + 1, &read_fd, NULL, NULL, config->query_timeout ? &wake : NULL);
+ if (r == 0) {
+ too_long:
+ ERROR("rlm_sql_postgresql: Socket read timeout after %d seconds", config->query_timeout);
+ return RLM_SQL_RECONNECT;
+ }
+ if (r < 0) {
+ if (errno == EINTR) continue;
+ ERROR("rlm_sql_postgresql: Failed in select: %s", fr_syserror(errno));
+ return RLM_SQL_RECONNECT;
+ }
+ if (!PQconsumeInput(conn->db)) {
+ ERROR("rlm_sql_postgresql: Failed reading input: %s", PQerrorMessage(conn->db));
+ return RLM_SQL_RECONNECT;
+ }
+ }
+
+ /*
+ * Returns a PGresult pointer or possibly a null pointer.
+ * A non-null pointer will generally be returned except in
+ * out-of-memory conditions or serious errors such as inability
+ * to send the command to the server. If a null pointer is
+ * returned, it should be treated like a PGRES_FATAL_ERROR
+ * result.
+ */
+ conn->result = PQgetResult(conn->db);
+
+ /* Discard results for appended queries */
+ while ((tmp_result = PQgetResult(conn->db)) != NULL)
+ PQclear(tmp_result);
+
+ /*
+ * As this error COULD be a connection error OR an out-of-memory
+ * condition return value WILL be wrong SOME of the time
+ * regardless! Pick your poison...
+ */
+ if (!conn->result) {
+ ERROR("rlm_sql_postgresql: Failed getting query result: %s", PQerrorMessage(conn->db));
+ return RLM_SQL_RECONNECT;
+ }
+
+ status = PQresultStatus(conn->result);
+ DEBUG("rlm_sql_postgresql: Status: %s", PQresStatus(status));
+
+ switch (status){
+ /*
+ * Successful completion of a command returning no data.
+ */
+ case PGRES_COMMAND_OK:
+ /*
+ * Affected_rows function only returns the number of affected rows of a command
+ * returning no data...
+ */
+ conn->affected_rows = affected_rows(conn->result);
+ DEBUG("rlm_sql_postgresql: query affected rows = %i", conn->affected_rows);
+ return RLM_SQL_OK;
+ /*
+ * Successful completion of a command returning data (such as a SELECT or SHOW).
+ */
+#ifdef HAVE_PGRES_SINGLE_TUPLE
+ case PGRES_SINGLE_TUPLE:
+#endif
+ case PGRES_TUPLES_OK:
+ conn->cur_row = 0;
+ conn->affected_rows = PQntuples(conn->result);
+ numfields = PQnfields(conn->result); /*Check row storing functions..*/
+ DEBUG("rlm_sql_postgresql: query affected rows = %i , fields = %i", conn->affected_rows, numfields);
+ return RLM_SQL_OK;
+
+#ifdef HAVE_PGRES_COPY_BOTH
+ case PGRES_COPY_BOTH:
+#endif
+ case PGRES_COPY_OUT:
+ case PGRES_COPY_IN:
+ DEBUG("rlm_sql_postgresql: Data transfer started");
+ return RLM_SQL_OK;
+
+ /*
+ * Weird.. this shouldn't happen.
+ */
+ case PGRES_EMPTY_QUERY:
+ ERROR("rlm_sql_postgresql: Empty query");
+ return RLM_SQL_QUERY_INVALID;
+
+ /*
+ * The server's response was not understood.
+ */
+ case PGRES_BAD_RESPONSE:
+ ERROR("rlm_sql_postgresql: Bad Response From Server");
+ return RLM_SQL_RECONNECT;
+
+
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ return sql_classify_error(conn->result);
+
+#ifdef HAVE_PGRES_PIPELINE_SYNC
+ case PGRES_PIPELINE_SYNC:
+ case PGRES_PIPELINE_ABORTED:
+ ERROR("rlm_sql_postgresql: Pipeline flagged as aborted");
+ return RLM_SQL_ERROR;
+#endif
+ }
+
+ return RLM_SQL_ERROR;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char const *query)
+{
+ return sql_query(handle, config, query);
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+
+ int records, i, len;
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+
+ handle->row = NULL;
+
+ if (conn->cur_row >= PQntuples(conn->result)) return RLM_SQL_NO_MORE_ROWS;
+
+ free_result_row(conn);
+
+ records = PQnfields(conn->result);
+ conn->num_fields = records;
+
+ if ((PQntuples(conn->result) > 0) && (records > 0)) {
+ conn->row = talloc_zero_array(conn, char *, records + 1);
+ for (i = 0; i < records; i++) {
+ len = PQgetlength(conn->result, conn->cur_row, i);
+ conn->row[i] = talloc_array(conn->row, char, len + 1);
+ strlcpy(conn->row[i], PQgetvalue(conn->result, conn->cur_row, i), len + 1);
+ }
+ conn->cur_row++;
+ handle->row = conn->row;
+ } else {
+ return RLM_SQL_NO_MORE_ROWS;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+
+ conn->affected_rows = PQntuples(conn->result);
+ if (conn->result)
+ return PQnfields(conn->result);
+
+ return 0;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+
+ if (conn->result != NULL) {
+ PQclear(conn->result);
+ conn->result = NULL;
+ }
+
+ free_result_row(conn);
+
+ return 0;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+ char const *p, *q;
+ size_t i = 0;
+
+ rad_assert(outlen > 0);
+
+ p = PQerrorMessage(conn->db);
+ while ((q = strchr(p, '\n'))) {
+ out[i].type = L_ERR;
+ out[i].msg = talloc_asprintf(ctx, "%.*s", (int) (q - p), p);
+ p = q + 1;
+ if (++i == outlen) return outlen;
+ }
+ if (*p != '\0') {
+ out[i].type = L_ERR;
+ out[i].msg = p;
+ i++;
+ }
+
+ return i;
+}
+
+static int sql_affected_rows(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+
+ return conn->affected_rows;
+}
+
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
+{
+ size_t inlen, ret;
+ rlm_sql_handle_t *handle = talloc_get_type_abort(arg, rlm_sql_handle_t);
+ rlm_sql_postgres_conn_t *conn = handle->conn;
+ int err;
+
+ /* Check for potential buffer overflow */
+ inlen = strlen(in);
+ if ((inlen * 2 + 1) > outlen) return 0;
+ /* Prevent integer overflow */
+ if ((inlen * 2 + 1) <= inlen) return 0;
+
+ ret = PQescapeStringConn(conn->db, out, in, inlen, &err);
+ if (err) {
+ REDEBUG("Error escaping string \"%s\": %s", in, PQerrorMessage(conn->db));
+ return 0;
+ }
+
+ return ret;
+}
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_postgresql;
+rlm_sql_module_t rlm_sql_postgresql = {
+ .name = "rlm_sql_postgresql",
+ .flags = RLM_SQL_RCODE_FLAGS_ALT_QUERY,
+ .mod_instantiate = mod_instantiate,
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_free_result,
+ .sql_finish_select_query = sql_free_result,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_escape_func = sql_escape_func
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/sql_postgresql.h b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/sql_postgresql.h
new file mode 100644
index 0000000..d90e7f2
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/sql_postgresql.h
@@ -0,0 +1,250 @@
+/* Copyright 2006 The FreeRADIUS server project */
+
+#ifndef _SQL_POSTGRESQL_H_
+#define _SQL_POSTGRESQL_H_
+
+RCSIDH(sql_postgresql_h, "$Id$")
+
+/** Error Codes and required information
+ *
+ */
+typedef struct pgsql_error{
+ char const *errorcode; //!< 5 char error code from PG_DIAG_SQLSTATE.
+ char const *meaning; //!< Verbose description.
+ bool reconnect; //!< Should reconnect socket when receiving this error.
+} pgerror;
+
+static pgerror errorcodes[] = {
+ { "0100C", "DYNAMIC RESULT SETS RETURNED", false },
+ { "01008", "IMPLICIT ZERO BIT PADDING", false },
+ { "01003", "NULL VALUE ELIMINATED IN SET FUNCTION", false },
+ { "01007", "PRIVILEGE NOT GRANTED", false },
+ { "01006", "PRIVILEGE NOT REVOKED", false },
+ { "01004", "STRING DATA RIGHT TRUNCATION", false },
+ { "01P01", "DEPRECATED FEATURE", false },
+
+ { "02000", "NO DATA", false },
+ { "02001", "NO ADDITIONAL DYNAMIC RESULT SETS RETURNED", false },
+
+ { "03000", "SQL STATEMENT NOT YET COMPLETE", false },
+
+ { "08000", "CONNECTION EXCEPTION", false },
+ { "08003", "CONNECTION DOES NOT EXIST", false },
+ { "08006", "CONNECTION FAILURE", false },
+ { "08001", "SQLCLIENT UNABLE TO ESTABLISH SQLCONNECTION", false },
+ { "08004", "SQLSERVER REJECTED ESTABLISHMENT OF SQLCONNECTION", false },
+ { "08007", "TRANSACTION RESOLUTION UNKNOWN", false },
+ { "08P01", "PROTOCOL VIOLATION", false },
+
+ { "9000", "TRIGGERED ACTION EXCEPTION", false },
+
+ { "0A000", "FEATURE NOT SUPPORTED", false },
+
+ { "0B000", "INVALID TRANSACTION INITIATION", false },
+
+ { "0F000", "LOCATOR EXCEPTION", false },
+ { "0F001", "INVALID LOCATOR SPECIFICATION", false },
+
+ { "0L000", "INVALID GRANTOR", false },
+ { "0LP01", "INVALID GRANT OPERATION", false },
+
+ { "21000", "CARDINALITY VIOLATION", false },
+
+ { "22000", "DATA EXCEPTION", false },
+ { "2202E", "ARRAY SUBSCRIPT ERROR", false },
+ { "22021", "CHARACTER NOT IN REPERTOIRE", false },
+ { "22008", "DATETIME FIELD OVERFLOW", false },
+ { "22012", "DIVISION BY ZERO", false },
+ { "22005", "ERROR IN ASSIGNMENT", false },
+ { "2200B", "ESCAPE CHARACTER CONFLICT", false },
+ { "22022", "INDICATOR OVERFLOW", false },
+ { "22015", "INTERVAL FIELD OVERFLOW", false },
+ { "2201E", "INVALID ARGUMENT FOR LOGARITHM", false },
+ { "2201F", "INVALID ARGUMENT FOR POWER FUNCTION", false },
+ { "2201G", "INVALID ARGUMENT FOR WIDTH BUCKET FUNCTION", false },
+ { "22018", "INVALID CHARACTER VALUE FOR CAST", false },
+ { "22007", "INVALID DATETIME FORMAT", false },
+ { "22019", "INVALID ESCAPE CHARACTER", false },
+ { "2200D", "INVALID ESCAPE OCTET", false },
+ { "22025", "INVALID ESCAPE SEQUENCE", false },
+ { "22P06", "NONSTANDARD USE OF ESCAPE CHARACTER", false },
+ { "22010", "INVALID INDICATOR PARAMETER VALUE", false },
+ { "22020", "INVALID LIMIT VALUE", false },
+ { "22023", "INVALID PARAMETER VALUE", false },
+ { "2201B", "INVALID REGULAR EXPRESSION", false },
+ { "22009", "INVALID TIME ZONE DISPLACEMENT VALUE", false },
+ { "2200C", "INVALID USE OF ESCAPE CHARACTER", false },
+ { "2200G", "MOST SPECIFIC TYPE MISMATCH", false },
+ { "22004", "NULL VALUE NOT ALLOWED", false },
+ { "22002", "NULL VALUE NO INDICATOR PARAMETER", false },
+ { "22003", "NUMERIC VALUE OUT OF RANGE", false },
+ { "22026", "STRING DATA LENGTH MISMATCH", false },
+ { "22001", "STRING DATA RIGHT TRUNCATION", false },
+ { "22011", "SUBSTRING ERROR", false },
+ { "22027", "TRIM ERROR", false },
+ { "22024", "UNTERMINATED C STRING", false },
+ { "2200F", "ZERO LENGTH CHARACTER STRING", false },
+ { "22P01", "FLOATING POINT EXCEPTION", false },
+ { "22P02", "INVALID TEXT REPRESENTATION", false },
+ { "22P03", "INVALID BINARY REPRESENTATION", false },
+ { "22P04", "BAD COPY FILE FORMAT", false },
+ { "22P05", "UNTRANSLATABLE CHARACTER", false },
+
+ { "23000", "INTEGRITY CONSTRAINT VIOLATION", false },
+ { "23001", "RESTRICT VIOLATION", false },
+ { "23502", "NOT NULL VIOLATION", false },
+ { "23503", "FOREIGN KEY VIOLATION", false },
+ { "23514", "CHECK VIOLATION", false },
+
+ { "24000", "INVALID CURSOR STATE", false },
+
+ { "25000", "INVALID TRANSACTION STATE", false },
+ { "25001", "ACTIVE SQL TRANSACTION", false },
+ { "25002", "BRANCH TRANSACTION ALREADY ACTIVE", false },
+ { "25008", "HELD CURSOR REQUIRES SAME ISOLATION LEVEL", false },
+ { "25003", "INAPPROPRIATE ACCESS MODE FOR BRANCH TRANSACTION", false },
+ { "25004", "INAPPROPRIATE ISOLATION LEVEL FOR BRANCH TRANSACTION", false },
+ { "25005", "NO ACTIVE SQL TRANSACTION FOR BRANCH TRANSACTION", false },
+ { "25006", "READ ONLY SQL TRANSACTION", false },
+ { "25007", "SCHEMA AND DATA STATEMENT MIXING NOT SUPPORTED", false },
+ { "25P01", "NO ACTIVE SQL TRANSACTION", false },
+ { "25P02", "IN FAILED SQL TRANSACTION", false },
+
+ { "26000", "INVALID SQL STATEMENT NAME", false },
+
+ { "27000", "TRIGGERED DATA CHANGE VIOLATION", false },
+
+ { "28000", "INVALID AUTHORIZATION SPECIFICATION", false },
+
+ { "2B000", "DEPENDENT PRIVILEGE DESCRIPTORS STILL EXIST", false },
+ { "2BP01", "DEPENDENT OBJECTS STILL EXIST", false },
+
+ { "2D000", "INVALID TRANSACTION TERMINATION", false },
+
+ { "2F000", "SQL ROUTINE EXCEPTION", false },
+ { "2F005", "FUNCTION EXECUTED NO RETURN STATEMENT", false },
+ { "2F002", "MODIFYING SQL DATA NOT PERMITTED", false },
+ { "2F003", "PROHIBITED SQL STATEMENT ATTEMPTED", false },
+ { "2F004", "READING SQL DATA NOT PERMITTED", false },
+
+ { "34000", "INVALID CURSOR NAME", false },
+
+ { "38000", "EXTERNAL ROUTINE EXCEPTION", false },
+ { "38001", "CONTAINING SQL NOT PERMITTED", false },
+ { "38002", "MODIFYING SQL DATA NOT PERMITTED", false },
+ { "38003", "PROHIBITED SQL STATEMENT ATTEMPTED", false },
+ { "38004", "READING SQL DATA NOT PERMITTED", false },
+
+ { "39000", "EXTERNAL ROUTINE INVOCATION EXCEPTION", false },
+ { "39001", "INVALID SQLSTATE RETURNED", false },
+ { "39004", "NULL VALUE NOT ALLOWED", false },
+ { "39P01", "TRIGGER PROTOCOL VIOLATED", false },
+ { "39P02", "SRF PROTOCOL VIOLATED", false },
+
+ { "3B000", "SAVEPOINT EXCEPTION", false },
+ { "3B001", "INVALID SAVEPOINT SPECIFICATION", false },
+
+ { "3D000", "INVALID CATALOG NAME", false },
+ { "3F000", "INVALID SCHEMA NAME", false },
+
+ { "40000", "TRANSACTION ROLLBACK", false },
+ { "40002", "TRANSACTION INTEGRITY CONSTRAINT VIOLATION", false },
+ { "40001", "SERIALIZATION FAILURE", false },
+ { "40003", "STATEMENT COMPLETION UNKNOWN", false },
+ { "40P01", "DEADLOCK DETECTED", false },
+
+ { "44000", "WITH CHECK OPTION VIOLATION", false },
+
+ { "53000", "INSUFFICIENT RESOURCES", false },
+ { "53100", "DISK FULL", false },
+ { "53200", "OUT OF MEMORY", false },
+ { "53300", "TOO MANY CONNECTIONS", false },
+
+ { "54000", "PROGRAM LIMIT EXCEEDED", false },
+ { "54001", "STATEMENT TOO COMPLEX", false },
+ { "54011", "TOO MANY COLUMNS", false },
+ { "54023", "TOO MANY ARGUMENTS", false },
+
+ { "55000", "OBJECT NOT IN PREREQUISITE STATE", false },
+ { "55006", "OBJECT IN USE", false },
+ { "55P02", "CANT CHANGE RUNTIME PARAM", false },
+ { "55P03", "LOCK NOT AVAILABLE", false },
+
+ { "57000", "OPERATOR INTERVENTION", true },
+
+ /*
+ * This is really 'statement_timeout' or the error which is returned when
+ * 'statement_timeout' is hit.
+ *
+ * It's unlikely that this has been caused by a connection failure, and
+ * most likely to have been caused by a long running query.
+ *
+ * If the query is persistently long running then the database/query should
+ * be optimised, or 'statement_timeout' should be increased.
+ *
+ * Forcing a reconnect here only eats more resources on the DB so we will
+ * no longer do so as of 3.0.4.
+ */
+ { "57014", "QUERY CANCELED", false },
+ { "57P01", "ADMIN SHUTDOWN", true },
+ { "57P02", "CRASH SHUTDOWN", true },
+ { "57P03", "CANNOT CONNECT NOW", true },
+
+ { "58030", "IO ERROR", true },
+ { "58P01", "UNDEFINED FILE", true },
+ { "58P02", "DUPLICATE FILE", true },
+
+ { "F0000", "CONFIG FILE ERROR", true },
+ { "F0001", "LOCK FILE EXISTS", true },
+
+ { "P0000", "PLPGSQL ERROR", false },
+ { "P0001", "RAISE EXCEPTION", false },
+
+ { "42000", "SYNTAX ERROR OR ACCESS RULE VIOLATION", false },
+ { "42601", "SYNTAX ERROR", false },
+ { "42501", "INSUFFICIENT PRIVILEGE", false },
+ { "42846", "CANNOT COERCE", false },
+ { "42803", "GROUPING ERROR", false },
+ { "42830", "INVALID FOREIGN KEY", false },
+ { "42602", "INVALID NAME", false },
+ { "42622", "NAME TOO LONG", false },
+ { "42939", "RESERVED NAME", false },
+ { "42804", "DATATYPE MISMATCH", false },
+ { "42P18", "INDETERMINATE DATATYPE", false },
+ { "42809", "WRONG OBJECT TYPE", false },
+ { "42703", "UNDEFINED COLUMN", false },
+ { "42883", "UNDEFINED FUNCTION", false },
+ { "42P01", "UNDEFINED TABLE", false },
+ { "42P02", "UNDEFINED PARAMETER", false },
+ { "42704", "UNDEFINED OBJECT", false },
+ { "42701", "DUPLICATE COLUMN", false },
+ { "42P03", "DUPLICATE CURSOR", false },
+ { "42P04", "DUPLICATE DATABASE", false },
+ { "42723", "DUPLICATE FUNCTION", false },
+ { "42P05", "DUPLICATE PREPARED STATEMENT", false },
+ { "42P06", "DUPLICATE SCHEMA", false },
+ { "42P07", "DUPLICATE TABLE", false },
+ { "42712", "DUPLICATE ALIAS", false },
+ { "42710", "DUPLICATE OBJECT", false },
+ { "42702", "AMBIGUOUS COLUMN", false },
+ { "42725", "AMBIGUOUS FUNCTION", false },
+ { "42P08", "AMBIGUOUS PARAMETER", false },
+ { "42P09", "AMBIGUOUS ALIAS", false },
+ { "42P10", "INVALID COLUMN REFERENCE", false },
+ { "42611", "INVALID COLUMN DEFINITION", false },
+ { "42P11", "INVALID CURSOR DEFINITION", false },
+ { "42P12", "INVALID DATABASE DEFINITION", false },
+ { "42P13", "INVALID FUNCTION DEFINITION", false },
+ { "42P14", "INVALID PREPARED STATEMENT DEFINITION", false },
+ { "42P15", "INVALID SCHEMA DEFINITION", false },
+ { "42P16", "INVALID TABLE DEFINITION", false },
+ { "42P17", "INVALID OBJECT DEFINITION", false },
+
+ { "XX000", "INTERNAL ERROR", false },
+ { "XX001", "DATA CORRUPTED", false },
+ { "XX002", "INDEX CORRUPTED", false },
+
+ { NULL, NULL, 0 }
+};
+
+#endif /*_SQL_POSTGRESQL_H_*/
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/README.md b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/README.md
new file mode 100644
index 0000000..0e87133
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_sqlite
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for SQLite. Commonly used in examples, as it can be used to easily bootstrap local, ondisk databases.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/config.h.in b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/config.h.in
new file mode 100644
index 0000000..3977158
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/config.h.in
@@ -0,0 +1,19 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `sqlite3_create_function_v2' function. */
+#undef HAVE_SQLITE3_CREATE_FUNCTION_V2
+
+/* Define to 1 if you have the `sqlite3_errstr' function. */
+#undef HAVE_SQLITE3_ERRSTR
+
+/* Define to 1 if you have the `sqlite3_extended_result_codes' function. */
+#undef HAVE_SQLITE3_EXTENDED_RESULT_CODES
+
+/* Define to 1 if the system has the type `sqlite3_int64'. */
+#undef HAVE_SQLITE3_INT64
+
+/* Define to 1 if you have the `sqlite3_open_v2' function. */
+#undef HAVE_SQLITE3_OPEN_V2
+
+/* Define to 1 if you have the `sqlite3_prepare_v2' function. */
+#undef HAVE_SQLITE3_PREPARE_V2
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure
new file mode 100755
index 0000000..3e15470
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure
@@ -0,0 +1,4474 @@
+#! /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_sql_sqlite.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_sqlite
+with_sqlite_include_dir
+with_sqlite_lib_dir
+with_sqlite_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_sqlite
+ build without rlm_sql_sqlite
+ --with-sqlite-include-dir=DIR
+ Directory where the sqlite includes may be found
+ --with-sqlite-lib-dir=DIR
+ Directory where the sqlite libraries may be found
+ --with-sqlite-dir=DIR Base directory where sqlite is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_sqlite
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+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_sql_sqlite was given.
+if test "${with_rlm_sql_sqlite+set}" = set; then :
+ withval=$with_rlm_sql_sqlite;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_sqlite" != xno; then
+
+
+
+sqlite_include_dir=
+
+# Check whether --with-sqlite-include-dir was given.
+if test "${with_sqlite_include_dir+set}" = set; then :
+ withval=$with_sqlite_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need sqlite-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+sqlite_lib_dir=
+
+# Check whether --with-sqlite-lib-dir was given.
+if test "${with_sqlite_lib_dir+set}" = set; then :
+ withval=$with_sqlite_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need sqlite-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-sqlite-dir was given.
+if test "${with_sqlite_dir+set}" = set; then :
+ withval=$with_sqlite_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need sqlite-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_lib_dir="$withval/lib"
+ sqlite_include_dir="$withval/include"
+ ;;
+ esac
+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
+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
+
+
+
+smart_try_dir="$sqlite_lib_dir"
+
+
+
+sm_lib_safe=`echo "sqlite3" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "sqlite3_open" | 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 sqlite3_open in -lsqlite3 in $try" >&5
+$as_echo_n "checking for sqlite3_open in -lsqlite3 in $try... " >&6; }
+ LIBS="-lsqlite3 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sqlite3_open();
+int
+main ()
+{
+sqlite3_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lsqlite3"
+ 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 sqlite3_open in -lsqlite3" >&5
+$as_echo_n "checking for sqlite3_open in -lsqlite3... " >&6; }
+ LIBS="-lsqlite3 $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sqlite3_open();
+int
+main ()
+{
+sqlite3_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lsqlite3"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_open in -lsqlite3 in $try" >&5
+$as_echo_n "checking for sqlite3_open in -lsqlite3 in $try... " >&6; }
+ LIBS="-lsqlite3 $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char sqlite3_open();
+int
+main ()
+{
+sqlite3_open()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lsqlite3"
+ 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
+
+LDFLAGS="${LDFLAGS} ${SMART_LIBS}"
+if test "x$ac_cv_lib_sqlite3_sqlite3_open" != "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>." >&2;}
+
+fail="$fail libsqlite3"
+
+else
+ for ac_func in \
+ sqlite3_prepare_v2 \
+ sqlite3_open_v2 \
+ sqlite3_create_function_v2 \
+ sqlite3_errstr \
+ sqlite3_extended_result_codes \
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
+smart_try_dir="$sqlite_include_dir"
+
+
+ac_safe=`echo "sqlite3.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 sqlite3.h in $try" >&5
+$as_echo_n "checking for sqlite3.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlite3.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}/sqlite3.h" >&5
+$as_echo_n "checking for ${_prefix}/sqlite3.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlite3.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 sqlite3.h" >&5
+$as_echo_n "checking for sqlite3.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlite3.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 sqlite3.h in $try" >&5
+$as_echo_n "checking for sqlite3.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sqlite3.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_sqlite3_h" != "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sqlite headers not found. Use --with-sqlite-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: Sqlite headers not found. Use --with-sqlite-include-dir=<path>." >&2;}
+
+fail="$fail sqlite.h"
+
+fi
+CFLAGS="$SMART_CPPFLAGS"
+ac_fn_c_check_type "$LINENO" "sqlite3_int64" "ac_cv_type_sqlite3_int64" "#include <sqlite3.h>
+"
+if test "x$ac_cv_type_sqlite3_int64" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SQLITE3_INT64 1
+_ACEOF
+
+
+fi
+
+
+
+ targetname=rlm_sql_sqlite
+else
+ targetname=
+ echo \*\*\* module rlm_sql_sqlite is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_sqlite to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_sqlite." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_sqlite." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_sqlite requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_sqlite requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_sql/drivers/rlm_sql_sqlite/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure.ac
new file mode 100644
index 0000000..485f09a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/configure.ac
@@ -0,0 +1,117 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_sqlite.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_sqlite])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl extra argument: --with-sqlite-include-dir=DIR
+sqlite_include_dir=
+AC_ARG_WITH(sqlite-include-dir,
+ [AS_HELP_STRING([--with-sqlite-include-dir=DIR],
+ [Directory where the sqlite includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need sqlite-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-sqlite-lib-dir=DIR
+sqlite_lib_dir=
+AC_ARG_WITH(sqlite-lib-dir,
+ [AS_HELP_STRING([--with-sqlite-lib-dir=DIR],
+ [Directory where the sqlite libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need sqlite-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-sqlite-dir=DIR
+AC_ARG_WITH(sqlite-dir,
+ [AS_HELP_STRING([--with-sqlite-dir=DIR],
+ [Base directory where sqlite is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need sqlite-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ sqlite_lib_dir="$withval/lib"
+ sqlite_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for programs
+dnl ############################################################
+
+AC_PROG_CC
+
+dnl ############################################################
+dnl # Check for libraries
+dnl ############################################################
+
+dnl try to link to libsqlite3
+smart_try_dir="$sqlite_lib_dir"
+FR_SMART_CHECK_LIB(sqlite3, sqlite3_open)
+dnl # Ensure we use the library we just found the rest of the checks
+LDFLAGS="${LDFLAGS} ${SMART_LIBS}"
+if test "x$ac_cv_lib_sqlite3_sqlite3_open" != "xyes"
+then
+ AC_MSG_WARN([Sqlite libraries not found. Use --with-sqlite-lib-dir=<path>.])
+ FR_MODULE_FAIL([libsqlite3])
+else
+ dnl # Add any v2 variants here
+ AC_CHECK_FUNCS(\
+ sqlite3_prepare_v2 \
+ sqlite3_open_v2 \
+ sqlite3_create_function_v2 \
+ sqlite3_errstr \
+ sqlite3_extended_result_codes \
+ )
+fi
+
+dnl ############################################################
+dnl # Check for header files
+dnl ############################################################
+
+smart_try_dir="$sqlite_include_dir"
+FR_SMART_CHECK_INCLUDE(sqlite3.h)
+if test "x$ac_cv_header_sqlite3_h" != "xyes"; then
+ AC_MSG_WARN([Sqlite headers not found. Use --with-sqlite-include-dir=<path>.])
+ FR_MODULE_FAIL([sqlite.h])
+fi
+CFLAGS="$SMART_CPPFLAGS"
+AC_CHECK_TYPES([sqlite3_int64], [], [], [[#include <sqlite3.h>]])
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c
new file mode 100644
index 0000000..65b7d9a
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c
@@ -0,0 +1,800 @@
+/*
+ * 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_sql_sqlite.c
+ * @brief SQLite driver.
+ *
+ * @copyright 2013 Network RADIUS SARL <info@networkradius.com>
+ * @copyright 2007 Apple Inc.
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sqlite3.h>
+
+#include "rlm_sql.h"
+#include "config.h"
+
+#define BOOTSTRAP_MAX (1048576 * 10)
+
+/*
+ * Allow us to use versions < 3.6.0 beta0
+ */
+#ifndef SQLITE_OPEN_NOMUTEX
+# define SQLITE_OPEN_NOMUTEX 0
+#endif
+
+#ifndef HAVE_SQLITE3_INT64
+typedef sqlite_int64 sqlite3_int64;
+#endif
+
+typedef struct rlm_sql_sqlite_conn {
+ sqlite3 *db;
+ sqlite3_stmt *statement;
+ int col_count;
+} rlm_sql_sqlite_conn_t;
+
+typedef struct rlm_sql_sqlite_config {
+ char const *filename;
+ uint32_t busy_timeout;
+} rlm_sql_sqlite_config_t;
+
+static const CONF_PARSER driver_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_sql_sqlite_config_t, filename), NULL },
+ { "busy_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sql_sqlite_config_t, busy_timeout), "200" },
+ CONF_PARSER_TERMINATOR
+};
+
+/** Convert an sqlite status code to an sql_rcode_t
+ *
+ * @param status to convert.
+ * @return
+ * - RLM_SQL_OK - If no errors found.
+ * - RLM_SQL_ERROR - If a known, non-fatal, error occurred.
+ * - RLM_SQL_ALT_QUERY - If a constraints violation occurred.
+ * - RLM_SQL_RECONNECT - Anything else, we assume the connection can no longer be used.
+ */
+static sql_rcode_t sql_error_to_rcode(int status)
+{
+ /*
+ * Lowest byte is error category, other byte may contain
+ * the extended error, depending on version.
+ */
+ switch (status & 0xff) {
+ /*
+ * Not errors
+ */
+ case SQLITE_OK:
+ case SQLITE_DONE:
+ case SQLITE_ROW:
+ return RLM_SQL_OK;
+ /*
+ * User/transient errors
+ */
+ case SQLITE_ERROR: /* SQL error or missing database */
+ case SQLITE_FULL:
+ case SQLITE_MISMATCH:
+ case SQLITE_BUSY: /* Database file busy - can be caused by locking */
+ return RLM_SQL_ERROR;
+
+ /*
+ * Constraints violations
+ */
+ case SQLITE_CONSTRAINT:
+ return RLM_SQL_ALT_QUERY;
+
+ /*
+ * Errors with the handle, that probably require reinitialisation
+ */
+ default:
+ return RLM_SQL_RECONNECT;
+ }
+}
+
+/** Determine if an error occurred, and what type of error it was
+ *
+ * @param db handle to extract error from (may be NULL).
+ * @param status to check (if unused, set to SQLITE_OK).
+ * @return
+ * - RLM_SQL_OK - If no errors found.
+ * - RLM_SQL_ERROR - If a known, non-fatal, error occurred.
+ * - RLM_SQL_ALT_QUERY - If a constraints violation occurred.
+ * - RLM_SQL_RECONNECT - Anything else. We assume the connection can no longer be used.
+ */
+static sql_rcode_t sql_check_error(sqlite3 *db, int status)
+{
+ int hstatus = SQLITE_OK;
+
+ if (db) {
+ hstatus = sqlite3_errcode(db);
+ switch (hstatus & 0xff) {
+ case SQLITE_OK:
+ case SQLITE_DONE:
+ case SQLITE_ROW:
+ hstatus = SQLITE_OK;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (status & 0xff) {
+ case SQLITE_OK:
+ case SQLITE_DONE:
+ case SQLITE_ROW:
+ status = SQLITE_OK;
+ break;
+
+ default:
+ break;
+ }
+
+ if (status != SQLITE_OK) return sql_error_to_rcode(status);
+ if (hstatus != SQLITE_OK) return sql_error_to_rcode(status);
+
+ return RLM_SQL_OK;
+}
+
+/** Print an error to the global debug log
+ *
+ * If status does not indicate success, write an error to the global error log.
+ *
+ * @note The error code will be appended to the fmt string in the format ": code 0x<hex> (<int>)[: <string>]".
+ *
+ * @param db handle to extract error from (may be NULL).
+ * @param status to check (if unused, set to SQLITE_OK).
+ * @param fmt to preprend.
+ * @param ... arguments to fmt.
+ */
+static void sql_print_error(sqlite3 *db, int status, char const *fmt, ...)
+ CC_HINT(format (printf, 3, 4)) CC_HINT(nonnull (3));
+static void sql_print_error(sqlite3 *db, int status, char const *fmt, ...)
+{
+ va_list ap;
+ char *p;
+ int hstatus = SQLITE_OK;
+
+ if (db) {
+ hstatus = sqlite3_errcode(db);
+ switch (hstatus & 0xff) {
+ case SQLITE_OK:
+ case SQLITE_DONE:
+ case SQLITE_ROW:
+ hstatus = SQLITE_OK;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (status & 0xff) {
+ case SQLITE_OK:
+ case SQLITE_DONE:
+ case SQLITE_ROW:
+ status = SQLITE_OK;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * No errors!
+ */
+ if ((hstatus == SQLITE_OK) && (status == SQLITE_OK)) return;
+
+ /*
+ * At least one error...
+ */
+ va_start(ap, fmt);
+ MEM(p = talloc_vasprintf(NULL, fmt, ap));
+ va_end(ap);
+
+ /*
+ * Disagreement between handle, and function return code,
+ * print them both.
+ */
+ if ((status != SQLITE_OK) && (status != hstatus)) {
+#ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: %s: Code 0x%04x (%i): %s", p, status, status, sqlite3_errstr(status));
+#else
+ ERROR("rlm_sql_sqlite: %s: Code 0x%04x (%i)", p, status, status);
+#endif
+ }
+
+ if (hstatus != SQLITE_OK) ERROR("rlm_sql_sqlite: %s: Code 0x%04x (%i): %s",
+ p, hstatus, hstatus, sqlite3_errmsg(db));
+}
+
+#ifdef HAVE_SQLITE3_OPEN_V2
+static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db, char const *filename)
+{
+ ssize_t len;
+ int statement_cnt = 0;
+ char *buffer;
+ char *p, *q;
+ int cl;
+ FILE *f;
+ struct stat finfo;
+
+ int status;
+ sqlite3_stmt *statement;
+ char const *z_tail;
+
+ INFO("rlm_sql_sqlite: Executing SQL statements from file \"%s\"", filename);
+
+ f = fopen(filename, "r");
+ if (!f) {
+ ERROR("rlm_sql_sqlite: Failed opening SQL file \"%s\": %s", filename,
+ fr_syserror(errno));
+
+ return -1;
+ }
+
+ if (fstat(fileno(f), &finfo) < 0) {
+ ERROR("rlm_sql_sqlite: Failed stating SQL file \"%s\": %s", filename,
+ fr_syserror(errno));
+
+ fclose(f);
+
+ return -1;
+ }
+
+ if (finfo.st_size > BOOTSTRAP_MAX) {
+ too_big:
+ ERROR("rlm_sql_sqlite: Size of SQL (%zu) file exceeds limit (%uk)",
+ (size_t) finfo.st_size / 1024, BOOTSTRAP_MAX / 1024);
+
+ fclose(f);
+
+ return -1;
+ }
+
+ MEM(buffer = talloc_array(ctx, char, finfo.st_size + 1));
+ len = fread(buffer, sizeof(char), finfo.st_size + 1, f);
+ if (len > finfo.st_size) {
+ talloc_free(buffer);
+ goto too_big;
+ }
+
+ if (!len) {
+ if (ferror(f)) {
+ ERROR("rlm_sql_sqlite: Error reading SQL file: %s", fr_syserror(errno));
+
+ fclose(f);
+ talloc_free(buffer);
+
+ return -1;
+ }
+
+ DEBUG("rlm_sql_sqlite: Ignoring empty SQL file");
+
+ fclose(f);
+ talloc_free(buffer);
+
+ return 0;
+ }
+
+ buffer[len] = '\0';
+ fclose(f);
+
+ /*
+ * Check if input data is UTF-8. Allow CR/LF \t, too.
+ */
+ for (p = buffer; p < (buffer + len); p += cl) {
+ if (*p < ' ') {
+ if ((*p != 0x0a) && (*p != 0x0d) && (*p != '\t')) break;
+ cl = 1;
+ } else {
+ cl = fr_utf8_char((uint8_t *) p, -1);
+ if (!cl) break;
+ }
+ }
+
+ if ((p - buffer) != len) {
+ ERROR("rlm_sql_sqlite: Bootstrap file contains non-UTF8 char at offset %zu", p - buffer);
+ talloc_free(buffer);
+ return -1;
+ }
+
+ /*
+ * Statement delimiter is ;\n
+ */
+ p = buffer;
+ while ((q = strchr(p, ';'))) {
+ if ((q[1] != '\n') && (q[1] != '\0')) {
+ p = q + 1;
+ statement_cnt++;
+ continue;
+ }
+
+#ifdef HAVE_SQLITE3_PREPARE_V2
+ status = sqlite3_prepare_v2(db, p, q - p, &statement, &z_tail);
+#else
+ status = sqlite3_prepare(db, p, q - p, &statement, &z_tail);
+#endif
+
+ if (sql_check_error(db, status) != RLM_SQL_OK) {
+ sql_print_error(db, status, "Failed preparing statement %i", statement_cnt);
+ talloc_free(buffer);
+ return -1;
+ }
+
+ status = sqlite3_step(statement);
+ if (sql_check_error(db, status) != RLM_SQL_OK) {
+ sql_print_error(db, status, "Failed executing statement %i", statement_cnt);
+ sqlite3_finalize(statement);
+ talloc_free(buffer);
+ return -1;
+ }
+
+ status = sqlite3_finalize(statement);
+ if (sql_check_error(db, status) != RLM_SQL_OK) {
+ sql_print_error(db, status, "Failed finalizing statement %i", statement_cnt);
+ talloc_free(buffer);
+ return -1;
+ }
+
+ statement_cnt++;
+ p = q + 1;
+ }
+
+ talloc_free(buffer);
+ return 0;
+}
+#endif
+
+static int mod_instantiate(CONF_SECTION *conf, rlm_sql_config_t *config)
+{
+ static bool version_done;
+
+ bool exists;
+ rlm_sql_sqlite_config_t *driver;
+ struct stat buf;
+
+ if (!version_done) {
+ version_done = true;
+
+ if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) {
+ WARN("rlm_sql_sqlite: libsqlite version changed since the server was built");
+ WARN("rlm_sql_sqlite: linked: %s built: %s", sqlite3_libversion(), SQLITE_VERSION);
+ }
+ INFO("rlm_sql_sqlite: libsqlite version: %s", sqlite3_libversion());
+ }
+
+ MEM(driver = config->driver = talloc_zero(config, rlm_sql_sqlite_config_t));
+ if (cf_section_parse(conf, driver, driver_config) < 0) {
+ return -1;
+ }
+ if (!driver->filename) {
+ MEM(driver->filename = talloc_typed_asprintf(driver, "%s/%s", get_radius_dir(), config->sql_db));
+ }
+
+ if (stat(driver->filename, &buf) == 0) {
+ exists = true;
+ } else if (errno == ENOENT) {
+ exists = false;
+ } else {
+ ERROR("rlm_sql_sqlite: Database exists, but couldn't be opened: %s", fr_syserror(errno));
+ return -1;
+ }
+
+ if (cf_pair_find(conf, "bootstrap") && !exists) {
+# ifdef HAVE_SQLITE3_OPEN_V2
+ int status;
+ int ret;
+ char const *p;
+ char *buff;
+ sqlite3 *db = NULL;
+ CONF_PAIR *cp;
+
+ INFO("rlm_sql_sqlite: Database doesn't exist, creating it and loading schema");
+
+ p = strrchr(driver->filename, '/');
+ if (p) {
+ size_t len = (p - driver->filename) + 1;
+
+ buff = talloc_array(conf, char, len);
+ strlcpy(buff, driver->filename, len);
+ } else {
+ MEM(buff = talloc_typed_strdup(conf, driver->filename));
+ }
+
+ ret = rad_mkdir(buff, 0700, -1, -1);
+ talloc_free(buff);
+ if (ret < 0) {
+ ERROR("rlm_sql_sqlite: Failed creating directory for SQLite database: %s", fr_syserror(errno));
+
+ return -1;
+ };
+
+ status = sqlite3_open_v2(driver->filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+ if (!db) {
+# ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database: %s",
+ sqlite3_errstr(status));
+# else
+ ERROR("rlm_sql_sqlite: Failed creating opening/creating SQLite database, got code (%i)",
+ status);
+# endif
+
+ goto unlink;
+ }
+
+ if (sql_check_error(db, status) != RLM_SQL_OK) {
+ (void) sqlite3_close(db);
+
+ goto unlink;
+ }
+
+ /*
+ * Execute multiple bootstrap SQL files in order
+ */
+ for (cp = cf_pair_find(conf, "bootstrap");
+ cp;
+ cp = cf_pair_find_next(conf, cp, "bootstrap")) {
+ p = cf_pair_value(cp);
+ if (!p) continue;
+
+ ret = sql_loadfile(conf, db, p);
+ if (ret < 0) goto unlink;
+ }
+
+ status = sqlite3_close(db);
+ if (status != SQLITE_OK) {
+ /*
+ * Safer to use sqlite3_errstr here, just in case the handle is in a weird state
+ */
+# ifdef HAVE_SQLITE3_ERRSTR
+ ERROR("rlm_sql_sqlite: Error closing SQLite handle: %s", sqlite3_errstr(status));
+# else
+ ERROR("rlm_sql_sqlite: Error closing SQLite handle, got code (%i)", status);
+# endif
+
+ goto unlink;
+ }
+
+ if (ret < 0) {
+ unlink:
+ if ((unlink(driver->filename) < 0) && (errno != ENOENT)) {
+ ERROR("rlm_sql_sqlite: Error removing partially initialised database: %s",
+ fr_syserror(errno));
+ }
+ return -1;
+ }
+#else
+ WARN("rlm_sql_sqlite: sqlite3_open_v2() not available, cannot bootstrap database. "
+ "Upgrade to SQLite >= 3.5.1 if you need this functionality");
+#endif
+ }
+
+ return 0;
+}
+
+static int _sql_socket_destructor(rlm_sql_sqlite_conn_t *conn)
+{
+ int status = 0;
+
+ DEBUG2("rlm_sql_sqlite: Socket destructor called, closing socket");
+
+ if (conn->db) {
+ status = sqlite3_close(conn->db);
+ if (status != SQLITE_OK) WARN("rlm_sql_sqlite: Got SQLite error code (%u) when closing socket", status);
+ }
+
+ return 0;
+}
+
+static void _sql_greatest(sqlite3_context *ctx, int num_values, sqlite3_value **values)
+{
+ int i;
+ sqlite3_int64 value, max = 0;
+
+ for (i = 0; i < num_values; i++) {
+ value = sqlite3_value_int64(values[i]);
+ if (value > max) {
+ max = value;
+ }
+ }
+
+ sqlite3_result_int64(ctx, max);
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn;
+ rlm_sql_sqlite_config_t *driver = config->driver;
+
+ int status;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_sqlite_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ INFO("rlm_sql_sqlite: Opening SQLite database \"%s\"", driver->filename);
+#ifdef HAVE_SQLITE3_OPEN_V2
+ status = sqlite3_open_v2(driver->filename, &(conn->db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX, NULL);
+#else
+ status = sqlite3_open(driver->filename, &(conn->db));
+#endif
+
+ if (!conn->db || (sql_check_error(conn->db, status) != RLM_SQL_OK)) {
+ sql_print_error(conn->db, status, "Error opening SQLite database \"%s\"", driver->filename);
+ return RLM_SQL_ERROR;
+ }
+ status = sqlite3_busy_timeout(conn->db, driver->busy_timeout);
+ if (sql_check_error(conn->db, status) != RLM_SQL_OK) {
+ sql_print_error(conn->db, status, "Error setting busy timeout");
+ return RLM_SQL_ERROR;
+ }
+
+ /*
+ * Enable extended return codes for extra debugging info.
+ */
+#ifdef HAVE_SQLITE3_EXTENDED_RESULT_CODES
+ status = sqlite3_extended_result_codes(conn->db, 1);
+ if (sql_check_error(conn->db, status) != RLM_SQL_OK) {
+ sql_print_error(conn->db, status, "Error enabling extended result codes");
+ return RLM_SQL_ERROR;
+ }
+#endif
+
+#ifdef HAVE_SQLITE3_CREATE_FUNCTION_V2
+ status = sqlite3_create_function_v2(conn->db, "GREATEST", -1, SQLITE_ANY, NULL,
+ _sql_greatest, NULL, NULL, NULL);
+#else
+ status = sqlite3_create_function(conn->db, "GREATEST", -1, SQLITE_ANY, NULL,
+ _sql_greatest, NULL, NULL);
+#endif
+ if (sql_check_error(conn->db, status) != RLM_SQL_OK) {
+ sql_print_error(conn->db, status, "Failed registering 'GREATEST' sql function");
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+ char const *z_tail;
+ int status;
+
+#ifdef HAVE_SQLITE3_PREPARE_V2
+ status = sqlite3_prepare_v2(conn->db, query, strlen(query), &conn->statement, &z_tail);
+#else
+ status = sqlite3_prepare(conn->db, query, strlen(query), &conn->statement, &z_tail);
+#endif
+
+ conn->col_count = 0;
+
+ return sql_check_error(conn->db, status);
+}
+
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
+{
+
+ sql_rcode_t rcode;
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+ char const *z_tail;
+ int status;
+
+#ifdef HAVE_SQLITE3_PREPARE_V2
+ status = sqlite3_prepare_v2(conn->db, query, strlen(query), &conn->statement, &z_tail);
+#else
+ status = sqlite3_prepare(conn->db, query, strlen(query), &conn->statement, &z_tail);
+#endif
+ rcode = sql_check_error(conn->db, status);
+ if (rcode != RLM_SQL_OK) return rcode;
+
+ status = sqlite3_step(conn->statement);
+ return sql_check_error(conn->db, status);
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+
+ if (conn->statement) {
+ return sqlite3_column_count(conn->statement);
+ }
+
+ return 0;
+}
+
+static int sql_num_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+
+ if (conn->statement) {
+ return sqlite3_data_count(conn->statement);
+ }
+
+ return 0;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ int status;
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+
+ int i = 0;
+
+ char **row;
+
+ TALLOC_FREE(handle->row);
+
+ /*
+ * Executes the SQLite query and interates over the results
+ */
+ status = sqlite3_step(conn->statement);
+
+ /*
+ * Error getting next row
+ */
+ if (sql_check_error(conn->db, status) != RLM_SQL_OK) return RLM_SQL_ERROR;
+
+ /*
+ * No more rows to process (were done)
+ */
+ if (status == SQLITE_DONE) return RLM_SQL_NO_MORE_ROWS;
+
+ /*
+ * We only need to do this once per result set, because
+ * the number of columns won't change.
+ */
+ if (conn->col_count == 0) {
+ conn->col_count = sql_num_fields(handle, config);
+ if (conn->col_count == 0) return RLM_SQL_ERROR;
+ }
+
+ MEM(row = handle->row = talloc_zero_array(handle->conn, char *, conn->col_count + 1));
+
+ for (i = 0; i < conn->col_count; i++) {
+ switch (sqlite3_column_type(conn->statement, i)) {
+ case SQLITE_INTEGER:
+ MEM(row[i] = talloc_typed_asprintf(row, "%d", sqlite3_column_int(conn->statement, i)));
+ break;
+
+ case SQLITE_FLOAT:
+ MEM(row[i] = talloc_typed_asprintf(row, "%f", sqlite3_column_double(conn->statement, i)));
+ break;
+
+ case SQLITE_TEXT:
+ {
+ char const *p;
+ p = (char const *) sqlite3_column_text(conn->statement, i);
+
+ if (p) MEM(row[i] = talloc_typed_strdup(row, p));
+ }
+ break;
+
+ case SQLITE_BLOB:
+ {
+ uint8_t const *p;
+ size_t len;
+
+ p = sqlite3_column_blob(conn->statement, i);
+ if (p) {
+ len = sqlite3_column_bytes(conn->statement, i);
+
+ MEM(row[i] = talloc_zero_array(row, char, len + 1));
+ memcpy(row[i], p, len);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+
+ if (conn->statement) {
+ TALLOC_FREE(handle->row);
+
+ (void) sqlite3_finalize(conn->statement);
+ conn->statement = NULL;
+ conn->col_count = 0;
+ }
+
+ /*
+ * There's no point in checking the code returned by finalize
+ * as it'll have already been encountered elsewhere in the code.
+ *
+ * It's just the last error that occurred processing the
+ * statement.
+ */
+ return RLM_SQL_OK;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+ char const *error;
+
+ rad_assert(outlen > 0);
+
+ error = sqlite3_errmsg(conn->db);
+ if (!error) return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = error;
+
+ return 1;
+}
+
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ return sql_free_result(handle, config);
+}
+
+static int sql_affected_rows(rlm_sql_handle_t *handle,
+ UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_sqlite_conn_t *conn = handle->conn;
+
+ if (conn->db) return sqlite3_changes(conn->db);
+
+ return -1;
+}
+
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_sqlite;
+rlm_sql_module_t rlm_sql_sqlite = {
+ .name = "rlm_sql_sqlite",
+ .flags = RLM_SQL_RCODE_FLAGS_ALT_QUERY,
+ .mod_instantiate = mod_instantiate,
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_num_rows = sql_num_rows,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_query
+};
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/.gitignore b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/README.md b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/README.md
new file mode 100644
index 0000000..86e9fbc
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/README.md
@@ -0,0 +1,8 @@
+# rlm_sql_unixodbc
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+SQL driver for the unixodbc ODBC connector library.
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/all.mk.in b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/all.mk.in
new file mode 100644
index 0000000..4dde03c
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I${top_srcdir}/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure
new file mode 100755
index 0000000..f920178
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure
@@ -0,0 +1,4192 @@
+#! /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_sql_unixodbc.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_unixodbc
+with_unixodbc_include_dir
+with_unixodbc_lib_dir
+with_unixodbc_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_unixodbc
+ build without rlm_sql_unixodbc
+ --with-unixodbc-include-dir=DIR
+ Directory where the unixODBC includes may be found
+ --with-unixodbc-lib-dir=DIR
+ Directory where the unixODBC libraries may be found
+ --with-unixodbc-dir=DIR Base directory where unixODBC is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_unixodbc
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_sql_unixodbc was given.
+if test "${with_rlm_sql_unixodbc+set}" = set; then :
+ withval=$with_rlm_sql_unixodbc;
+fi
+
+
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_unixodbc" != xno; then
+
+
+unixodbc_include_dir=
+
+# Check whether --with-unixodbc-include-dir was given.
+if test "${with_unixodbc_include_dir+set}" = set; then :
+ withval=$with_unixodbc_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need unixodbc-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+unixodbc_lib_dir=
+
+# Check whether --with-unixodbc-lib-dir was given.
+if test "${with_unixodbc_lib_dir+set}" = set; then :
+ withval=$with_unixodbc_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need unixodbc-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-unixodbc-dir was given.
+if test "${with_unixodbc_dir+set}" = set; then :
+ withval=$with_unixodbc_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need unixodbc-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_lib_dir="$withval/lib"
+ unixodbc_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+smart_try_dir="$unixodbc_lib_dir /usr/local/unixodbc/lib"
+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
+
+
+
+
+sm_lib_safe=`echo "odbc" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "SQLConnect" | 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 SQLConnect in -lodbc in $try" >&5
+$as_echo_n "checking for SQLConnect in -lodbc in $try... " >&6; }
+ LIBS="-lodbc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lodbc"
+ 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 SQLConnect in -lodbc" >&5
+$as_echo_n "checking for SQLConnect in -lodbc... " >&6; }
+ LIBS="-lodbc $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lodbc"
+ { $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 SQLConnect in -lodbc in $try" >&5
+$as_echo_n "checking for SQLConnect in -lodbc in $try... " >&6; }
+ LIBS="-lodbc $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char SQLConnect();
+int
+main ()
+{
+SQLConnect()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lodbc"
+ 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_odbc_SQLConnect" != xyes; then
+
+fail="$fail libodbc"
+
+fi
+
+smart_try_dir="$unixodbc_include_dir /usr/local/unixodbc/include"
+
+
+ac_safe=`echo "sql.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 sql.h in $try" >&5
+$as_echo_n "checking for sql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sql.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}/sql.h" >&5
+$as_echo_n "checking for ${_prefix}/sql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sql.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 sql.h" >&5
+$as_echo_n "checking for sql.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sql.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 sql.h in $try" >&5
+$as_echo_n "checking for sql.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <sql.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_sql_h" != xyes; then
+
+fail="$fail sql.h"
+
+fi
+
+
+ targetname=rlm_sql_unixodbc
+else
+ targetname=
+ echo \*\*\* module rlm_sql_unixodbc is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sql_unixodbc to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_unixodbc." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_unixodbc." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_unixodbc requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_unixodbc requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure.ac b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure.ac
new file mode 100644
index 0000000..3bdfae6
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/configure.ac
@@ -0,0 +1,83 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_unixodbc.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_unixodbc])
+
+SMART_LIBS=
+SMART_CLFAGS=
+
+FR_MODULE_START_TESTS
+
+dnl extra argument: --with-unixodbc-include-dir
+unixodbc_include_dir=
+AC_ARG_WITH(unixodbc-include-dir,
+ [AS_HELP_STRING([--with-unixodbc-include-dir=DIR],
+ [Directory where the unixODBC includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need unixodbc-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-unixodbc-lib-dir
+unixodbc_lib_dir=
+AC_ARG_WITH(unixodbc-lib-dir,
+ [AS_HELP_STRING([--with-unixodbc-lib-dir=DIR],
+ [Directory where the unixODBC libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need unixodbc-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-unixodbc-dir
+AC_ARG_WITH(unixodbc-dir,
+ [AS_HELP_STRING([--with-unixodbc-dir=DIR],
+ [Base directory where unixODBC is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need unixodbc-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ unixodbc_lib_dir="$withval/lib"
+ unixodbc_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl Check for SQLConnect in -lodbc
+smart_try_dir="$unixodbc_lib_dir /usr/local/unixodbc/lib"
+FR_SMART_CHECK_LIB(odbc, SQLConnect)
+if test "x$ac_cv_lib_odbc_SQLConnect" != xyes; then
+ FR_MODULE_FAIL([libodbc])
+fi
+
+dnl Check for sql.h
+smart_try_dir="$unixodbc_include_dir /usr/local/unixodbc/include"
+FR_SMART_CHECK_INCLUDE(sql.h)
+if test "x$ac_cv_header_sql_h" != xyes; then
+ FR_MODULE_FAIL([sql.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c
new file mode 100644
index 0000000..248b55e
--- /dev/null
+++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c
@@ -0,0 +1,364 @@
+/*
+ * sql_unixodbc.c unixODBC rlm_sql driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2000,2006 The FreeRADIUS server project
+ * Copyright 2000 Dmitri Ageev <d_ageev@ortcc.ru>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sqltypes.h>
+#include "rlm_sql.h"
+
+typedef struct rlm_sql_unixodbc_conn {
+ SQLHENV env;
+ SQLHDBC dbc;
+ SQLHSTMT stmt;
+ rlm_sql_row_t row;
+ void *conn;
+} rlm_sql_unixodbc_conn_t;
+
+USES_APPLE_DEPRECATED_API
+#include <sql.h>
+#include <sqlext.h>
+
+/* Forward declarations */
+static int sql_check_error(long err_handle, rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+static int _sql_socket_destructor(rlm_sql_unixodbc_conn_t *conn)
+{
+ DEBUG2("rlm_sql_unixodbc: Socket destructor called, closing socket");
+
+ if (conn->stmt) SQLFreeStmt(conn->stmt, SQL_DROP);
+
+ if (conn->dbc) {
+ SQLDisconnect(conn->dbc);
+ SQLFreeConnect(conn->dbc);
+ }
+
+ if (conn->env) SQLFreeEnv(conn->env);
+
+ return 0;
+}
+
+static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn;
+ long err_handle;
+
+ MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_unixodbc_conn_t));
+ talloc_set_destructor(conn, _sql_socket_destructor);
+
+ /* 1. Allocate environment handle and register version */
+ err_handle = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn->env);
+ if (sql_check_error(err_handle, handle, config)) {
+ ERROR("rlm_sql_unixodbc: Can't allocate environment handle");
+ return RLM_SQL_ERROR;
+ }
+
+ err_handle = SQLSetEnvAttr(conn->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
+ if (sql_check_error(err_handle, handle, config)) {
+ ERROR("rlm_sql_unixodbc: Can't register ODBC version");
+ return RLM_SQL_ERROR;
+ }
+
+ /* 2. Allocate connection handle */
+ err_handle = SQLAllocHandle(SQL_HANDLE_DBC, conn->env, &conn->dbc);
+ if (sql_check_error(err_handle, handle, config)) {
+ ERROR("rlm_sql_unixodbc: Can't allocate connection handle");
+ return RLM_SQL_ERROR;
+ }
+
+ /* 3. Connect to the datasource */
+ {
+ SQLCHAR *odbc_server, *odbc_login, *odbc_password;
+
+ memcpy(&odbc_server, &config->sql_server, sizeof(odbc_server));
+ memcpy(&odbc_login, &config->sql_login, sizeof(odbc_login));
+ memcpy(&odbc_password, &config->sql_password, sizeof(odbc_password));
+ err_handle = SQLConnect(conn->dbc,
+ odbc_server, strlen(config->sql_server),
+ odbc_login, strlen(config->sql_login),
+ odbc_password, strlen(config->sql_password));
+ }
+
+ if (sql_check_error(err_handle, handle, config)) {
+ ERROR("rlm_sql_unixodbc: Connection failed");
+ return RLM_SQL_ERROR;
+ }
+
+ /* 4. Allocate the stmt */
+ err_handle = SQLAllocHandle(SQL_HANDLE_STMT, conn->dbc, &conn->stmt);
+ if (sql_check_error(err_handle, handle, config)) {
+ ERROR("rlm_sql_unixodbc: Can't allocate the stmt");
+ return RLM_SQL_ERROR;
+ }
+
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ long err_handle;
+ int state;
+
+ /* Executing query */
+ {
+ SQLCHAR *odbc_query;
+
+ memcpy(&odbc_query, &query, sizeof(odbc_query));
+ err_handle = SQLExecDirect(conn->stmt, odbc_query, strlen(query));
+ }
+ if ((state = sql_check_error(err_handle, handle, config))) {
+ if(state == RLM_SQL_RECONNECT) {
+ DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect");
+ }
+ return state;
+ }
+ return 0;
+}
+
+static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ SQLINTEGER i;
+ SQLLEN len;
+ int colcount;
+ int state;
+
+ /* Only state = 0 means success */
+ if ((state = sql_query(handle, config, query))) {
+ return state;
+ }
+
+ colcount = sql_num_fields(handle, config);
+ if (colcount < 0) {
+ return RLM_SQL_ERROR;
+ }
+
+ /* Reserving memory for result */
+ conn->row = talloc_zero_array(conn, char *, colcount + 1); /* Space for pointers */
+
+ for (i = 1; i <= colcount; i++) {
+ len = 0;
+ SQLColAttributes(conn->stmt, ((SQLUSMALLINT) i), SQL_DESC_LENGTH, NULL, 0, NULL, &len);
+ conn->row[i - 1] = talloc_array(conn->row, char, ++len);
+ SQLBindCol(conn->stmt, i, SQL_C_CHAR, (SQLCHAR *)conn->row[i - 1], len, NULL);
+ }
+
+ return RLM_SQL_OK;
+}
+
+static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ long err_handle;
+ SQLSMALLINT num_fields = 0;
+
+ err_handle = SQLNumResultCols(conn->stmt,&num_fields);
+ if (sql_check_error(err_handle, handle, config)) return -1;
+
+ return num_fields;
+}
+
+static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ long err_handle;
+ int state;
+
+ handle->row = NULL;
+
+ err_handle = SQLFetch(conn->stmt);
+ if (err_handle == SQL_NO_DATA_FOUND) return RLM_SQL_NO_MORE_ROWS;
+
+ if ((state = sql_check_error(err_handle, handle, config))) return state;
+
+ handle->row = conn->row;
+ return RLM_SQL_OK;
+}
+
+static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+
+ sql_free_result(handle, config);
+
+ /*
+ * SQL_CLOSE - The cursor (if any) associated with the statement
+ * handle (StatementHandle) is closed and all pending results are
+ * discarded. The application can reopen the cursor by calling
+ * SQLExecute() with the same or different values in the
+ * application variables (if any) that are bound to StatementHandle.
+ * If no cursor has been associated with the statement handle,
+ * this option has no effect (no warning or error is generated).
+ *
+ * So, this call does NOT free the statement at all, it merely
+ * resets it for the next call. This is terrible terrible naming.
+ */
+ SQLFreeStmt(conn->stmt, SQL_CLOSE);
+
+ return 0;
+}
+
+static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+
+ SQLFreeStmt(conn->stmt, SQL_CLOSE);
+
+ return 0;
+}
+
+static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+
+ TALLOC_FREE(conn->row);
+
+ return 0;
+}
+
+/** Retrieves any errors associated with the connection handle
+ *
+ * @note Caller will free any memory allocated in ctx.
+ *
+ * @param ctx to allocate temporary error buffers in.
+ * @param out Array of sql_log_entrys to fill.
+ * @param outlen Length of out array.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return number of errors written to the sql_log_entry array.
+ */
+static size_t sql_error(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
+ rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ SQLCHAR state[256];
+ SQLCHAR errbuff[256];
+ SQLINTEGER errnum = 0;
+ SQLSMALLINT length = 255;
+
+ rad_assert(outlen > 0);
+
+ errbuff[0] = state[0] = '\0';
+ SQLError(conn->env, conn->dbc, conn->stmt, state, &errnum,
+ errbuff, sizeof(errbuff), &length);
+ if (errnum == 0) return 0;
+
+ out[0].type = L_ERR;
+ out[0].msg = talloc_asprintf(ctx, "%s: %s", state, errbuff);
+
+ return 1;
+}
+
+/** Checks the error code to determine if the connection needs to be re-esttablished
+ *
+ * @param error_handle Return code from a failed unixodbc call.
+ * @param handle rlm_sql connection handle.
+ * @param config rlm_sql config.
+ * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if reconnect is needed, or RLM_SQL_ERROR on error.
+ */
+static sql_rcode_t sql_check_error(long error_handle, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
+{
+ SQLCHAR state[256];
+ SQLCHAR error[256];
+ SQLINTEGER errornum = 0;
+ SQLSMALLINT length = 255;
+ int res = -1;
+
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+
+ if (SQL_SUCCEEDED(error_handle)) return 0; /* on success, just return 0 */
+
+ error[0] = state[0] = '\0';
+
+ SQLError(conn->env, conn->dbc, conn->stmt, state, &errornum,
+ error, sizeof(error), &length);
+
+ if (state[0] == '0') {
+ switch (state[1]) {
+ /* SQLSTATE 01 class contains info and warning messages */
+ case '1':
+ INFO("rlm_sql_unixodbc: %s %s", state, error);
+ /* FALL-THROUGH */
+ case '0': /* SQLSTATE 00 class means success */
+ res = RLM_SQL_OK;
+ break;
+
+ /* SQLSTATE 08 class describes various connection errors */
+ case '8':
+ ERROR("rlm_sql_unixodbc: SQL down %s %s", state, error);
+ res = RLM_SQL_RECONNECT;
+ break;
+
+ /* any other SQLSTATE means error */
+ default:
+ ERROR("rlm_sql_unixodbc: %s %s", state, error);
+ res = RLM_SQL_ERROR;
+ break;
+ }
+ } else {
+ ERROR("rlm_sql_unixodbc: %s %s", state, error);
+ }
+
+ return res;
+}
+
+/*************************************************************************
+ *
+ * Function: sql_affected_rows
+ *
+ * Purpose: Return the number of rows affected by the query (update,
+ * or insert)
+ *
+ *************************************************************************/
+static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
+{
+ rlm_sql_unixodbc_conn_t *conn = handle->conn;
+ long error_handle;
+ SQLLEN affected_rows;
+
+ error_handle = SQLRowCount(conn->stmt, &affected_rows);
+ if (sql_check_error(error_handle, handle, config)) return -1;
+
+ return affected_rows;
+}
+
+
+/* Exported to rlm_sql */
+extern rlm_sql_module_t rlm_sql_unixodbc;
+rlm_sql_module_t rlm_sql_unixodbc = {
+ .name = "rlm_sql_unixodbc",
+ .sql_socket_init = sql_socket_init,
+ .sql_query = sql_query,
+ .sql_select_query = sql_select_query,
+ .sql_num_fields = sql_num_fields,
+ .sql_affected_rows = sql_affected_rows,
+ .sql_fetch_row = sql_fetch_row,
+ .sql_free_result = sql_free_result,
+ .sql_error = sql_error,
+ .sql_finish_query = sql_finish_query,
+ .sql_finish_select_query = sql_finish_select_query
+};
diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c
new file mode 100644
index 0000000..4989dd4
--- /dev/null
+++ b/src/modules/rlm_sql/rlm_sql.c
@@ -0,0 +1,1847 @@
+/*
+ * 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_sql.c
+ * @brief Implements SQL 'users' file, and SQL accounting.
+ *
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Mike Machado <mike@innercite.com>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <ctype.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/token.h>
+#include <freeradius-devel/rad_assert.h>
+#include <freeradius-devel/exfile.h>
+
+#include <sys/stat.h>
+
+#include "rlm_sql.h"
+
+/*
+ * So we can do pass2 xlat checks on the queries.
+ */
+static const CONF_PARSER query_config[] = {
+ { "query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_MULTI, rlm_sql_config_t, accounting.query), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * For now hard-code the subsections. This isn't perfect, but it
+ * helps the average case.
+ */
+static const CONF_PARSER type_config[] = {
+ { "accounting-on", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) query_config },
+ { "accounting-off", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) query_config },
+ { "start", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) query_config },
+ { "interim-update", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) query_config },
+ { "stop", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) query_config },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER acct_config[] = {
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, accounting.reference), ".query" },
+ { "logfile", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, accounting.logfile), NULL },
+
+ { "type", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) type_config },
+
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER postauth_config[] = {
+ { "reference", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, postauth.reference), ".query" },
+ { "logfile", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, postauth.logfile), NULL },
+
+ { "query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_MULTI, rlm_sql_config_t, postauth.query), NULL },
+ CONF_PARSER_TERMINATOR
+};
+
+static const CONF_PARSER module_config[] = {
+ { "driver", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_driver_name), "rlm_sql_null" },
+ { "server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_server), "" }, /* Must be zero length so drivers can determine if it was set */
+ { "port", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sql_config_t, sql_port), "0" },
+ { "login", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_login), "" },
+ { "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_sql_config_t, sql_password), "" },
+ { "radius_db", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, sql_db), "radius" },
+ { "read_groups", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, read_groups), "yes" },
+ { "read_profiles", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, read_profiles), "yes" },
+ { "readclients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_sql_config_t, do_clients), NULL },
+ { "read_clients", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, do_clients), "no" },
+ { "deletestalesessions", FR_CONF_OFFSET(PW_TYPE_BOOLEAN | PW_TYPE_DEPRECATED, rlm_sql_config_t, delete_stale_sessions), NULL },
+ { "delete_stale_sessions", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, delete_stale_sessions), "yes" },
+ { "sql_user_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, query_user), "" },
+ { "logfile", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, logfile), NULL },
+ { "default_user_profile", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, default_profile), "" },
+ { "nas_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sql_config_t, client_query), NULL },
+ { "client_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, client_query), "SELECT id,nasname,shortname,type,secret FROM nas" },
+ { "open_query", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, connect_query), NULL },
+
+ { "authorize_check_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, authorize_check_query), NULL },
+ { "authorize_reply_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, authorize_reply_query), NULL },
+
+ { "authorize_group_check_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, authorize_group_check_query), NULL },
+ { "authorize_group_reply_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, authorize_group_reply_query), NULL },
+ { "group_membership_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, groupmemb_query), NULL },
+#ifdef WITH_SESSION_MGMT
+ { "simul_count_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, simul_count_query), NULL },
+ { "simul_verify_query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sql_config_t, simul_verify_query), NULL },
+#endif
+ { "safe-characters", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sql_config_t, allowed_chars), NULL },
+ { "safe_characters", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sql_config_t, allowed_chars), "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
+ { "auto_escape", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_config_t, driver_specific_escape), "no" },
+
+ /*
+ * This only works for a few drivers.
+ */
+ { "query_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sql_config_t, query_timeout), NULL },
+
+ { "accounting", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) acct_config },
+
+ { "post-auth", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) postauth_config },
+ CONF_PARSER_TERMINATOR
+};
+
+static size_t sql_escape_for_xlat_func(REQUEST *request, char *out, size_t outlen, char const *in, void *arg);
+
+/*
+ * Fall-Through checking function from rlm_files.c
+ */
+static sql_fall_through_t fall_through(VALUE_PAIR *vp)
+{
+ VALUE_PAIR *tmp;
+ tmp = fr_pair_find_by_num(vp, PW_FALL_THROUGH, 0, TAG_ANY);
+
+ return tmp ? tmp->vp_integer : FALL_THROUGH_DEFAULT;
+}
+
+/*
+ * Yucky prototype.
+ */
+static int generate_sql_clients(rlm_sql_t *inst);
+static size_t sql_escape_func(REQUEST *, char *out, size_t outlen, char const *in, void *arg);
+
+/*
+ * SQL xlat function
+ *
+ * For selects the first value of the first column will be returned,
+ * for inserts, updates and deletes the number of rows affected will be
+ * returned instead.
+ */
+static ssize_t sql_xlat(void *instance, REQUEST *request, char const *query, char *out, size_t freespace)
+{
+ rlm_sql_handle_t *handle = NULL;
+ rlm_sql_row_t row;
+ rlm_sql_t *inst = instance;
+ sql_rcode_t rcode;
+ ssize_t ret = 0;
+ size_t len = 0;
+ char const *p;
+
+ /*
+ * Add SQL-User-Name attribute just in case it is needed
+ * We could search the string fmt for SQL-User-Name to see if this is
+ * needed or not
+ */
+ sql_set_user(inst, request, NULL);
+
+ handle = fr_connection_get(inst->pool); /* connection pool should produce error */
+ if (!handle) return 0;
+
+ rlm_sql_query_log(inst, request, NULL, query);
+
+ /*
+ * Trim whitespace for the prefix check
+ */
+ for (p = query; is_whitespace(p); p++);
+
+ /*
+ * If the query starts with any of the following prefixes,
+ * then return the number of rows affected
+ */
+ if ((strncasecmp(p, "insert", 6) == 0) ||
+ (strncasecmp(p, "update", 6) == 0) ||
+ (strncasecmp(p, "delete", 6) == 0)) {
+ int numaffected;
+ char buffer[21]; /* 64bit max is 20 decimal chars + null byte */
+
+ rcode = rlm_sql_query(inst, request, &handle, query);
+ if (rcode != RLM_SQL_OK) {
+ query_error:
+ RERROR("SQL query failed: %s", fr_int2str(sql_rcode_table, rcode, "<INVALID>"));
+
+ ret = -1;
+ goto finish;
+ }
+
+ numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
+ if (numaffected < 1) {
+ RDEBUG("SQL query affected no rows");
+ (inst->module->sql_finish_query)(handle, inst->config);
+
+ goto finish;
+ }
+
+ /*
+ * Don't chop the returned number if freespace is
+ * too small. This hack is necessary because
+ * some implementations of snprintf return the
+ * size of the written data, and others return
+ * the size of the data they *would* have written
+ * if the output buffer was large enough.
+ */
+ snprintf(buffer, sizeof(buffer), "%d", numaffected);
+
+ len = strlen(buffer);
+ if (len >= freespace){
+ RDEBUG("rlm_sql (%s): Can't write result, insufficient string space", inst->name);
+
+ (inst->module->sql_finish_query)(handle, inst->config);
+
+ ret = -1;
+ goto finish;
+ }
+
+ memcpy(out, buffer, len + 1); /* we did bounds checking above */
+ ret = len;
+
+ (inst->module->sql_finish_query)(handle, inst->config);
+
+ goto finish;
+ } /* else it's a SELECT statement */
+
+ rcode = rlm_sql_select_query(inst, request, &handle, query);
+ if (rcode != RLM_SQL_OK) goto query_error;
+
+ rcode = rlm_sql_fetch_row(inst, request, &handle);
+ if (rcode < 0) {
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ goto query_error;
+ }
+
+ row = handle->row;
+ if (!row) {
+ RDEBUG("SQL query returned no results");
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ ret = -1;
+
+ goto finish;
+ }
+
+ if (!row[0]){
+ RDEBUG("NULL value in first column of result");
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ ret = -1;
+
+ goto finish;
+ }
+
+ len = strlen(row[0]);
+ if (len >= freespace){
+ RDEBUG("Insufficient string space");
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+
+ ret = -1;
+ goto finish;
+ }
+
+ strlcpy(out, row[0], freespace);
+ ret = len;
+
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+
+finish:
+ fr_connection_release(inst->pool, handle);
+
+ return ret;
+}
+
+static int generate_sql_clients(rlm_sql_t *inst)
+{
+ rlm_sql_handle_t *handle;
+ rlm_sql_row_t row;
+ unsigned int i = 0;
+ RADCLIENT *c;
+
+ DEBUG("rlm_sql (%s): Processing generate_sql_clients",
+ inst->name);
+
+ DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
+ inst->name, inst->config->client_query);
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) return -1;
+
+ if (rlm_sql_select_query(inst, NULL, &handle, inst->config->client_query) != RLM_SQL_OK) return -1;
+
+ while ((rlm_sql_fetch_row(inst, NULL, &handle) == RLM_SQL_OK) && (row = handle->row)) {
+ int num_rows;
+ char *server = NULL;
+
+ i++;
+
+ num_rows = (inst->module->sql_num_fields)(handle, inst->config);
+ if (num_rows < 5) {
+ WARN("SELECT returned too few fields. Please do not edit 'client_query'");
+ continue;
+ }
+
+ /*
+ * The return data for each row MUST be in the following order:
+ *
+ * 0. Row ID (currently unused)
+ * 1. Name (or IP address)
+ * 2. Shortname
+ * 3. Type
+ * 4. Secret
+ * 5. Virtual Server (optional)
+ */
+ if (!row[0]){
+ ERROR("rlm_sql (%s): No row id found on pass %d",inst->name,i);
+ continue;
+ }
+ if (!row[1]){
+ ERROR("rlm_sql (%s): No nasname found for row %s",inst->name,row[0]);
+ continue;
+ }
+ if (!row[2]){
+ ERROR("rlm_sql (%s): No short name found for row %s",inst->name,row[0]);
+ continue;
+ }
+ if (!row[4]){
+ ERROR("rlm_sql (%s): No secret found for row %s",inst->name,row[0]);
+ continue;
+ }
+
+ if ((num_rows > 5) && (row[5] != NULL) && *row[5]) {
+ server = row[5];
+ }
+
+ DEBUG("rlm_sql (%s): Adding client %s (%s) to %s clients list",
+ inst->name,
+ row[1], row[2], server ? server : "global");
+
+ /* FIXME: We should really pass a proper ctx */
+ c = client_afrom_query(NULL,
+ row[1], /* identifier */
+ row[4], /* secret */
+ row[2], /* shortname */
+ row[3], /* type */
+ server, /* server */
+ false); /* require message authenticator */
+ if (!c) {
+ continue;
+ }
+
+ if (!client_add(NULL, c)) {
+ WARN("Failed to add client, possible duplicate?");
+
+ client_free(c);
+ continue;
+ }
+
+ DEBUG("rlm_sql (%s): Client \"%s\" (%s) added", c->longname, c->shortname,
+ inst->name);
+ }
+
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ fr_connection_release(inst->pool, handle);
+
+ return 0;
+}
+
+
+/*
+ * Translate the SQL queries.
+ */
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen,
+ char const *in, void *arg)
+{
+ rlm_sql_handle_t *handle = talloc_get_type_abort(arg, rlm_sql_handle_t);
+ rlm_sql_t *inst = handle->inst;
+ size_t len = 0;
+
+ while (in[0]) {
+ size_t utf8_len;
+
+ /*
+ * Allow all multi-byte UTF8 characters.
+ */
+ utf8_len = fr_utf8_char((uint8_t const *) in, -1);
+ if (utf8_len > 1) {
+ if (outlen <= utf8_len) break;
+
+ memcpy(out, in, utf8_len);
+ in += utf8_len;
+ out += utf8_len;
+
+ outlen -= utf8_len;
+ len += utf8_len;
+ continue;
+ }
+
+ /*
+ * Because we register our own escape function
+ * we're now responsible for escaping all special
+ * chars in an xlat expansion or attribute value.
+ */
+ switch (in[0]) {
+ case '\n':
+ if (outlen <= 2) break;
+ out[0] = '\\';
+ out[1] = 'n';
+
+ in++;
+ out += 2;
+ outlen -= 2;
+ len += 2;
+ break;
+
+ case '\r':
+ if (outlen <= 2) break;
+ out[0] = '\\';
+ out[1] = 'r';
+
+ in++;
+ out += 2;
+ outlen -= 2;
+ len += 2;
+ break;
+
+ case '\t':
+ if (outlen <= 2) break;
+ out[0] = '\\';
+ out[1] = 't';
+
+ in++;
+ out += 2;
+ outlen -= 2;
+ len += 2;
+ break;
+ }
+
+ /*
+ * Non-printable characters get replaced with their
+ * mime-encoded equivalents.
+ */
+ if ((in[0] < 32) ||
+ strchr(inst->config->allowed_chars, *in) == NULL) {
+ /*
+ * Only 3 or less bytes available.
+ */
+ if (outlen <= 3) {
+ break;
+ }
+
+ snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
+ in++;
+ out += 3;
+ outlen -= 3;
+ len += 3;
+ continue;
+ }
+
+ /*
+ * Only one byte left.
+ */
+ if (outlen <= 1) {
+ break;
+ }
+
+ /*
+ * Allowed character.
+ */
+ *out = *in;
+ out++;
+ in++;
+ outlen--;
+ len++;
+ }
+ *out = '\0';
+ return len;
+}
+
+/** Passed as the escape function to map_proc and sql xlat methods
+ *
+ * The variant reserves a connection for the escape functions to use, and releases it after
+ * escaping is complete.
+ */
+static size_t sql_escape_for_xlat_func(REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
+{
+ size_t ret;
+ rlm_sql_t *inst = talloc_get_type_abort(arg, rlm_sql_t);
+ rlm_sql_handle_t *handle;
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) {
+ out[0] = '\0';
+ return 0;
+ }
+ ret = inst->sql_escape_func(request, out, outlen, in, handle);
+ fr_connection_release(inst->pool, handle);
+
+ return ret;
+}
+
+/*
+ * Set the SQL user name.
+ *
+ * We don't call the escape function here. The resulting string
+ * will be escaped later in the queries xlat so we don't need to
+ * escape it twice. (it will make things wrong if we have an
+ * escape candidate character in the username)
+ */
+int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username)
+{
+ char *expanded = NULL;
+ VALUE_PAIR *vp = NULL;
+ char const *sqluser;
+ ssize_t len;
+
+ rad_assert(request->packet != NULL);
+
+ if (username != NULL) {
+ sqluser = username;
+ } else if (inst->config->query_user[0] != '\0') {
+ sqluser = inst->config->query_user;
+ } else {
+ return 0;
+ }
+
+ len = radius_axlat(&expanded, request, sqluser, NULL, NULL);
+ if (len < 0) {
+ return -1;
+ }
+
+ vp = fr_pair_afrom_da(request->packet, inst->sql_user);
+ if (!vp) {
+ talloc_free(expanded);
+ return -1;
+ }
+
+ fr_pair_value_strsteal(vp, expanded);
+ RDEBUG2("SQL-User-Name set to '%s'", vp->vp_strvalue);
+ vp->op = T_OP_SET;
+
+ /*
+ * Delete any existing SQL-User-Name, and replace it with ours.
+ */
+ fr_pair_delete_by_num(&request->packet->vps, vp->da->attr, vp->da->vendor, TAG_ANY);
+ fr_pair_add(&request->packet->vps, vp);
+
+ return 0;
+}
+
+/*
+ * Do a set/unset user, so it's a bit clearer what's going on.
+ */
+#define sql_unset_user(_i, _r) fr_pair_delete_by_num(&_r->packet->vps, _i->sql_user->attr, _i->sql_user->vendor, TAG_ANY)
+
+static int sql_get_grouplist(rlm_sql_t *inst, rlm_sql_handle_t **handle, REQUEST *request,
+ rlm_sql_grouplist_t **phead)
+{
+ char *expanded = NULL;
+ int num_groups = 0;
+ rlm_sql_row_t row;
+ rlm_sql_grouplist_t *entry;
+ int ret;
+
+ /* NOTE: sql_set_user should have been run before calling this function */
+
+ entry = *phead = NULL;
+
+ if (!inst->config->groupmemb_query) return 0;
+
+ if (radius_axlat(&expanded, request, inst->config->groupmemb_query, sql_escape_func, *handle) < 0) return -1;
+
+ ret = rlm_sql_select_query(inst, request, handle, expanded);
+ talloc_free(expanded);
+ if (ret != RLM_SQL_OK) return -1;
+
+ while (rlm_sql_fetch_row(inst, request, handle) == RLM_SQL_OK) {
+ row = (*handle)->row;
+ if (!row)
+ break;
+
+ if (!row[0]){
+ RDEBUG("row[0] returned NULL");
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
+ talloc_free(entry);
+ return -1;
+ }
+
+ if (!*phead) {
+ *phead = talloc_zero(*handle, rlm_sql_grouplist_t);
+ entry = *phead;
+ } else {
+ entry->next = talloc_zero(*phead, rlm_sql_grouplist_t);
+ entry = entry->next;
+ }
+ entry->next = NULL;
+ entry->name = talloc_typed_strdup(entry, row[0]);
+
+ num_groups++;
+ }
+
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
+
+ return num_groups;
+}
+
+
+/*
+ * sql groupcmp function. That way we can do group comparisons (in the users file for example)
+ * with the group memberships residing in sql
+ * The group membership query should only return one element which is the username. The returned
+ * username will then be checked with the passed check string.
+ */
+static int sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp,
+ VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs) CC_HINT(nonnull (1, 2, 4));
+
+static int sql_groupcmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *request_vp,
+ VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ rlm_sql_handle_t *handle;
+ rlm_sql_t *inst = instance;
+ rlm_sql_grouplist_t *head, *entry;
+
+ /*
+ * No group queries, don't do group comparisons.
+ */
+ if (!inst->config->groupmemb_query) {
+ RWARN("Cannot do group comparison when group_membership_query is not set");
+ return 1;
+ }
+
+ RDEBUG("sql_groupcmp");
+
+ if (check->vp_length == 0){
+ RDEBUG("sql_groupcmp: Illegal group name");
+ return 1;
+ }
+
+ /*
+ * Set, escape, and check the user attr here
+ */
+ if (sql_set_user(inst, request, NULL) < 0)
+ return 1;
+
+ /*
+ * Get a socket for this lookup
+ */
+ handle = fr_connection_get(inst->pool);
+ if (!handle) {
+ return 1;
+ }
+
+ /*
+ * Get the list of groups this user is a member of
+ */
+ if (sql_get_grouplist(inst, &handle, request, &head) < 0) {
+ REDEBUG("Error getting group membership");
+ fr_connection_release(inst->pool, handle);
+ return 1;
+ }
+
+ for (entry = head; entry != NULL; entry = entry->next) {
+ if (strcmp(entry->name, check->vp_strvalue) == 0){
+ RDEBUG("sql_groupcmp finished: User is a member of group %s",
+ check->vp_strvalue);
+ talloc_free(head);
+ fr_connection_release(inst->pool, handle);
+ return 0;
+ }
+ }
+
+ /* Free the grouplist */
+ talloc_free(head);
+ fr_connection_release(inst->pool, handle);
+
+ RDEBUG("sql_groupcmp finished: User is NOT a member of group %s", check->vp_strvalue);
+
+ return 1;
+}
+
+static rlm_rcode_t rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle,
+ sql_fall_through_t *do_fall_through)
+{
+ rlm_rcode_t rcode = RLM_MODULE_NOOP;
+ VALUE_PAIR *check_tmp = NULL, *reply_tmp = NULL, *sql_group = NULL;
+ rlm_sql_grouplist_t *head = NULL, *entry = NULL;
+
+ char *expanded = NULL;
+ int rows;
+
+ rad_assert(request->packet != NULL);
+
+ if (!inst->config->groupmemb_query) {
+ RWARN("Cannot do check groups when group_membership_query is not set");
+
+ do_nothing:
+ *do_fall_through = FALL_THROUGH_DEFAULT;
+
+ /*
+ * Didn't add group attributes or allocate
+ * memory, so don't do anything else.
+ */
+ return RLM_MODULE_NOTFOUND;
+ }
+
+ /*
+ * Get the list of groups this user is a member of
+ */
+ rows = sql_get_grouplist(inst, handle, request, &head);
+ if (rows < 0) {
+ REDEBUG("Error retrieving group list");
+
+ return RLM_MODULE_FAIL;
+ }
+ if (rows == 0) {
+ RDEBUG2("User not found in any groups");
+ goto do_nothing;
+ }
+ rad_assert(head);
+
+ RDEBUG2("User found in the group table");
+
+ /*
+ * Add the Sql-Group attribute to the request list so we know
+ * which group we're retrieving attributes for
+ */
+ sql_group = pair_make_request(inst->group_da->name, NULL, T_OP_EQ);
+ if (!sql_group) {
+ REDEBUG("Error creating %s attribute", inst->group_da->name);
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ entry = head;
+ do {
+ next:
+ rad_assert(entry != NULL);
+ fr_pair_value_strcpy(sql_group, entry->name);
+
+ if (inst->config->authorize_group_check_query) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ /*
+ * Expand the group query
+ */
+ if (radius_axlat(&expanded, request, inst->config->authorize_group_check_query,
+ inst->sql_escape_func, *handle) < 0) {
+ REDEBUG("Error generating query");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ rows = sql_getvpdata(request, inst, request, handle, &check_tmp, expanded);
+ TALLOC_FREE(expanded);
+ if (rows < 0) {
+ REDEBUG("Error retrieving check pairs for group %s", entry->name);
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ /*
+ * If we got check rows we need to process them before we decide to
+ * process the reply rows
+ */
+ if ((rows > 0) &&
+ (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0)) {
+ fr_pair_list_free(&check_tmp);
+ entry = entry->next;
+
+ if (!entry) break;
+
+ goto next; /* != continue */
+ }
+
+ RDEBUG2("Group \"%s\": Conditional check items matched", entry->name);
+ rcode = RLM_MODULE_OK;
+
+ RDEBUG2("Group \"%s\": Merging assignment check items", entry->name);
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &check_tmp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (!fr_assignment_op[vp->op]) continue;
+
+ rdebug_pair(L_DBG_LVL_2, request, vp, NULL);
+ }
+ REXDENT();
+ radius_pairmove(request, &request->config, check_tmp, true);
+ check_tmp = NULL;
+ }
+
+ if (inst->config->authorize_group_reply_query) {
+ /*
+ * Now get the reply pairs since the paircompare matched
+ */
+ if (radius_axlat(&expanded, request, inst->config->authorize_group_reply_query,
+ inst->sql_escape_func, *handle) < 0) {
+ REDEBUG("Error generating query");
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ rows = sql_getvpdata(request->reply, inst, request, handle, &reply_tmp, expanded);
+ TALLOC_FREE(expanded);
+ if (rows < 0) {
+ REDEBUG("Error retrieving reply pairs for group %s", entry->name);
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ *do_fall_through = fall_through(reply_tmp);
+
+ RDEBUG2("Group \"%s\": Merging reply items", entry->name);
+ rcode = RLM_MODULE_OK;
+
+ rdebug_pair_list(L_DBG_LVL_2, request, reply_tmp, NULL);
+
+ radius_pairmove(request, &request->reply->vps, reply_tmp, true);
+ reply_tmp = NULL;
+ /*
+ * If there's no reply query configured, then we assume
+ * FALL_THROUGH_NO, which is the same as the users file if you
+ * had no reply attributes.
+ */
+ } else {
+ *do_fall_through = FALL_THROUGH_DEFAULT;
+ }
+
+ entry = entry->next;
+ } while (entry != NULL && (*do_fall_through == FALL_THROUGH_YES));
+
+finish:
+ talloc_free(head);
+ fr_pair_delete_by_num(&request->packet->vps, inst->group_da->attr, 0, TAG_ANY);
+
+ return rcode;
+}
+
+
+static int mod_detach(void *instance)
+{
+ rlm_sql_t *inst = instance;
+
+ if (inst->pool) fr_connection_pool_free(inst->pool);
+
+ /*
+ * We need to explicitly free all children, so if the driver
+ * parented any memory off the instance, their destructors
+ * run before we unload the bytecode for them.
+ *
+ * If we don't do this, we get a SEGV deep inside the talloc code
+ * when it tries to call a destructor that no longer exists.
+ */
+ talloc_free_children(inst);
+
+ /*
+ * Decrements the reference count. The driver object won't be unloaded
+ * until all instances of rlm_sql that use it have been destroyed.
+ */
+ if (inst->handle) dlclose(inst->handle);
+
+ return 0;
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_sql_t *inst = instance;
+
+ /*
+ * Hack...
+ */
+ inst->config = &inst->myconfig;
+ inst->cs = conf;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+ /*
+ * Load the appropriate driver for our database.
+ */
+ inst->handle = fr_dlopenext(inst->config->sql_driver_name);
+ if (!inst->handle) {
+ ERROR("Could not link driver %s: %s", inst->config->sql_driver_name, fr_strerror());
+ ERROR("Make sure it (and all its dependent libraries!) are in the search path of your system's ld");
+ return -1;
+ }
+
+ inst->module = (rlm_sql_module_t *) dlsym(inst->handle, inst->config->sql_driver_name);
+ if (!inst->module) {
+ ERROR("Could not link symbol %s: %s", inst->config->sql_driver_name, dlerror());
+ return -1;
+ }
+
+ INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked", inst->name,
+ inst->config->sql_driver_name, inst->module->name);
+
+ if (inst->config->groupmemb_query) {
+ if (cf_section_name2(conf)) {
+ char buffer[256];
+
+ snprintf(buffer, sizeof(buffer), "%s-SQL-Group", inst->name);
+
+ if (paircompare_register_byname(buffer, dict_attrbyvalue(PW_USER_NAME, 0),
+ false, sql_groupcmp, inst) < 0) {
+ ERROR("Error registering group comparison: %s", fr_strerror());
+ return -1;
+ }
+
+ inst->group_da = dict_attrbyname(buffer);
+
+ /*
+ * We're the default instance
+ */
+ } else {
+ if (paircompare_register_byname("SQL-Group", dict_attrbyvalue(PW_USER_NAME, 0),
+ false, sql_groupcmp, inst) < 0) {
+ ERROR("Error registering group comparison: %s", fr_strerror());
+ return -1;
+ }
+
+ inst->group_da = dict_attrbyname("SQL-Group");
+ }
+
+ if (!inst->group_da) {
+ ERROR("Failed resolving group attribute");
+ return -1;
+ }
+ }
+
+ /*
+ * Register the SQL xlat function
+ */
+ xlat_register(inst->name, sql_xlat, sql_escape_for_xlat_func, inst);
+
+ return 0;
+}
+
+
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ int rcode;
+ rlm_sql_t *inst = instance;
+ rlm_sql_handle_t *handle;
+
+ /*
+ * Connections cannot be alloced from the inst or
+ * pool contexts due to threading issues.
+ */
+ handle = talloc_zero(ctx, rlm_sql_handle_t);
+ if (!handle) return NULL;
+
+ handle->log_ctx = talloc_pool(handle, 2048);
+ if (!handle->log_ctx) {
+ talloc_free(handle);
+ return NULL;
+ }
+
+ /*
+ * Handle requires a pointer to the SQL inst so the
+ * destructor has access to the module configuration.
+ */
+ handle->inst = inst;
+
+ rcode = (inst->module->sql_socket_init)(handle, inst->config);
+ if (rcode != 0) {
+ fail:
+ exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
+
+ /*
+ * Destroy any half opened connections.
+ */
+ talloc_free(handle);
+ return NULL;
+ }
+
+ if (inst->config->connect_query) {
+ if (rlm_sql_select_query(inst, NULL, &handle, inst->config->connect_query) != RLM_SQL_OK) goto fail;
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ }
+
+ return handle;
+}
+
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_sql_t *inst = instance;
+
+ /*
+ * Complain if the strings exist, but are empty.
+ */
+#define CHECK_STRING(_x) if (inst->config->_x && !inst->config->_x[0]) \
+do { \
+ WARN("rlm_sql (%s): " STRINGIFY(_x) " is empty. Please delete it from the configuration", inst->name);\
+ inst->config->_x = NULL;\
+} while (0)
+
+ CHECK_STRING(groupmemb_query);
+ CHECK_STRING(authorize_check_query);
+ CHECK_STRING(authorize_reply_query);
+ CHECK_STRING(authorize_group_check_query);
+ CHECK_STRING(authorize_group_reply_query);
+ CHECK_STRING(simul_count_query);
+ CHECK_STRING(simul_verify_query);
+ CHECK_STRING(connect_query);
+ CHECK_STRING(client_query);
+ if (strncmp(inst->config->sql_driver_name, "rlm_sql_", 8) != 0) {
+ ERROR("rlm_sql (%s): \"%s\" is NOT an SQL driver!", inst->name, inst->config->sql_driver_name);
+ return -1;
+ }
+
+ /*
+ * We need authorize_group_check_query or authorize_group_reply_query
+ * if group_membership_query is set.
+ *
+ * Or we need group_membership_query if authorize_group_check_query or
+ * authorize_group_reply_query is set.
+ */
+ if (!inst->config->groupmemb_query) {
+ if (inst->config->authorize_group_check_query) {
+ WARN("rlm_sql (%s): Ignoring authorize_group_reply_query as group_membership_query "
+ "is not configured", inst->name);
+ }
+
+ if (inst->config->authorize_group_reply_query) {
+ WARN("rlm_sql (%s): Ignoring authorize_group_check_query as group_membership_query "
+ "is not configured", inst->name);
+ }
+
+ if (!inst->config->read_groups) {
+ WARN("rlm_sql (%s): Ignoring read_groups as group_membership_query "
+ "is not configured", inst->name);
+ inst->config->read_groups = false;
+ }
+ } /* allow the group check / reply queries to be NULL */
+
+ /*
+ * This will always exist, as cf_section_parse_init()
+ * will create it if it doesn't exist. However, the
+ * "reference" config item won't exist in an auto-created
+ * configuration. So if that doesn't exist, we ignore
+ * the whole subsection.
+ */
+ inst->config->accounting.cs = cf_section_sub_find(conf, "accounting");
+ inst->config->accounting.reference_cp = (cf_pair_find(inst->config->accounting.cs, "reference") != NULL);
+
+ inst->config->postauth.cs = cf_section_sub_find(conf, "post-auth");
+ inst->config->postauth.reference_cp = (cf_pair_find(inst->config->postauth.cs, "reference") != NULL);
+
+ /*
+ * Cache the SQL-User-Name DICT_ATTR, so we can be slightly
+ * more efficient about creating SQL-User-Name attributes.
+ */
+ inst->sql_user = dict_attrbyname("SQL-User-Name");
+ if (!inst->sql_user) {
+ return -1;
+ }
+
+ /*
+ * Export these methods, too. This avoids RTDL_GLOBAL.
+ */
+ inst->sql_set_user = sql_set_user;
+ inst->sql_query = rlm_sql_query;
+ inst->sql_select_query = rlm_sql_select_query;
+ inst->sql_fetch_row = rlm_sql_fetch_row;
+
+ /*
+ * Either use the module specific escape function
+ * or our default one.
+ */
+ inst->sql_escape_func = inst->module->sql_escape_func && inst->config->driver_specific_escape ?
+ inst->module->sql_escape_func :
+ sql_escape_func;
+
+ if (inst->module->mod_instantiate) {
+ CONF_SECTION *cs;
+ char const *name;
+
+ name = strrchr(inst->config->sql_driver_name, '_');
+ if (!name) {
+ name = inst->config->sql_driver_name;
+ } else {
+ name++;
+ }
+
+ cs = cf_section_sub_find(conf, name);
+ if (!cs) {
+ cs = cf_section_alloc(conf, name, NULL);
+ if (!cs) {
+ return -1;
+ }
+ }
+
+ /*
+ * It's up to the driver to register a destructor
+ */
+ if (inst->module->mod_instantiate(cs, inst->config) < 0) {
+ return -1;
+ }
+ }
+
+ inst->ef = exfile_init(inst, 256, 30, true);
+ if (!inst->ef) {
+ cf_log_err_cs(conf, "Failed creating log file context");
+ return -1;
+ }
+
+ /*
+ * Initialise the connection pool for this instance
+ */
+ INFO("rlm_sql (%s): Attempting to connect to database \"%s\"", inst->name, inst->config->sql_db);
+
+ inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL);
+ if (!inst->pool) return -1;
+
+ if (inst->config->do_clients) {
+ if (generate_sql_clients(inst) == -1){
+ ERROR("Failed to load clients from SQL");
+ return -1;
+ }
+ }
+
+ return RLM_MODULE_OK;
+}
+
+static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_NOOP;
+
+ rlm_sql_t *inst = instance;
+ rlm_sql_handle_t *handle;
+
+ VALUE_PAIR *check_tmp = NULL;
+ VALUE_PAIR *reply_tmp = NULL;
+ VALUE_PAIR *user_profile = NULL;
+
+ bool user_found = false;
+
+ sql_fall_through_t do_fall_through = FALL_THROUGH_DEFAULT;
+
+ int rows;
+
+ char *expanded = NULL;
+
+ rad_assert(request->packet != NULL);
+ rad_assert(request->reply != NULL);
+
+ if (!inst->config->authorize_check_query && !inst->config->authorize_reply_query &&
+ !inst->config->read_groups && !inst->config->read_profiles) {
+ RWDEBUG("No authorization checks configured, returning noop");
+
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Set, escape, and check the user attr here
+ */
+ if (sql_set_user(inst, request, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Reserve a socket
+ *
+ * After this point use goto error or goto release to cleanup socket temporary pairlists and
+ * temporary attributes.
+ */
+ handle = fr_connection_get(inst->pool);
+ if (!handle) {
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ /*
+ * Query the check table to find any conditions associated with this user/realm/whatever...
+ */
+ if (inst->config->authorize_check_query) {
+ vp_cursor_t cursor;
+ VALUE_PAIR *vp;
+
+ if (radius_axlat(&expanded, request, inst->config->authorize_check_query,
+ inst->sql_escape_func, handle) < 0) {
+ REDEBUG("Error generating query");
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ rows = sql_getvpdata(request, inst, request, &handle, &check_tmp, expanded);
+ TALLOC_FREE(expanded);
+ if (rows < 0) {
+ REDEBUG("Error getting check attributes");
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ if (rows == 0) {
+ RWDEBUG2("User not found in radcheck table.");
+ goto skipreply; /* Don't need to free VPs we don't have */
+ }
+
+ /*
+ * Only do this if *some* check pairs were returned
+ */
+ RDEBUG2("User found in radcheck table");
+ user_found = true;
+ if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0) {
+ RWDEBUG2("check items do not match.");
+ fr_pair_list_free(&check_tmp);
+ check_tmp = NULL;
+ goto skipreply;
+ }
+
+ RDEBUG2("Conditional check items matched, merging assignment check items");
+ RINDENT();
+ for (vp = fr_cursor_init(&cursor, &check_tmp);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (!fr_assignment_op[vp->op]) continue;
+
+ rdebug_pair(2, request, vp, NULL);
+ }
+ REXDENT();
+ radius_pairmove(request, &request->config, check_tmp, true);
+
+ rcode = RLM_MODULE_OK;
+ check_tmp = NULL;
+ }
+
+ if (inst->config->authorize_reply_query) {
+ /*
+ * Now get the reply pairs since the paircompare matched
+ */
+ if (radius_axlat(&expanded, request, inst->config->authorize_reply_query,
+ inst->sql_escape_func, handle) < 0) {
+ REDEBUG("Error generating query");
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ rows = sql_getvpdata(request->reply, inst, request, &handle, &reply_tmp, expanded);
+ TALLOC_FREE(expanded);
+ if (rows < 0) {
+ REDEBUG("SQL query error getting reply attributes");
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ if (rows == 0) goto skipreply;
+
+ do_fall_through = fall_through(reply_tmp);
+
+ RDEBUG2("User found in radreply table, merging reply items");
+ user_found = true;
+
+ rdebug_pair_list(L_DBG_LVL_2, request, reply_tmp, NULL);
+
+ radius_pairmove(request, &request->reply->vps, reply_tmp, true);
+
+ rcode = RLM_MODULE_OK;
+ reply_tmp = NULL;
+ }
+
+skipreply:
+ if ((do_fall_through == FALL_THROUGH_YES) ||
+ (inst->config->read_groups && (do_fall_through == FALL_THROUGH_DEFAULT))) {
+ rlm_rcode_t ret;
+
+ RDEBUG3("... falling-through to group processing");
+ ret = rlm_sql_process_groups(inst, request, &handle, &do_fall_through);
+ switch (ret) {
+ /*
+ * Nothing bad happened, continue...
+ */
+ case RLM_MODULE_UPDATED:
+ rcode = RLM_MODULE_UPDATED;
+ /* FALL-THROUGH */
+ case RLM_MODULE_OK:
+ if (rcode != RLM_MODULE_UPDATED) {
+ rcode = RLM_MODULE_OK;
+ }
+ /* FALL-THROUGH */
+ case RLM_MODULE_NOOP:
+ user_found = true;
+ break;
+
+ case RLM_MODULE_NOTFOUND:
+ break;
+
+ default:
+ rcode = ret;
+ goto release;
+ }
+ }
+
+ /*
+ * Repeat the above process with the default profile or User-Profile
+ */
+ if ((do_fall_through == FALL_THROUGH_YES) ||
+ (inst->config->read_profiles && (do_fall_through == FALL_THROUGH_DEFAULT))) {
+ rlm_rcode_t ret;
+
+ /*
+ * Check for a default_profile or for a User-Profile.
+ */
+ RDEBUG3("... falling-through to profile processing");
+ user_profile = fr_pair_find_by_num(request->config, PW_USER_PROFILE, 0, TAG_ANY);
+
+ char const *profile = user_profile ?
+ user_profile->vp_strvalue :
+ inst->config->default_profile;
+
+ if (!profile || !*profile) {
+ goto release;
+ }
+
+ RDEBUG2("Checking profile %s", profile);
+
+ if (sql_set_user(inst, request, profile) < 0) {
+ REDEBUG("Error setting profile");
+ rcode = RLM_MODULE_FAIL;
+ goto error;
+ }
+
+ ret = rlm_sql_process_groups(inst, request, &handle, &do_fall_through);
+ switch (ret) {
+ /*
+ * Nothing bad happened, continue...
+ */
+ case RLM_MODULE_UPDATED:
+ rcode = RLM_MODULE_UPDATED;
+ /* FALL-THROUGH */
+ case RLM_MODULE_OK:
+ if (rcode != RLM_MODULE_UPDATED) {
+ rcode = RLM_MODULE_OK;
+ }
+ /* FALL-THROUGH */
+ case RLM_MODULE_NOOP:
+ user_found = true;
+ break;
+
+ case RLM_MODULE_NOTFOUND:
+ break;
+
+ default:
+ rcode = ret;
+ goto release;
+ }
+ }
+
+ /*
+ * At this point the key (user) hasn't been found in the check table, the reply table
+ * or the group mapping table, and there was no matching profile.
+ */
+release:
+ if (!user_found) {
+ rcode = RLM_MODULE_NOTFOUND;
+ }
+
+ fr_connection_release(inst->pool, handle);
+ sql_unset_user(inst, request);
+
+ return rcode;
+
+error:
+ fr_pair_list_free(&check_tmp);
+ fr_pair_list_free(&reply_tmp);
+ sql_unset_user(inst, request);
+
+ fr_connection_release(inst->pool, handle);
+
+ return rcode;
+}
+
+/*
+ * Generic function for failing between a bunch of queries.
+ *
+ * Uses the same principle as rlm_linelog, expanding the 'reference' config
+ * item using xlat to figure out what query it should execute.
+ *
+ * If the reference matches multiple config items, and a query fails or
+ * doesn't update any rows, the next matching config item is used.
+ *
+ */
+static int acct_redundant(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+
+ rlm_sql_handle_t *handle = NULL;
+ int sql_ret;
+ int numaffected = 0;
+
+ CONF_ITEM *item;
+ CONF_PAIR *pair;
+ char const *attr = NULL;
+ char const *value;
+
+ char path[MAX_STRING_LEN];
+ char *p = path;
+ char *expanded = NULL;
+
+ rad_assert(section);
+
+ if (section->reference[0] != '.') {
+ *p++ = '.';
+ }
+
+ if (radius_xlat(p, sizeof(path) - (p - path), request, section->reference, NULL, NULL) < 0) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ /*
+ * If we can't find a matching config item we do
+ * nothing so return RLM_MODULE_NOOP.
+ */
+ item = cf_reference_item(NULL, section->cs, path);
+ if (!item) {
+ RWDEBUG("No such configuration item %s", path);
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+ if (cf_item_is_section(item)){
+ RWDEBUG("Sections are not supported as references");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ pair = cf_item_to_pair(item);
+ attr = cf_pair_attr(pair);
+
+ RDEBUG2("Using query template '%s'", attr);
+
+ handle = fr_connection_get(inst->pool);
+ if (!handle) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ sql_set_user(inst, request, NULL);
+
+ while (true) {
+ value = cf_pair_value(pair);
+ if (!value) {
+ RDEBUG("Ignoring null query");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ if (radius_axlat(&expanded, request, value, inst->sql_escape_func, handle) < 0) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (!*expanded) {
+ RDEBUG("Ignoring null query");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ rlm_sql_query_log(inst, request, section, expanded);
+
+ sql_ret = rlm_sql_query(inst, request, &handle, expanded);
+ TALLOC_FREE(expanded);
+ RDEBUG("SQL query returned: %s", fr_int2str(sql_rcode_table, sql_ret, "<INVALID>"));
+
+ switch (sql_ret) {
+ /*
+ * Query was a success! Now we just need to check if it did anything.
+ */
+ case RLM_SQL_OK:
+ break;
+
+ /*
+ * A general, unrecoverable server fault.
+ */
+ case RLM_SQL_ERROR:
+ /*
+ * If we get RLM_SQL_RECONNECT it means all connections in the pool
+ * were exhausted and we couldn't create a new connection,
+ * so we do not need to call fr_connection_release.
+ */
+ case RLM_SQL_RECONNECT:
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+
+ /*
+ * Query was invalid, this is a terminal error, but we still need
+ * to do cleanup, as the connection handle is still valid.
+ */
+ case RLM_SQL_QUERY_INVALID:
+ rcode = RLM_MODULE_INVALID;
+ goto finish;
+
+ /*
+ * Driver found an error (like a unique key constraint violation)
+ * that hinted it might be a good idea to try an alternative query.
+ */
+ case RLM_SQL_ALT_QUERY:
+ goto next;
+ }
+ rad_assert(handle);
+
+ /*
+ * We need to have updated something for the query to have been
+ * counted as successful.
+ */
+ numaffected = (inst->module->sql_affected_rows)(handle, inst->config);
+ (inst->module->sql_finish_query)(handle, inst->config);
+ RDEBUG("%i record(s) updated", numaffected);
+
+ if (numaffected > 0) break; /* A query succeeded, we're done! */
+ next:
+ /*
+ * We assume all entries with the same name form a redundant
+ * set of queries.
+ */
+ pair = cf_pair_find_next(section->cs, pair, attr);
+
+ if (!pair) {
+ char const *name;
+
+ /*
+ * Hack for RADIUS!
+ */
+ name = cf_section_name1(section->cs);
+ if ((strcmp(name, "accounting-on") == 0) ||
+ (strcmp(name, "accounting-off") == 0)) {
+ RDEBUG("Accounting on/off had no updates. Returning 'ok'");
+ rcode = RLM_MODULE_OK;
+ goto finish;
+ }
+
+
+ RDEBUG("No additional queries configured");
+ rcode = RLM_MODULE_NOOP;
+
+ goto finish;
+ }
+
+ RDEBUG("Trying next query...");
+ }
+
+
+finish:
+ talloc_free(expanded);
+ fr_connection_release(inst->pool, handle);
+ sql_unset_user(inst, request);
+
+ return rcode;
+}
+
+#ifdef WITH_ACCOUNTING
+
+/*
+ * Accounting: Insert or update session data in our sql table
+ */
+static rlm_rcode_t mod_accounting(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
+{
+ rlm_sql_t *inst = instance;
+
+ if (inst->config->accounting.reference_cp) {
+ return acct_redundant(inst, request, &inst->config->accounting);
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+#endif
+
+#ifdef WITH_SESSION_MGMT
+/*
+ * See if a user is already logged in. Sets request->simul_count to the
+ * current session count for this user.
+ *
+ * Check twice. If on the first pass the user exceeds his
+ * max. number of logins, do a second pass and validate all
+ * logins by querying the terminal server (using eg. SNMP).
+ */
+static rlm_rcode_t mod_checksimul(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_checksimul(void *instance, REQUEST * request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ rlm_sql_handle_t *handle = NULL;
+ rlm_sql_t *inst = instance;
+ rlm_sql_row_t row;
+ int check = 0;
+ uint32_t ipno = 0;
+ char const *call_num = NULL;
+ VALUE_PAIR *vp;
+ int ret;
+ fr_ipaddr_t nas_addr;
+ char const *nas_port_id = NULL;
+
+ char *expanded = NULL;
+
+ /* If simul_count_query is not defined, we don't do any checking */
+ if (!inst->config->simul_count_query) {
+ RWDEBUG("Simultaneous-Use checking requires 'simul_count_query' to be configured");
+ return RLM_MODULE_NOOP;
+ }
+
+ if ((!request->username) || (request->username->vp_length == 0)) {
+ REDEBUG("Zero Length username not permitted");
+
+ return RLM_MODULE_INVALID;
+ }
+
+ if (sql_set_user(inst, request, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /* initialize the sql socket */
+ handle = fr_connection_get(inst->pool);
+ if (!handle) {
+ talloc_free(expanded);
+ sql_unset_user(inst, request);
+ return RLM_MODULE_FAIL;
+ }
+
+ if (radius_axlat(&expanded, request, inst->config->simul_count_query, inst->sql_escape_func, handle) < 0) {
+ sql_unset_user(inst, request);
+ return RLM_MODULE_FAIL;
+ }
+
+ if (rlm_sql_select_query(inst, request, &handle, expanded) != RLM_SQL_OK) {
+ rcode = RLM_MODULE_FAIL;
+ goto release; /* handle may no longer be valid */
+ }
+
+ ret = rlm_sql_fetch_row(inst, request, &handle);
+ if (ret != 0) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ row = handle->row;
+ if (!row) {
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+
+ request->simul_count = atoi(row[0]);
+
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+ TALLOC_FREE(expanded);
+
+ if (request->simul_count < request->simul_max) {
+ rcode = RLM_MODULE_OK;
+ goto finish;
+ }
+
+ /*
+ * Looks like too many sessions, so let's start verifying
+ * them, unless told to rely on count query only.
+ */
+ if (!inst->config->simul_verify_query) {
+ rcode = RLM_MODULE_OK;
+
+ goto finish;
+ }
+
+ if (radius_axlat(&expanded, request, inst->config->simul_verify_query, inst->sql_escape_func, handle) < 0) {
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (rlm_sql_select_query(inst, request, &handle, expanded) != RLM_SQL_OK) goto release;
+
+ /*
+ * Setup some stuff, like for MPP detection.
+ */
+ request->simul_count = 0;
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL) {
+ ipno = vp->vp_ipaddr;
+ }
+
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL) {
+ call_num = vp->vp_strvalue;
+ }
+
+ while (rlm_sql_fetch_row(inst, request, &handle) == RLM_SQL_OK) {
+ int num_rows;
+
+ row = handle->row;
+ if (!row) {
+ break;
+ }
+
+ num_rows = (inst->module->sql_num_fields)(handle, inst->config);
+ if (num_rows < 8) {
+ RDEBUG("Too few rows returned. Please do not edit 'simul_verify_query'");
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (!row[2]){
+ RDEBUG("Cannot zap stale entry. No username present in entry");
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (!row[1]){
+ RDEBUG("Cannot zap stale entry. No session id in entry");
+ rcode = RLM_MODULE_FAIL;
+
+ goto finish;
+ }
+
+ if (row[3]) {
+ if (fr_pton(&nas_addr, row[3], -1, AF_UNSPEC, false) < 0) {
+ RDEBUG("Cannot parse '%s' as an IPv4 or an IPv6 address - %s", row[3], fr_strerror());
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+
+ nas_port_id = row[4];
+
+ check = rad_check_ts(&nas_addr, 0, nas_port_id, row[2], row[1]);
+ if (check == 0) {
+ /*
+ * Stale record - zap it.
+ */
+ if (inst->config->delete_stale_sessions == true) {
+ uint32_t framed_addr = 0;
+ char proto = 0;
+ int sess_time = 0;
+
+ if (row[5])
+ framed_addr = inet_addr(row[5]);
+ if (row[7]){
+ if (strcmp(row[7], "PPP") == 0)
+ proto = 'P';
+ else if (strcmp(row[7], "SLIP") == 0)
+ proto = 'S';
+ }
+ if ((num_rows > 8) && row[8])
+ sess_time = atoi(row[8]);
+ session_zap(request, &nas_addr, 0, nas_port_id,
+ row[2], row[1], framed_addr,
+ proto, sess_time);
+ }
+ }
+ else if (check == 1) {
+ /*
+ * User is still logged in.
+ */
+ ++request->simul_count;
+
+ /*
+ * Does it look like a MPP attempt?
+ */
+ if (row[5] && ipno && inet_addr(row[5]) == ipno) {
+ request->simul_mpp = 2;
+ } else if (row[6] && call_num && !strncmp(row[6],call_num,16)) {
+ request->simul_mpp = 2;
+ }
+ } else {
+ /*
+ * Failed to check the terminal server for
+ * duplicate logins: return an error.
+ */
+ REDEBUG("Failed to check the terminal server for user '%s'.", row[2]);
+
+ rcode = RLM_MODULE_FAIL;
+ goto finish;
+ }
+ }
+
+finish:
+ (inst->module->sql_finish_select_query)(handle, inst->config);
+release:
+ fr_connection_release(inst->pool, handle);
+ talloc_free(expanded);
+ sql_unset_user(inst, request);
+
+ /*
+ * The Auth module apparently looks at request->simul_count,
+ * not the return value of this module when deciding to deny
+ * a call for too many sessions.
+ */
+ return rcode;
+}
+#endif
+
+/*
+ * Postauth: Write a record of the authentication attempt
+ */
+static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull);
+static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_sql_t *inst = instance;
+
+ if (inst->config->postauth.reference_cp) {
+ return acct_redundant(inst, request, &inst->config->postauth);
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+/*
+ * Execute postauth_query after authentication
+ */
+
+
+/* globally exported name */
+extern module_t rlm_sql;
+module_t rlm_sql = {
+ .magic = RLM_MODULE_INIT,
+ .name = "sql",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_sql_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_ACCOUNTING
+ [MOD_ACCOUNTING] = mod_accounting,
+#endif
+#ifdef WITH_SESSION_MGMT
+ [MOD_SESSION] = mod_checksimul,
+#endif
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_sql/rlm_sql.h b/src/modules/rlm_sql/rlm_sql.h
new file mode 100644
index 0000000..5af8db4
--- /dev/null
+++ b/src/modules/rlm_sql/rlm_sql.h
@@ -0,0 +1,258 @@
+/*
+ * 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_sql.h
+ * @brief Prototypes and functions for the SQL module
+ *
+ * @copyright 2012-2014 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Mike Machado <mike@innercite.com>
+ * @copyright 2000 Alan DeKok <aland@ox.org>
+ */
+#ifndef _RLM_SQL_H
+#define _RLM_SQL_H
+
+RCSIDH(rlm_sql_h, "$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/connection.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/exfile.h>
+
+#define MOD_PREFIX "rlm_sql"
+
+#define PW_ITEM_CHECK 0
+#define PW_ITEM_REPLY 1
+
+
+/* SQL Errors */
+typedef enum {
+ RLM_SQL_QUERY_INVALID = -3, //!< Query syntax error.
+ RLM_SQL_ERROR = -2, //!< General connection/server error.
+ RLM_SQL_OK = 0, //!< Success.
+ RLM_SQL_RECONNECT = 1, //!< Stale connection, should reconnect.
+ RLM_SQL_ALT_QUERY, //!< Key constraint violation, use an alternative query.
+ RLM_SQL_NO_MORE_ROWS, //!< No more rows available
+} sql_rcode_t;
+
+typedef enum {
+ FALL_THROUGH_NO = 0,
+ FALL_THROUGH_YES,
+ FALL_THROUGH_DEFAULT,
+} sql_fall_through_t;
+
+
+typedef char **rlm_sql_row_t;
+
+typedef struct sql_log_entry {
+ log_type_t type; //!< Type of log entry L_ERR, L_WARN, L_INFO, L_DBG etc..
+ char const *msg; //!< Log message.
+} sql_log_entry_t;
+
+/*
+ * Sections where we dynamically resolve the config entry to use,
+ * by xlating reference.
+ */
+typedef struct sql_acct_section {
+ CONF_SECTION *cs; //!< The CONF_SECTION representing the group
+ //!< of queries to process.
+
+ char const *reference; //!< Reference string, expanded to point to
+ //!< a group of queries.
+ bool reference_cp;
+
+ char const *logfile;
+
+ char const *query; /* for xlat parsing */
+} sql_acct_section_t;
+
+typedef struct sql_config {
+ char const *sql_driver_name; //!< SQL driver module name e.g. rlm_sql_sqlite.
+ char const *sql_server; //!< Server to connect to.
+ uint32_t sql_port; //!< Port to connect to.
+ char const *sql_login; //!< Login credentials to use.
+ char const *sql_password; //!< Login password to use.
+ char const *sql_db; //!< Database to run queries against.
+
+ char const *query_user; //!< xlat expansion used to specify the user
+ //!< to use as the subject of queries.
+
+ char const *default_profile; //!< Default profile to use if no other
+ //!< profiles were configured.
+
+ char const *client_query; //!< Query used to get FreeRADIUS client
+ //!< definitions.
+
+ char const *authorize_check_query; //!< Query used get check VPs for a user.
+ char const *authorize_reply_query; //!< Query used get reply VPs for a user.
+ char const *authorize_group_check_query; //!< Query used get check VPs for a group.
+ char const *authorize_group_reply_query; //!< Query used get reply VPs for a group.
+ char const *simul_count_query; //!< Query used get number of active sessions
+ //!< for a user (basic simultaneous use check).
+ char const *simul_verify_query; //!< Query to get active sessions for a user
+ //!< the result is fed to session_zap.
+ char const *groupmemb_query; //!< Query to determine group membership.
+
+ bool do_clients; //!< Read clients from SQL database.
+ bool read_groups; //!< Read user groups by default.
+ //!< If false, Fall-Through = yes is required
+ //!< in the previous reply list to process
+ //!< groups.
+ bool read_profiles; //!< Read user profiles by default.
+ //!< If false, Fall-Through = yes is required
+ //!< in the previous reply list to process
+ //!< profiles.
+ char const *logfile; //!< Keep a log of all SQL queries executed
+ //!< Useful for batch insertion with the
+ //!< NULL drivers.
+
+ bool delete_stale_sessions; //!< Whether we should use session_zap to create
+ //!< a fake stop packet, to terminate any
+ //!< stale sessions.
+
+ char const *allowed_chars; //!< Chars which done need escaping..
+ bool driver_specific_escape; //!< Use the driver specific SQL escape method
+ uint32_t query_timeout; //!< How long to allow queries to run for.
+
+ char const *connect_query; //!< Query executed after establishing
+ //!< new connection.
+ struct timeval connect_timeout_tv; //!< Connection timeout timeval.
+ uint32_t connect_timeout_ms; //!< Connection timeout ms.
+ uint32_t connect_timeout_s; //!< Connection timeout in seconds.
+
+ void *driver; //!< Where drivers should write a
+ //!< pointer to their configurations.
+
+ /*
+ * @todo The rest of the queries should also be moved into
+ * their own sections.
+ */
+
+ /*
+ * Section configurations
+ */
+ sql_acct_section_t postauth;
+ sql_acct_section_t accounting;
+} rlm_sql_config_t;
+
+typedef struct sql_inst rlm_sql_t;
+
+typedef struct rlm_sql_handle {
+ void *conn; //!< Database specific connection handle.
+ rlm_sql_row_t row; //!< Row data from the last query.
+ rlm_sql_t *inst; //!< The rlm_sql instance this connection belongs to.
+ TALLOC_CTX *log_ctx; //!< Talloc pool used to avoid mallocing memory on
+ //!< when log strings need to be copied.
+} rlm_sql_handle_t;
+
+extern const FR_NAME_NUMBER sql_rcode_table[];
+/*
+ * Capabilities flags for drivers
+ */
+#define RLM_SQL_RCODE_FLAGS_ALT_QUERY 1 //!< Can distinguish between other errors and those
+ //!< resulting from a unique key violation.
+
+/** Retrieve errors from the last query operation
+ *
+ * @note Buffers allocated in the context provided will be automatically freed. The driver
+ * should not free these buffers explicitly.
+ * @note If the driver uses its own buffers to aggregate messages, they should be cleared
+ * on sql_query_finish, and after each call to sql_error, to prevent the same messages
+ * being printed multiple times.
+ *
+ * @param[in,out] ctx to allocate any buffers required. If static buffers are provided by the
+ * driver they need not be strduped, just write the pointer to those buffers to the .msg
+ * field of a sql_log_entry_t element.
+ * @param[out] out a pre-allocated array of log entries to fill. Need not be NULL terminated.
+ * @param[in] outlen Number of log entries available for populating. Do not write to index
+ * out[outlen] or higher.
+ * @param[in] handle to retrieve errors from.
+ * @param[in] config of the SQL instance.
+ * @return
+ * 0 - If no error messages are available.
+ * >0 - Number of log entries
+ */
+typedef size_t (*sql_error_t)(TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle,
+ rlm_sql_config_t *config);
+
+typedef struct rlm_sql_module_t {
+ char const *name;
+ int flags;
+
+ sql_rcode_t (*mod_instantiate)(CONF_SECTION *conf, rlm_sql_config_t *config);
+ sql_rcode_t (*sql_socket_init)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+ sql_rcode_t (*sql_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
+ sql_rcode_t (*sql_select_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query);
+ sql_rcode_t (*sql_store_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+ int (*sql_num_fields)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+ int (*sql_num_rows)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+ int (*sql_affected_rows)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+ sql_rcode_t (*sql_fetch_row)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+ sql_rcode_t (*sql_free_result)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+ sql_error_t sql_error; //!< Get any errors from the previous query.
+
+ sql_rcode_t (*sql_finish_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+ sql_rcode_t (*sql_finish_select_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
+
+ xlat_escape_t sql_escape_func;
+} rlm_sql_module_t;
+
+struct sql_inst {
+ rlm_sql_config_t myconfig; /* HACK */
+ fr_connection_pool_t *pool;
+ rlm_sql_config_t *config;
+ CONF_SECTION *cs;
+
+ DICT_ATTR const *sql_user; //!< Cached pointer to SQL-User-Name
+ //!< dictionary attribute.
+ exfile_t *ef;
+
+ void *handle;
+ rlm_sql_module_t *module;
+
+ int (*sql_set_user)(rlm_sql_t *inst, REQUEST *request, char const *username);
+ size_t (*sql_escape_func)(REQUEST *, char *out, size_t outlen, char const *in, void *arg);
+ sql_rcode_t (*sql_query)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
+ sql_rcode_t (*sql_select_query)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
+ sql_rcode_t (*sql_fetch_row)(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle);
+
+ char const *name; //!< Module instance name.
+ DICT_ATTR const *group_da;
+};
+
+typedef struct sql_grouplist {
+ char *name;
+ struct sql_grouplist *next;
+} rlm_sql_grouplist_t;
+
+int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **first_pair, rlm_sql_row_t row);
+int sql_read_realms(rlm_sql_handle_t *handle);
+int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, VALUE_PAIR **pair, char const *query);
+int sql_read_clients(rlm_sql_handle_t *handle);
+int sql_dict_init(rlm_sql_handle_t *handle);
+void CC_HINT(nonnull (1, 2, 4)) rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section, char const *query);
+sql_rcode_t CC_HINT(nonnull (1, 3, 4)) rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
+sql_rcode_t CC_HINT(nonnull (1, 3, 4)) rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query);
+int rlm_sql_fetch_row(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle);
+void rlm_sql_print_error(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, bool force_debug);
+int sql_set_user(rlm_sql_t *inst, REQUEST *request, char const *username);
+#endif
diff --git a/src/modules/rlm_sql/rlm_sql.mk b/src/modules/rlm_sql/rlm_sql.mk
new file mode 100644
index 0000000..319326c
--- /dev/null
+++ b/src/modules/rlm_sql/rlm_sql.mk
@@ -0,0 +1,5 @@
+TARGET := rlm_sql.a
+SOURCES := rlm_sql.c sql.c
+
+SRC_CFLAGS := $(rlm_sql_CFLAGS)
+TGT_LDLIBS := $(rlm_sql_LDLIBS)
diff --git a/src/modules/rlm_sql/sql.c b/src/modules/rlm_sql/sql.c
new file mode 100644
index 0000000..a18e00b
--- /dev/null
+++ b/src/modules/rlm_sql/sql.c
@@ -0,0 +1,516 @@
+/*
+ * sql.c rlm_sql - FreeRADIUS SQL Module
+ * Main code directly taken from ICRADIUS
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2001,2006 The FreeRADIUS server project
+ * Copyright 2000 Mike Machado <mike@innercite.com>
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ * Copyright 2001 Chad Miller <cmiller@surfsouth.com>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+
+#include "rlm_sql.h"
+
+#ifdef HAVE_PTHREAD_H
+#endif
+
+/*
+ * Translate rlm_sql rcodes to humanly
+ * readable reason strings.
+ */
+const FR_NAME_NUMBER sql_rcode_table[] = {
+ { "success", RLM_SQL_OK },
+ { "need alt query", RLM_SQL_ALT_QUERY },
+ { "server error", RLM_SQL_ERROR },
+ { "query invalid", RLM_SQL_QUERY_INVALID },
+ { "no connection", RLM_SQL_RECONNECT },
+ { "no more rows", RLM_SQL_NO_MORE_ROWS },
+ { NULL, 0 }
+};
+
+
+/*************************************************************************
+ *
+ * Function: sql_fr_pair_list_afrom_str
+ *
+ * Purpose: Read entries from the database and fill VALUE_PAIR structures
+ *
+ *************************************************************************/
+int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_row_t row)
+{
+ VALUE_PAIR *vp;
+ char const *ptr, *value;
+ char buf[MAX_STRING_LEN];
+ char do_xlat = 0;
+ FR_TOKEN token, op = T_EOL;
+ size_t num_fields = talloc_array_length(row) - 1; /* includes a trailing NULL ptr */
+
+ if (num_fields < 4) {
+ REDEBUG("Insufficient fields for 'id,username,attribute,value,operator'");
+ return -1;
+ }
+
+ /*
+ * Verify the 'Attribute' field
+ */
+ if (!row[2] || row[2][0] == '\0') {
+ REDEBUG("Attribute field is empty or NULL, skipping the entire row");
+ return -1;
+ }
+
+ /*
+ * Verify the 'op' field
+ */
+ if ((num_fields >= 4) && row[4] != NULL && row[4][0] != '\0') {
+ ptr = row[4];
+ op = gettoken(&ptr, buf, sizeof(buf), false);
+ if (!fr_assignment_op[op] && !fr_equality_op[op]) {
+ REDEBUG("Invalid op \"%s\" for attribute %s", row[4], row[2]);
+ return -1;
+ }
+
+ } else {
+ /*
+ * Complain about empty or invalid 'op' field
+ */
+ op = T_OP_CMP_EQ;
+ REDEBUG("The op field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
+ REDEBUG("You MUST FIX THIS if you want the configuration to behave as you expect");
+ }
+
+ /*
+ * The 'Value' field may be empty or NULL
+ */
+ if (!row[3]) {
+ REDEBUG("Value field is empty or NULL, skipping the entire row");
+ return -1;
+ }
+
+ value = row[3];
+
+ /*
+ * If we have a new-style quoted string, where the
+ * *entire* string is quoted, do xlat's.
+ */
+ if (row[3] != NULL &&
+ ((row[3][0] == '\'') || (row[3][0] == '`') || (row[3][0] == '"')) &&
+ (row[3][0] == row[3][strlen(row[3])-1])) {
+
+ token = gettoken(&value, buf, sizeof(buf), false);
+ switch (token) {
+ /*
+ * Mark the pair to be allocated later.
+ */
+ case T_BACK_QUOTED_STRING:
+ do_xlat = 1;
+ /* FALL-THROUGH */
+
+ /*
+ * Take the unquoted string.
+ */
+ case T_SINGLE_QUOTED_STRING:
+ case T_DOUBLE_QUOTED_STRING:
+ value = buf;
+ break;
+
+ /*
+ * Keep the original string.
+ */
+ default:
+ value = row[3];
+ break;
+ }
+ }
+
+ /*
+ * Create the pair
+ */
+ vp = fr_pair_make(ctx, NULL, row[2], NULL, op);
+ if (!vp) {
+ REDEBUG("Failed to create the pair: %s", fr_strerror());
+ return -1;
+ }
+
+ if (do_xlat) {
+ if (fr_pair_mark_xlat(vp, value) < 0) {
+ REDEBUG("Error marking pair for xlat: %s", fr_strerror());
+
+ talloc_free(vp);
+ return -1;
+ }
+ } else {
+ if (fr_pair_value_from_str(vp, value, -1) < 0) {
+ REDEBUG("Error parsing value: %s", fr_strerror());
+
+ talloc_free(vp);
+ return -1;
+ }
+ }
+
+ /*
+ * Add the pair into the packet
+ */
+ fr_pair_add(head, vp);
+ return 0;
+}
+
+/** Call the driver's sql_fetch_row function
+ *
+ * Calls the driver's sql_fetch_row logging any errors. On success, will
+ * write row data to (*handle)->row.
+ *
+ * @param inst Instance of rlm_sql.
+ * @param request The Current request, may be NULL.
+ * @param handle Handle to retrieve errors for.
+ * @return on success RLM_SQL_OK, other sql_rcode_t constants on error.
+ */
+sql_rcode_t rlm_sql_fetch_row(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle)
+{
+ int ret;
+
+ if (!*handle || !(*handle)->conn) return RLM_SQL_ERROR;
+
+ /*
+ * We can't implement reconnect logic here, because the caller
+ * may require the original connection to free up queries or
+ * result sets associated with that connection.
+ */
+ ret = (inst->module->sql_fetch_row)(*handle, inst->config);
+ if (ret < 0) {
+ MOD_ROPTIONAL(RERROR, ERROR, "Error fetching row");
+
+ rlm_sql_print_error(inst, request, *handle, false);
+ }
+
+ return ret;
+}
+
+/** Retrieve any errors from the SQL driver
+ *
+ * Retrieves errors from the driver from the last operation and writes them to
+ * to request/global log, in the ERROR, WARN, INFO and DEBUG categories.
+ *
+ * @param inst Instance of rlm_sql.
+ * @param request Current request, may be NULL.
+ * @param handle Handle to retrieve errors for.
+ * @param force_debug Force all errors to be logged as debug messages.
+ */
+void rlm_sql_print_error(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, bool force_debug)
+{
+ char const *driver;
+ sql_log_entry_t log[20];
+ size_t num, i;
+
+ num = (inst->module->sql_error)(handle->log_ctx, log, (sizeof(log) / sizeof(*log)), handle, inst->config);
+ if (num == 0) {
+ MOD_ROPTIONAL(RERROR, ERROR, "Unknown error");
+ return;
+ }
+
+ driver = inst->config->sql_driver_name;
+
+ for (i = 0; i < num; i++) {
+ if (force_debug) goto debug;
+
+ switch (log[i].type) {
+ case L_ERR:
+ MOD_ROPTIONAL(RERROR, ERROR, "%s: %s", driver, log[i].msg);
+ break;
+
+ case L_WARN:
+ MOD_ROPTIONAL(RWARN, WARN, "%s: %s", driver, log[i].msg);
+ break;
+
+ case L_INFO:
+ MOD_ROPTIONAL(RINFO, INFO, "%s: %s", driver, log[i].msg);
+ break;
+
+ case L_DBG:
+ default:
+ debug:
+ MOD_ROPTIONAL(RDEBUG, DEBUG, "%s: %s", driver, log[i].msg);
+ break;
+ }
+ }
+
+ talloc_free_children(handle->log_ctx);
+}
+
+/** Call the driver's sql_query method, reconnecting if necessary.
+ *
+ * @note Caller must call (inst->module->sql_finish_query)(handle, inst->config);
+ * after they're done with the result.
+ *
+ * @param handle to query the database with. *handle should not be NULL, as this indicates
+ * previous reconnection attempt has failed.
+ * @param request Current request.
+ * @param inst rlm_sql instance data.
+ * @param query to execute. Should not be zero length.
+ * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required
+ * (also sets *handle = NULL), RLM_SQL_QUERY_INVALID/RLM_SQL_ERROR on invalid query or
+ * connection error, RLM_SQL_ALT_QUERY on constraints violation.
+ */
+sql_rcode_t rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query)
+{
+ int ret = RLM_SQL_ERROR;
+ int i, count;
+
+ /* Caller should check they have a valid handle */
+ rad_assert(*handle);
+
+ /* There's no query to run, return an error */
+ if (query[0] == '\0') {
+ if (request) REDEBUG("Zero length query");
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ /*
+ * inst->pool may be NULL is this function is called by mod_conn_create.
+ */
+ count = inst->pool ? fr_connection_pool_get_retries(inst->pool) : 0;
+
+ /*
+ * Here we try with each of the existing connections, then try to create
+ * a new connection, then give up.
+ */
+ for (i = 0; i < (count + 1); i++) {
+ MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query);
+
+ ret = (inst->module->sql_query)(*handle, inst->config, query);
+ switch (ret) {
+ case RLM_SQL_OK:
+ break;
+
+ /*
+ * Run through all available sockets until we exhaust all existing
+ * sockets in the pool and fail to establish a *new* connection.
+ */
+ case RLM_SQL_RECONNECT:
+ *handle = fr_connection_reconnect(inst->pool, *handle);
+ /* Reconnection failed */
+ if (!*handle) return RLM_SQL_RECONNECT;
+ /* Reconnection succeeded, try again with the new handle */
+ continue;
+
+ /*
+ * These are bad and should make rlm_sql return invalid
+ */
+ case RLM_SQL_QUERY_INVALID:
+ rlm_sql_print_error(inst, request, *handle, false);
+ (inst->module->sql_finish_query)(*handle, inst->config);
+ break;
+
+ /*
+ * Server or client errors.
+ *
+ * If the driver claims to be able to distinguish between
+ * duplicate row errors and other errors, and we hit a
+ * general error treat it as a failure.
+ *
+ * Otherwise rewrite it to RLM_SQL_ALT_QUERY.
+ */
+ case RLM_SQL_ERROR:
+ if (inst->module->flags & RLM_SQL_RCODE_FLAGS_ALT_QUERY) {
+ rlm_sql_print_error(inst, request, *handle, false);
+ (inst->module->sql_finish_query)(*handle, inst->config);
+ break;
+ }
+ ret = RLM_SQL_ALT_QUERY;
+ /* FALL-THROUGH */
+
+ /*
+ * Driver suggested using an alternative query
+ */
+ case RLM_SQL_ALT_QUERY:
+ rlm_sql_print_error(inst, request, *handle, true);
+ (inst->module->sql_finish_query)(*handle, inst->config);
+ break;
+
+ }
+
+ return ret;
+ }
+
+ MOD_ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
+
+ return RLM_SQL_ERROR;
+}
+
+/** Call the driver's sql_select_query method, reconnecting if necessary.
+ *
+ * @note Caller must call (inst->module->sql_finish_select_query)(handle, inst->config);
+ * after they're done with the result.
+ *
+ * @param inst rlm_sql instance data.
+ * @param request Current request.
+ * @param handle to query the database with. *handle should not be NULL, as this indicates
+ * previous reconnection attempt has failed.
+ * @param query to execute. Should not be zero length.
+ * @return RLM_SQL_OK on success, RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL),
+ * RLM_SQL_QUERY_INVALID/RLM_SQL_ERROR on invalid query or connection error.
+ */
+sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query)
+{
+ int ret = RLM_SQL_ERROR;
+ int i, count;
+
+ /* Caller should check they have a valid handle */
+ rad_assert(*handle);
+
+ /* There's no query to run, return an error */
+ if (query[0] == '\0') {
+ if (request) REDEBUG("Zero length query");
+
+ return RLM_SQL_QUERY_INVALID;
+ }
+
+ /*
+ * inst->pool may be NULL is this function is called by mod_conn_create.
+ */
+ count = inst->pool ? fr_connection_pool_get_retries(inst->pool) : 0;
+
+ /*
+ * For sanity, for when no connections are viable, and we can't make a new one
+ */
+ for (i = 0; i < (count + 1); i++) {
+ MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Executing select query: %s", query);
+
+ ret = (inst->module->sql_select_query)(*handle, inst->config, query);
+ switch (ret) {
+ case RLM_SQL_OK:
+ break;
+
+ /*
+ * Run through all available sockets until we exhaust all existing
+ * sockets in the pool and fail to establish a *new* connection.
+ */
+ case RLM_SQL_RECONNECT:
+ *handle = fr_connection_reconnect(inst->pool, *handle);
+ /* Reconnection failed */
+ if (!*handle) return RLM_SQL_RECONNECT;
+ /* Reconnection succeeded, try again with the new handle */
+ continue;
+
+ case RLM_SQL_QUERY_INVALID:
+ case RLM_SQL_ERROR:
+ default:
+ rlm_sql_print_error(inst, request, *handle, false);
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
+ break;
+ }
+
+ return ret;
+ }
+
+ MOD_ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
+
+ return RLM_SQL_ERROR;
+}
+
+
+/*************************************************************************
+ *
+ * Function: sql_getvpdata
+ *
+ * Purpose: Get any group check or reply pairs
+ *
+ *************************************************************************/
+int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle,
+ VALUE_PAIR **pair, char const *query)
+{
+ rlm_sql_row_t row;
+ int rows = 0;
+ sql_rcode_t rcode;
+
+ rad_assert(request);
+
+ rcode = rlm_sql_select_query(inst, request, handle, query);
+ if (rcode != RLM_SQL_OK) return -1; /* error handled by rlm_sql_select_query */
+
+ while (rlm_sql_fetch_row(inst, request, handle) == RLM_SQL_OK) {
+ row = (*handle)->row;
+ if (!row) break;
+ if (sql_fr_pair_list_afrom_str(ctx, request, pair, row) != 0) {
+ REDEBUG("Error parsing user data from database result");
+
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
+
+ return -1;
+ }
+ rows++;
+ }
+ (inst->module->sql_finish_select_query)(*handle, inst->config);
+
+ return rows;
+}
+
+/*
+ * Log the query to a file.
+ */
+void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request,
+ sql_acct_section_t *section, char const *query)
+{
+ int fd;
+ char const *filename = NULL;
+ char *expanded = NULL;
+ size_t len;
+ bool failed = false; /* Write the log message outside of the critical region */
+
+ filename = inst->config->logfile;
+ if (section && section->logfile) filename = section->logfile;
+
+ if (!filename || !*filename) {
+ return;
+ }
+
+ if (radius_axlat(&expanded, request, filename, NULL, NULL) < 0) {
+ return;
+ }
+
+ fd = exfile_open(inst->ef, expanded, 0640, NULL);
+ if (fd < 0) {
+ ERROR("rlm_sql (%s): Couldn't open logfile '%s': %s", inst->name,
+ expanded, fr_syserror(errno));
+
+ talloc_free(expanded);
+ return;
+ }
+
+ len = strlen(query);
+ if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) {
+ failed = true;
+ }
+
+ if (failed) {
+ ERROR("rlm_sql (%s): Failed writing to logfile '%s': %s", inst->name, expanded,
+ fr_syserror(errno));
+ }
+
+ talloc_free(expanded);
+ exfile_close(inst->ef, fd);
+}
diff --git a/src/modules/rlm_sql/stable b/src/modules/rlm_sql/stable
new file mode 100644
index 0000000..7d23dd2
--- /dev/null
+++ b/src/modules/rlm_sql/stable
@@ -0,0 +1,7 @@
+rlm_sql_iodbc
+rlm_sql_mysql
+rlm_sql_postgresql
+rlm_sql_oracle
+rlm_sql_unixodbc
+rlm_sql_sqlite
+rlm_sql_freetds
diff --git a/src/modules/rlm_sql_map/.gitignore b/src/modules/rlm_sql_map/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sql_map/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sql_map/README.md b/src/modules/rlm_sql_map/README.md
new file mode 100644
index 0000000..81fe73c
--- /dev/null
+++ b/src/modules/rlm_sql_map/README.md
@@ -0,0 +1,9 @@
+# rlm_sql_map
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Allows mapping of SQL columns to RADIUS dictionary attributes.
diff --git a/src/modules/rlm_sql_map/all.mk.in b/src/modules/rlm_sql_map/all.mk.in
new file mode 100644
index 0000000..34b0489
--- /dev/null
+++ b/src/modules/rlm_sql_map/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I$(top_builddir)/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sql_map/configure b/src/modules/rlm_sql_map/configure
new file mode 100755
index 0000000..b9ca1bf
--- /dev/null
+++ b/src/modules/rlm_sql_map/configure
@@ -0,0 +1,2924 @@
+#! /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_sql_map.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sql_map
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sql_map build without rlm_sql_map
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sql_map
+echo
+
+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_sql_map was given.
+if test "${with_rlm_sql_map+set}" = set; then :
+ withval=$with_rlm_sql_map;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sql_map" != xno; then
+
+
+
+
+ targetname=rlm_sql_map
+else
+ targetname=
+ echo \*\*\* module rlm_sql_map is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sql_map." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sql_map." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sql_map requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sql_map requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sql_map/configure.ac b/src/modules/rlm_sql_map/configure.ac
new file mode 100644
index 0000000..e79413a
--- /dev/null
+++ b/src/modules/rlm_sql_map/configure.ac
@@ -0,0 +1,21 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sql_map.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sql_map])
+
+FR_MODULE_START_TESTS
+
+dnl This module doesn't need any autoconf test which is not already
+dnl in top-level configure.
+
+FR_MODULE_END_TESTS([nostrict])
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sql_map/rlm_sql_map.c b/src/modules/rlm_sql_map/rlm_sql_map.c
new file mode 100644
index 0000000..b6a27e5
--- /dev/null
+++ b/src/modules/rlm_sql_map/rlm_sql_map.c
@@ -0,0 +1,426 @@
+/*
+ * 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_sql_map.c
+ * @brief Tracks data usage and other counters using SQL.
+ *
+ * @copyright 2021 The FreeRADIUS server project
+ * @copyright 2021 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include <rlm_sql.h>
+
+#define MAX_QUERY_LEN 2048
+
+typedef struct rlm_sql_map_t {
+ char const *sql_instance_name; //!< Instance of SQL module to use,
+ //!< usually just 'sql'.
+ bool multiple_rows; //!< Process all rows creating an attr[*] array
+
+ char const *query; //!< SQL query to retrieve current
+
+ rlm_sql_t *sql_inst;
+
+ CONF_SECTION *cs;
+
+ /*
+ * SQL columns to RADIUS stuff
+ */
+ vp_map_t *user_map;
+} rlm_sql_map_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sql_map_t, sql_instance_name), NULL },
+ { "multiple_rows", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sql_map_t, multiple_rows), "no" },
+ { "query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_REQUIRED | PW_TYPE_NOT_EMPTY, rlm_sql_map_t, query), NULL },
+
+ CONF_PARSER_TERMINATOR
+};
+
+#define SQL_MAX_ATTRMAP (128)
+
+static int sql_map_verify(vp_map_t *map, UNUSED void *instance)
+{
+ /*
+ * Destinations where we can put the VALUE_PAIRs we
+ * create using SQL values.
+ */
+ switch (map->lhs->type) {
+ case TMPL_TYPE_ATTR:
+ break;
+
+ case TMPL_TYPE_ATTR_UNDEFINED:
+ cf_log_err(map->ci, "Unknown attribute %s", map->lhs->tmpl_unknown_name);
+ return -1;
+
+ default:
+ cf_log_err(map->ci, "Left hand side of map must be an attribute, not a %s",
+ fr_int2str(tmpl_names, map->lhs->type, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * The RHS MUST be only a column number.
+ */
+ switch (map->rhs->type) {
+ case TMPL_TYPE_LITERAL:
+ case TMPL_TYPE_DATA:
+ if (tmpl_cast_in_place(map->rhs, PW_TYPE_INTEGER, NULL) < 0) {
+ cf_log_err(map->ci, "Failed parsing right hand side of map as an integer.");
+ return -1;
+ }
+
+ if (map->rhs->tmpl_data_value.integer > SQL_MAX_ATTRMAP) {
+ cf_log_err(map->ci, "Column number %u is larger than allowed maximum %u",
+ map->rhs->tmpl_data_value.integer, SQL_MAX_ATTRMAP);
+ return -1;
+ }
+ break;
+
+ default:
+ cf_log_err(map->ci, "Right hand side of map must be a column number, not a %s",
+ fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
+ return -1;
+ }
+
+ /*
+ * Only =, :=, += and -= operators are supported for SQL mappings.
+ */
+ switch (map->op) {
+ case T_OP_SET:
+ case T_OP_EQ:
+ case T_OP_SUB:
+ case T_OP_ADD:
+ break;
+
+ default:
+ cf_log_err(map->ci, "Operator \"%s\" not allowed for SQL mappings",
+ fr_int2str(fr_tokens, map->op, "<INVALID>"));
+ return -1;
+ }
+
+ return 0;
+}
+
+typedef struct sql_map_row_s {
+ int num_columns;
+ char **row;
+} sql_map_row_t;
+
+
+/** Callback for map_to_request
+ *
+ * Performs exactly the same job as map_to_vp, but pulls attribute values from SQL entries
+ *
+ * @see map_to_vp
+ */
+static int sql_map_getvalue(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx)
+{
+ VALUE_PAIR *head = NULL, *vp;
+ int column;
+ sql_map_row_t *data = uctx;
+ char *value;
+ vp_cursor_t cursor;
+
+ *out = NULL;
+ fr_cursor_init(&cursor, &head);
+
+ switch (map->lhs->type) {
+ /*
+ * Iterate over all the retrieved values,
+ * don't try and be clever about changing operators
+ * just use whatever was set in the attribute map.
+ */
+ case TMPL_TYPE_ATTR:
+ fr_assert(map->rhs->type == TMPL_TYPE_DATA);
+ fr_assert(map->rhs->tmpl_data_type == PW_TYPE_INTEGER);
+
+ column = map->rhs->tmpl_data_value.integer;
+ if (column >= data->num_columns) {
+ RWDEBUG("Ignoring source column number %u, as it is larger than the number of returned columns %d",
+ column, data->num_columns);
+ return 0;
+ }
+
+ if (!data->row[column]) {
+ RWDEBUG("Ignoring source column number %u - it is empty", column);
+ return 0;
+ }
+
+ value = data->row[column];
+
+ vp = fr_pair_afrom_da(ctx, map->lhs->tmpl_da);
+ rad_assert(vp);
+
+ if (fr_pair_value_from_str(vp, value, -1) < 0) {
+ char *escaped;
+
+ escaped = fr_aprints(vp, value, -1, '"');
+ RWDEBUG("Failed parsing value \"%s\" for attribute %s: %s", escaped,
+ map->lhs->tmpl_da->name, fr_strerror());
+ talloc_free(vp); /* also frees escaped */
+ break;
+ }
+
+ vp->op = map->op;
+ fr_cursor_insert(&cursor, vp);
+ break;
+
+ default:
+ rad_assert(0);
+ }
+
+ *out = head;
+
+ return 0;
+}
+
+
+/** Convert attribute map into valuepairs
+ *
+ * Use the attribute map built earlier to convert SQL values into valuepairs and insert them into whichever
+ * list they need to go into.
+ *
+ * This is *NOT* atomic, but there's no condition for which we should error out...
+ *
+ * @param[in] inst module configuration.
+ * @param[in] request Current request.
+ * @param[in] handle associated with entry.
+ * @return
+ * - Number of maps successfully applied.
+ * - -1 on failure.
+ */
+static int sql_map_do(const rlm_sql_map_t *inst, REQUEST *request, rlm_sql_handle_t **handle)
+{
+ vp_map_t const *map;
+ int applied = 0; /* How many maps have been applied to the current request */
+ sql_map_row_t ctx;
+
+ /*
+ * Cache all of the rows in a simple array.
+ */
+ while ((inst->sql_inst->module->sql_fetch_row)(*handle, inst->sql_inst->config) == RLM_SQL_OK) {
+#ifdef __clang_analyzer__
+ if (!*handle) return -1; /* only true when return code is not RLM_SQL_OK */
+#endif
+
+ ctx.row = (*handle)->row;
+ ctx.num_columns = (inst->sql_inst->module->sql_num_fields)(*handle, inst->sql_inst->config);
+
+ if (applied >= 1 && !inst->multiple_rows) {
+ RWDEBUG("Ignoring multiple rows. Enable the option 'multiple_rows' if you need multiple rows.");
+ break;
+ }
+
+ for (map = inst->user_map; map != NULL; map = map->next) {
+ /*
+ * If something bad happened, just skip, this is probably
+ * a case of the dst being incorrect for the current
+ * request context
+ */
+ if (map_to_request(request, map, sql_map_getvalue, &ctx) < 0) {
+ return -1; /* Fail */
+ }
+ }
+
+ applied++;
+ }
+
+ return applied;
+}
+
+/*
+ * 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_sql_map_t *inst = instance;
+ module_instance_t *sql_inst;
+ CONF_SECTION *update;
+
+ sql_inst = module_instantiate(cf_section_find("modules"),
+ inst->sql_instance_name);
+ if (!sql_inst) {
+ cf_log_err_cs(conf, "Failed to find sql instance named %s",
+ inst->sql_instance_name);
+ return -1;
+ }
+ inst->sql_inst = (rlm_sql_t *)sql_inst->insthandle;
+
+ inst->cs = conf;
+
+ /*
+ * Build the attribute map
+ */
+ update = cf_section_sub_find(inst->cs, "update");
+ if (!update) {
+ cf_log_err_cs(conf, "Failed to find 'update' section");
+ return -1;
+ }
+
+ if (map_afrom_cs(&inst->user_map, update,
+ PAIR_LIST_REPLY, PAIR_LIST_REQUEST, sql_map_verify, inst,
+ SQL_MAX_ATTRMAP) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_sql_map_t *inst = instance;
+ char const *p = inst->query;
+
+ if (!p || !*p) {
+ cf_log_err_cs(conf, "'query' cannot be empty");
+ return -1;
+ }
+
+ while (isspace((uint8_t) *p)) p++;
+
+ if ((strncasecmp(p, "insert", 6) == 0) ||
+ (strncasecmp(p, "update", 6) == 0) ||
+ (strncasecmp(p, "delete", 6) == 0)) {
+ cf_log_err_cs(conf, "'query' MUST be 'SELECT ...', not 'INSERT', 'UPDATE', or 'DELETE'");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/** Detach from the SQL server and cleanup internal state.
+ *
+ */
+static int mod_detach(void *instance)
+{
+ rlm_sql_map_t *inst = instance;
+
+ talloc_free(inst->user_map);
+
+ return 0;
+}
+
+
+/*
+ * 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_map(void *instance, REQUEST *request)
+{
+ int res;
+ rlm_rcode_t rcode = RLM_MODULE_NOOP;
+ char *query;
+ rlm_sql_map_t *inst = instance;
+ rlm_sql_handle_t *handle;
+
+ handle = fr_connection_get(inst->sql_inst->pool);
+ if (!handle) {
+ REDEBUG("Failed reserving SQL connection");
+ return RLM_MODULE_FAIL;
+ }
+
+ if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ if (radius_axlat(&query, request, inst->query, inst->sql_inst->sql_escape_func, handle) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ res = inst->sql_inst->sql_select_query(inst->sql_inst, request, &handle, query);
+ talloc_free(query);
+ if (res != RLM_SQL_OK) {
+ if (handle) fr_connection_release(inst->sql_inst->pool, handle);
+
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_assert(handle != NULL);
+
+ if (sql_map_do(inst, request, &handle) > 0) rcode = RLM_MODULE_UPDATED;
+
+ if (handle) {
+ (inst->sql_inst->module->sql_finish_query)(handle, inst->sql_inst->config);
+
+ fr_connection_release(inst->sql_inst->pool, handle);
+ }
+
+ return rcode;
+}
+
+/*
+ * 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_sql_map;
+module_t rlm_sql_map = {
+ .magic = RLM_MODULE_INIT,
+ .name = "sqlcounter",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_sql_map_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_map,
+ [MOD_AUTHORIZE] = mod_map,
+ [MOD_PREACCT] = mod_map,
+ [MOD_ACCOUNTING] = mod_map,
+ [MOD_PRE_PROXY] = mod_map,
+ [MOD_POST_PROXY] = mod_map,
+ [MOD_POST_AUTH] = mod_map,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_map,
+ [MOD_SEND_COA] = mod_map
+#endif
+ },
+};
+
diff --git a/src/modules/rlm_sqlcounter/.gitignore b/src/modules/rlm_sqlcounter/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sqlcounter/README.md b/src/modules/rlm_sqlcounter/README.md
new file mode 100644
index 0000000..b015273
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/README.md
@@ -0,0 +1,10 @@
+# rlm_sqlcounter
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Records statistics for users such as data transfer and session
+time, and prevent further logins when limits are reached.
diff --git a/src/modules/rlm_sqlcounter/all.mk.in b/src/modules/rlm_sqlcounter/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sqlcounter/configure b/src/modules/rlm_sqlcounter/configure
new file mode 100755
index 0000000..c057c17
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/configure
@@ -0,0 +1,3959 @@
+#! /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_sqlcounter.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sqlcounter
+'
+ 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_sqlcounter
+ build without rlm_sqlcounter
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sqlcounter
+echo
+
+
+# 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
+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_sqlcounter was given.
+if test "${with_rlm_sqlcounter+set}" = set; then :
+ withval=$with_rlm_sqlcounter;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sqlcounter" != 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
+
+
+
+ targetname=rlm_sqlcounter
+else
+ targetname=
+ echo \*\*\* module rlm_sqlcounter is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_sqlcounter to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sqlcounter." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sqlcounter." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sqlcounter requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sqlcounter requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sqlcounter/configure.ac b/src/modules/rlm_sqlcounter/configure.ac
new file mode 100644
index 0000000..2cfd549
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/configure.ac
@@ -0,0 +1,21 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sqlcounter.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sqlcounter])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sqlcounter/rlm_sqlcounter.c b/src/modules/rlm_sqlcounter/rlm_sqlcounter.c
new file mode 100644
index 0000000..5987ae6
--- /dev/null
+++ b/src/modules/rlm_sqlcounter/rlm_sqlcounter.c
@@ -0,0 +1,707 @@
+/*
+ * 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_sqlcounter.c
+ * @brief Tracks data usage and other counters using SQL.
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ * @copyright 2001 Alan DeKok <aland@ox.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#define MAX_QUERY_LEN 2048
+
+/*
+ * Note: When your counter spans more than 1 period (ie 3 months
+ * or 2 weeks), this module probably does NOT do what you want! It
+ * calculates the range of dates to count across by first calculating
+ * the End of the Current period and then subtracting the number of
+ * periods you specify from that to determine the beginning of the
+ * range.
+ *
+ * For example, if you specify a 3 month counter and today is June 15th,
+ * the end of the current period is June 30. Subtracting 3 months from
+ * that gives April 1st. So, the counter will sum radacct entries from
+ * April 1st to June 30. Then, next month, it will sum entries from
+ * May 1st to July 31st.
+ *
+ * To fix this behavior, we need to add some way of storing the Next
+ * Reset Time.
+ */
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_sqlcounter_t {
+ char const *counter_name; //!< Daily-Session-Time.
+ char const *limit_name; //!< Max-Daily-Session.
+ char const *reply_name; //!< Session-Timeout.
+ char const *key_name; //!< User-Name.
+ char const *sqlmod_inst; //!< Instance of SQL module to use,
+ //!< usually just 'sql'.
+ char const *query; //!< SQL query to retrieve current
+ //!< session time.
+ char const *reset; //!< Daily, weekly, monthly,
+ //!< never or user defined.
+ uint32_t reset_day; //!< Reset day.
+ time_t reset_time;
+ time_t last_reset;
+ DICT_ATTR const *key_attr; //!< Attribute number for key field.
+ DICT_ATTR const *dict_attr; //!< Attribute number for the counter.
+ DICT_ATTR const *reply_attr; //!< Attribute number for the reply.
+} rlm_sqlcounter_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "sql-module-instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, sqlmod_inst), NULL },
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, sqlmod_inst), NULL },
+
+ { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sqlcounter_t, key_name), NULL },
+ { "query", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_REQUIRED, rlm_sqlcounter_t, query), NULL },
+ { "reset", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, reset), NULL },
+
+ { "reset_day", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlcounter_t, reset_day), "1" },
+
+ { "counter-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, counter_name), NULL },
+ { "counter_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, counter_name), NULL },
+
+ { "check-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, limit_name), NULL },
+ { "check_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlcounter_t, limit_name), NULL },
+
+ { "reply-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlcounter_t, reply_name), NULL },
+ { "reply_name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_ATTRIBUTE, rlm_sqlcounter_t, reply_name), "Session-Timeout" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int find_next_reset(rlm_sqlcounter_t *inst, REQUEST *request, time_t timeval)
+{
+ int ret = 0;
+ size_t len;
+ unsigned int num = 1;
+ char last = '\0';
+ struct tm *tm, s_tm;
+ char sCurrentTime[40], sNextTime[40];
+ bool is_monthly = false;
+
+ tm = localtime_r(&timeval, &s_tm);
+ tm->tm_sec = tm->tm_min = 0;
+
+ rad_assert(inst->reset != NULL);
+
+ /*
+ * Reset every N hours, days, weeks, months.
+ */
+ if (isdigit((uint8_t) inst->reset[0])){
+ len = strlen(inst->reset);
+ if (len == 0) return -1;
+
+ last = inst->reset[len - 1];
+ if (!isalpha((uint8_t) last)) {
+ last = 'd';
+ }
+
+ num = atoi(inst->reset);
+ DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last);
+ }
+
+ if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
+ /*
+ * Round up to the next nearest hour.
+ */
+ tm->tm_hour += num;
+ inst->reset_time = mktime(tm);
+
+ } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
+ /*
+ * Round up to the next nearest day.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday += num;
+ inst->reset_time = mktime(tm);
+ } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
+ /*
+ * Round up to the next nearest week.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday += (7 - tm->tm_wday) +(7*(num-1));
+ inst->reset_time = mktime(tm);
+
+ } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
+ tm->tm_hour = 0;
+ tm->tm_mday = inst->reset_day;
+ tm->tm_mon += num;
+ inst->reset_time = mktime(tm);
+ is_monthly = true;
+ } else if (strcmp(inst->reset, "never") == 0) {
+ inst->reset_time = 0;
+
+ } else {
+ return -1;
+ }
+
+ if (!request || (rad_debug_lvl < 2)) return ret;
+
+ len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);
+ if (len == 0) *sCurrentTime = '\0';
+
+ len = strftime(sNextTime, sizeof(sNextTime),"%Y-%m-%d %H:%M:%S",tm);
+ if (len == 0) *sNextTime = '\0';
+
+ if (is_monthly) {
+ DEBUG("rlm_sqlcounter: Current Time: %" PRId64 " [%s], Next reset %" PRId64 " [%s], Reset day [%d]",
+ (int64_t) timeval, sCurrentTime, (int64_t) inst->reset_time, sNextTime, inst->reset_day);
+ } else {
+ DEBUG("rlm_sqlcounter: Current Time: %" PRId64 " [%s], Next reset %" PRId64 " [%s]",
+ (int64_t) timeval, sCurrentTime, (int64_t) inst->reset_time, sNextTime);
+ }
+ return ret;
+}
+
+
+/* I don't believe that this routine handles Daylight Saving Time adjustments
+ properly. Any suggestions?
+*/
+
+static int find_prev_reset(rlm_sqlcounter_t *inst, time_t timeval)
+{
+ int ret = 0;
+ size_t len;
+ unsigned int num = 1;
+ char last = '\0';
+ struct tm *tm, s_tm;
+ char sCurrentTime[40], sPrevTime[40];
+ bool is_monthly = false;
+
+ tm = localtime_r(&timeval, &s_tm);
+ len = strftime(sCurrentTime, sizeof(sCurrentTime), "%Y-%m-%d %H:%M:%S", tm);
+ if (len == 0) *sCurrentTime = '\0';
+ tm->tm_sec = tm->tm_min = 0;
+
+ rad_assert(inst->reset != NULL);
+
+ if (isdigit((uint8_t) inst->reset[0])){
+ len = strlen(inst->reset);
+ if (len == 0)
+ return -1;
+ last = inst->reset[len - 1];
+ if (!isalpha((uint8_t) last))
+ last = 'd';
+ num = atoi(inst->reset);
+ DEBUG("rlm_sqlcounter: num=%d, last=%c",num,last);
+ }
+
+ if (strcmp(inst->reset, "hourly") == 0 || last == 'h') {
+ /*
+ * Round down to the prev nearest hour.
+ */
+ tm->tm_hour -= num - 1;
+ inst->last_reset = mktime(tm);
+
+ } else if (strcmp(inst->reset, "daily") == 0 || last == 'd') {
+ /*
+ * Round down to the prev nearest day.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday -= num - 1;
+ inst->last_reset = mktime(tm);
+
+ } else if (strcmp(inst->reset, "weekly") == 0 || last == 'w') {
+ /*
+ * Round down to the prev nearest week.
+ */
+ tm->tm_hour = 0;
+ tm->tm_mday -= tm->tm_wday +(7*(num-1));
+ inst->last_reset = mktime(tm);
+
+ } else if (strcmp(inst->reset, "monthly") == 0 || last == 'm') {
+ tm->tm_hour = 0;
+ tm->tm_mday = inst->reset_day;
+ tm->tm_mon -= num - 1;
+ inst->last_reset = mktime(tm);
+ is_monthly = true;
+
+ } else if (strcmp(inst->reset, "never") == 0) {
+ inst->reset_time = 0;
+
+ } else {
+ return -1;
+ }
+
+ len = strftime(sPrevTime, sizeof(sPrevTime), "%Y-%m-%d %H:%M:%S", tm);
+ if (len == 0) *sPrevTime = '\0';
+
+ if (is_monthly) {
+ DEBUG2("rlm_sqlcounter: Current Time: %" PRId64 " [%s], Prev reset %" PRId64 " [%s], Reset day [%d]",
+ (int64_t) timeval, sCurrentTime, (int64_t) inst->last_reset, sPrevTime, inst->reset_day);
+ } else {
+ DEBUG2("rlm_sqlcounter: Current Time: %" PRId64 " [%s], Prev reset %" PRId64 " [%s]",
+ (int64_t) timeval, sCurrentTime, (int64_t) inst->last_reset, sPrevTime);
+ }
+
+ return ret;
+}
+
+
+/*
+ * Replace %%<whatever> in a string.
+ *
+ * %%b last_reset
+ * %%e reset_time
+ * %%r reset_day
+ * %%k key_name
+ *
+ */
+
+static size_t sqlcounter_expand(char *out, int outlen, char const *fmt, rlm_sqlcounter_t *inst)
+{
+ int freespace;
+ char const *p;
+ char *q;
+ char tmpdt[40]; /* For temporary storing of dates */
+
+ q = out;
+ p = fmt;
+ while (*p) {
+ /* Calculate freespace in output */
+ freespace = outlen - (q - out);
+ if (freespace <= 1) {
+ return -1;
+ }
+
+ /*
+ * Non-% get copied as-is.
+ */
+ if (*p != '%') {
+ *q++ = *p++;
+ continue;
+ }
+ p++;
+ if (!*p) { /* % and then EOS --> % */
+ *q++ = '%';
+ break;
+ }
+
+ if (freespace <= 2) return -1;
+
+ /*
+ * We need TWO %% in a row before we do our expansions.
+ * If we only get one, just copy the %s as-is.
+ */
+ if (*p != '%') {
+ *q++ = '%';
+ *q++ = *p++;
+ continue;
+ }
+ p++;
+ if (!*p) {
+ *q++ = '%';
+ *q++ = '%';
+ break;
+ }
+
+ if (freespace <= 3) return -1;
+
+ switch (*p) {
+ case 'b': /* last_reset */
+ snprintf(tmpdt, sizeof(tmpdt), "%" PRId64, (int64_t) inst->last_reset);
+ strlcpy(q, tmpdt, freespace);
+ q += strlen(q);
+ p++;
+ break;
+ case 'e': /* reset_time */
+ snprintf(tmpdt, sizeof(tmpdt), "%" PRId64, (int64_t) inst->reset_time);
+ strlcpy(q, tmpdt, freespace);
+ q += strlen(q);
+ p++;
+ break;
+ case 'r': /* reset_day */
+ snprintf(tmpdt, sizeof(tmpdt), "%" PRId64, (int64_t) inst->reset_day);
+ strlcpy(q, tmpdt, freespace);
+ q += strlen(q);
+ p++;
+ break;
+ case 'k': /* Key Name */
+ WARN("Please replace '%%k' with '${key}'");
+ strlcpy(q, inst->key_name, freespace);
+ q += strlen(q);
+ p++;
+ break;
+
+ /*
+ * %%s gets copied over as-is.
+ */
+ default:
+ *q++ = '%';
+ *q++ = '%';
+ *q++ = *p++;
+ break;
+ }
+ }
+ *q = '\0';
+
+ DEBUG2("sqlcounter_expand: '%s'", out);
+
+ return strlen(out);
+}
+
+
+/*
+ * See if the counter matches.
+ */
+static int sqlcounter_cmp(void *instance, REQUEST *request, UNUSED VALUE_PAIR *req , VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ rlm_sqlcounter_t *inst = instance;
+ uint64_t counter;
+
+ char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN];
+ char *expanded = NULL;
+ size_t len;
+
+ /* First, expand %k, %b and %e in query */
+ if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) {
+ REDEBUG("Insufficient query buffer space");
+
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Then combine that with the name of the module were using to do the query */
+ len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst);
+ if (len >= sizeof(query) - 1) {
+ REDEBUG("Insufficient query buffer space");
+
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Finally, xlat resulting SQL query */
+ if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ if (sscanf(expanded, "%" PRIu64, &counter) != 1) {
+ RDEBUG2("No integer found in string \"%s\"", expanded);
+ }
+ talloc_free(expanded);
+
+ if (counter < check->vp_integer64) {
+ return -1;
+ }
+ if (counter > check->vp_integer64) {
+ return 1;
+ }
+ return 0;
+}
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_sqlcounter_t *inst = instance;
+ DICT_ATTR const *da;
+ ATTR_FLAGS flags;
+
+ memset(&flags, 0, sizeof(flags));
+ flags.compare = 1; /* ugly hack */
+ da = dict_attrbyname(inst->counter_name);
+ if (da && (da->type != PW_TYPE_INTEGER64)) {
+ cf_log_err_cs(conf, "Counter attribute %s MUST be integer64", inst->counter_name);
+ return -1;
+ }
+
+ if (!da && (dict_addattr(inst->counter_name, -1, 0, PW_TYPE_INTEGER64, flags) < 0)) {
+ cf_log_err_cs(conf, "Failed to create counter attribute %s: %s", inst->counter_name, fr_strerror());
+ return -1;
+ }
+
+ /*
+ * Register the counter comparison operation.
+ */
+ if (paircompare_register_byname(inst->counter_name, NULL, true, sqlcounter_cmp, inst) < 0) {
+ cf_log_err_cs(conf, "Failed registering counter attribute %s: %s", inst->counter_name, fr_strerror());
+ return -1;
+ }
+
+ inst->dict_attr = dict_attrbyname(inst->counter_name);
+ if (!inst->dict_attr) {
+ cf_log_err_cs(conf, "Failed to find counter attribute %s", inst->counter_name);
+ return -1;
+ }
+
+ /*
+ * Create a new attribute for the check item.
+ */
+ flags.compare = 0;
+ if ((dict_addattr(inst->limit_name, -1, 0, PW_TYPE_INTEGER64, flags) < 0) ||
+ !dict_attrbyname(inst->limit_name)) {
+ cf_log_err_cs(conf, "Failed to create check attribute %s: %s", inst->limit_name, fr_strerror());
+ return -1;
+ }
+
+ 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_sqlcounter_t *inst = instance;
+ DICT_ATTR const *da;
+ time_t now;
+
+ rad_assert(inst->query && *inst->query);
+
+ da = dict_attrbyname(inst->key_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Invalid attribute '%s'", inst->key_name);
+ return -1;
+ }
+ inst->key_attr = da;
+
+ da = dict_attrbyname(inst->reply_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Invalid attribute '%s'", inst->reply_name);
+ return -1;
+ }
+ inst->reply_attr = da;
+
+ now = time(NULL);
+ inst->reset_time = 0;
+
+ if (!(inst->reset_day >= 1 && inst->reset_day <= 28)) {
+ cf_log_err_cs(conf, "Invalid reset_day '%d', valid range is from 1 to 28", inst->reset_day);
+ return -1;
+ }
+
+ if (find_next_reset(inst, NULL, now) < 0) {
+ cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
+ return -1;
+ }
+
+ /*
+ * Discover the beginning of the current time period.
+ */
+ inst->last_reset = 0;
+
+ if (find_prev_reset(inst, now) < 0) {
+ cf_log_err_cs(conf, "Invalid reset '%s'", inst->reset);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * 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_sqlcounter_t *inst = instance;
+ int rcode = RLM_MODULE_NOOP;
+ uint64_t counter, unused;
+ DICT_ATTR const *da;
+ VALUE_PAIR *key_vp, *limit;
+ VALUE_PAIR *reply_item;
+ char msg[128];
+
+ char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN];
+ char *expanded = NULL;
+
+ size_t len;
+
+ /*
+ * Before doing anything else, see if we have to reset
+ * the counters.
+ */
+ if (inst->reset_time && (inst->reset_time <= request->timestamp)) {
+ /*
+ * Re-set the next time and prev_time for this counters range
+ */
+ inst->last_reset = inst->reset_time;
+ find_next_reset(inst, request, request->timestamp);
+ }
+
+ /*
+ * Look for the key. User-Name is special. It means
+ * The REAL username, after stripping.
+ */
+ if ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) {
+ key_vp = request->username;
+ } else {
+ key_vp = fr_pair_find_by_da(request->packet->vps, inst->key_attr, TAG_ANY);
+ }
+ if (!key_vp) {
+ RWDEBUG2("Couldn't find key attribute, request:%s, doing nothing...", inst->key_attr->name);
+ return rcode;
+ }
+
+ /*
+ * Look for the check item
+ */
+ if ((da = dict_attrbyname(inst->limit_name)) == NULL) {
+ return rcode;
+ }
+
+ limit = fr_pair_find_by_da(request->config, da, TAG_ANY);
+ if (limit == NULL) {
+ /* Yes this really is 'check' as distinct from control */
+ RWDEBUG2("Couldn't find check attribute, control:%s, doing nothing...", inst->limit_name);
+ return rcode;
+ }
+
+ /* First, expand %k, %b and %e in query */
+ if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) {
+ REDEBUG("Insufficient query buffer space");
+
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Then combine that with the name of the module were using to do the query */
+ len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst);
+ if (len >= (sizeof(query) - 1)) {
+ REDEBUG("Insufficient query buffer space");
+
+ return RLM_MODULE_FAIL;
+ }
+
+ /* Finally, xlat resulting SQL query */
+ if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ if (sscanf(expanded, "%" PRIu64, &counter) != 1) {
+ RDEBUG2("No integer found in result string \"%s\". May be first session, setting counter to 0",
+ expanded);
+ counter = 0;
+ }
+
+ talloc_free(expanded);
+
+ /*
+ * Check if check item > counter
+ */
+ if (limit->vp_integer64 <= counter) {
+ /* User is denied access, send back a reply message */
+ snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset);
+ pair_make_reply("Reply-Message", msg, T_OP_EQ);
+
+ REDEBUG2("Maximum %s usage time reached", inst->reset);
+ REDEBUG2("Rejecting user, &control:%s value (%" PRIu64 ") is less than counter value (%" PRIu64 ")",
+ inst->limit_name, limit->vp_integer64, counter);
+
+ return RLM_MODULE_REJECT;
+ }
+
+ unused = limit->vp_integer64 - counter;
+ RDEBUG2("Allowing user, &control:%s value (%" PRIu64 ") is greater than counter value (%" PRIu64 ")",
+ inst->limit_name, limit->vp_integer64, counter);
+ /*
+ * We are assuming that simultaneous-use=1. But
+ * even if that does not happen then our user
+ * could login at max for 2*max-usage-time Is
+ * that acceptable?
+ */
+
+ /*
+ * If we are near a reset then add the next
+ * limit, so that the user will not need to login
+ * again. Do this only for Session-Timeout.
+ */
+ if (((inst->reply_attr->vendor == 0) && (inst->reply_attr->attr == PW_SESSION_TIMEOUT)) &&
+ inst->reset_time && (unused >= (uint64_t)(inst->reset_time - request->timestamp))) {
+ uint64_t next_reset = inst->reset_time - request->timestamp;
+
+ RDEBUG2("Time (%" PRIu64 "s) to next reset is smaller than time remaining this reset (%" PRIu64 "s). "
+ "Extending limit to end of next reset time (%" PRIu64 "s).",
+ next_reset, unused, next_reset + limit->vp_integer);
+
+ unused = next_reset + limit->vp_integer;
+ }
+
+ /*
+ * Limit the reply attribute to the minimum of the existing value, or this new one.
+ */
+ reply_item = fr_pair_find_by_da(request->reply->vps, inst->reply_attr, TAG_ANY);
+ if (reply_item) {
+ if (reply_item->vp_integer64 <= unused) {
+ RDEBUG2("Leaving existing &reply:%s value of %" PRIu64, inst->reply_attr->name,
+ reply_item->vp_integer64);
+
+ return RLM_MODULE_OK;
+ }
+ } else {
+ reply_item = radius_pair_create(request->reply, &request->reply->vps, inst->reply_attr->attr,
+ inst->reply_attr->vendor);
+ }
+ reply_item->vp_integer64 = unused;
+
+ RDEBUG2("Setting &reply:%s value to %" PRIu64, inst->reply_name, reply_item->vp_integer64);
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * 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_sqlcounter;
+module_t rlm_sqlcounter = {
+ .magic = RLM_MODULE_INIT,
+ .name = "sqlcounter",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_sqlcounter_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_POST_AUTH] = mod_authorize,
+ },
+};
+
diff --git a/src/modules/rlm_sqlippool/.gitignore b/src/modules/rlm_sqlippool/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_sqlippool/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_sqlippool/README.md b/src/modules/rlm_sqlippool/README.md
new file mode 100644
index 0000000..481351c
--- /dev/null
+++ b/src/modules/rlm_sqlippool/README.md
@@ -0,0 +1,10 @@
+# rlm_sqlippool
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+SQL based IP allocation module. May be used with both RADIUS and
+DHCP for assigning and recording use of IP addresses.
diff --git a/src/modules/rlm_sqlippool/all.mk.in b/src/modules/rlm_sqlippool/all.mk.in
new file mode 100644
index 0000000..34b0489
--- /dev/null
+++ b/src/modules/rlm_sqlippool/all.mk.in
@@ -0,0 +1,11 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+SRC_CFLAGS += -I$(top_builddir)/src/modules/rlm_sql
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_sqlippool/configure b/src/modules/rlm_sqlippool/configure
new file mode 100755
index 0000000..b5ded19
--- /dev/null
+++ b/src/modules/rlm_sqlippool/configure
@@ -0,0 +1,2924 @@
+#! /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_sqlippool.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+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_sqlippool
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_sqlippool build without support for IP pools in SQL
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_sqlippool
+echo
+
+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_sqlippool was given.
+if test "${with_rlm_sqlippool+set}" = set; then :
+ withval=$with_rlm_sqlippool;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_sqlippool" != xno; then
+
+
+
+
+ targetname=rlm_sqlippool
+else
+ targetname=
+ echo \*\*\* module rlm_sqlippool is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_sqlippool." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_sqlippool." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_sqlippool requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_sqlippool requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$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}'
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
+t clear
+:clear
+s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g
+t quote
+b any
+:quote
+s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+ g
+ s/^\n//
+ s/\n/ /g
+ p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
+
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h | --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+
+eval set X " :F $CONFIG_FILES "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/src/modules/rlm_sqlippool/configure.ac b/src/modules/rlm_sqlippool/configure.ac
new file mode 100644
index 0000000..e4bafcf
--- /dev/null
+++ b/src/modules/rlm_sqlippool/configure.ac
@@ -0,0 +1,21 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_sqlippool.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_sqlippool], [support for IP pools in SQL])
+
+FR_MODULE_START_TESTS
+
+dnl This module doesn't need any autoconf test which is not already
+dnl in top-level configure.
+
+FR_MODULE_END_TESTS([nostrict])
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_sqlippool/rlm_sqlippool.c b/src/modules/rlm_sqlippool/rlm_sqlippool.c
new file mode 100644
index 0000000..22e9381
--- /dev/null
+++ b/src/modules/rlm_sqlippool/rlm_sqlippool.c
@@ -0,0 +1,900 @@
+/*
+ * 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_sqlippool.c
+ * @brief Allocates an IP address / prefix from pools stored in SQL.
+ *
+ * @copyright 2002 Globe.Net Communications Limited
+ * @copyright 2006 The FreeRADIUS server project
+ * @copyright 2006 Suntel Communications
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include <rlm_sql.h>
+
+#define MAX_QUERY_LEN 4096
+
+/*
+ * Define a structure for our module configuration.
+ */
+typedef struct rlm_sqlippool_t {
+ char const *sql_instance_name;
+
+ uint32_t lease_duration;
+
+ rlm_sql_t *sql_inst;
+
+ char const *pool_name; //!< Name of the attribute in the check VPS for which the value will be used as key
+ bool ipv6; //!< Whether or not we do IPv6 pools.
+ bool allow_duplicates; //!< assign even if it already exists
+ char const *attribute_name; //!< name of the IP address attribute
+ char const *req_attribute_name; //!< name of the requested IP address attribute
+
+ DICT_ATTR const *framed_ip_address; //!< the attribute for IP address allocation
+ DICT_ATTR const *req_framed_ip_address; //!< the attribute for requested IP address
+ DICT_ATTR const *pool_attribute; //!< the attribute corresponding to the pool_name
+
+ time_t last_clear; //!< So we only do it once a second.
+ char const *allocate_begin; //!< SQL query to begin.
+ char const *allocate_clear; //!< SQL query to clear an IP.
+ uint32_t allocate_clear_timeout; //!< Number of second between two allocate_clear SQL query
+ char const *allocate_existing; //!< SQL query to find existing IP leased to the device.
+ char const *allocate_requested; //!< SQL query to find requested IP.
+ char const *allocate_find; //!< SQL query to find an unused IP.
+ char const *allocate_update; //!< SQL query to mark an IP as used.
+ char const *allocate_commit; //!< SQL query to commit.
+
+ char const *pool_check; //!< Query to check for the existence of the pool.
+
+ /* Start sequence */
+ char const *start_begin; //!< SQL query to begin.
+ char const *start_update; //!< SQL query to update an IP entry.
+ char const *start_commit; //!< SQL query to commit.
+
+ /* Alive sequence */
+ char const *alive_begin; //!< SQL query to begin.
+ char const *alive_update; //!< SQL query to update an IP entry.
+ char const *alive_commit; //!< SQL query to commit.
+
+ /* Stop sequence */
+ char const *stop_begin; //!< SQL query to begin.
+ char const *stop_clear; //!< SQL query to clear an IP.
+ char const *stop_commit; //!< SQL query to commit.
+
+ /* On sequence */
+ char const *on_begin; //!< SQL query to begin.
+ char const *on_clear; //!< SQL query to clear an entire NAS.
+ char const *on_commit; //!< SQL query to commit.
+
+ /* Off sequence */
+ char const *off_begin; //!< SQL query to begin.
+ char const *off_clear; //!< SQL query to clear an entire NAS.
+ char const *off_commit; //!< SQL query to commit.
+
+ /* Logging Section */
+ char const *log_exists; //!< There was an ip address already assigned.
+ char const *log_success; //!< We successfully allocated ip address from pool.
+ char const *log_clear; //!< We successfully deallocated ip address from pool.
+ char const *log_failed; //!< Failed to allocate ip from the pool.
+ char const *log_nopool; //!< There was no Framed-IP-Address but also no Pool-Name.
+
+ /* Reserved to handle 255.255.255.254 Requests */
+ char const *defaultpool; //!< Default Pool-Name if there is none in the check items.
+
+} rlm_sqlippool_t;
+
+static CONF_PARSER message_config[] = {
+ { "exists", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_exists), NULL },
+ { "success", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_success), NULL },
+ { "clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_clear), NULL },
+ { "failed", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_failed), NULL },
+ { "nopool", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_nopool), NULL },
+ 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 CONF_PARSER module_config[] = {
+ { "sql-instance-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, sql_instance_name), NULL },
+ { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, sql_instance_name), "sql" },
+
+ { "lease-duration", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_sqlippool_t, lease_duration), NULL },
+ { "lease_duration", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlippool_t, lease_duration), "86400" },
+
+ { "pool-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_name), NULL },
+ { "pool_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, pool_name), "Pool-Name" },
+
+ { "default-pool", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, defaultpool), NULL },
+ { "default_pool", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, defaultpool), "main_pool" },
+
+
+ { "ipv6", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sqlippool_t, ipv6), NULL},
+ { "allow_duplicates", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sqlippool_t, allow_duplicates), NULL},
+ { "attribute_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, attribute_name), NULL},
+ { "req_attribute_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, req_attribute_name), NULL},
+
+ { "allocate-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_begin), NULL },
+ { "allocate_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_begin), "START TRANSACTION" },
+
+ { "allocate-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_clear), NULL },
+ { "allocate_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_clear), "" },
+
+ { "allocate_clear_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlippool_t, allocate_clear_timeout), "1" },
+
+ { "allocate-existing", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_existing), NULL },
+ { "allocate_existing", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_existing), "" },
+
+ { "allocate-requested", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_requested), NULL },
+ { "allocate_requested", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_requested), "" },
+
+ { "allocate-find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_find), NULL },
+ { "allocate_find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_find), "" },
+
+ { "allocate-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_update), NULL },
+ { "allocate_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_update), "" },
+
+ { "allocate-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_commit), NULL },
+ { "allocate_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_commit), "COMMIT" },
+
+
+ { "pool-check", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_check), NULL },
+ { "pool_check", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, pool_check), "" },
+
+
+ { "start-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_begin), NULL },
+ { "start_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_begin), "" },
+
+ { "start-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_update), NULL },
+ { "start_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, start_update), "" },
+
+ { "start-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_commit), NULL },
+ { "start_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_commit), "" },
+
+
+ { "alive-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_begin), NULL },
+ { "alive_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_begin), "" },
+
+ { "alive-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_update), NULL },
+ { "alive_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, alive_update), "" },
+
+ { "alive-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_commit), NULL },
+ { "alive_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_commit), "" },
+
+
+ { "stop-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_begin), NULL },
+ { "stop_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_begin), "" },
+
+ { "stop-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_clear), NULL },
+ { "stop_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, stop_clear), "" },
+
+ { "stop-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_commit), NULL },
+ { "stop_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_commit), "" },
+
+
+ { "on-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_begin), NULL },
+ { "on_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_begin), "" },
+
+ { "on-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_clear), NULL },
+ { "on_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, on_clear), "" },
+
+ { "on-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_commit), NULL },
+ { "on_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_commit), "" },
+
+
+ { "off-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_begin), NULL },
+ { "off_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_begin), "" },
+
+ { "off-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_clear), NULL },
+ { "off_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, off_clear), "" },
+
+ { "off-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_commit), NULL },
+ { "off_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_commit), "" },
+
+ { "messages", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) message_config },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Replace %<whatever> in a string.
+ *
+ * %P pool_name
+ * %I param
+ * %J lease_duration
+ *
+ */
+static int sqlippool_expand(char * out, int outlen, char const * fmt,
+ rlm_sqlippool_t *data, char * param, int param_len)
+{
+ char *q;
+ char const *p;
+ char tmp[40]; /* For temporary storing of integers */
+
+ q = out;
+ for (p = fmt; *p ; p++) {
+ int freespace;
+ int c;
+
+ /* Calculate freespace in output */
+ freespace = outlen - (q - out);
+ if (freespace <= 1)
+ break;
+
+ c = *p;
+ if (c != '%') {
+ *q++ = *p;
+ continue;
+ }
+
+ if (*++p == '\0') {
+ break;
+ }
+
+ if (c == '%') {
+ switch (*p) {
+ case 'P': /* pool name */
+ strlcpy(q, data->pool_name, freespace);
+ q += strlen(q);
+ break;
+ case 'I': /* IP address */
+ if (param && param_len > 0) {
+ if (param_len > freespace) {
+ strlcpy(q, param, freespace);
+ q += strlen(q);
+ }
+ else {
+ memcpy(q, param, param_len);
+ q += param_len;
+ }
+ }
+ break;
+ case 'J': /* lease duration */
+ sprintf(tmp, "%d", data->lease_duration);
+ strlcpy(q, tmp, freespace);
+ q += strlen(q);
+ break;
+
+ default:
+ *q++ = '%';
+ *q++ = *p;
+ break;
+ }
+ }
+ }
+ *q = '\0';
+
+#if 0
+ DEBUG2("sqlippool_expand: \"%s\"", out);
+#endif
+
+ return strlen(out);
+}
+
+/** Perform a single sqlippool query
+ *
+ * Mostly wrapper around sql_query which does some special sqlippool sequence substitutions and expands
+ * the format string.
+ *
+ * @param fmt sql query to expand.
+ * @param handle sql connection handle.
+ * @param data Instance of rlm_sqlippool.
+ * @param request Current request.
+ * @param param ip address string.
+ * @param param_len ip address string len.
+ * @return 0 on success or < 0 on error.
+ */
+static int sqlippool_command(char const *fmt, rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *data, REQUEST *request,
+ char *param, int param_len)
+{
+ char query[MAX_QUERY_LEN];
+ char *expanded = NULL;
+
+ int ret;
+ int affected;
+
+ /*
+ * If we don't have a command, do nothing.
+ */
+ if (!fmt || !*fmt) return 0;
+
+ /*
+ * No handle? That's an error.
+ */
+ if (!handle || !*handle) return -1;
+
+ /*
+ * @todo this needs to die (should just be done in xlat expansion)
+ */
+ sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
+
+ if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, *handle) < 0) return -1;
+
+ ret = data->sql_inst->sql_query(data->sql_inst, request, handle, expanded);
+ if (ret < 0){
+ talloc_free(expanded);
+ return -1;
+ }
+ talloc_free(expanded);
+
+ /*
+ * No handle, we can't continue.
+ */
+ if (!*handle) return -1;
+
+ affected = (data->sql_inst->module->sql_affected_rows)(*handle, data->sql_inst->config);
+
+ if (*handle) (data->sql_inst->module->sql_finish_query)(*handle, data->sql_inst->config);
+
+ return affected;
+}
+
+/*
+ * Don't repeat yourself
+ */
+#undef DO
+#define DO(_x) if (sqlippool_command(inst->_x, handle, inst, request, NULL, 0) < 0) return RLM_MODULE_FAIL
+#define DO_AFFECTED(_x, _affected) _affected = sqlippool_command(inst->_x, handle, inst, request, NULL, 0); if (_affected < 0) return RLM_MODULE_FAIL
+#define DO_PART(_x) if (sqlippool_command(inst->_x, &handle, inst, request, NULL, 0) < 0) goto error
+
+/*
+ * Query the database expecting a single result row
+ */
+static int CC_HINT(nonnull (1, 3, 4, 5)) sqlippool_query1(char *out, int outlen, char const *fmt,
+ rlm_sql_handle_t **handle, rlm_sqlippool_t *data,
+ REQUEST *request, char *param, int param_len)
+{
+ char query[MAX_QUERY_LEN];
+ char *expanded = NULL;
+
+ int rlen, retval;
+
+ /*
+ * @todo this needs to die (should just be done in xlat expansion)
+ */
+ sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
+
+ *out = '\0';
+
+ /*
+ * Do an xlat on the provided string
+ *
+ * Note that on an escaping error the handle is still valid!
+ */
+ if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, *handle) < 0) {
+ return 0;
+ }
+
+ retval = data->sql_inst->sql_select_query(data->sql_inst, request, handle, expanded);
+ talloc_free(expanded);
+
+ if ((retval != 0) || !*handle) {
+ REDEBUG("database query error on '%s'", query);
+ return 0;
+ }
+
+ if (data->sql_inst->sql_fetch_row(data->sql_inst, request, handle) < 0) {
+ REDEBUG("Failed fetching query result");
+ goto finish;
+ }
+
+ if (!(*handle)->row) {
+ REDEBUG("SQL query did not return any results");
+ goto finish;
+ }
+
+ if (!(*handle)->row[0]) {
+ REDEBUG("The first column of the result was NULL");
+ goto finish;
+ }
+
+ rlen = strlen((*handle)->row[0]);
+ if (rlen >= outlen) {
+ RDEBUG("insufficient string space");
+ goto finish;
+ }
+
+ strcpy(out, (*handle)->row[0]);
+ retval = rlen;
+finish:
+ (data->sql_inst->module->sql_finish_select_query)(*handle, data->sql_inst->config);
+
+ return retval;
+}
+
+/*
+ * 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)
+{
+ module_instance_t *sql_inst;
+ rlm_sqlippool_t *inst = instance;
+
+ sql_inst = module_instantiate(cf_section_find("modules"),
+ inst->sql_instance_name);
+ if (!sql_inst) {
+ cf_log_err_cs(conf, "failed to find sql instance named %s",
+ inst->sql_instance_name);
+ return -1;
+ }
+
+ if (inst->pool_name) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbyname(inst->pool_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Unknown attribute 'pool_name = %s'", inst->pool_name);
+ return -1;
+ }
+
+ if (da->type != PW_TYPE_STRING) {
+ cf_log_err_cs(conf, "Cannot use non-string attributes for 'pool_name = %s'", inst->pool_name);
+ return -1;
+ }
+
+ inst->pool_attribute = da;
+ }
+
+ if (inst->attribute_name) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbyname(inst->attribute_name);
+ if (!da) {
+ fail:
+ cf_log_err_cs(conf, "Unknown attribute 'attribute_name = %s'", inst->attribute_name);
+ return -1;
+ }
+
+ switch (da->type) {
+ default:
+ cf_log_err_cs(conf, "Cannot use non-IP attributes for 'attribute_name = %s'", inst->attribute_name);
+ return -1;
+
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
+ break;
+
+ }
+
+ inst->framed_ip_address = da;
+ } else {
+ if (!inst->ipv6) {
+ inst->attribute_name = "Framed-IP-Address";
+ inst->framed_ip_address = dict_attrbyvalue(PW_FRAMED_IP_ADDRESS, 0);
+ } else {
+ inst->attribute_name = "Framed-IPv6-Prefix";
+ inst->framed_ip_address = dict_attrbyvalue(PW_FRAMED_IPV6_PREFIX, 0);
+ }
+
+ if (!inst->framed_ip_address) goto fail;
+ }
+
+ if (inst->req_attribute_name) {
+ DICT_ATTR const *da;
+
+ da = dict_attrbyname(inst->req_attribute_name);
+ if (!da) {
+ cf_log_err_cs(conf, "Unknown attribute 'req_attribute_name = %s'", inst->req_attribute_name);
+ return -1;
+ }
+
+ switch (da->type) {
+ default:
+ cf_log_err_cs(conf, "Cannot use non-IP attributes for 'req_attribute_name = %s'", inst->req_attribute_name);
+ return -1;
+
+ case PW_TYPE_IPV4_ADDR:
+ case PW_TYPE_IPV6_ADDR:
+ case PW_TYPE_IPV4_PREFIX:
+ case PW_TYPE_IPV6_PREFIX:
+ break;
+
+ }
+
+ inst->req_framed_ip_address = da;
+ }
+
+ if (strcmp(sql_inst->entry->name, "rlm_sql") != 0) {
+ cf_log_err_cs(conf, "Module \"%s\""
+ " is not an instance of the rlm_sql module",
+ inst->sql_instance_name);
+ return -1;
+ }
+
+ if (inst->allocate_clear) {
+ FR_INTEGER_BOUND_CHECK("allocate_clear_timeout", inst->allocate_clear_timeout, >=, 1);
+ FR_INTEGER_BOUND_CHECK("allocate_clear_timeout", inst->allocate_clear_timeout, <=, 2*86400);
+ }
+
+ inst->sql_inst = (rlm_sql_t *) sql_inst->insthandle;
+ return 0;
+}
+
+
+/*
+ * If we have something to log, then we log it.
+ * Otherwise we return the retcode as soon as possible
+ */
+static int do_logging(REQUEST *request, char const *str, int rcode)
+{
+ char *expanded = NULL;
+
+ if (!str || !*str) return rcode;
+
+ if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) {
+ return rcode;
+ }
+
+ pair_make_config("Module-Success-Message", expanded, T_OP_SET);
+
+ talloc_free(expanded);
+
+ return rcode;
+}
+
+
+/*
+ * Allocate an IP number from the pool.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
+ char allocation[MAX_STRING_LEN];
+ int allocation_len;
+ VALUE_PAIR *vp = NULL;
+ rlm_sql_handle_t *handle;
+ time_t now;
+ uint32_t diff_time;
+
+ /*
+ * If there is already an attribute in the reply do nothing
+ */
+ if (!inst->allow_duplicates && (fr_pair_find_by_num(request->reply->vps, inst->framed_ip_address->attr, inst->framed_ip_address->vendor, TAG_ANY) != NULL)) {
+ RDEBUG("%s already exists", inst->attribute_name);
+
+ return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
+ }
+
+ if (fr_pair_find_by_num(request->config, inst->pool_attribute->attr, inst->pool_attribute->vendor, TAG_ANY) == NULL) {
+ RDEBUG("No %s defined", inst->pool_name);
+
+ return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
+ }
+
+ handle = fr_connection_get(inst->sql_inst->pool);
+ if (!handle) {
+ REDEBUG("Failed reserving SQL connection");
+ return RLM_MODULE_FAIL;
+ }
+
+ if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Limit the number of clears we do. There are minor
+ * race conditions for the check, but so what. The
+ * actual work is protected by a transaction. The idea
+ * here is that if we're allocating 100 IPs a second,
+ * we're only do 1 CLEAR per allocate_clear_timeout.
+ *
+ * This will avoid having several queries to deadlock and blocking all
+ * the sqlippool module.
+ */
+ now = time(NULL);
+ diff_time = difftime(now, inst->last_clear);
+ if (inst->allocate_clear && *inst->allocate_clear && (diff_time >= inst->allocate_clear_timeout)) {
+ inst->last_clear = now;
+
+ DO_PART(allocate_begin);
+ DO_PART(allocate_clear);
+ DO_PART(allocate_commit);
+ }
+
+ DO_PART(allocate_begin);
+
+ /*
+ * If we have a query to find an existing IP run that first
+ */
+ if (inst->allocate_existing && *inst->allocate_existing) {
+ allocation_len = sqlippool_query1(allocation, sizeof(allocation),
+ inst->allocate_existing, &handle,
+ inst, request, (char *) NULL, 0);
+ if (!handle) return RLM_MODULE_FAIL;
+ } else {
+ allocation_len = 0;
+ }
+
+ /*
+ * If we have a requested IP address and a query to find whether
+ * it is available then run that next
+ */
+ if (allocation_len == 0 && inst->allocate_requested && *inst->allocate_requested &&
+ fr_pair_find_by_num(request->packet->vps,
+ inst->req_framed_ip_address->attr,
+ inst->req_framed_ip_address->vendor,
+ TAG_ANY) != NULL) {
+ allocation_len = sqlippool_query1(allocation, sizeof(allocation),
+ inst->allocate_requested, &handle,
+ inst, request, (char *) NULL, 0);
+ if (!handle) return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * If no IP found, look for a free one
+ */
+ if (allocation_len == 0) {
+ allocation_len = sqlippool_query1(allocation, sizeof(allocation),
+ inst->allocate_find, &handle,
+ inst, request, (char *) NULL, 0);
+ if (!handle) return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Nothing found...
+ */
+ if (allocation_len == 0) {
+ DO_PART(allocate_commit);
+
+ /*
+ *Should we perform pool-check ?
+ */
+ if (inst->pool_check && *inst->pool_check) {
+
+ /*
+ *Ok, so the allocate-find query found nothing ...
+ *Let's check if the pool exists at all
+ */
+ allocation_len = sqlippool_query1(allocation, sizeof(allocation),
+ inst->pool_check, &handle, inst, request,
+ (char *) NULL, 0);
+ if (!handle) return RLM_MODULE_FAIL;
+
+ fr_connection_release(inst->sql_inst->pool, handle);
+
+ if (allocation_len) {
+
+ /*
+ * Pool exists after all... So,
+ * the failure to allocate the IP
+ * address was most likely due to
+ * the depletion of the pool. In
+ * that case, we should return
+ * NOTFOUND
+ */
+ REDEBUG("pool appears to be full");
+ return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);
+
+ }
+
+ /*
+ * Pool doesn't exist in the table. It
+ * may be handled by some other instance of
+ * sqlippool, so we should just ignore this
+ * allocation failure and return NOOP
+ */
+ REDEBUG("IP address could not be allocated as no pool exists with that name");
+ return RLM_MODULE_NOOP;
+
+ }
+
+ fr_connection_release(inst->sql_inst->pool, handle);
+
+ REDEBUG("IP address could not be allocated");
+ return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
+ }
+
+ /*
+ * See if we can create the VP from the returned data. If not,
+ * error out. If so, add it to the list.
+ */
+ vp = fr_pair_afrom_num(request->reply, inst->framed_ip_address->attr, inst->framed_ip_address->vendor);
+ if (fr_pair_value_from_str(vp, allocation, allocation_len) < 0) {
+ DO_PART(allocate_commit);
+
+ talloc_free(vp);
+ REDEBUG("Invalid IP address [%s] returned from database query.", allocation);
+ fr_connection_release(inst->sql_inst->pool, handle);
+ return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
+ }
+
+ /*
+ * UPDATE
+ */
+ if (sqlippool_command(inst->allocate_update, &handle, inst, request,
+ allocation, allocation_len) < 0) {
+ error:
+ talloc_free(vp);
+ if (handle) fr_connection_release(inst->sql_inst->pool, handle);
+ return RLM_MODULE_FAIL;
+ }
+
+ DO_PART(allocate_commit);
+
+ RDEBUG("Allocated IP %s", allocation);
+ fr_pair_add(&request->reply->vps, vp);
+
+ if (handle) fr_connection_release(inst->sql_inst->pool, handle);
+
+ return do_logging(request, inst->log_success, RLM_MODULE_OK);
+}
+
+static int mod_accounting_start(rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *inst, REQUEST *request)
+{
+ DO(start_begin);
+ DO(start_update);
+ DO(start_commit);
+
+ return RLM_MODULE_OK;
+}
+
+static int mod_accounting_alive(rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *inst, REQUEST *request)
+{
+ int affected;
+
+ DO(alive_begin);
+ DO_AFFECTED(alive_update, affected);
+ DO(alive_commit);
+
+ return (affected == 0 ? RLM_MODULE_NOTFOUND : RLM_MODULE_OK);
+}
+
+static int mod_accounting_stop(rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *inst, REQUEST *request)
+{
+ DO(stop_begin);
+ DO(stop_clear);
+ DO(stop_commit);
+
+ return do_logging(request, inst->log_clear, RLM_MODULE_OK);
+}
+
+static int mod_accounting_on(rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *inst, REQUEST *request)
+{
+ DO(on_begin);
+ DO(on_clear);
+ DO(on_commit);
+
+ return RLM_MODULE_OK;
+}
+
+static int mod_accounting_off(rlm_sql_handle_t **handle,
+ rlm_sqlippool_t *inst, REQUEST *request)
+{
+ DO(off_begin);
+ DO(off_clear);
+ DO(off_commit);
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Check for an Accounting-Stop
+ * If we find one and we have allocated an IP to this nas/port
+ * combination, then deallocate it.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ int rcode = RLM_MODULE_NOOP;
+ VALUE_PAIR *vp;
+
+ int acct_status_type;
+
+ rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
+ rlm_sql_handle_t *handle;
+
+ vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
+ if (!vp) {
+ RDEBUG("Could not find account status type in packet");
+ return RLM_MODULE_NOOP;
+ }
+ acct_status_type = vp->vp_integer;
+
+ switch (acct_status_type) {
+ case PW_STATUS_START:
+ case PW_STATUS_ALIVE:
+ case PW_STATUS_STOP:
+ case PW_STATUS_ACCOUNTING_ON:
+ case PW_STATUS_ACCOUNTING_OFF:
+ break; /* continue through to the next section */
+
+ default:
+ /* We don't care about any other accounting packet */
+ return RLM_MODULE_NOOP;
+ }
+
+ handle = fr_connection_get(inst->sql_inst->pool);
+ if (!handle) {
+ RDEBUG("Failed reserving SQL connection");
+ return RLM_MODULE_FAIL;
+ }
+
+ if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) return RLM_MODULE_FAIL;
+
+ switch (acct_status_type) {
+ case PW_STATUS_START:
+ rcode = mod_accounting_start(&handle, inst, request);
+ break;
+
+ case PW_STATUS_ALIVE:
+ rcode = mod_accounting_alive(&handle, inst, request);
+ break;
+
+ case PW_STATUS_STOP:
+ rcode = mod_accounting_stop(&handle, inst, request);
+ break;
+
+ case PW_STATUS_ACCOUNTING_ON:
+ rcode = mod_accounting_on(&handle, inst, request);
+ break;
+
+ case PW_STATUS_ACCOUNTING_OFF:
+ rcode = mod_accounting_off(&handle, inst, request);
+ break;
+ }
+
+ if (handle) fr_connection_release(inst->sql_inst->pool, handle);
+
+ return rcode;
+}
+
+/*
+ * 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_sqlippool;
+module_t rlm_sqlippool = {
+ .magic = RLM_MODULE_INIT,
+ .name = "sqlippool",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_sqlippool_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_test/README.md b/src/modules/rlm_test/README.md
new file mode 100644
index 0000000..887769d
--- /dev/null
+++ b/src/modules/rlm_test/README.md
@@ -0,0 +1,10 @@
+# rlm_test
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Contains test stubs for CIT and the ``make test`` build target. No
+use in a production server.
diff --git a/src/modules/rlm_test/all.mk b/src/modules/rlm_test/all.mk
new file mode 100644
index 0000000..5eeaf2e
--- /dev/null
+++ b/src/modules/rlm_test/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_test.a
+SOURCES := rlm_test.c
diff --git a/src/modules/rlm_test/rlm_test.c b/src/modules/rlm_test/rlm_test.c
new file mode 100644
index 0000000..22ecb60
--- /dev/null
+++ b/src/modules/rlm_test/rlm_test.c
@@ -0,0 +1,227 @@
+/*
+ * 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_test.c
+ * @brief test module code.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 your name \<your address\>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_test_t {
+ bool boolean;
+ uint32_t value;
+ char const *string;
+ fr_ipaddr_t ipaddr;
+} rlm_test_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER module_config[] = {
+ { "integer", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_test_t, value), "1" },
+ { "boolean", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_test_t, boolean), "no" },
+ { "string", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_test_t, string), NULL },
+ { "ipaddr", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, rlm_test_t, ipaddr), "*" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int rlm_test_cmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PAIR *thing, VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
+{
+ rad_assert(check->da->type == PW_TYPE_STRING);
+
+ RINFO("test-Paircmp called with \"%s\"", check->vp_strvalue);
+
+ if (strcmp(check->vp_strvalue, "yes") == 0) return 0;
+ return 1;
+}
+
+/*
+ * Do any per-module initialization that is separate to each
+ * configured instance of the module. e.g. set up connections
+ * to external databases, read configuration files, set up
+ * dictionary entries, etc.
+ *
+ * If configuration information is given in the config section
+ * that must be referenced in later calls, store a handle to it
+ * in *instance otherwise put a null pointer there.
+ */
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_test_t *inst = instance;
+ ATTR_FLAGS flags;
+
+ memset(&flags, 0, sizeof(flags));
+
+ if (dict_addattr("test-Paircmp", -1, 0, PW_TYPE_STRING, flags) < 0) {
+ ERROR("Failed creating paircmp attribute: %s", fr_strerror());
+
+ return -1;
+ }
+
+ paircompare_register(dict_attrbyname("test-Paircmp"), dict_attrbyvalue(PW_USER_NAME, 0), false,
+ rlm_test_cmp, inst);
+
+ /*
+ * Log some messages
+ */
+ INFO("rlm_test: Informational message");
+ WARN("rlm_test: Warning message");
+ ERROR("rlm_test: Error message");
+ DEBUG("rlm_test: Debug message");
+ DEBUG2("rlm_test: Debug2 message");
+ DEBUG3("rlm_test: Debug3 message");
+ DEBUG4("rlm_test: Debug4 message");
+ AUTH("rlm_test: Auth message");
+ ACCT("rlm_test: Acct message");
+ PROXY("rlm_test: Proxy message");
+
+ return 0;
+}
+
+/*
+ * 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(UNUSED void *instance, REQUEST *request)
+{
+ RINFO("RINFO message");
+ RDEBUG("RDEBUG message");
+ RDEBUG2("RDEBUG2 message");
+
+ RWARN("RWARN message");
+ RWDEBUG("RWDEBUG message");
+ RWDEBUG("RWDEBUG2 message");
+
+ RAUTH("RAUTH message");
+ RACCT("RACCT message");
+ RPROXY("RPROXY message");
+
+ /*
+ * Should appear wavy
+ */
+ RERROR("RERROR error message");
+ RINDENT();
+ REDEBUG("RDEBUG error message");
+ REXDENT();
+ REDEBUG2("RDEBUG2 error message");
+ RINDENT();
+ REDEBUG3("RDEBUG3 error message");
+ REXDENT();
+ REDEBUG4("RDEBUG4 error message");
+
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Authenticate the user with the given password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+#ifdef WITH_ACCOUNTING
+/*
+ * Massage the request before recording it or proxying it
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+/*
+ * Write accounting information to this modules database.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(UNUSED void *instance, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+/*
+ * See if a user is already logged in. Sets request->simul_count to the
+ * current session count for this user and sets request->simul_mpp to 2
+ * if it looks like a multilink attempt based on the requested IP
+ * address, otherwise leaves request->simul_mpp alone.
+ *
+ * Check twice. If on the first pass the user exceeds his
+ * max. number of logins, do a second pass and validate all
+ * logins by querying the terminal server (using eg. SNMP).
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_checksimul(UNUSED void *instance, REQUEST *request)
+{
+ request->simul_count=0;
+
+ return RLM_MODULE_OK;
+}
+#endif
+
+
+/*
+ * Only free memory we allocated. The strings allocated via
+ * cf_section_parse() do not need to be freed.
+ */
+static int mod_detach(UNUSED void *instance)
+{
+ /* free things here */
+ 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_test;
+module_t rlm_test = {
+ .magic = RLM_MODULE_INIT,
+ .name = "test",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_test_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize,
+#ifdef WITH_ACCOUNTING
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_ACCOUNTING] = mod_accounting,
+ [MOD_SESSION] = mod_checksimul
+#endif
+ },
+};
diff --git a/src/modules/rlm_totp/.gitignore b/src/modules/rlm_totp/.gitignore
new file mode 100644
index 0000000..fb9b99c
--- /dev/null
+++ b/src/modules/rlm_totp/.gitignore
@@ -0,0 +1,3 @@
+totp
+src
+freeradius-devel
diff --git a/src/modules/rlm_totp/Makefile b/src/modules/rlm_totp/Makefile
new file mode 100644
index 0000000..5ad2ae9
--- /dev/null
+++ b/src/modules/rlm_totp/Makefile
@@ -0,0 +1,33 @@
+#
+# TOTP isn't simple, so we need test cases.
+#
+all: totp
+
+include ../../../Make.inc
+
+#
+# Hack up stuff so we can build in a subdirectory.
+#
+.PHONY: src
+src:
+ @ln -sf ../../../src
+
+.PHONY: freeradius-devel
+freeradius-devel:
+ @ln -sf ../../../src/include freeradius-devel
+
+#
+# ./totp decode <base32>
+#
+# ./totp totp <time> <sha1key> <8-character-challenge>
+#
+totp: rlm_totp.c | src freeradius-devel
+ @$(CC) -DTESTING $(CFLAGS) $(OPENSSL_CPPFLAGS) -o $@ $(LDFLAGS) $(LIBS) ../../../build/lib/.libs/libfreeradius-radius.a rlm_totp.c
+
+#
+# Test vectors from RFC 6238, Appendix B
+#
+test: totp
+ @while IFS= read -r line; do \
+ ./totp totp $$line || exit 1; \
+ done < sha1.txt
diff --git a/src/modules/rlm_totp/README.md b/src/modules/rlm_totp/README.md
new file mode 100644
index 0000000..2dd5711
--- /dev/null
+++ b/src/modules/rlm_totp/README.md
@@ -0,0 +1,9 @@
+# rlm_totp
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Implement the TOTP algorithm as given in RFC 6238.
diff --git a/src/modules/rlm_totp/all.mk b/src/modules/rlm_totp/all.mk
new file mode 100644
index 0000000..4f58d0e
--- /dev/null
+++ b/src/modules/rlm_totp/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_totp.a
+SOURCES := rlm_totp.c
diff --git a/src/modules/rlm_totp/rlm_totp.c b/src/modules/rlm_totp/rlm_totp.c
new file mode 100644
index 0000000..1459716
--- /dev/null
+++ b/src/modules/rlm_totp/rlm_totp.c
@@ -0,0 +1,320 @@
+/*
+ * 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_totp.c
+ * @brief Execute commands and parse the results.
+ *
+ * @copyright 2021 The FreeRADIUS server project
+ * @copyright 2021 Network RADIUS SARL (legal@networkradius.com)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/rad_assert.h>
+
+#define TIME_STEP (30)
+
+/*
+ * RFC 4648 base32 decoding.
+ */
+static const uint8_t alphabet[UINT8_MAX] = {
+ ['A'] = 1,
+ ['B'] = 2,
+ ['C'] = 3,
+ ['D'] = 4,
+ ['E'] = 5,
+ ['F'] = 6,
+ ['G'] = 7,
+ ['H'] = 8,
+ ['I'] = 9,
+ ['J'] = 10,
+ ['K'] = 11,
+ ['L'] = 12,
+ ['M'] = 13,
+ ['N'] = 14,
+ ['O'] = 15,
+ ['P'] = 16,
+ ['Q'] = 17,
+ ['R'] = 18,
+ ['S'] = 19,
+ ['T'] = 20,
+ ['U'] = 21,
+ ['V'] = 22,
+ ['W'] = 23,
+ ['X'] = 24,
+ ['Y'] = 25,
+ ['Z'] = 26,
+ ['2'] = 27,
+ ['3'] = 28,
+ ['4'] = 29,
+ ['5'] = 30,
+ ['6'] = 31,
+ ['7'] = 32,
+};
+
+static ssize_t base32_decode(uint8_t *out, size_t outlen, char const *in)
+{
+ uint8_t *p, *end, *b;
+ char const *q;
+
+ p = out;
+ end = p + outlen;
+
+ memset(out, 0, outlen);
+
+ /*
+ * Convert ASCII to binary.
+ */
+ for (q = in; *q != '\0'; q++) {
+ /*
+ * Padding at the end, stop.
+ */
+ if (*q == '=') {
+ break;
+ }
+
+ if (!alphabet[*((uint8_t const *) q)]) return -1;
+
+ *(p++) = alphabet[*((uint8_t const *) q)] - 1;
+
+ if (p == end) return -1; /* too much data */
+ }
+
+ /*
+ * Reset to the end of the actual data we have
+ */
+ end = p;
+
+ /*
+ * Convert input 5-bit groups into output 8-bit groups.
+ * We do this in 8-byte blocks.
+ *
+ * 00011111 00022222 00033333 00044444 00055555 00066666 00077777 00088888
+ *
+ * Will get converted to
+ *
+ * 11111222 22333334 44445555 56666677 77788888
+ */
+ for (p = b = out; p < end; p += 8) {
+ b[0] = p[0] << 3;
+ b[0] |= p[1] >> 2;
+
+ b[1] = p[1] << 6;
+ b[1] |= p[2] << 1;
+ b[1] |= p[3] >> 4;
+
+ b[2] = p[3] << 4;
+ b[2] |= p[4] >> 1;
+
+ b[3] = p[4] << 7;
+ b[3] |= p[5] << 2;
+ b[3] |= p[6] >> 3;
+
+ b[4] = p[6] << 5;
+ b[4] |= p[7];
+
+ b += 5;
+
+ /*
+ * Clear out the remaining 3 octets of this block.
+ */
+ b[0] = 0;
+ b[1] = 0;
+ b[2] = 0;
+ }
+
+ return b - out;
+}
+
+#ifndef TESTING
+#define LEN 6
+#define PRINT "%06u"
+#define DIV 1000000
+#else
+#define LEN 8
+#define PRINT "%08u"
+#define DIV 100000000
+#endif
+
+/*
+ * Implement RFC 6238 TOTP algorithm.
+ *
+ * Appendix B has test vectors. Note that the test vectors are
+ * for 8-character challenges, and not for 6 character
+ * challenges!
+ */
+static int totp_cmp(time_t now, uint8_t const *key, size_t keylen, char const *totp)
+{
+ uint8_t offset;
+ uint32_t challenge;
+ uint64_t padded;
+ char buffer[9];
+ uint8_t data[8];
+ uint8_t digest[SHA1_DIGEST_LENGTH];
+
+ padded = ((uint64_t) now) / TIME_STEP;
+ data[0] = padded >> 56;
+ data[1] = padded >> 48;
+ data[2] = padded >> 40;
+ data[3] = padded >> 32;
+ data[4] = padded >> 24;
+ data[5] = padded >> 16;
+ data[6] = padded >> 8;
+ data[7] = padded & 0xff;
+
+ /*
+ * Encrypt the network order time with the key.
+ */
+ fr_hmac_sha1(digest, data, 8, key, keylen);
+
+ /*
+ * Take the least significant 4 bits.
+ */
+ offset = digest[SHA1_DIGEST_LENGTH - 1] & 0x0f;
+
+ /*
+ * Grab the 32bits at "offset", and drop the high bit.
+ */
+ challenge = (digest[offset] & 0x7f) << 24;
+ challenge |= digest[offset + 1] << 16;
+ challenge |= digest[offset + 2] << 8;
+ challenge |= digest[offset + 3];
+
+ /*
+ * The token is the last 6 digits in the number.
+ */
+ snprintf(buffer, sizeof(buffer), PRINT, challenge % DIV);
+
+ return rad_digest_cmp((uint8_t const *) buffer, (uint8_t const *) totp, LEN);
+}
+
+#ifndef TESTING
+
+/*
+ * Do the authentication
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request)
+{
+ VALUE_PAIR *vp, *password;
+ uint8_t const *key;
+ size_t keylen;
+ uint8_t buffer[80]; /* multiple of 5*8 characters */
+
+
+ password = fr_pair_find_by_num(request->packet->vps, PW_TOTP_PASSWORD, 0, TAG_ANY);
+ if (!password) return RLM_MODULE_NOOP;
+
+ if (password->vp_length != 6) {
+ RDEBUG("TOTP-Password has incorrect length %d", (int) password->vp_length);
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Look for the raw key first.
+ */
+ vp = fr_pair_find_by_num(request->config, PW_TOTP_KEY, 0, TAG_ANY);
+ if (vp) {
+ key = vp->vp_octets;
+ keylen = vp->vp_length;
+
+ } else {
+ ssize_t len;
+
+ vp = fr_pair_find_by_num(request->config, PW_TOTP_SECRET, 0, TAG_ANY);
+ if (!vp) return RLM_MODULE_NOOP;
+
+ len = base32_decode(buffer, sizeof(buffer), vp->vp_strvalue);
+ if (len < 0) {
+ RDEBUG("TOTP-Secret cannot be decoded");
+ return RLM_MODULE_FAIL;
+ }
+
+ key = buffer;
+ keylen = len;
+ }
+
+ if (totp_cmp(time(NULL), key, keylen, password->vp_strvalue) != 0) return RLM_MODULE_FAIL;
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * 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_totp;
+module_t rlm_totp = {
+ .magic = RLM_MODULE_INIT,
+ .name = "totp",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ },
+};
+
+#else /* TESTING */
+int main(int argc, char **argv)
+{
+ size_t len;
+ uint8_t *p;
+ uint8_t key[80];
+
+ if (argc < 2) return 0;
+
+ if (strcmp(argv[1], "decode") == 0) {
+ if (argc < 3) return 0;
+
+ len = base32_decode(key, sizeof(key), argv[2]);
+ printf("Decoded %ld %s\n", len, key);
+
+ for (p = key; p < (key + len); p++) {
+ printf("%02x ", *p);
+ };
+ printf("\n");
+
+ return 0;
+ }
+
+ /*
+ * TOTP <time> <key> <8-character-expected-token>
+ */
+ if (strcmp(argv[1], "totp") == 0) {
+ uint64_t now;
+
+ if (argc < 5) return 0;
+
+ (void) sscanf(argv[2], "%llu", &now);
+
+ if (totp_cmp((time_t) now, (uint8_t const *) argv[3], strlen(argv[3]), argv[4]) == 0) {
+ return 0;
+ }
+ printf("Fail\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Unknown command argv[1]\n", argv[1]);
+ return 1;
+}
+#endif
diff --git a/src/modules/rlm_totp/sha1.txt b/src/modules/rlm_totp/sha1.txt
new file mode 100644
index 0000000..da85ab1
--- /dev/null
+++ b/src/modules/rlm_totp/sha1.txt
@@ -0,0 +1,6 @@
+59 12345678901234567890 94287082
+1111111109 12345678901234567890 07081804
+1111111111 12345678901234567890 14050471
+1234567890 12345678901234567890 89005924
+2000000000 12345678901234567890 69279037
+20000000000 12345678901234567890 65353130
diff --git a/src/modules/rlm_unbound/.gitignore b/src/modules/rlm_unbound/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_unbound/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_unbound/README.md b/src/modules/rlm_unbound/README.md
new file mode 100644
index 0000000..1684e25
--- /dev/null
+++ b/src/modules/rlm_unbound/README.md
@@ -0,0 +1,10 @@
+# rlm_unbound
+## Metadata
+<dl>
+ <dt>category</dt><dd>io</dd>
+</dl>
+
+## Summary
+
+Performs queries against a DNS service to allow FQDNs to be
+resolved during request processing.
diff --git a/src/modules/rlm_unbound/all.mk.in b/src/modules/rlm_unbound/all.mk.in
new file mode 100644
index 0000000..202165c
--- /dev/null
+++ b/src/modules/rlm_unbound/all.mk.in
@@ -0,0 +1,12 @@
+TARGETNAME := @targetname@
+
+ifneq "$(OPENSSL_LIBS)" ""
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@ $(OPENSSL_LIBS)
diff --git a/src/modules/rlm_unbound/config.h.in b/src/modules/rlm_unbound/config.h.in
new file mode 100644
index 0000000..b429c2f
--- /dev/null
+++ b/src/modules/rlm_unbound/config.h.in
@@ -0,0 +1 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
diff --git a/src/modules/rlm_unbound/configure b/src/modules/rlm_unbound/configure
new file mode 100755
index 0000000..735bbe7
--- /dev/null
+++ b/src/modules/rlm_unbound/configure
@@ -0,0 +1,4288 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_unbound.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_unbound
+with_rlm_unbound_lib_dir
+with_rlm_unbound_include_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_unbound build without rlm_unbound
+ --with-rlm-unbound-lib-dir=DIR
+ directory for libunbound library files
+ --with-rlm-unbound-include-dir=DIR
+ directory for libunbound include files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_unbound
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_unbound was given.
+if test "${with_rlm_unbound+set}" = set; then :
+ withval=$with_rlm_unbound;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_unbound" != xno; then
+
+
+rlm_unbound_lib_dir=
+
+# Check whether --with-rlm-unbound-lib-dir was given.
+if test "${with_rlm_unbound_lib_dir+set}" = set; then :
+ withval=$with_rlm_unbound_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-unbound-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_unbound_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+rlm_unbound_include_dir=
+
+# Check whether --with-rlm-unbound-include-dir was given.
+if test "${with_rlm_unbound_include_dir+set}" = set; then :
+ withval=$with_rlm_unbound_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need rlm-unbound-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_unbound_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+smart_try_dir=$rlm_unbound_lib_dir
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+sm_lib_safe=`echo "unbound" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ub_ctx_create" | 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 ub_ctx_create in -lunbound in $try" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound in $try... " >&6; }
+ LIBS="-lunbound $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lunbound"
+ 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 ub_ctx_create in -lunbound" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound... " >&6; }
+ LIBS="-lunbound $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lunbound"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$old_LIBS"
+fi
+
+if test "x$smart_lib" = "x"; then
+ for try in /usr/local/lib /opt/lib; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ub_ctx_create in -lunbound in $try" >&5
+$as_echo_n "checking for ub_ctx_create in -lunbound in $try... " >&6; }
+ LIBS="-lunbound $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ub_ctx_create();
+int
+main ()
+{
+ub_ctx_create()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lunbound"
+ 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_unbound_ub_ctx_create" != "xyes"; then
+
+fail="$fail libunbound"
+
+fi
+
+smart_try_dir=$rlm_unbound_include_dir
+
+
+ac_safe=`echo "unbound.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 unbound.h in $try" >&5
+$as_echo_n "checking for unbound.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ 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}/unbound.h" >&5
+$as_echo_n "checking for ${_prefix}/unbound.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-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 unbound.h" >&5
+$as_echo_n "checking for unbound.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include=" "
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$smart_include" = "x"; then
+
+ for try in $_smart_include_dir; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unbound.h in $try" >&5
+$as_echo_n "checking for unbound.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <unbound.h>
+int
+main ()
+{
+int a = 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ smart_include="-isystem $try"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+
+else
+
+ smart_include=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ CPPFLAGS="$old_CPPFLAGS"
+fi
+
+if test "x$smart_include" != "x"; then
+ eval "ac_cv_header_$ac_safe=yes"
+ CPPFLAGS="$smart_include $old_CPPFLAGS"
+ SMART_CPPFLAGS="$smart_include $SMART_CPPFLAGS"
+fi
+
+smart_prefix=
+
+if test "$ac_cv_header_unbound_h" != "yes"; then
+
+fail="$fail unbound.h"
+
+fi
+
+
+ targetname=rlm_unbound
+else
+ targetname=
+ echo \*\*\* module rlm_unbound is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_unbound to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_unbound." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_unbound." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_unbound requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_unbound requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_unbound/configure.ac b/src/modules/rlm_unbound/configure.ac
new file mode 100644
index 0000000..7d2fcff
--- /dev/null
+++ b/src/modules/rlm_unbound/configure.ac
@@ -0,0 +1,66 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_unbound.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_unbound])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl extra argument: --with-rlm-unbound-lib-dir
+rlm_unbound_lib_dir=
+AC_ARG_WITH(rlm-unbound-lib-dir,
+ [AS_HELP_STRING([--with-rlm-unbound-lib-dir=DIR],
+ [directory for libunbound library files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-unbound-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_unbound_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-rlm-unbound-include-dir
+rlm_unbound_include_dir=
+AC_ARG_WITH(rlm-unbound-include-dir,
+ [AS_HELP_STRING([--with-rlm-unbound-include-dir=DIR],
+ [directory for libunbound include files])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need rlm-unbound-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ rlm_unbound_include_dir="$withval"
+ ;;
+ esac])
+
+smart_try_dir=$rlm_unbound_lib_dir
+FR_SMART_CHECK_LIB(unbound, ub_ctx_create)
+if test "x$ac_cv_lib_unbound_ub_ctx_create" != "xyes"; then
+ FR_MODULE_FAIL([libunbound])
+fi
+
+smart_try_dir=$rlm_unbound_include_dir
+FR_SMART_CHECK_INCLUDE(unbound.h)
+if test "$ac_cv_header_unbound_h" != "yes"; then
+ FR_MODULE_FAIL([unbound.h])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="${SMART_LIBS}"
+mod_cflags="${SMART_CPPFLAGS}"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_unbound/rlm_unbound.c b/src/modules/rlm_unbound/rlm_unbound.c
new file mode 100644
index 0000000..dddc3bf
--- /dev/null
+++ b/src/modules/rlm_unbound/rlm_unbound.c
@@ -0,0 +1,758 @@
+/*
+ * 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_unbound.c
+ * @brief DNS services via libunbound.
+ *
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Brian S. Julin <bjulin@clarku.edu>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/log.h>
+#include <fcntl.h>
+
+#ifdef HAVE_WDOCUMENTATION
+DIAG_OFF(documentation)
+#endif
+#include <unbound.h>
+#ifdef HAVE_WDOCUMENTATION
+DIAG_ON(documentation)
+#endif
+
+typedef struct rlm_unbound_t {
+ struct ub_ctx *ub; /* This must come first. Do not move */
+ fr_event_list_t *el; /* This must come second. Do not move. */
+
+ char const *name;
+ char const *xlat_a_name;
+ char const *xlat_aaaa_name;
+ char const *xlat_ptr_name;
+
+ uint32_t timeout;
+
+ char const *filename;
+ char const *resolvconf;
+ char const *hosts;
+
+ int log_fd;
+ FILE *log_stream;
+
+ int log_pipe[2];
+ FILE *log_pipe_stream[2];
+ bool log_pipe_in_use;
+} rlm_unbound_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ */
+static const CONF_PARSER module_config[] = {
+ { "filename", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT | PW_TYPE_REQUIRED, rlm_unbound_t, filename), "${modconfdir}/unbound/default.conf" },
+ { "resolvconf", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_unbound_t, resolvconf), NULL },
+ { "hosts", FR_CONF_OFFSET(PW_TYPE_FILE_INPUT, rlm_unbound_t, hosts), NULL },
+ { "timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_unbound_t, timeout), "3000" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Callback sent to libunbound for xlat functions. Simply links the
+ * new ub_result via a pointer that has been allocated from the heap.
+ * This pointer has been pre-initialized to a magic value.
+ */
+static void link_ubres(void* my_arg, int err, struct ub_result* result)
+{
+ struct ub_result **ubres = (struct ub_result **)my_arg;
+
+ /*
+ * Note that while result will be NULL on error, we are explicit
+ * here because that is actually a behavior that is suboptimal
+ * and only documented in the examples. It could change.
+ */
+ if (err) {
+ ERROR("rlm_unbound: %s", ub_strerror(err));
+ *ubres = NULL;
+ } else {
+ *ubres = result;
+ }
+}
+
+/*
+ * Convert labels as found in a DNS result to a NULL terminated string.
+ *
+ * Result is written to memory pointed to by "out" but no result will
+ * be written unless it and its terminating NULL character fit in "left"
+ * bytes. Returns the number of bytes written excluding the terminating
+ * NULL, or -1 if nothing was written because it would not fit or due
+ * to a violation in the labels format.
+ */
+static int rrlabels_tostr(char *out, char *rr, size_t left)
+{
+ int offset = 0;
+
+ /*
+ * TODO: verify that unbound results (will) always use this label
+ * format, and review the specs on this label format for nuances.
+ */
+
+ if (!left) {
+ return -1;
+ }
+ if (left > 253) {
+ left = 253; /* DNS length limit */
+ }
+ /* As a whole this should be "NULL terminated" by the 0-length label */
+ if (strnlen(rr, left) > left - 1) {
+ return -1;
+ }
+
+ /* It will fit, but does it it look well formed? */
+ while (1) {
+ size_t count;
+
+ count = *((unsigned char *)(rr + offset));
+ if (!count) break;
+
+ offset++;
+ if (count > 63 || strlen(rr + offset) < count) {
+ return -1;
+ }
+ offset += count;
+ }
+
+ /* Data is valid and fits. Copy it. */
+ offset = 0;
+ while (1) {
+ int count;
+
+ count = *((unsigned char *)(rr));
+ if (!count) break;
+
+ if (offset) {
+ *(out + offset) = '.';
+ offset++;
+ }
+
+ rr++;
+ memcpy(out + offset, rr, count);
+ rr += count;
+ offset += count;
+ }
+
+ *(out + offset) = '\0';
+ return offset;
+}
+
+static int ub_common_wait(rlm_unbound_t *inst, REQUEST *request, char const *tag, struct ub_result **ub, int async_id)
+{
+ useconds_t iv, waited;
+
+ iv = inst->timeout > 64 ? 64000 : inst->timeout * 1000;
+ ub_process(inst->ub);
+
+ for (waited = 0; (void*)*ub == (void *)inst; waited += iv, iv *= 2) {
+
+ if (waited + iv > (useconds_t)inst->timeout * 1000) {
+ usleep(inst->timeout * 1000 - waited);
+ ub_process(inst->ub);
+ break;
+ }
+
+ usleep(iv);
+
+ /* Check if already handled by event loop */
+ if ((void *)*ub != (void *)inst) {
+ break;
+ }
+
+ /* In case we are running single threaded */
+ ub_process(inst->ub);
+ }
+
+ if ((void *)*ub == (void *)inst) {
+ int res;
+
+ RDEBUG("rlm_unbound (%s): DNS took too long", tag);
+
+ res = ub_cancel(inst->ub, async_id);
+ if (res) {
+ REDEBUG("rlm_unbound (%s): ub_cancel: %s",
+ tag, ub_strerror(res));
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ub_common_fail(REQUEST *request, char const *tag, struct ub_result *ub)
+{
+ if (ub->bogus) {
+ RWDEBUG("rlm_unbound (%s): Bogus DNS response", tag);
+ return -1;
+ }
+
+ if (ub->nxdomain) {
+ RDEBUG("rlm_unbound (%s): NXDOMAIN", tag);
+ return -1;
+ }
+
+ if (!ub->havedata) {
+ RDEBUG("rlm_unbound (%s): empty result", tag);
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t xlat_a(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ ub_resolve_async(inst->ub, fmt, 1, 1, ubres, link_ubres, &async_id);
+
+ if (ub_common_wait(inst, request, inst->xlat_a_name, ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_a_name, *ubres)) {
+ goto error1;
+ }
+
+ if (!inet_ntop(AF_INET, (*ubres)->data[0], out, freespace)) {
+ goto error1;
+ };
+
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_a_name);
+
+ error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+ error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+static ssize_t xlat_aaaa(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ ub_resolve_async(inst->ub, fmt, 28, 1, ubres, link_ubres, &async_id);
+
+ if (ub_common_wait(inst, request, inst->xlat_aaaa_name, ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_aaaa_name, *ubres)) {
+ goto error1;
+ }
+ if (!inet_ntop(AF_INET6, (*ubres)->data[0], out, freespace)) {
+ goto error1;
+ };
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_aaaa_name);
+
+error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+static ssize_t xlat_ptr(void *instance, REQUEST *request, char const *fmt, char *out, size_t freespace)
+{
+ rlm_unbound_t *inst = instance;
+ struct ub_result **ubres;
+ int async_id;
+
+ /* This has to be on the heap, because threads. */
+ ubres = talloc(inst, struct ub_result *);
+
+ /* Used and thus impossible value from heap to designate incomplete */
+ *ubres = (void *)instance;
+
+ ub_resolve_async(inst->ub, fmt, 12, 1, ubres, link_ubres, &async_id);
+
+ if (ub_common_wait(inst, request, inst->xlat_ptr_name,
+ ubres, async_id)) {
+ goto error0;
+ }
+
+ if (*ubres) {
+ if (ub_common_fail(request, inst->xlat_ptr_name, *ubres)) {
+ goto error1;
+ }
+ if (rrlabels_tostr(out, (*ubres)->data[0], freespace) < 0) {
+ goto error1;
+ }
+ ub_resolve_free(*ubres);
+ talloc_free(ubres);
+ return strlen(out);
+ }
+
+ RWDEBUG("rlm_unbound (%s): no result", inst->xlat_ptr_name);
+
+error1:
+ ub_resolve_free(*ubres); /* Handles NULL gracefully */
+
+error0:
+ talloc_free(ubres);
+ return -1;
+}
+
+/*
+ * Even when run in asyncronous mode, callbacks sent to libunbound still
+ * must be run in an application-side thread (via ub_process.) This is
+ * probably to keep the API usage consistent across threaded and forked
+ * embedded client modes. This callback function lets an event loop call
+ * ub_process when the instance's file descriptor becomes ready.
+ */
+static void ub_fd_handler(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
+{
+ rlm_unbound_t *inst = ctx;
+ int err;
+
+ err = ub_process(inst->ub);
+ if (err) {
+ ERROR("rlm_unbound (%s) async ub_process: %s",
+ inst->name, ub_strerror(err));
+ }
+}
+
+#ifndef HAVE_PTHREAD_H
+
+/* If we have to use a pipe to redirect logging, this does the work. */
+static void log_spew(UNUSED fr_event_list_t *el, UNUSED int sock, void *ctx)
+{
+ rlm_unbound_t *inst = ctx;
+ char line[1024];
+
+ /*
+ * This works for pipes from processes, but not from threads
+ * right now. The latter is hinky and will require some fancy
+ * blocking/nonblocking trickery which is not figured out yet,
+ * since selecting on a pipe from a thread in the same process
+ * seems to behave differently. It will likely preclude the use
+ * of fgets and streams. Left for now since some unbound logging
+ * infrastructure is still global across multiple contexts. Maybe
+ * we can get unbound folks to provide a ub_ctx_debugout_async that
+ * takes a function hook instead to just bypass the piping when
+ * used in threaded mode.
+ */
+ while (fgets(line, 1024, inst->log_pipe_stream[0])) {
+ DEBUG("rlm_unbound (%s): %s", inst->name, line);
+ }
+}
+
+#endif
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_unbound_t *inst = instance;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ if (inst->timeout > 10000) {
+ cf_log_err_cs(conf, "timeout must be 0 to 10000");
+ return -1;
+ }
+
+ MEM(inst->xlat_a_name = talloc_typed_asprintf(inst, "%s-a", inst->name));
+ MEM(inst->xlat_aaaa_name = talloc_typed_asprintf(inst, "%s-aaaa", inst->name));
+ MEM(inst->xlat_ptr_name = talloc_typed_asprintf(inst, "%s-ptr", inst->name));
+
+ if (xlat_register(inst->xlat_a_name, xlat_a, NULL, inst) ||
+ xlat_register(inst->xlat_aaaa_name, xlat_aaaa, NULL, inst) ||
+ xlat_register(inst->xlat_ptr_name, xlat_ptr, NULL, inst)) {
+ cf_log_err_cs(conf, "Failed registering xlats");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mod_instantiate(CONF_SECTION *conf, void *instance)
+{
+ rlm_unbound_t *inst = instance;
+ int res;
+ char *optval;
+
+ log_dst_t log_dst;
+ int log_level;
+ int log_fd = -1;
+
+ inst->el = radius_event_list_corral(EVENT_CORRAL_AUX);
+ inst->log_pipe_stream[0] = NULL;
+ inst->log_pipe_stream[1] = NULL;
+ inst->log_fd = -1;
+ inst->log_pipe_in_use = false;
+
+ inst->ub = ub_ctx_create();
+ if (!inst->ub) {
+ cf_log_err_cs(conf, "ub_ctx_create failed");
+ return -1;
+ }
+
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Note unbound threads WILL happen with -s option, if it matters.
+ * We cannot tell from here whether that option is in effect.
+ */
+ res = ub_ctx_async(inst->ub, 1);
+#else
+ /*
+ * Uses forked subprocesses instead.
+ */
+ res = ub_ctx_async(inst->ub, 0);
+#endif
+
+ if (res) goto error;
+
+ /* Glean some default settings to match the main server. */
+ /* TODO: debug_level can be changed at runtime. */
+ /* TODO: log until fork when stdout or stderr and !rad_debug_lvl. */
+ log_level = 0;
+
+ if (rad_debug_lvl > 0) {
+ log_level = rad_debug_lvl;
+
+ } else if (main_config.debug_level > 0) {
+ log_level = main_config.debug_level;
+ }
+
+ switch (log_level) {
+ /* TODO: This will need some tweaking */
+ case 0:
+ case 1:
+ break;
+
+ case 2:
+ log_level = 1;
+ break;
+
+ case 3:
+ case 4:
+ log_level = 2; /* mid-to-heavy levels of output */
+ break;
+
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ log_level = 3; /* Pretty crazy amounts of output */
+ break;
+
+ default:
+ log_level = 4; /* Insane amounts of output including crypts */
+ break;
+ }
+
+ res = ub_ctx_debuglevel(inst->ub, log_level);
+ if (res) goto error;
+
+ switch (default_log.dst) {
+ case L_DST_STDOUT:
+ if (!rad_debug_lvl) {
+ log_dst = L_DST_NULL;
+ break;
+ }
+ log_dst = L_DST_STDOUT;
+ log_fd = dup(STDOUT_FILENO);
+ break;
+
+ case L_DST_STDERR:
+ if (!rad_debug_lvl) {
+ log_dst = L_DST_NULL;
+ break;
+ }
+ log_dst = L_DST_STDOUT;
+ log_fd = dup(STDERR_FILENO);
+ break;
+
+ case L_DST_FILES:
+ if (main_config.log_file) {
+ res = ub_ctx_set_option(inst->ub, "logfile:", main_config.log_file);
+ if (res) {
+ goto error;
+ }
+ log_dst = L_DST_FILES;
+ break;
+ }
+ /* FALL-THROUGH */
+
+ case L_DST_NULL:
+ log_dst = L_DST_NULL;
+ break;
+
+ default:
+ log_dst = L_DST_SYSLOG;
+ break;
+ }
+
+ /* Now load the config file, which can override gleaned settings. */
+ {
+ res = ub_ctx_config(inst->ub, inst->filename);
+ if (res) goto error;
+ }
+
+ /*
+ * Check if the config file tried to use syslog. Unbound
+ * does not share syslog gracefully.
+ */
+ res = ub_ctx_get_option(inst->ub, "use-syslog", &optval);
+ if (res || !optval) goto error;
+
+ if (!strcmp(optval, "yes")) {
+ free(optval);
+
+ WARN("rlm_unbound (%s): Overriding syslog settings.", inst->name);
+ res = ub_ctx_set_option(inst->ub, "use-syslog:", "no");
+ if (res) goto error;
+
+ if (log_dst == L_DST_FILES) {
+ /* Reinstate the log file name JIC */
+ res = ub_ctx_set_option(inst->ub, "logfile:", main_config.log_file);
+ if (res) goto error;
+ }
+
+ } else {
+ if (optval) free(optval);
+
+ res = ub_ctx_get_option(inst->ub, "logfile", &optval);
+ if (res) goto error;
+
+ if (optval && strlen(optval)) {
+ log_dst = L_DST_FILES;
+
+ } else if (!rad_debug_lvl) {
+ log_dst = L_DST_NULL;
+ }
+
+ if (optval) free(optval);
+ }
+
+ switch (log_dst) {
+ case L_DST_STDOUT:
+ /*
+ * We have an fd to log to. And we've already attempted to
+ * dup it so libunbound doesn't close it on us.
+ */
+ if (log_fd == -1) {
+ cf_log_err_cs(conf, "Could not dup fd");
+ goto error_nores;
+ }
+
+ inst->log_stream = fdopen(log_fd, "w");
+ if (!inst->log_stream) {
+ cf_log_err_cs(conf, "error setting up log stream");
+ goto error_nores;
+ }
+
+ res = ub_ctx_debugout(inst->ub, inst->log_stream);
+ if (res) goto error;
+ break;
+
+ case L_DST_FILES:
+ /* We gave libunbound a filename. It is on its own now. */
+ break;
+
+ case L_DST_NULL:
+ /* We tell libunbound not to log at all. */
+ res = ub_ctx_debugout(inst->ub, NULL);
+ if (res) goto error;
+ break;
+
+ case L_DST_SYSLOG:
+#ifdef HAVE_PTHREAD_H
+ /*
+ * Currently this wreaks havoc when running threaded, so just
+ * turn logging off until that gets figured out.
+ */
+ res = ub_ctx_debugout(inst->ub, NULL);
+ if (res) goto error;
+ break;
+#else
+ /*
+ * We need to create a pipe, because libunbound does not
+ * share syslog nicely. Or the core added some new logsink.
+ */
+ if (pipe(inst->log_pipe)) {
+ error_pipe:
+ cf_log_err_cs(conf, "Error setting up log pipes");
+ goto error_nores;
+ }
+
+ if ((fcntl(inst->log_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
+ (fcntl(inst->log_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
+ goto error_pipe;
+ }
+
+ /* Opaque to us when this can be closed, so we do not. */
+ if (fcntl(inst->log_pipe[1], F_SETFL, O_NONBLOCK) < 0) {
+ goto error_pipe;
+ }
+
+ inst->log_pipe_stream[0] = fdopen(inst->log_pipe[0], "r");
+ inst->log_pipe_stream[1] = fdopen(inst->log_pipe[1], "w");
+
+ if (!inst->log_pipe_stream[0] || !inst->log_pipe_stream[1]) {
+ if (!inst->log_pipe_stream[1]) {
+ close(inst->log_pipe[1]);
+ }
+
+ if (!inst->log_pipe_stream[0]) {
+ close(inst->log_pipe[0]);
+ }
+ cf_log_err_cs(conf, "Error setting up log stream");
+ goto error_nores;
+ }
+
+ res = ub_ctx_debugout(inst->ub, inst->log_pipe_stream[1]);
+ if (res) goto error;
+
+ if (!fr_event_fd_insert(inst->el, 0, inst->log_pipe[0], log_spew, inst)) {
+ cf_log_err_cs(conf, "could not insert log fd");
+ goto error_nores;
+ }
+
+ inst->log_pipe_in_use = true;
+#endif
+ default:
+ break;
+ }
+
+ /*
+ * Load resolv.conf if specified
+ */
+ if (inst->resolvconf) ub_ctx_resolvconf(inst->ub, inst->resolvconf);
+
+ /*
+ * Load hosts file if specified
+ */
+ if (inst->hosts) ub_ctx_hosts(inst->ub, inst->hosts);
+
+ /*
+ * Now we need to finalize the context.
+ *
+ * There's no clean API to just finalize the context made public
+ * in libunbound. But we can trick it by trying to delete data
+ * which as it happens fails quickly and quietly even though the
+ * data did not exist.
+ */
+ ub_ctx_data_remove(inst->ub, "notar33lsite.foo123.nottld A 127.0.0.1");
+
+ inst->log_fd = ub_fd(inst->ub);
+ if (inst->log_fd >= 0) {
+ if (!fr_event_fd_insert(inst->el, 0, inst->log_fd, ub_fd_handler, inst)) {
+ cf_log_err_cs(conf, "could not insert async fd");
+ inst->log_fd = -1;
+ goto error_nores;
+ }
+
+ }
+
+ return 0;
+
+ error:
+ cf_log_err_cs(conf, "%s", ub_strerror(res));
+
+ error_nores:
+ if (log_fd > -1) close(log_fd);
+
+ return -1;
+}
+
+static int mod_detach(UNUSED void *instance)
+{
+ rlm_unbound_t *inst = instance;
+
+ if (inst->log_fd >= 0) {
+ fr_event_fd_delete(inst->el, 0, inst->log_fd);
+ if (inst->ub) {
+ ub_process(inst->ub);
+ /* This can hang/leave zombies currently
+ * see upstream bug #519
+ * ...so expect valgrind to complain with -m
+ */
+#if 0
+ ub_ctx_delete(inst->ub);
+#endif
+ }
+ }
+
+ if (inst->log_pipe_stream[1]) {
+ fclose(inst->log_pipe_stream[1]);
+ }
+
+ if (inst->log_pipe_stream[0]) {
+ if (inst->log_pipe_in_use) {
+ fr_event_fd_delete(inst->el, 0, inst->log_pipe[0]);
+ }
+ fclose(inst->log_pipe_stream[0]);
+ }
+
+ if (inst->log_stream) {
+ fclose(inst->log_stream);
+ }
+
+ return 0;
+}
+
+extern module_t rlm_unbound;
+module_t rlm_unbound = {
+ .magic = RLM_MODULE_INIT,
+ .name = "unbound",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_unbound_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+ .detach = mod_detach
+};
diff --git a/src/modules/rlm_unix/.gitignore b/src/modules/rlm_unix/.gitignore
new file mode 100644
index 0000000..e936973
--- /dev/null
+++ b/src/modules/rlm_unix/.gitignore
@@ -0,0 +1,2 @@
+config.h
+all.mk
diff --git a/src/modules/rlm_unix/README.md b/src/modules/rlm_unix/README.md
new file mode 100644
index 0000000..46b4b23
--- /dev/null
+++ b/src/modules/rlm_unix/README.md
@@ -0,0 +1,15 @@
+# rlm_unix
+## Metadata
+<dl>
+ <dt>category</dt><dd>datastore</dd>
+</dl>
+
+## Summary
+
+Retrieves a user's encrypted password from the local system and
+places it into the `&control:Crypt-Password` attribute. The
+password is retrieved via the `getpwent()` and `getspwent()`
+system calls.
+
+When used for accounting, works in conjunction with rlm_radutmp to
+update the utmp database.
diff --git a/src/modules/rlm_unix/all.mk.in b/src/modules/rlm_unix/all.mk.in
new file mode 100644
index 0000000..671a659
--- /dev/null
+++ b/src/modules/rlm_unix/all.mk.in
@@ -0,0 +1,10 @@
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_unix/config.h.in b/src/modules/rlm_unix/config.h.in
new file mode 100644
index 0000000..e5831bc
--- /dev/null
+++ b/src/modules/rlm_unix/config.h.in
@@ -0,0 +1,49 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `getpwnam' function. */
+#undef HAVE_GETPWNAM
+
+/* Define to 1 if you have the `getspnam' function. */
+#undef HAVE_GETSPNAM
+
+/* Define to 1 if you have the `getusershell' function. */
+#undef HAVE_GETUSERSHELL
+
+/* Define to 1 if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/src/modules/rlm_unix/configure b/src/modules/rlm_unix/configure
new file mode 100755
index 0000000..a375122
--- /dev/null
+++ b/src/modules/rlm_unix/configure
@@ -0,0 +1,4757 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="rlm_unix.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_cflags
+mod_ldflags
+targetname
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_rlm_unix
+'
+ 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_unix build without rlm_unix
+
+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. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_unix
+echo
+
+
+# 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_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $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
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ 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; } && { ac_try='./conftest$ac_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 :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ 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_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ 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. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_unix was given.
+if test "${with_rlm_unix+set}" = set; then :
+ withval=$with_rlm_unix;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_unix" != 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
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for system password file" >&5
+$as_echo_n "checking for system password file... " >&6; }
+if test -f /etc/passwd; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /etc/passwd" >&5
+$as_echo "/etc/passwd" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no /etc/passwd file" >&5
+$as_echo "no /etc/passwd file" >&6; }
+
+fail="$fail /etc/passwd"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for system shadow password file" >&5
+$as_echo_n "checking for system shadow password file... " >&6; }
+if test -f /etc/shadow; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: /etc/shadow" >&5
+$as_echo "/etc/shadow" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no /etc/shadow file" >&5
+$as_echo "no /etc/shadow file" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in shadow.h pwd.h grp.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in getspnam getusershell getpwnam
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+if test "$ac_cv_func_getpwnam" != "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no getpwnam" >&5
+$as_echo "no getpwnam" >&6; }
+
+fail="$fail getpwnam"
+
+fi
+
+if test "$ac_cv_header_pwd_h" != "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no pwd.h" >&5
+$as_echo "no pwd.h" >&6; }
+
+fail="$fail pwd.h"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getspnam in -lshadow" >&5
+$as_echo_n "checking for getspnam in -lshadow... " >&6; }
+if ${ac_cv_lib_shadow_getspnam+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lshadow $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getspnam ();
+int
+main ()
+{
+return getspnam ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_shadow_getspnam=yes
+else
+ ac_cv_lib_shadow_getspnam=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_shadow_getspnam" >&5
+$as_echo "$ac_cv_lib_shadow_getspnam" >&6; }
+if test "x$ac_cv_lib_shadow_getspnam" = xyes; then :
+
+ mod_ldflags="${mod_ldflags} -lshadow"
+ $as_echo "#define HAVE_GETSPNAM 1" >>confdefs.h
+
+
+fi
+
+
+
+ targetname=rlm_unix
+else
+ targetname=
+ echo \*\*\* module rlm_unix is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_unix to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_unix." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_unix." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_unix requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_unix requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_unix/configure.ac b/src/modules/rlm_unix/configure.ac
new file mode 100644
index 0000000..0e48ec2
--- /dev/null
+++ b/src/modules/rlm_unix/configure.ac
@@ -0,0 +1,53 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_unix.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_unix])
+
+FR_MODULE_START_TESTS
+
+AC_PROG_CC
+AC_PROG_CPP
+
+AC_MSG_CHECKING([for system password file])
+if test -f /etc/passwd; then
+ AC_MSG_RESULT(/etc/passwd)
+else
+ AC_MSG_RESULT(no /etc/passwd file)
+ FR_MODULE_FAIL([/etc/passwd])
+fi
+
+dnl useless?
+AC_MSG_CHECKING([for system shadow password file])
+if test -f /etc/shadow; then
+ AC_MSG_RESULT(/etc/shadow)
+else
+ AC_MSG_RESULT(no /etc/shadow file)
+fi
+
+AC_CHECK_HEADERS(shadow.h pwd.h grp.h)
+AC_CHECK_FUNCS(getspnam getusershell getpwnam)
+
+if test "$ac_cv_func_getpwnam" != "yes"; then
+ AC_MSG_RESULT(no getpwnam)
+ FR_MODULE_FAIL([getpwnam])
+fi
+
+if test "$ac_cv_header_pwd_h" != "yes"; then
+ AC_MSG_RESULT(no pwd.h)
+ FR_MODULE_FAIL([pwd.h])
+fi
+
+AC_CHECK_LIB(shadow, getspnam, [
+ mod_ldflags="${mod_ldflags} -lshadow"
+ AC_DEFINE(HAVE_GETSPNAM)
+])
+
+FR_MODULE_END_TESTS
+
+AC_SUBST(mod_ldflags)
+AC_SUBST(mod_cflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_unix/rlm_unix.c b/src/modules/rlm_unix/rlm_unix.c
new file mode 100644
index 0000000..229644f
--- /dev/null
+++ b/src/modules/rlm_unix/rlm_unix.c
@@ -0,0 +1,546 @@
+/*
+ * 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_unix.c
+ * @brief Unixy things
+ *
+ * authentication: Unix user authentication
+ * accounting: Functions to write radwtmp file.
+ * Also contains handler for "Group".
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ * @copyright 2000 Jeff Carneal <jeff@apex.net>
+ * @copyright 2000 Alan Curry <pacman@world.std.com>
+ */
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API
+
+#include <freeradius-devel/radiusd.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef HAVE_SHADOW_H
+# include <shadow.h>
+#endif
+
+#ifdef OSFC2
+# include <sys/security.h>
+# include <prot.h>
+#endif
+
+#ifdef OSFSIA
+# include <sia.h>
+# include <siad.h>
+#endif
+
+#include <freeradius-devel/modules.h>
+#include <freeradius-devel/sysutmp.h>
+
+static char trans[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#define ENC(c) trans[c]
+
+typedef struct rlm_unix {
+ char const *name; //!< Instance name.
+ char const *radwtmp;
+} rlm_unix_t;
+
+static const CONF_PARSER module_config[] = {
+ { "radwtmp", FR_CONF_OFFSET(PW_TYPE_FILE_OUTPUT | PW_TYPE_REQUIRED, rlm_unix_t, radwtmp), "NULL" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * The Group = handler.
+ */
+static int groupcmp(UNUSED void *instance, REQUEST *request, UNUSED VALUE_PAIR *req_vp,
+ VALUE_PAIR *check, UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ char **member;
+ int retval = -1;
+
+ /*
+ * No user name, can't compare.
+ */
+ if (!request->username) return -1;
+
+ if (rad_getpwnam(request, &pwd, request->username->vp_strvalue) < 0) {
+ RDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ if (rad_getgrnam(request, &grp, check->vp_strvalue) < 0) {
+ RDEBUG("%s", fr_strerror());
+ talloc_free(pwd);
+ return -1;
+ }
+
+ /*
+ * The users default group isn't the one we're looking for,
+ * look through the list of group members.
+ */
+ if (pwd->pw_gid == grp->gr_gid) {
+ retval = 0;
+
+ } else {
+ for (member = grp->gr_mem; *member && retval; member++) {
+ if (strcmp(*member, pwd->pw_name) == 0) {
+ retval = 0;
+ break;
+ }
+ }
+ }
+
+ /* lifo */
+ talloc_free(grp);
+ talloc_free(pwd);
+
+ return retval;
+}
+
+
+/*
+ * Read the config
+ */
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_unix_t *inst = instance;
+
+ DICT_ATTR const *group_da, *user_name_da;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) {
+ inst->name = cf_section_name1(conf);
+ }
+
+ group_da = dict_attrbyvalue(PW_GROUP, 0);
+ if (!group_da) {
+ ERROR("rlm_unix (%s): 'Group' attribute not found in dictionary", inst->name);
+ return -1;
+ }
+
+ user_name_da = dict_attrbyvalue(PW_USER_NAME, 0);
+ if (!user_name_da) {
+ ERROR("rlm_unix (%s): 'User-Name' attribute not found in dictionary", inst->name);
+ return -1;
+ }
+
+ /* FIXME - delay these until a group file has been read so we know
+ * groupcmp can actually do something */
+ paircompare_register(group_da, user_name_da, false, groupcmp, inst);
+
+#ifdef PW_GROUP_NAME /* compat */
+ {
+ DICT_ATTR const *group_name_da;
+
+ group_name_da = dict_attrbyvalue(PW_GROUP_NAME, 0);
+ if (!group_name_da) {
+ ERROR("rlm_unix (%s): 'Group-Name' attribute not found in dictionary", inst->name);
+ return -1;
+ }
+ paircompare_register(group_name_da, user_name_da, true, groupcmp, inst);
+ }
+#endif
+
+ if (paircompare_register_byname("Unix-Group", user_name_da, false, groupcmp, inst) < 0) {
+ ERROR("rlm_unix (%s): Failed registering Unix-Group: %s", inst->name,
+ fr_strerror());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Pull the users password from where-ever, and add it to
+ * the given vp list.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request)
+{
+ char const *name;
+ char const *encrypted_pass;
+#ifdef HAVE_GETSPNAM
+ struct spwd *spwd = NULL;
+#endif
+#ifdef OSFC2
+ struct pr_passwd *pr_pw;
+#else
+ struct passwd *pwd;
+#endif
+#ifdef HAVE_GETUSERSHELL
+ char *shell;
+#endif
+ VALUE_PAIR *vp;
+
+ /*
+ * We can only authenticate user requests which HAVE
+ * a User-Name attribute.
+ */
+ if (!request->username) {
+ return RLM_MODULE_NOOP;
+ }
+
+ name = request->username->vp_strvalue;
+ encrypted_pass = NULL;
+
+#ifdef OSFC2
+ if ((pr_pw = getprpwnam(name)) == NULL)
+ return RLM_MODULE_NOTFOUND;
+ encrypted_pass = pr_pw->ufld.fd_encrypt;
+
+ /*
+ * Check if account is locked.
+ */
+ if (pr_pw->uflg.fg_lock!=1) {
+ AUTH("rlm_unix: [%s]: account locked", name);
+ return RLM_MODULE_USERLOCK;
+ }
+#else /* OSFC2 */
+ if ((pwd = getpwnam(name)) == NULL) {
+ return RLM_MODULE_NOTFOUND;
+ }
+ encrypted_pass = pwd->pw_passwd;
+#endif /* OSFC2 */
+
+#ifdef HAVE_GETSPNAM
+ /*
+ * See if there is a shadow password.
+ *
+ * Only query the _system_ shadow file if the encrypted
+ * password from the passwd file is < 10 characters (i.e.
+ * a valid password would never crypt() to it). This will
+ * prevents users from using NULL password fields as things
+ * stand right now.
+ */
+ if ((!encrypted_pass) || (strlen(encrypted_pass) < 10)) {
+ if ((spwd = getspnam(name)) == NULL) {
+ return RLM_MODULE_NOTFOUND;
+ }
+ encrypted_pass = spwd->sp_pwdp;
+ }
+#endif /* HAVE_GETSPNAM */
+
+/*
+ * These require 'pwd != NULL', which isn't true on OSFC2
+ */
+#ifndef OSFC2
+#ifdef DENY_SHELL
+ /*
+ * Users with a particular shell are denied access
+ */
+ if (strcmp(pwd->pw_shell, DENY_SHELL) == 0) {
+ RAUTH("rlm_unix: [%s]: invalid shell", name);
+ return RLM_MODULE_REJECT;
+ }
+#endif
+
+#ifdef HAVE_GETUSERSHELL
+ /*
+ * Check /etc/shells for a valid shell. If that file
+ * contains /RADIUSD/ANY/SHELL then any shell will do.
+ */
+ while ((shell = getusershell()) != NULL) {
+ if (strcmp(shell, pwd->pw_shell) == 0 ||
+ strcmp(shell, "/RADIUSD/ANY/SHELL") == 0) {
+ break;
+ }
+ }
+ endusershell();
+ if (!shell) {
+ RAUTH("[%s]: invalid shell [%s]",
+ name, pwd->pw_shell);
+ return RLM_MODULE_REJECT;
+ }
+#endif
+#endif /* OSFC2 */
+
+#if defined(HAVE_GETSPNAM) && !defined(M_UNIX)
+ /*
+ * Check if password has expired.
+ */
+ if (spwd && spwd->sp_lstchg > 0 && spwd->sp_max >= 0 &&
+ (request->timestamp / 86400) > (spwd->sp_lstchg + spwd->sp_max)) {
+ RAUTH("[%s]: password has expired", name);
+ return RLM_MODULE_REJECT;
+ }
+ /*
+ * Check if account has expired.
+ */
+ if (spwd && spwd->sp_expire > 0 &&
+ (request->timestamp / 86400) > spwd->sp_expire) {
+ RAUTH("[%s]: account has expired", name);
+ return RLM_MODULE_REJECT;
+ }
+#endif
+
+#if defined(__FreeBSD__) || defined(bsdi) || defined(_PWF_EXPIRE)
+ /*
+ * Check if password has expired.
+ */
+ if ((pwd->pw_expire > 0) &&
+ (request->timestamp > pwd->pw_expire)) {
+ RAUTH("[%s]: password has expired", name);
+ return RLM_MODULE_REJECT;
+ }
+#endif
+
+ /*
+ * We might have a passwordless account.
+ *
+ * FIXME: Maybe add Auth-Type := Accept?
+ */
+ if (encrypted_pass[0] == 0)
+ return RLM_MODULE_NOOP;
+
+ vp = pair_make_config("Crypt-Password", encrypted_pass, T_OP_SET);
+ if (!vp) return RLM_MODULE_FAIL;
+
+ return RLM_MODULE_UPDATED;
+}
+
+
+/*
+ * UUencode 4 bits base64. We use this to turn a 4 byte field
+ * (an IP address) into 6 bytes of ASCII. This is used for the
+ * wtmp file if we didn't find a short name in the naslist file.
+ */
+static char *uue(void *in)
+{
+ int i;
+ static unsigned char res[7];
+ unsigned char *data = (unsigned char *)in;
+
+ res[0] = ENC( data[0] >> 2 );
+ res[1] = ENC( ((data[0] << 4) & 060) + ((data[1] >> 4) & 017) );
+ res[2] = ENC( ((data[1] << 2) & 074) + ((data[2] >> 6) & 03) );
+ res[3] = ENC( data[2] & 077 );
+
+ res[4] = ENC( data[3] >> 2 );
+ res[5] = ENC( (data[3] << 4) & 060 );
+ res[6] = 0;
+
+ for(i = 0; i < 6; i++) {
+ if (res[i] == ' ') res[i] = '`';
+ if (res[i] < 32 || res[i] > 127)
+ printf("uue: protocol error ?!\n");
+ }
+ return (char *)res;
+}
+
+
+/*
+ * Unix accounting - write a wtmp file.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
+{
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+ FILE *fp;
+ struct utmp ut;
+ time_t t;
+ char buf[64];
+ char const *s;
+ int delay = 0;
+ int status = -1;
+ int nas_address = 0;
+ int framed_address = 0;
+#ifdef USER_PROCESS
+ int protocol = -1;
+#endif
+ uint32_t nas_port = 0;
+ bool port_seen = true;
+ rlm_unix_t *inst = (rlm_unix_t *) instance;
+
+ /*
+ * No radwtmp. Don't do anything.
+ */
+ if (!inst->radwtmp) {
+ RDEBUG2("No radwtmp file configured. Ignoring accounting request");
+ return RLM_MODULE_NOOP;
+ }
+
+ if (request->packet->src_ipaddr.af != AF_INET) {
+ RDEBUG2("IPv6 is not supported for the radwtmp file.");
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Which type is this.
+ */
+ if ((vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY))==NULL) {
+ RDEBUG("no Accounting-Status-Type attribute in request");
+ return RLM_MODULE_NOOP;
+ }
+ status = vp->vp_integer;
+
+ /*
+ * FIXME: handle PW_STATUS_ALIVE like 1.5.4.3 did.
+ */
+ if (status != PW_STATUS_START &&
+ status != PW_STATUS_STOP)
+ return RLM_MODULE_NOOP;
+
+ /*
+ * We're only interested in accounting messages
+ * with a username in it.
+ */
+ if (fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY) == NULL)
+ return RLM_MODULE_NOOP;
+
+ t = request->timestamp;
+ memset(&ut, 0, sizeof(ut));
+
+ /*
+ * First, find the interesting attributes.
+ */
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (!vp->da->vendor) switch (vp->da->attr) {
+ case PW_USER_NAME:
+ if (vp->vp_length >= sizeof(ut.ut_name)) {
+ memcpy(ut.ut_name, vp->vp_strvalue, sizeof(ut.ut_name));
+ } else {
+ strlcpy(ut.ut_name, vp->vp_strvalue, sizeof(ut.ut_name));
+ }
+ break;
+
+ case PW_LOGIN_IP_HOST:
+ case PW_FRAMED_IP_ADDRESS:
+ framed_address = vp->vp_ipaddr;
+ break;
+#ifdef USER_PROCESS
+ case PW_FRAMED_PROTOCOL:
+ protocol = vp->vp_integer;
+ break;
+#endif
+ case PW_NAS_IP_ADDRESS:
+ nas_address = vp->vp_ipaddr;
+ break;
+
+ case PW_NAS_PORT:
+ nas_port = vp->vp_integer;
+ port_seen = true;
+ break;
+
+ case PW_ACCT_DELAY_TIME:
+ delay = vp->vp_integer;
+ break;
+ }
+ }
+
+ /*
+ * We don't store !root sessions, or sessions
+ * where we didn't see a NAS-Port attribute.
+ */
+ if (strncmp(ut.ut_name, "!root", sizeof(ut.ut_name)) == 0 || !port_seen)
+ return RLM_MODULE_NOOP;
+
+ /*
+ * If we didn't find out the NAS address, use the
+ * originator's IP address.
+ */
+ if (nas_address == 0) {
+ nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+ }
+ s = request->client->shortname;
+ if (!s || s[0] == 0) s = uue(&(nas_address));
+
+#ifdef __linux__
+ /*
+ * Linux has a field for the client address.
+ */
+ ut.ut_addr = framed_address;
+#endif
+ /*
+ * We use the tty field to store the terminal servers' port
+ * and address so that the tty field is unique.
+ */
+ snprintf(buf, sizeof(buf), "%03d:%s", nas_port, s);
+ strlcpy(ut.ut_line, buf, sizeof(ut.ut_line));
+
+ /*
+ * We store the dynamic IP address in the hostname field.
+ */
+#ifdef UT_HOSTSIZE
+ if (framed_address) {
+ ip_ntoa(buf, framed_address);
+ strlcpy(ut.ut_host, buf, sizeof(ut.ut_host));
+ }
+#endif
+#ifdef HAVE_UTMPX_H
+ ut.ut_xtime = t- delay;
+#else
+ ut.ut_time = t - delay;
+#endif
+#ifdef USER_PROCESS
+ /*
+ * And we can use the ID field to store
+ * the protocol.
+ */
+ if (protocol == PW_PPP)
+ strcpy(ut.ut_id, "P");
+ else if (protocol == PW_SLIP)
+ strcpy(ut.ut_id, "S");
+ else
+ strcpy(ut.ut_id, "T");
+ ut.ut_type = status == PW_STATUS_STOP ? DEAD_PROCESS : USER_PROCESS;
+#endif
+ if (status == PW_STATUS_STOP)
+ ut.ut_name[0] = 0;
+
+ /*
+ * Write a RADIUS wtmp log file.
+ *
+ * Try to open the file if we can't, we don't write the
+ * wtmp file. If we can try to write. If we fail,
+ * return RLM_MODULE_FAIL ..
+ */
+ if ((fp = fopen(inst->radwtmp, "a")) != NULL) {
+ if ((fwrite(&ut, sizeof(ut), 1, fp)) != 1) {
+ fclose(fp);
+ return RLM_MODULE_FAIL;
+ }
+ fclose(fp);
+ } else
+ return RLM_MODULE_FAIL;
+
+ return RLM_MODULE_OK;
+}
+
+/* globally exported name */
+extern module_t rlm_unix;
+module_t rlm_unix = {
+ .magic = RLM_MODULE_INIT,
+ .name = "unix",
+ .type = RLM_TYPE_THREAD_UNSAFE,
+ .inst_size = sizeof(rlm_unix_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_ACCOUNTING] = mod_accounting
+ },
+};
diff --git a/src/modules/rlm_unpack/README.md b/src/modules/rlm_unpack/README.md
new file mode 100644
index 0000000..7cc8d1b
--- /dev/null
+++ b/src/modules/rlm_unpack/README.md
@@ -0,0 +1,9 @@
+# rlm_unpack
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Unpacks binary data from octets type attributes into individual attributes.
diff --git a/src/modules/rlm_unpack/all.mk b/src/modules/rlm_unpack/all.mk
new file mode 100644
index 0000000..e569fbe
--- /dev/null
+++ b/src/modules/rlm_unpack/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_unpack.a
+SOURCES := rlm_unpack.c
diff --git a/src/modules/rlm_unpack/rlm_unpack.c b/src/modules/rlm_unpack/rlm_unpack.c
new file mode 100644
index 0000000..dfdc81a
--- /dev/null
+++ b/src/modules/rlm_unpack/rlm_unpack.c
@@ -0,0 +1,422 @@
+/*
+ * 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_unpack.c
+ * @brief Unpack binary data
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ * @copyright 2014 Alan DeKok <aland@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <ctype.h>
+
+#define PW_CAST_BASE (1850)
+
+#define GOTO_ERROR do { REDEBUG("Unexpected text at '%s'", p); goto error;} while (0)
+
+/** Unpack data
+ *
+ * Example: %{unpack:&Class 0 integer}
+ *
+ * Expands Class, treating octet at offset 0 (bytes 0-3) as an "integer".
+ */
+static ssize_t unpack_xlat(UNUSED void *instance, REQUEST *request, char const *fmt,
+ char *out, size_t outlen)
+{
+ char *data_name, *data_size, *data_type;
+ char *p;
+ size_t len, input_len;
+ int offset;
+ PW_TYPE type;
+ DICT_ATTR const *da;
+ VALUE_PAIR *vp, *cast;
+ uint8_t const *input;
+ char buffer[256];
+ uint8_t blob[256];
+
+ /*
+ * FIXME: copy only the fields here, as we parse them.
+ */
+ strlcpy(buffer, fmt, sizeof(buffer));
+
+ p = buffer;
+ while (isspace((uint8_t) *p)) p++; /* skip leading spaces */
+
+ data_name = p;
+
+ while (*p && !isspace((uint8_t) *p)) p++;
+
+ if (!*p) {
+ error:
+ REDEBUG("Format string should be '<data> <offset> <type>' e.g. '&Class 1 integer'");
+ nothing:
+ *out = '\0';
+ return -1;
+ }
+
+ while (isspace((uint8_t) *p)) *(p++) = '\0';
+ if (!*p) GOTO_ERROR;
+
+ data_size = p;
+
+ while (*p && !isspace((uint8_t) *p)) p++;
+ if (!*p) GOTO_ERROR;
+
+ while (isspace((uint8_t) *p)) *(p++) = '\0';
+ if (!*p) GOTO_ERROR;
+
+ data_type = p;
+
+ while (*p && !isspace((uint8_t) *p)) p++;
+ if (*p) GOTO_ERROR; /* anything after the type is an error */
+
+ /*
+ * Attribute reference
+ */
+ if (*data_name == '&') {
+ if (radius_get_vp(&vp, request, data_name) < 0) goto nothing;
+
+ if ((vp->da->type != PW_TYPE_OCTETS) &&
+ (vp->da->type != PW_TYPE_STRING)) {
+ REDEBUG("unpack requires the input attribute to be 'string' or 'octets'");
+ goto nothing;
+ }
+ input = vp->vp_octets;
+ input_len = vp->vp_length;
+
+ } else if ((data_name[0] == '0') && (data_name[1] == 'x')) {
+ /*
+ * Hex data.
+ */
+ len = strlen(data_name + 2);
+ if ((len & 0x01) != 0) {
+ RDEBUG("Invalid hex string in '%s'", data_name);
+ goto nothing;
+ }
+ input = blob;
+ input_len = fr_hex2bin(blob, sizeof(blob), data_name + 2, len);
+ vp = NULL;
+
+ } else {
+ GOTO_ERROR;
+ }
+
+ offset = (int) strtoul(data_size, &p, 10);
+ if (*p) {
+ REDEBUG("unpack requires a decimal number, not '%s'", data_size);
+ goto nothing;
+ }
+
+ if ((size_t) offset >= input_len) {
+ REDEBUG("Offset is larger then the input.");
+ goto nothing;
+ }
+
+ /*
+ * Allow for string(4) or octets(4), which says "take 4
+ * bytes from the thing.
+ */
+ p = strchr(data_type, '(');
+ if (p) {
+ char *end;
+ unsigned long to_copy;
+
+ *p = '\0';
+
+ /*
+ * Allow the caller to say "get me everything
+ * else"
+ */
+ if (p[1] == ')') {
+ to_copy = input_len - offset;
+ end = p + 1;
+
+ } else {
+ to_copy = strtoul(p + 1, &end, 10);
+ }
+ if (to_copy > input_len) {
+ REDEBUG("Invalid length at '%s'", p + 1);
+ goto nothing;
+ }
+
+ if ((end[0] != ')') || (end[1] != '\0')) {
+ REDEBUG("Invalid ending at '%s'", end);
+ goto nothing;
+ }
+
+ type = fr_str2int(dict_attr_types, data_type, PW_TYPE_INVALID);
+ if (type == PW_TYPE_INVALID) {
+ REDEBUG("Invalid data type '%s'", data_type);
+ goto nothing;
+ }
+
+ if ((type != PW_TYPE_OCTETS) && (type != PW_TYPE_STRING)) {
+ REDEBUG("Cannot take substring of data type '%s'", data_type);
+ goto nothing;
+ }
+
+ if (input_len < (offset + to_copy)) {
+ REDEBUG("Insufficient data to unpack '%s' from '%s'", data_type, data_name);
+ goto nothing;
+ }
+
+ /*
+ * Just copy the string over.
+ */
+ if (type == PW_TYPE_STRING) {
+ if (outlen <= to_copy) {
+ REDEBUG("Insufficient buffer space to unpack data");
+ goto nothing;
+ }
+
+ memcpy(out, input + offset, to_copy);
+ out[to_copy] = '\0';
+ return to_copy;
+ }
+
+ /*
+ * We hex encode octets.
+ */
+ if (outlen <= (to_copy * 2)) {
+ REDEBUG("Insufficient buffer space to unpack data");
+ goto nothing;
+ }
+
+ return fr_bin2hex(out, input + offset, to_copy);
+ }
+
+ type = fr_str2int(dict_attr_types, data_type, PW_TYPE_INVALID);
+ if (type == PW_TYPE_INVALID) {
+ REDEBUG("Invalid data type '%s'", data_type);
+ goto nothing;
+ }
+
+ /*
+ * Output must be a non-zero limited size.
+ */
+ if ((dict_attr_sizes[type][0] == 0) ||
+ (dict_attr_sizes[type][0] != dict_attr_sizes[type][1])) {
+ REDEBUG("unpack requires fixed-size output type, not '%s'", data_type);
+ goto nothing;
+ }
+
+ if (input_len < (offset + dict_attr_sizes[type][0])) {
+ REDEBUG("Insufficient data to unpack '%s' from '%s'", data_type, data_name);
+ goto nothing;
+ }
+
+ da = dict_attrbyvalue(PW_CAST_BASE + type, 0);
+ if (!da) {
+ REDEBUG("Cannot decode type '%s'", data_type);
+ goto nothing;
+ }
+
+ cast = fr_pair_afrom_da(request, da);
+ if (!cast) goto nothing;
+
+ memcpy(&(cast->data), input + offset, dict_attr_sizes[type][0]);
+ cast->vp_length = dict_attr_sizes[type][0];
+
+ /*
+ * Hacks
+ */
+ switch (type) {
+ case PW_TYPE_SIGNED:
+ case PW_TYPE_INTEGER:
+ case PW_TYPE_DATE:
+ cast->vp_integer = ntohl(cast->vp_integer);
+ break;
+
+ case PW_TYPE_SHORT:
+ cast->vp_short = ((input[offset] << 8) | input[offset + 1]);
+ break;
+
+ case PW_TYPE_INTEGER64:
+ cast->vp_integer64 = ntohll(cast->vp_integer64);
+ break;
+
+ default:
+ break;
+ }
+
+ len = vp_prints_value(out, outlen, cast, 0);
+ talloc_free(cast);
+
+ if (is_truncated(len, outlen)) {
+ REDEBUG("Insufficient buffer space to unpack data");
+ goto nothing;
+ }
+
+ return len;
+}
+
+/** Return a substring from a starting character for a given length
+ *
+ * Example: "%{substring:foobar 2 3}" == "oba"
+ * Example: "%{substring:foobar -3 2}" == "ba"
+ * Example: "%{substring:foobar 1 -1}" == "ooba"
+ *
+ * Syntax: "%{substring:<string|attribute> <start> <len>}"
+ */
+static ssize_t substring_xlat(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ ssize_t slen;
+ long start, len;
+ char const *p = fmt;
+ char *end, *buffer;
+
+ /*
+ * Trim whitespace
+ */
+ while (isspace((uint8_t) *p) && p++);
+
+ /*
+ * Find numeric parameters at the end.
+ * Start with final space in fmt
+ */
+ end = strrchr(p, ' ');
+ if (!end) {
+ arg_error:
+ REDEBUG("substring needs exactly three arguments: &ref <start> <len>");
+ return -1;
+ }
+ if (end == fmt) goto arg_error;
+
+ /*
+ * Walk back for previous space
+ */
+ end--;
+ while ((end >= p) && (*end != ' ') && end--);
+ if (*end != ' ') goto arg_error;
+ /*
+ * Store the total length of fmt up to the parameters including
+ * leading whitespace - if we're given a plain string we need the
+ * whole thing
+ */
+ slen = end - fmt;
+
+ end++;
+ start = strtol(end, &end, 10);
+ end++;
+ len = strtol(end, &end, 10);
+
+ /*
+ * Check for an attribute
+ */
+ if (*p == '&') {
+ vp_tmpl_t vpt;
+ slen = tmpl_from_attr_substr(&vpt, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false);
+ if (slen <= 0) {
+ REDEBUG("%s", fr_strerror());
+ return -1;
+ }
+
+ slen = tmpl_aexpand(NULL, &buffer, request, &vpt, NULL, NULL);
+ if (slen < 0) {
+ talloc_free(buffer);
+ REDEBUG("Unable to expand substring value");
+ return -1;
+ }
+
+ } else {
+ /*
+ * Input is a string, copy it to the workspace
+ */
+ buffer = talloc_array(NULL, char, slen + 1);
+ strncpy(buffer, fmt, slen);
+ buffer[slen] = '\0';
+ }
+ /*
+ * Negative start counts in from the end of the string,
+ * calculate the actual start position
+ */
+ if (start < 0) {
+ if ((0 - start) > slen) {
+ start = 0;
+ } else {
+ start = slen + start;
+ }
+ }
+
+ if (start > slen) {
+ *out = '\0';
+ talloc_free(buffer);
+ WARN("Start position %li is after end of string length of %li", start, slen);
+ return 0;
+ }
+
+ /*
+ * Negative length drops characters from the end of the string,
+ * calculate the actual length
+ */
+ if (len < 0) len = slen - start + len;
+
+ if (len < 0) {
+ WARN("String length of %li too short for substring parameters", slen);
+ len = 0;
+ }
+
+ /*
+ * Reduce length to match available string length
+ */
+ if (len > (slen - start)) len = slen - start;
+
+ /*
+ * Reduce length to "out" capacity
+ */
+ if (len > (long) outlen) len = outlen;
+
+ strncpy(out, buffer + start, len);
+ out[len] = '\0';
+ talloc_free(buffer);
+ return len;
+}
+
+/*
+ * Register the xlats
+ */
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ if (cf_section_name2(conf)) return 0;
+
+ xlat_register("unpack", unpack_xlat, NULL, instance);
+ xlat_register("substring", substring_xlat, NULL, instance);
+
+ return 0;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ *
+ * If the module needs to temporarily modify it's instantiation
+ * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
+ * The server will then take care of ensuring that the module
+ * is single-threaded.
+ */
+extern module_t rlm_unpack;
+module_t rlm_unpack = {
+ .magic = RLM_MODULE_INIT,
+ .name = "unpack",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .bootstrap = mod_bootstrap
+};
diff --git a/src/modules/rlm_utf8/README.md b/src/modules/rlm_utf8/README.md
new file mode 100644
index 0000000..a7f63be
--- /dev/null
+++ b/src/modules/rlm_utf8/README.md
@@ -0,0 +1,10 @@
+# rlm_utf8
+## Metadata
+<dl>
+ <dt>category</dt><dd>policy</dd>
+</dl>
+
+## Summary
+
+Checks all attributes of type string in the current request, to
+ensure that they only contain valid UTF8 sequences.
diff --git a/src/modules/rlm_utf8/all.mk b/src/modules/rlm_utf8/all.mk
new file mode 100644
index 0000000..1f6f103
--- /dev/null
+++ b/src/modules/rlm_utf8/all.mk
@@ -0,0 +1,2 @@
+TARGET := rlm_utf8.a
+SOURCES := rlm_utf8.c
diff --git a/src/modules/rlm_utf8/rlm_utf8.c b/src/modules/rlm_utf8/rlm_utf8.c
new file mode 100644
index 0000000..d2031c6
--- /dev/null
+++ b/src/modules/rlm_utf8/rlm_utf8.c
@@ -0,0 +1,73 @@
+/*
+ * 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_utf8.c
+ * @brief Enforce UTF8 encoding in strings.
+ *
+ * @copyright 2000,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+/*
+ * Reject any non-UTF8 data.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_utf8_clean(UNUSED void *instance, REQUEST *request)
+{
+ size_t i, len;
+ VALUE_PAIR *vp;
+ vp_cursor_t cursor;
+
+ for (vp = fr_cursor_init(&cursor, &request->packet->vps);
+ vp;
+ vp = fr_cursor_next(&cursor)) {
+ if (vp->da->type != PW_TYPE_STRING) continue;
+
+ for (i = 0; i < vp->vp_length; i += len) {
+ len = fr_utf8_char(&vp->vp_octets[i], -1);
+ if (len == 0) return RLM_MODULE_FAIL;
+ }
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+/*
+ * 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_utf8;
+module_t rlm_utf8 = {
+ .magic = RLM_MODULE_INIT,
+ .name = "utf8",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_utf8_clean,
+ [MOD_PREACCT] = mod_utf8_clean,
+#ifdef WITH_COA
+ [MOD_RECV_COA] = mod_utf8_clean
+#endif
+ },
+};
diff --git a/src/modules/rlm_wimax/README.md b/src/modules/rlm_wimax/README.md
new file mode 100644
index 0000000..6d1b342
--- /dev/null
+++ b/src/modules/rlm_wimax/README.md
@@ -0,0 +1,9 @@
+# rlm_wimax
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Implements WiMAX authentication over RADIUS.
diff --git a/src/modules/rlm_wimax/all.mk b/src/modules/rlm_wimax/all.mk
new file mode 100644
index 0000000..89e759b
--- /dev/null
+++ b/src/modules/rlm_wimax/all.mk
@@ -0,0 +1,9 @@
+TARGETNAME := rlm_wimax
+
+ifneq "$(OPENSSL_LIBS)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c milenage.c
+
+TGT_LDLIBS := $(OPENSSL_LIBS)
diff --git a/src/modules/rlm_wimax/milenage.c b/src/modules/rlm_wimax/milenage.c
new file mode 100644
index 0000000..e14086e
--- /dev/null
+++ b/src/modules/rlm_wimax/milenage.c
@@ -0,0 +1,642 @@
+/**
+ * @file src/modules/rlm_wimax/milenage.c
+ * @brief 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ *
+ * This file implements an example authentication algorithm defined for 3GPP
+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
+ * EAP-AKA to be tested properly with real USIM cards.
+ *
+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in
+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
+ * be AES (Rijndael).
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * @copyright 2017 The FreeRADIUS server project
+ * @copyright 2006-2007 (j@w1.fi)
+ */
+#include <stddef.h>
+#include <string.h>
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <openssl/evp.h>
+#include "milenage.h"
+
+#define MILENAGE_MAC_A_SIZE 8
+#define MILENAGE_MAC_S_SIZE 8
+
+static inline int aes_128_encrypt_block(EVP_CIPHER_CTX *evp_ctx,
+ uint8_t const key[16], uint8_t const in[16], uint8_t out[16])
+{
+ size_t len;
+
+ if (unlikely(EVP_EncryptInit_ex(evp_ctx, EVP_aes_128_ecb(), NULL, key, NULL) != 1)) {
+ fr_strerror_printf("Failed initialising AES-128-ECB context");
+ return -1;
+ }
+
+ /*
+ * By default OpenSSL will try and pad out a 16 byte
+ * plaintext to 32 bytes so that it's detectable that
+ * there was padding.
+ *
+ * In this case we know the length of the plaintext
+ * we're trying to recover, so we explicitly tell
+ * OpenSSL not to pad here, and not to expected padding
+ * when decrypting.
+ */
+ EVP_CIPHER_CTX_set_padding(evp_ctx, 0);
+ if (unlikely(EVP_EncryptUpdate(evp_ctx, out, (int *)&len, in, 16) != 1) ||
+ unlikely(EVP_EncryptFinal_ex(evp_ctx, out + len, (int *)&len) != 1)) {
+ fr_strerror_printf("Failed encrypting data");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** milenage_f1 - Milenage f1 and f1* algorithms
+ *
+ * @param[in] opc 128-bit value derived from OP and K.
+ * @param[in] k 128-bit subscriber key.
+ * @param[in] rand 128-bit random challenge.
+ * @param[in] sqn 48-bit sequence number.
+ * @param[in] amf 16-bit authentication management field.
+ * @param[out] mac_a Buffer for MAC-A = 64-bit network authentication code, or NULL
+ * @param[out] mac_s Buffer for MAC-S = 64-bit resync authentication code, or NULL
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+static int milenage_f1(uint8_t mac_a[MILENAGE_MAC_A_SIZE],
+ uint8_t mac_s[MILENAGE_MAC_S_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const k[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE],
+ uint8_t const sqn[MILENAGE_SQN_SIZE],
+ uint8_t const amf[MILENAGE_AMF_SIZE])
+{
+ uint8_t tmp1[16], tmp2[16], tmp3[16];
+ int i;
+ EVP_CIPHER_CTX *evp_ctx;
+
+ /* tmp1 = TEMP = E_K(RAND XOR OP_C) */
+ for (i = 0; i < 16; i++) tmp1[i] = rand[i] ^ opc[i];
+
+ evp_ctx = EVP_CIPHER_CTX_new();
+ if (!evp_ctx) {
+ //tls_strerror_printf("Failed allocating EVP context");
+ return -1;
+ }
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp1) < 0) {
+ error:
+ EVP_CIPHER_CTX_free(evp_ctx);
+ return -1;
+ }
+
+ /* tmp2 = IN1 = SQN || AMF || SQN || AMF */
+ memcpy(tmp2, sqn, 6);
+ memcpy(tmp2 + 6, amf, 2);
+ memcpy(tmp2 + 8, tmp2, 8);
+
+ /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
+
+ /*
+ * rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes)
+ */
+ for (i = 0; i < 16; i++) tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
+
+ /*
+ * XOR with TEMP = E_K(RAND XOR OP_C)
+ */
+ for (i = 0; i < 16; i++) tmp3[i] ^= tmp1[i];
+ /* XOR with c1 (= ..00, i.e., NOP) */
+
+ /*
+ * f1 || f1* = E_K(tmp3) XOR OP_c
+ */
+ if (aes_128_encrypt_block(evp_ctx, k, tmp3, tmp1) < 0) goto error; /* Reuses existing key */
+
+ for (i = 0; i < 16; i++) tmp1[i] ^= opc[i];
+
+ if (mac_a) memcpy(mac_a, tmp1, 8); /* f1 */
+ if (mac_s) memcpy(mac_s, tmp1 + 8, 8); /* f1* */
+
+ EVP_CIPHER_CTX_free(evp_ctx);
+
+ return 0;
+}
+
+/** milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
+ *
+ * @param[out] res Buffer for RES = 64-bit signed response (f2), or NULL
+ * @param[out] ck Buffer for CK = 128-bit confidentiality key (f3), or NULL
+ * @param[out] ik Buffer for IK = 128-bit integrity key (f4), or NULL
+ * @param[out] ak Buffer for AK = 48-bit anonymity key (f5), or NULL
+ * @param[out] ak_resync Buffer for AK = 48-bit anonymity key (f5*), or NULL
+ * @param[in] opc 128-bit value derived from OP and K.
+ * @param[in] k 128-bit subscriber key
+ * @param[in] rand 128-bit random challenge
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+static int milenage_f2345(uint8_t res[MILENAGE_RES_SIZE],
+ uint8_t ik[MILENAGE_IK_SIZE],
+ uint8_t ck[MILENAGE_CK_SIZE],
+ uint8_t ak[MILENAGE_AK_SIZE],
+ uint8_t ak_resync[MILENAGE_AK_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const k[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE])
+{
+ uint8_t tmp1[16], tmp2[16], tmp3[16];
+ int i;
+ EVP_CIPHER_CTX *evp_ctx;
+
+ /* tmp2 = TEMP = E_K(RAND XOR OP_C) */
+ for (i = 0; i < 16; i++) tmp1[i] = rand[i] ^ opc[i];
+
+ evp_ctx = EVP_CIPHER_CTX_new();
+ if (!evp_ctx) {
+ fr_strerror_printf("Failed allocating EVP context");
+ return -1;
+ }
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp2) < 0) {
+ error:
+ EVP_CIPHER_CTX_free(evp_ctx);
+ return -1;
+ }
+
+ /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
+ /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
+ /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
+ /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
+
+ /* f2 and f5 */
+ /* rotate by r2 (= 0, i.e., NOP) */
+ for (i = 0; i < 16; i++) tmp1[i] = tmp2[i] ^ opc[i];
+ tmp1[15] ^= 1; /* XOR c2 (= ..01) */
+ /* f5 || f2 = E_K(tmp1) XOR OP_c */
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp3) < 0) goto error;
+
+ for (i = 0; i < 16; i++) tmp3[i] ^= opc[i];
+ if (res) memcpy(res, tmp3 + 8, 8); /* f2 */
+ if (ak) memcpy(ak, tmp3, 6); /* f5 */
+
+ /* f3 */
+ if (ck) {
+ /* rotate by r3 = 0x20 = 4 bytes */
+ for (i = 0; i < 16; i++) tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
+ tmp1[15] ^= 2; /* XOR c3 (= ..02) */
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, ck) < 0) goto error;
+
+ for (i = 0; i < 16; i++) ck[i] ^= opc[i];
+ }
+
+ /* f4 */
+ if (ik) {
+ /* rotate by r4 = 0x40 = 8 bytes */
+ for (i = 0; i < 16; i++) tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
+ tmp1[15] ^= 4; /* XOR c4 (= ..04) */
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, ik) < 0) goto error;
+
+ for (i = 0; i < 16; i++) ik[i] ^= opc[i];
+ }
+
+ /* f5* */
+ if (ak_resync) {
+ /* rotate by r5 = 0x60 = 12 bytes */
+ for (i = 0; i < 16; i++) tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
+ tmp1[15] ^= 8; /* XOR c5 (= ..08) */
+
+ if (aes_128_encrypt_block(evp_ctx, k, tmp1, tmp1) < 0) goto error;
+
+ for (i = 0; i < 6; i++) ak_resync[i] = tmp1[i] ^ opc[i];
+ }
+ EVP_CIPHER_CTX_free(evp_ctx);
+
+ return 0;
+}
+
+/** Derive OPc from OP and Ki
+ *
+ * @param[out] opc The derived Operator Code used as an input to other Milenage
+ * functions.
+ * @param[in] op Operator Code.
+ * @param[in] ki Subscriber key.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE],
+ uint8_t const op[MILENAGE_OP_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE])
+{
+ int ret;
+ uint8_t tmp[MILENAGE_OPC_SIZE];
+ EVP_CIPHER_CTX *evp_ctx;
+ size_t i;
+
+ evp_ctx = EVP_CIPHER_CTX_new();
+ if (!evp_ctx) {
+ fr_strerror_printf("Failed allocating EVP context");
+ return -1;
+ }
+ ret = aes_128_encrypt_block(evp_ctx, ki, op, tmp);
+ EVP_CIPHER_CTX_free(evp_ctx);
+ if (ret < 0) return ret;
+
+ for (i = 0; i < sizeof(tmp); i++) opc[i] = op[i] ^ tmp[i];
+
+ return 0;
+}
+
+/** Generate AKA AUTN, IK, CK, RES
+ *
+ * @param[out] autn Buffer for AUTN = 128-bit authentication token.
+ * @param[out] ik Buffer for IK = 128-bit integrity key (f4), or NULL.
+ * @param[out] ck Buffer for CK = 128-bit confidentiality key (f3), or NULL.
+ * @param[out] ak Buffer for AK = 48-bit anonymity key (f5), or NULL
+ * @param[out] res Buffer for RES = 64-bit signed response (f2), or NULL.
+ * @param[in] opc 128-bit operator variant algorithm configuration field (encr.).
+ * @param[in] amf 16-bit authentication management field.
+ * @param[in] ki 128-bit subscriber key.
+ * @param[in] sqn 48-bit sequence number (host byte order).
+ * @param[in] rand 128-bit random challenge.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int milenage_umts_generate(uint8_t autn[MILENAGE_AUTN_SIZE],
+ uint8_t ik[MILENAGE_IK_SIZE],
+ uint8_t ck[MILENAGE_CK_SIZE],
+ uint8_t ak[MILENAGE_AK_SIZE],
+ uint8_t res[MILENAGE_RES_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const amf[MILENAGE_AMF_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint64_t sqn,
+ uint8_t const rand[MILENAGE_RAND_SIZE])
+{
+ uint8_t mac_a[8], ak_buff[MILENAGE_AK_SIZE];
+ uint8_t sqn_buff[MILENAGE_SQN_SIZE];
+ uint8_t *p = autn;
+ size_t i;
+
+ if ((milenage_f1(mac_a, NULL, opc, ki, rand,
+ uint48_to_buff(sqn_buff, sqn), amf) < 0) ||
+ (milenage_f2345(res, ik, ck, ak_buff, NULL, opc, ki, rand) < 0)) return -1;
+
+ /*
+ * AUTN = (SQN ^ AK) || AMF || MAC_A
+ */
+ for (i = 0; i < sizeof(sqn_buff); i++) *p++ = sqn_buff[i] ^ ak_buff[i];
+ memcpy(p, amf, MILENAGE_AMF_SIZE);
+ p += MILENAGE_AMF_SIZE;
+ memcpy(p, mac_a, sizeof(mac_a));
+
+ /*
+ * Output the anonymity key if required
+ */
+ if (ak) memcpy(ak, ak_buff, sizeof(ak_buff));
+
+ return 0;
+}
+
+/** Milenage AUTS validation
+ *
+ * @param[out] sqn SQN = 48-bit sequence number (host byte order).
+ * @param[in] opc 128-bit operator variant algorithm configuration field (encr.).
+ * @param[in] ki 128-bit subscriber key.
+ * @param[in] rand 128-bit random challenge.
+ * @param[in] auts 112-bit authentication token from client.
+ * @return
+ * - 0 on success with sqn filled.
+ * - -1 on failure.
+ */
+int milenage_auts(uint64_t *sqn,
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE],
+ uint8_t const auts[MILENAGE_AUTS_SIZE])
+{
+ uint8_t amf[MILENAGE_AMF_SIZE] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+ uint8_t ak[MILENAGE_AK_SIZE], mac_s[MILENAGE_MAC_S_SIZE];
+ uint8_t sqn_buff[MILENAGE_SQN_SIZE];
+ size_t i;
+
+ if (milenage_f2345(NULL, NULL, NULL, NULL, ak, opc, ki, rand)) return -1;
+ for (i = 0; i < sizeof(sqn_buff); i++) sqn_buff[i] = auts[i] ^ ak[i];
+
+ if (milenage_f1(NULL, mac_s, opc, ki, rand, sqn_buff, amf) || CRYPTO_memcmp(mac_s, auts + 6, 8) != 0) return -1;
+
+ *sqn = uint48_from_buff(sqn_buff);
+
+ return 0;
+}
+
+/** Generate GSM-Milenage (3GPP TS 55.205) authentication triplet from a quintuplet
+ *
+ * @param[out] sres Buffer for SRES = 32-bit SRES.
+ * @param[out] kc 64-bit Kc.
+ * @param[in] ik 128-bit integrity.
+ * @param[in] ck Confidentiality key.
+ * @param[in] res 64-bit signed response.
+ */
+void milenage_gsm_from_umts(uint8_t sres[MILENAGE_SRES_SIZE],
+ uint8_t kc[MILENAGE_KC_SIZE],
+ uint8_t const ik[MILENAGE_IK_SIZE],
+ uint8_t const ck[MILENAGE_CK_SIZE],
+ uint8_t const res[MILENAGE_RES_SIZE])
+{
+ int i;
+
+ for (i = 0; i < 8; i++) kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
+
+#ifdef GSM_MILENAGE_ALT_SRES
+ memcpy(sres, res, 4);
+#else /* GSM_MILENAGE_ALT_SRES */
+ for (i = 0; i < 4; i++) sres[i] = res[i] ^ res[i + 4];
+#endif /* GSM_MILENAGE_ALT_SRES */
+}
+
+/** Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
+ *
+ * @param[out] sres Buffer for SRES = 32-bit SRES.
+ * @param[out] kc 64-bit Kc.
+ * @param[in] opc 128-bit operator variant algorithm configuration field (encr.).
+ * @param[in] ki 128-bit subscriber key.
+ * @param[in] rand 128-bit random challenge.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int milenage_gsm_generate(uint8_t sres[MILENAGE_SRES_SIZE],
+ uint8_t kc[MILENAGE_KC_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE])
+{
+ uint8_t res[MILENAGE_RES_SIZE], ck[MILENAGE_CK_SIZE], ik[MILENAGE_IK_SIZE];
+
+ if (milenage_f2345(res, ik, ck, NULL, NULL, opc, ki, rand)) return -1;
+
+ milenage_gsm_from_umts(sres, kc, ik, ck, res);
+
+ return 0;
+}
+
+/** Milenage check
+ *
+ * @param[out] ik Buffer for IK = 128-bit integrity key (f4), or NULL.
+ * @param[out] ck Buffer for CK = 128-bit confidentiality key (f3), or NULL.
+ * @param[out] res Buffer for RES = 64-bit signed response (f2), or NULL.
+ * @param[in] auts 112-bit buffer for AUTS.
+ * @param[in] opc 128-bit operator variant algorithm configuration field (encr.).
+ * @param[in] ki 128-bit subscriber key.
+ * @param[in] sqn 48-bit sequence number.
+ * @param[in] rand 128-bit random challenge.
+ * @param[in] autn 128-bit authentication token.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ * - -2 on synchronization failure
+ */
+int milenage_check(uint8_t ik[MILENAGE_IK_SIZE],
+ uint8_t ck[MILENAGE_CK_SIZE],
+ uint8_t res[MILENAGE_RES_SIZE],
+ uint8_t auts[MILENAGE_AUTS_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint64_t sqn,
+ uint8_t const rand[MILENAGE_RAND_SIZE],
+ uint8_t const autn[MILENAGE_AUTN_SIZE])
+{
+
+ uint8_t mac_a[MILENAGE_MAC_A_SIZE], ak[MILENAGE_AK_SIZE], rx_sqn[MILENAGE_SQN_SIZE];
+ uint8_t sqn_buff[MILENAGE_SQN_SIZE];
+ const uint8_t *amf;
+ size_t i;
+
+ uint48_to_buff(sqn_buff, sqn);
+
+ //FR_PROTO_HEX_DUMP(autn, MILENAGE_AUTN_SIZE, "AUTN");
+ //FR_PROTO_HEX_DUMP(rand, MILENAGE_RAND_SIZE, "RAND");
+
+ if (milenage_f2345(res, ck, ik, ak, NULL, opc, ki, rand)) return -1;
+
+ //FR_PROTO_HEX_DUMP(res, MILENAGE_RES_SIZE, "RES");
+ //FR_PROTO_HEX_DUMP(ck, MILENAGE_CK_SIZE, "CK");
+ //FR_PROTO_HEX_DUMP(ik, MILENAGE_IK_SIZE, "IK");
+ //FR_PROTO_HEX_DUMP(ak, MILENAGE_AK_SIZE, "AK");
+
+ /* AUTN = (SQN ^ AK) || AMF || MAC */
+ for (i = 0; i < 6; i++) rx_sqn[i] = autn[i] ^ ak[i];
+ //FR_PROTO_HEX_DUMP(rx_sqn, MILENAGE_SQN_SIZE, "SQN");
+
+ if (CRYPTO_memcmp(rx_sqn, sqn_buff, sizeof(rx_sqn)) <= 0) {
+ uint8_t auts_amf[MILENAGE_AMF_SIZE] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+
+ if (milenage_f2345(NULL, NULL, NULL, NULL, ak, opc, ki, rand)) return -1;
+
+ //FR_PROTO_HEX_DUMP(ak, sizeof(ak), "AK*");
+ for (i = 0; i < 6; i++) auts[i] = sqn_buff[i] ^ ak[i];
+
+ if (milenage_f1(NULL, auts + 6, opc, ki, rand, sqn_buff, auts_amf) < 0) return -1;
+ //FR_PROTO_HEX_DUMP(auts, 14, "AUTS");
+ return -2;
+ }
+
+ amf = autn + 6;
+ //FR_PROTO_HEX_DUMP(amf, MILENAGE_AMF_SIZE, "AMF");
+ if (milenage_f1(mac_a, NULL, opc, ki, rand, rx_sqn, amf) < 0) return -1;
+
+ //FR_PROTO_HEX_DUMP(mac_a, MILENAGE_MAC_A_SIZE, "MAC_A");
+
+ if (CRYPTO_memcmp(mac_a, autn + 8, 8) != 0) {
+ //FR_PROTO_HEX_DUMP(autn + 8, 8, "Received MAC_A");
+ fr_strerror_printf("MAC mismatch");
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef TESTING_MILENAGE
+/*
+ * cc milenage.c -g3 -Wall -DHAVE_DLFCN_H -DTESTING_MILENAGE -DWITH_TLS -I../../../../ -I../../../ -I ../base/ -I /usr/local/opt/openssl/include/ -include ../include/build.h -L /usr/local/opt/openssl/lib/ -l ssl -l crypto -l talloc -L ../../../../../build/lib/local/.libs/ -lfreeradius-server -lfreeradius-tls -lfreeradius-util -o test_milenage && ./test_milenage
+ */
+#include <freeradius-devel/util/acutest.h>
+
+void test_set_1(void)
+{
+ /*
+ * Inputs
+ */
+ uint8_t ki[] = { 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+ 0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc };
+ uint8_t rand[] = { 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+ 0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 };
+ uint8_t sqn[] = { 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 };
+ uint8_t amf[] = { 0xb9, 0xb9 };
+ uint8_t op[] = { 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6,
+ 0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 };
+ uint8_t opc[] = { 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+ 0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf };
+
+ /*
+ * Outputs
+ */
+ uint8_t opc_out[MILENAGE_OPC_SIZE];
+ uint8_t mac_a_out[MILENAGE_MAC_A_SIZE];
+ uint8_t mac_s_out[MILENAGE_MAC_S_SIZE];
+ uint8_t res_out[MILENAGE_RES_SIZE];
+ uint8_t ck_out[MILENAGE_CK_SIZE];
+ uint8_t ik_out[MILENAGE_IK_SIZE];
+ uint8_t ak_out[MILENAGE_AK_SIZE];
+ uint8_t ak_resync_out[MILENAGE_AK_SIZE];
+
+ /* function 1 */
+ uint8_t mac_a[] = { 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 };
+ /* function 1* */
+ uint8_t mac_s[] = { 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 };
+ /* function 2 */
+ uint8_t res[] = { 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf };
+ /* function 3 */
+ uint8_t ck[] = { 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05,
+ 0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb };
+ /* function 4 */
+ uint8_t ik[] = { 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04,
+ 0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 };
+ /* function 5 */
+ uint8_t ak[] = { 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 };
+ /* function 5* */
+ uint8_t ak_resync[] = { 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b };
+
+ int ret = 0;
+
+/*
+ fr_debug_lvl = 4;
+*/
+ ret = milenage_opc_generate(opc_out, op, ki);
+ TEST_CHECK(ret == 0);
+
+ //FR_PROTO_HEX_DUMP(opc_out, sizeof(opc_out), "opc");
+
+ TEST_CHECK(memcmp(opc_out, opc, sizeof(opc_out)) == 0);
+
+ if ((milenage_f1(mac_a_out, mac_s_out, opc, ki, rand, sqn, amf) < 0) ||
+ (milenage_f2345(res_out, ik_out, ck_out, ak_out, ak_resync_out, opc, ki, rand) < 0)) ret = -1;
+
+ //FR_PROTO_HEX_DUMP(mac_a, sizeof(mac_a_out), "mac_a");
+ //FR_PROTO_HEX_DUMP(mac_s, sizeof(mac_s_out), "mac_s");
+ //FR_PROTO_HEX_DUMP(ik_out, sizeof(ik_out), "ik");
+ //FR_PROTO_HEX_DUMP(ck_out, sizeof(ck_out), "ck");
+ //FR_PROTO_HEX_DUMP(res_out, sizeof(res_out), "res");
+ //FR_PROTO_HEX_DUMP(ak_out, sizeof(ak_out), "ak");
+ //FR_PROTO_HEX_DUMP(ak_resync_out, sizeof(ak_resync_out), "ak_resync");
+
+ TEST_CHECK(ret == 0);
+ TEST_CHECK(memcmp(mac_a_out, mac_a, sizeof(mac_a_out)) == 0);
+ TEST_CHECK(memcmp(mac_s_out, mac_s, sizeof(mac_s_out)) == 0);
+ TEST_CHECK(memcmp(res_out, res, sizeof(res_out)) == 0);
+ TEST_CHECK(memcmp(ck_out, ck, sizeof(ck_out)) == 0);
+ TEST_CHECK(memcmp(ik_out, ik, sizeof(ik_out)) == 0);
+ TEST_CHECK(memcmp(ak_out, ak, sizeof(ak_out)) == 0);
+ TEST_CHECK(memcmp(ak_resync, ak_resync, sizeof(ak_resync_out)) == 0);
+}
+
+void test_set_19(void)
+{
+ /*
+ * Inputs
+ */
+ uint8_t ki[] = { 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72,
+ 0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 };
+ uint8_t rand[] = { 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
+ 0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 };
+ uint8_t sqn[] = { 0x16, 0xf3, 0xb3, 0xf7, 0x0f, 0xc2 };
+ uint8_t amf[] = { 0xc3, 0xab };
+ uint8_t op[] = { 0xc9, 0xe8, 0x76, 0x32, 0x86, 0xb5, 0xb9, 0xff,
+ 0xbd, 0xf5, 0x6e, 0x12, 0x97, 0xd0, 0x88, 0x7b };
+ uint8_t opc[] = { 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e,
+ 0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf };
+
+ /*
+ * Outputs
+ */
+ uint8_t opc_out[MILENAGE_OPC_SIZE];
+ uint8_t mac_a_out[MILENAGE_MAC_A_SIZE];
+ uint8_t mac_s_out[MILENAGE_MAC_S_SIZE];
+ uint8_t res_out[MILENAGE_RES_SIZE];
+ uint8_t ck_out[MILENAGE_CK_SIZE];
+ uint8_t ik_out[MILENAGE_IK_SIZE];
+ uint8_t ak_out[MILENAGE_AK_SIZE];
+ uint8_t ak_resync_out[MILENAGE_AK_SIZE];
+
+ /* function 1 */
+ uint8_t mac_a[] = { 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 };
+ /* function 1* */
+ uint8_t mac_s[] = { 0x62, 0xda, 0xe3, 0x85, 0x3f, 0x3a, 0xf9, 0xd2 };
+ /* function 2 */
+ uint8_t res[] = { 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 };
+ /* function 3 */
+ uint8_t ck[] = { 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94,
+ 0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f };
+ /* function 4 */
+ uint8_t ik[] = { 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb,
+ 0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a };
+ /* function 5 */
+ uint8_t ak[] = { 0xad, 0xa1, 0x5a, 0xeb, 0x7b, 0xb8 };
+ /* function 5* */
+ uint8_t ak_resync[] = { 0xd4, 0x61, 0xbc, 0x15, 0x47, 0x5d };
+
+ int ret = 0;
+
+/*
+ fr_debug_lvl = 4;
+*/
+
+ ret = milenage_opc_generate(opc_out, op, ki);
+ TEST_CHECK(ret == 0);
+
+ //FR_PROTO_HEX_DUMP(opc_out, sizeof(opc_out), "opc");
+
+ TEST_CHECK(memcmp(opc_out, opc, sizeof(opc_out)) == 0);
+
+ if ((milenage_f1(mac_a_out, mac_s_out, opc, ki, rand, sqn, amf) < 0) ||
+ (milenage_f2345(res_out, ik_out, ck_out, ak_out, ak_resync_out, opc, ki, rand) < 0)) ret = -1;
+
+ //FR_PROTO_HEX_DUMP(mac_a, sizeof(mac_a_out), "mac_a");
+ //FR_PROTO_HEX_DUMP(mac_s, sizeof(mac_s_out), "mac_s");
+ //FR_PROTO_HEX_DUMP(ik_out, sizeof(ik_out), "ik");
+ //FR_PROTO_HEX_DUMP(ck_out, sizeof(ck_out), "ck");
+ //FR_PROTO_HEX_DUMP(res_out, sizeof(res_out), "res");
+ //FR_PROTO_HEX_DUMP(ak_out, sizeof(ak_out), "ak");
+ //FR_PROTO_HEX_DUMP(ak_resync_out, sizeof(ak_resync_out), "ak_resync");
+
+ TEST_CHECK(ret == 0);
+ TEST_CHECK(memcmp(mac_a_out, mac_a, sizeof(mac_a_out)) == 0);
+ TEST_CHECK(memcmp(mac_s_out, mac_s, sizeof(mac_s_out)) == 0);
+ TEST_CHECK(memcmp(res_out, res, sizeof(res_out)) == 0);
+ TEST_CHECK(memcmp(ck_out, ck, sizeof(ck_out)) == 0);
+ TEST_CHECK(memcmp(ik_out, ik, sizeof(ik_out)) == 0);
+ TEST_CHECK(memcmp(ak_out, ak, sizeof(ak_out)) == 0);
+ TEST_CHECK(memcmp(ak_resync, ak_resync, sizeof(ak_resync_out)) == 0);
+}
+
+TEST_LIST = {
+ { "test_set_1", test_set_1 },
+ { "test_set_19", test_set_19 },
+ { NULL }
+};
+#endif
diff --git a/src/modules/rlm_wimax/milenage.h b/src/modules/rlm_wimax/milenage.h
new file mode 100644
index 0000000..758383a
--- /dev/null
+++ b/src/modules/rlm_wimax/milenage.h
@@ -0,0 +1,128 @@
+#pragma once
+/**
+ * @file src/modules/rlm_wimax/milenage.h
+ * @brief 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ *
+ * This file implements an example authentication algorithm defined for 3GPP
+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
+ * EAP-AKA to be tested properly with real USIM cards.
+ *
+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in
+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
+ * be AES (Rijndael).
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * @copyright 2017 The FreeRADIUS server project
+ * @copyright 2006-2007 (j@w1.fi)
+ */
+#include <stddef.h>
+
+/*
+ * Inputs
+ */
+#define MILENAGE_KI_SIZE 16 //!< Subscriber key.
+#define MILENAGE_OP_SIZE 16 //!< Operator code (unique to the operator)
+#define MILENAGE_OPC_SIZE 16 //!< Derived operator code (unique to the operator and subscriber).
+#define MILENAGE_AMF_SIZE 2 //!< Authentication management field.
+#define MILENAGE_SQN_SIZE 6 //!< Sequence number.
+#define MILENAGE_RAND_SIZE 16 //!< Random challenge.
+
+/*
+ * UMTS Outputs
+ */
+#define MILENAGE_AK_SIZE 6 //!< Anonymisation key.
+#define MILENAGE_AUTN_SIZE 16 //!< Network authentication key.
+#define MILENAGE_IK_SIZE 16 //!< Integrity key.
+#define MILENAGE_CK_SIZE 16 //!< Ciphering key.
+#define MILENAGE_RES_SIZE 8
+#define MILENAGE_AUTS_SIZE 14
+
+/*
+ * GSM (COMP128-4) outputs
+ */
+#define MILENAGE_SRES_SIZE 4
+#define MILENAGE_KC_SIZE 8
+
+/** Copy a 48bit value from a 64bit integer into a uint8_t buff in big endian byte order
+ *
+ * There may be fast ways of doing this, but this is the *correct*
+ * way, and does not make assumptions about how integers are laid
+ * out in memory.
+ *
+ * @param[out] out 6 byte butter to store value.
+ * @param[in] i integer value.
+ * @return pointer to out.
+ */
+static inline uint8_t *uint48_to_buff(uint8_t out[6], uint64_t i)
+{
+ out[0] = (i & 0xff0000000000) >> 40;
+ out[1] = (i & 0x00ff00000000) >> 32;
+ out[2] = (i & 0x0000ff000000) >> 24;
+ out[3] = (i & 0x000000ff0000) >> 16;
+ out[4] = (i & 0x00000000ff00) >> 8;
+ out[5] = (i & 0x0000000000ff);
+
+ return out;
+}
+
+/** Convert a 48bit big endian value into a unsigned 64bit integer
+ *
+ */
+static inline uint64_t uint48_from_buff(uint8_t const in[6])
+{
+ uint64_t i = 0;
+
+ i |= ((uint64_t)in[0]) << 40;
+ i |= ((uint64_t)in[1]) << 32;
+ i |= ((uint32_t)in[2]) << 24;
+ i |= ((uint32_t)in[3]) << 16;
+ i |= ((uint16_t)in[4]) << 8;
+ i |= in[5];
+
+ return i;
+}
+
+int milenage_opc_generate(uint8_t opc[MILENAGE_OPC_SIZE],
+ uint8_t const op[MILENAGE_OP_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE]);
+
+int milenage_umts_generate(uint8_t autn[MILENAGE_AUTN_SIZE],
+ uint8_t ik[MILENAGE_IK_SIZE],
+ uint8_t ck[MILENAGE_CK_SIZE],
+ uint8_t ak[MILENAGE_AK_SIZE],
+ uint8_t res[MILENAGE_RES_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const amf[MILENAGE_AMF_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint64_t sqn,
+ uint8_t const rand[MILENAGE_RAND_SIZE]);
+
+int milenage_auts(uint64_t *sqn,
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE],
+ uint8_t const auts[MILENAGE_AUTS_SIZE]);
+
+void milenage_gsm_from_umts(uint8_t sres[MILENAGE_SRES_SIZE],
+ uint8_t kc[MILENAGE_KC_SIZE],
+ uint8_t const ik[MILENAGE_IK_SIZE],
+ uint8_t const ck[MILENAGE_CK_SIZE],
+ uint8_t const res[MILENAGE_RES_SIZE]);
+
+int milenage_gsm_generate(uint8_t sres[MILENAGE_SRES_SIZE], uint8_t kc[MILENAGE_KC_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint8_t const rand[MILENAGE_RAND_SIZE]);
+
+int milenage_check(uint8_t ik[MILENAGE_IK_SIZE],
+ uint8_t ck[MILENAGE_CK_SIZE],
+ uint8_t res[MILENAGE_RES_SIZE],
+ uint8_t auts[MILENAGE_AUTS_SIZE],
+ uint8_t const opc[MILENAGE_OPC_SIZE],
+ uint8_t const ki[MILENAGE_KI_SIZE],
+ uint64_t sqn,
+ uint8_t const rand[MILENAGE_RAND_SIZE],
+ uint8_t const autn[MILENAGE_AUTN_SIZE]);
diff --git a/src/modules/rlm_wimax/rlm_wimax.c b/src/modules/rlm_wimax/rlm_wimax.c
new file mode 100644
index 0000000..d2125eb
--- /dev/null
+++ b/src/modules/rlm_wimax/rlm_wimax.c
@@ -0,0 +1,842 @@
+/*
+ * 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_wimax.c
+ * @brief Supports various WiMax functionality.
+ *
+ * @copyright 2008 Alan DeKok <aland@networkradius.com>
+ */
+RCSID("$Id$")
+USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include "milenage.h"
+
+#ifdef HAVE_OPENSSL_HMAC_H
+#include <openssl/hmac.h>
+#endif
+
+#include <freeradius-devel/openssl3.h>
+
+#define WIMAX_EPSAKA_RAND_SIZE 16
+#define WIMAX_EPSAKA_KI_SIZE 16
+#define WIMAX_EPSAKA_OPC_SIZE 16
+#define WIMAX_EPSAKA_AMF_SIZE 2
+#define WIMAX_EPSAKA_SQN_SIZE 6
+#define WIMAX_EPSAKA_MAC_A_SIZE 8
+#define WIMAX_EPSAKA_MAC_S_SIZE 8
+#define WIMAX_EPSAKA_XRES_SIZE 8
+#define WIMAX_EPSAKA_CK_SIZE 16
+#define WIMAX_EPSAKA_IK_SIZE 16
+#define WIMAX_EPSAKA_AK_SIZE 6
+#define WIMAX_EPSAKA_AK_RESYNC_SIZE 6
+#define WIMAX_EPSAKA_KK_SIZE 32
+#define WIMAX_EPSAKA_KS_SIZE 14
+#define WIMAX_EPSAKA_PLMN_SIZE 3
+#define WIMAX_EPSAKA_KASME_SIZE 32
+#define WIMAX_EPSAKA_AUTN_SIZE 16
+#define WIMAX_EPSAKA_AUTS_SIZE 14
+
+/*
+ * FIXME: Fix the build system to create definitions from names.
+ */
+typedef struct rlm_wimax_t {
+ bool delete_mppe_keys;
+
+ DICT_ATTR const *resync_info;
+ DICT_ATTR const *xres;
+ DICT_ATTR const *autn;
+ DICT_ATTR const *kasme;
+} rlm_wimax_t;
+
+/*
+ * A mapping of configuration file names to internal variables.
+ *
+ * Note that the string is dynamically allocated, so it MUST
+ * be freed. When the configuration file parse re-reads the string,
+ * it free's the old one, and strdup's the new one, placing the pointer
+ * to the strdup'd string into 'config.string'. This gets around
+ * buffer over-flows.
+ */
+static const CONF_PARSER module_config[] = {
+ { "delete_mppe_keys", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_wimax_t, delete_mppe_keys), "no" },
+ CONF_PARSER_TERMINATOR
+};
+
+/*
+ * Print hex values in a readable format for debugging
+ * Example:
+ * FOO: 00 11 AA 22 00 FF
+ */
+static void rdebug_hex(REQUEST *request, char const *prefix, uint8_t const *data, int len)
+{
+ int i;
+ char buffer[256]; /* large enough for largest len */
+
+ /*
+ * Leave a trailing space, we don't really care about that.
+ */
+ for (i = 0; i < len; i++) {
+ snprintf(buffer + i * 3, sizeof(buffer) - i * 3, "%02x ", data[i]);
+ }
+
+ RDEBUG("%s %s", prefix, buffer);
+}
+#define RDEBUG_HEX if (rad_debug_lvl) rdebug_hex
+
+/*
+ * 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)
+{
+ VALUE_PAIR *vp;
+ rlm_wimax_t *inst = instance;
+
+ /*
+ * Fix Calling-Station-Id. Damn you, WiMAX!
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY);
+ if (vp && (vp->vp_length == 6)) {
+ int i;
+ char *p;
+ uint8_t buffer[6];
+
+ memcpy(buffer, vp->vp_strvalue, 6);
+ vp->vp_length = (5*3)+2;
+ vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
+ vp->type = VT_DATA;
+
+ /*
+ * RFC 3580 Section 3.20 says this is the preferred
+ * format. Everyone *SANE* is using this format,
+ * so we fix it here.
+ */
+ for (i = 0; i < 6; i++) {
+ fr_bin2hex(&p[i * 3], &buffer[i], 1);
+ p[(i * 3) + 2] = '-';
+ }
+
+ p[(5*3)+2] = '\0';
+
+ DEBUG2("rlm_wimax: Fixing WiMAX binary Calling-Station-Id to %s",
+ vp->vp_strvalue);
+ return RLM_MODULE_OK;
+ }
+
+ /*
+ * Check for attr WiMAX-Re-synchronization-Info
+ * which contains the concatenation of RAND and AUTS
+ *
+ * If it is present then we proceed to verify the SIM and
+ * extract the new value of SQN
+ */
+ VALUE_PAIR *resync_info, *ki, *opc, *sqn, *rand;
+ int m_ret;
+
+ /* Look for the Re-synchronization-Info attribute in the request */
+ resync_info = fr_pair_find_by_da(request->packet->vps, inst->resync_info, TAG_ANY);
+ if (resync_info && (resync_info->vp_length < (WIMAX_EPSAKA_RAND_SIZE + WIMAX_EPSAKA_AUTS_SIZE))) {
+ RWDEBUG("Found request:WiMAX-Re-synchronization-Info with incorrect length: Ignoring it");
+ resync_info = NULL;
+ }
+
+ /*
+ * These are the private keys which should be added to the control
+ * list after looking them up in a database by IMSI
+ *
+ * We grab them from the control list here
+ */
+ ki = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_KI, 0, TAG_ANY);
+ if (ki && (ki->vp_length < MILENAGE_CK_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-Ki with incorrect length: Ignoring it");
+ ki = NULL;
+ }
+
+ opc = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_OPC, 0, TAG_ANY);
+ if (opc && (opc->vp_length < MILENAGE_IK_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-OPC with incorrect length: Ignoring it");
+ opc = NULL;
+ }
+
+ /* If we have resync info (RAND and AUTS), Ki and OPc then we can proceed */
+ if (resync_info && ki && opc) {
+ uint64_t sqn_bin;
+ uint8_t rand_bin[WIMAX_EPSAKA_RAND_SIZE];
+ uint8_t auts_bin[WIMAX_EPSAKA_AUTS_SIZE];
+
+ RDEBUG("Found WiMAX-Re-synchronization-Info. Proceeding with SQN resync");
+
+ /* Split Re-synchronization-Info into seperate RAND and AUTS */
+
+ memcpy(rand_bin, &resync_info->vp_octets[0], WIMAX_EPSAKA_RAND_SIZE);
+ memcpy(auts_bin, &resync_info->vp_octets[WIMAX_EPSAKA_RAND_SIZE], WIMAX_EPSAKA_AUTS_SIZE);
+
+ RDEBUG_HEX(request, "RAND ", rand_bin, WIMAX_EPSAKA_RAND_SIZE);
+ RDEBUG_HEX(request, "AUTS ", auts_bin, WIMAX_EPSAKA_AUTS_SIZE);
+
+ /*
+ * This procedure uses the secret keys Ki and OPc to authenticate
+ * the SIM and extract the SQN
+ */
+ m_ret = milenage_auts(&sqn_bin, opc->vp_octets, ki->vp_octets, rand_bin, auts_bin);
+
+ /*
+ * If the SIM verification fails then we can't go any further as
+ * we don't have the keys. And that probably means something bad
+ * is happening so we bail out now
+ */
+ if (m_ret < 0) {
+ RDEBUG("SIM verification failed");
+ return RLM_MODULE_REJECT;
+ }
+
+ /*
+ * If we got this far it means have got a new SQN and RAND
+ * so we store them in:
+ * control:WiMAX-SIM-SQN
+ * control:WiMAX-SIM-RAND
+ *
+ * From there they can be grabbed by unlang and used later
+ */
+
+ /* SQN is six bytes so we extract what we need from the 64 bit variable */
+ uint8_t sqn_bin_arr[WIMAX_EPSAKA_SQN_SIZE] = {
+ (sqn_bin & 0x0000FF0000000000ull) >> 40,
+ (sqn_bin & 0x000000FF00000000ull) >> 32,
+ (sqn_bin & 0x00000000FF000000ull) >> 24,
+ (sqn_bin & 0x0000000000FF0000ull) >> 16,
+ (sqn_bin & 0x000000000000FF00ull) >> 8,
+ (sqn_bin & 0x00000000000000FFull) >> 0
+ };
+
+ /* Add SQN to control:WiMAX-SIM-SQN */
+ sqn = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_SQN, 0, TAG_ANY);
+ if (sqn && (sqn->vp_length < WIMAX_EPSAKA_SQN_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-SQN with incorrect length: Ignoring it");
+ sqn = NULL;
+ }
+
+ if (!sqn) {
+ MEM(sqn = pair_make_config("WiMAX-SIM-SQN", NULL, T_OP_SET));
+ fr_pair_value_memcpy(sqn, sqn_bin_arr, WIMAX_EPSAKA_SQN_SIZE);
+ }
+ RDEBUG_HEX(request, "SQN ", sqn->vp_octets, WIMAX_EPSAKA_SQN_SIZE);
+
+ /* Add RAND to control:WiMAX-SIM-RAND */
+ rand = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_RAND, 0, TAG_ANY);
+ if (rand && (rand->vp_length < WIMAX_EPSAKA_RAND_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-RAND with incorrect length: Ignoring it");
+ rand = NULL;
+ }
+
+ if (!rand) {
+ MEM(rand = pair_make_config("WiMAX-SIM-RAND", NULL, T_OP_SET));
+ fr_pair_value_memcpy(rand, rand_bin, WIMAX_EPSAKA_RAND_SIZE);
+ }
+ RDEBUG_HEX(request, "RAND ", rand->vp_octets, WIMAX_EPSAKA_RAND_SIZE);
+
+ return RLM_MODULE_UPDATED;
+ }
+
+ return RLM_MODULE_NOOP;
+}
+
+/*
+ * Massage the request before recording it or proxying it
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
+{
+ return mod_authorize(instance, request);
+}
+
+
+/*
+ * This function generates the keys for old style WiMAX (v1 to v2.0)
+ */
+static int mip_keys_generate(void *instance, REQUEST *request, VALUE_PAIR *msk, VALUE_PAIR *emsk)
+{
+ rlm_wimax_t *inst = instance;
+ VALUE_PAIR *vp;
+ VALUE_PAIR *mn_nai, *ip, *fa_rk;
+ HMAC_CTX *hmac;
+ unsigned int rk1_len, rk2_len, rk_len;
+ uint32_t mip_spi;
+ uint8_t usage_data[24];
+ uint8_t mip_rk_1[EVP_MAX_MD_SIZE], mip_rk_2[EVP_MAX_MD_SIZE];
+ uint8_t mip_rk[2 * EVP_MAX_MD_SIZE];
+
+ /*
+ * If we delete the MS-MPPE-*-Key attributes, then add in
+ * the WiMAX-MSK so that the client has a key available.
+ */
+ if (inst->delete_mppe_keys) {
+ fr_pair_delete_by_num(&request->reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
+ fr_pair_delete_by_num(&request->reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
+
+ MEM(vp = pair_make_reply("WiMAX-MSK", NULL, T_OP_EQ));
+ fr_pair_value_memcpy(vp, msk->vp_octets, msk->vp_length);
+ }
+
+ /*
+ * Initialize usage data.
+ */
+ memcpy(usage_data, "miprk@wimaxforum.org", 21); /* with trailing \0 */
+ usage_data[21] = 0x02;
+ usage_data[22] = 0x00;
+ usage_data[23] = 0x01;
+
+ /*
+ * MIP-RK-1 = HMAC-SSHA256(EMSK, usage-data | 0x01)
+ */
+ hmac = HMAC_CTX_new();
+ HMAC_Init_ex(hmac, emsk->vp_octets, emsk->vp_length, EVP_sha256(), NULL);
+ rk1_len = SHA256_DIGEST_LENGTH;
+
+ HMAC_Update(hmac, &usage_data[0], sizeof(usage_data));
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ /*
+ * MIP-RK-2 = HMAC-SSHA256(EMSK, MIP-RK-1 | usage-data | 0x01)
+ */
+ HMAC_Init_ex(hmac, emsk->vp_octets, emsk->vp_length, EVP_sha256(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) &mip_rk_1, rk1_len);
+ HMAC_Update(hmac, &usage_data[0], sizeof(usage_data));
+ rk2_len = SHA256_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_2[0], &rk2_len);
+
+ memcpy(mip_rk, mip_rk_1, rk1_len);
+ memcpy(mip_rk + rk1_len, mip_rk_2, rk2_len);
+ rk_len = rk1_len + rk2_len;
+
+ /*
+ * MIP-SPI = HMAC-SSHA256(MIP-RK, "SPI CMIP PMIP");
+ */
+ HMAC_Init_ex(hmac, mip_rk, rk_len, EVP_sha256(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) "SPI CMIP PMIP", 12);
+ rk1_len = SHA256_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ /*
+ * Take the 4 most significant octets.
+ * If less than 256, add 256.
+ */
+ mip_spi = ((mip_rk_1[0] << 24) | (mip_rk_1[1] << 16) |
+ (mip_rk_1[2] << 8) | mip_rk_1[3]);
+ if (mip_spi < 256) mip_spi += 256;
+
+ RDEBUG_HEX(request, "MIP-RK ", mip_rk, rk_len);
+ RDEBUG("MIP-SPI = %08x", ntohl(mip_spi));
+
+ /*
+ * FIXME: Perform SPI collision prevention
+ */
+
+ /*
+ * Calculate mobility keys
+ */
+ mn_nai = fr_pair_find_by_num(request->packet->vps, PW_WIMAX_MN_NAI, 0, TAG_ANY);
+ if (!mn_nai) mn_nai = fr_pair_find_by_num(request->reply->vps, PW_WIMAX_MN_NAI, 0, TAG_ANY);
+ if (!mn_nai) {
+ RWDEBUG("WiMAX-MN-NAI was not found in the request or in the reply");
+ RWDEBUG("We cannot calculate MN-HA keys");
+ }
+
+ /*
+ * WiMAX-IP-Technology
+ */
+ vp = NULL;
+ if (mn_nai) vp = fr_pair_find_by_num(request->reply->vps, 23, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ RWDEBUG("WiMAX-IP-Technology not found in reply");
+ RWDEBUG("Not calculating MN-HA keys");
+ }
+
+ if (vp) switch (vp->vp_integer) {
+ case 2: /* PMIP4 */
+ /*
+ * Look for WiMAX-hHA-IP-MIP4
+ */
+ ip = fr_pair_find_by_num(request->reply->vps, 6, VENDORPEC_WIMAX, TAG_ANY);
+ if (!ip) {
+ RWDEBUG("WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-PMIP4 key");
+ break;
+ }
+
+ /*
+ * MN-HA-PMIP4 =
+ * H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI);
+ */
+ HMAC_Init_ex(hmac, mip_rk, rk_len, EVP_sha1(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) "PMIP4 MN HA", 11);
+ HMAC_Update(hmac, (uint8_t const *) &ip->vp_ipaddr, 4);
+ HMAC_Update(hmac, (uint8_t const *) &mn_nai->vp_strvalue, mn_nai->vp_length);
+ rk1_len = SHA1_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ /*
+ * Put MN-HA-PMIP4 into WiMAX-MN-hHA-MIP4-Key
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 10, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 10, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP4-Key");
+ break;
+ }
+ fr_pair_value_memcpy(vp, &mip_rk_1[0], rk1_len);
+
+ /*
+ * Put MN-HA-PMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 11, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 11, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP4-SPI");
+ break;
+ }
+ vp->vp_integer = mip_spi + 1;
+ break;
+
+ case 3: /* CMIP4 */
+ /*
+ * Look for WiMAX-hHA-IP-MIP4
+ */
+ ip = fr_pair_find_by_num(request->reply->vps, 6, VENDORPEC_WIMAX, TAG_ANY);
+ if (!ip) {
+ RWDEBUG("WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-CMIP4 key");
+ break;
+ }
+
+ /*
+ * MN-HA-CMIP4 =
+ * H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI);
+ */
+ HMAC_Init_ex(hmac, mip_rk, rk_len, EVP_sha1(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) "CMIP4 MN HA", 11);
+ HMAC_Update(hmac, (uint8_t const *) &ip->vp_ipaddr, 4);
+ HMAC_Update(hmac, (uint8_t const *) &mn_nai->vp_strvalue, mn_nai->vp_length);
+ rk1_len = SHA1_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ /*
+ * Put MN-HA-CMIP4 into WiMAX-MN-hHA-MIP4-Key
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 10, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 10, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP4-Key");
+ break;
+ }
+ fr_pair_value_memcpy(vp, &mip_rk_1[0], rk1_len);
+
+ /*
+ * Put MN-HA-CMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 11, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 11, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP4-SPI");
+ break;
+ }
+ vp->vp_integer = mip_spi;
+ break;
+
+ case 4: /* CMIP6 */
+ /*
+ * Look for WiMAX-hHA-IP-MIP6
+ */
+ ip = fr_pair_find_by_num(request->reply->vps, 7, VENDORPEC_WIMAX, TAG_ANY);
+ if (!ip) {
+ RWDEBUG("WiMAX-hHA-IP-MIP6 not found. Cannot calculate MN-HA-CMIP6 key");
+ break;
+ }
+
+ /*
+ * MN-HA-CMIP6 =
+ * H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI);
+ */
+ HMAC_Init_ex(hmac, mip_rk, rk_len, EVP_sha1(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) "CMIP6 MN HA", 11);
+ HMAC_Update(hmac, (uint8_t const *) &ip->vp_ipv6addr, 16);
+ HMAC_Update(hmac, (uint8_t const *) &mn_nai->vp_strvalue, mn_nai->vp_length);
+ rk1_len = SHA1_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ /*
+ * Put MN-HA-CMIP6 into WiMAX-MN-hHA-MIP6-Key
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 12, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 12, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP6-Key");
+ break;
+ }
+ fr_pair_value_memcpy(vp, &mip_rk_1[0], rk1_len);
+
+ /*
+ * Put MN-HA-CMIP6-SPI into WiMAX-MN-hHA-MIP6-SPI
+ */
+ vp = fr_pair_find_by_num(request->reply->vps, 13, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 13, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-MN-hHA-MIP6-SPI");
+ break;
+ }
+ vp->vp_integer = mip_spi + 2;
+ break;
+
+ default:
+ break; /* do nothing */
+ }
+
+ /*
+ * Generate FA-RK, if requested.
+ *
+ * FA-RK= H(MIP-RK, "FA-RK")
+ */
+ fa_rk = fr_pair_find_by_num(request->reply->vps, 14, VENDORPEC_WIMAX, TAG_ANY);
+ if (fa_rk && (fa_rk->vp_length <= 1)) {
+ HMAC_Init_ex(hmac, mip_rk, rk_len, EVP_sha1(), NULL);
+
+ HMAC_Update(hmac, (uint8_t const *) "FA-RK", 5);
+
+ rk1_len = SHA1_DIGEST_LENGTH;
+ HMAC_Final(hmac, &mip_rk_1[0], &rk1_len);
+
+ fr_pair_value_memcpy(fa_rk, &mip_rk_1[0], rk1_len);
+ }
+
+ /*
+ * Create FA-RK-SPI, which is really SPI-CMIP4, which is
+ * really MIP-SPI. Clear? Of course. This is WiMAX.
+ */
+ if (fa_rk) {
+ vp = fr_pair_find_by_num(request->reply->vps, 61, VENDORPEC_WIMAX, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->reply, &request->reply->vps,
+ 61, VENDORPEC_WIMAX);
+ }
+ if (!vp) {
+ RWDEBUG("Failed creating WiMAX-FA-RK-SPI");
+ } else {
+ vp->vp_integer = mip_spi;
+ }
+ }
+
+ /*
+ * Give additional information about requests && responses
+ *
+ * WiMAX-RRQ-MN-HA-SPI
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, 20, VENDORPEC_WIMAX, TAG_ANY);
+ if (vp) {
+ RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage");
+ if (!mn_nai) {
+ RWDEBUG("MN-NAI was not found!");
+ }
+
+ /*
+ * WiMAX-RRQ-HA-IP
+ */
+ if (!fr_pair_find_by_num(request->packet->vps, 18, VENDORPEC_WIMAX, TAG_ANY)) {
+ RWDEBUG("HA-IP was not found!");
+ }
+
+
+ /*
+ * WiMAX-HA-RK-Key-Requested
+ */
+ vp = fr_pair_find_by_num(request->packet->vps, 58, VENDORPEC_WIMAX, TAG_ANY);
+ if (vp && (vp->vp_integer == 1)) {
+ RDEBUG("Client requested HA-RK: Should use IP to look it up from storage");
+ }
+ }
+
+ /*
+ * Wipe the context of all sensitive information.
+ */
+ HMAC_CTX_free(hmac);
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * Generate the EPS-AKA authentication vector
+ *
+ * These are the keys needed for new style WiMAX (LTE / 3gpp authentication),
+ for WiMAX v2.1
+ */
+static rlm_rcode_t aka_keys_generate(REQUEST *request, rlm_wimax_t const *inst, VALUE_PAIR *ki, VALUE_PAIR *opc,
+ VALUE_PAIR *amf, VALUE_PAIR *sqn, VALUE_PAIR *plmn)
+{
+ size_t i;
+ VALUE_PAIR *rand_previous, *rand, *xres, *autn, *kasme;
+
+ /*
+ * For most authentication requests we need to generate a fresh RAND
+ *
+ * The exception is after SQN re-syncronisation - in this case we
+ * get RAND in the request, and this module if called in authorize should
+ * have put it in control:WiMAX-SIM-RAND so we can grab it from there)
+ */
+ rand_previous = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_RAND, 0, TAG_ANY);
+ if (rand_previous && (rand_previous->vp_length < WIMAX_EPSAKA_RAND_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-Rand with incorrect size. Ignoring it.");
+ rand_previous = NULL;
+ }
+
+ MEM(rand = pair_make_reply("WiMAX-E-UTRAN-Vector-RAND", NULL, T_OP_SET));
+ if (!rand_previous) {
+ uint32_t lvalue;
+ uint8_t buffer[WIMAX_EPSAKA_RAND_SIZE];
+
+ for (i = 0; i < (WIMAX_EPSAKA_RAND_SIZE / 4); i++) {
+ lvalue = fr_rand();
+ memcpy(buffer + i * 4, &lvalue, sizeof(lvalue));
+ }
+
+ fr_pair_value_memcpy(rand, buffer, WIMAX_EPSAKA_RAND_SIZE);
+
+ } else {
+ fr_pair_value_memcpy(rand, rand_previous->vp_octets, WIMAX_EPSAKA_RAND_SIZE);
+ }
+
+ /*
+ * Feed AMF, Ki, SQN and RAND into the Milenage algorithm (f1, f2, f3, f4, f5)
+ * which returns AUTN, AK, CK, IK, XRES.
+ */
+ uint8_t xres_bin[WIMAX_EPSAKA_XRES_SIZE];
+ uint8_t ck_bin[WIMAX_EPSAKA_CK_SIZE];
+ uint8_t ik_bin[WIMAX_EPSAKA_IK_SIZE];
+ uint8_t ak_bin[WIMAX_EPSAKA_AK_SIZE];
+ uint8_t autn_bin[WIMAX_EPSAKA_AUTN_SIZE];
+
+ /* But first convert uint8 SQN to uint64 */
+ uint64_t sqn_bin = 0x0000000000000000;
+ for (i = 0; i < sqn->vp_length; ++i) sqn_bin = (sqn_bin << 8) | sqn->vp_octets[i];
+
+ if (!opc || (opc->vp_length < MILENAGE_OPC_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-OPC with incorrect size. Ignoring it");
+ return RLM_MODULE_NOOP;
+ }
+ if (!amf || (amf->vp_length < MILENAGE_AMF_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-AMF with incorrect size. Ignoring it");
+ return RLM_MODULE_NOOP;
+ }
+ if (!ki || (ki->vp_length < MILENAGE_KI_SIZE)) {
+ RWDEBUG("Found config:WiMAX-SIM-KI with incorrect size. Ignoring it");
+ return RLM_MODULE_NOOP;
+ }
+
+ /* Call milenage */
+ milenage_umts_generate(autn_bin, ik_bin, ck_bin, ak_bin, xres_bin, opc->vp_octets,
+ amf->vp_octets, ki->vp_octets, sqn_bin, rand->vp_octets);
+
+ /*
+ * Now we genertate KASME
+ *
+ * Officially described in 33401-g30.doc section A.2
+ * But an easier to read explanation can be found at:
+ * https://medium.com/uw-ictd/lte-authentication-2d0810a061ec
+ *
+ */
+
+ /* k = CK || IK */
+ uint8_t kk_bin[WIMAX_EPSAKA_KK_SIZE];
+ memcpy(kk_bin, ck_bin, sizeof(ck_bin));
+ memcpy(kk_bin + sizeof(ck_bin), ik_bin, sizeof(ik_bin));
+
+ /* Initialize a 14 byte buffer s */
+ uint8_t ks_bin[WIMAX_EPSAKA_KS_SIZE];
+
+ /* Assign the first byte of s as 0x10 */
+ ks_bin[0] = 0x10;
+
+ /* Copy the 3 bytes of PLMN into s */
+ memcpy(ks_bin + 1, plmn->vp_octets, 3);
+
+ /* Assign 5th and 6th byte as 0x00 and 0x03 */
+ ks_bin[4] = 0x00;
+ ks_bin[5] = 0x03;
+
+ /* Assign the next 6 bytes as SQN XOR AK */
+ for (i = 0; i < 6; i++) {
+ ks_bin[i+6] = sqn->vp_octets[i] ^ ak_bin[i];
+ }
+
+ /* Assign the last two bytes as 0x00 and 0x06 */
+ ks_bin[12] = 0x00;
+ ks_bin[13] = 0x06;
+
+ /* Perform an HMAC-SHA256 using Key k from step 1 and s as the message. */
+ uint8_t kasme_bin[WIMAX_EPSAKA_KASME_SIZE];
+ HMAC_CTX *hmac;
+ unsigned int kasme_len = sizeof(kasme_bin);
+
+ hmac = HMAC_CTX_new();
+ HMAC_Init_ex(hmac, kk_bin, sizeof(kk_bin), EVP_sha256(), NULL);
+ HMAC_Update(hmac, ks_bin, sizeof(ks_bin));
+ kasme_len = SHA256_DIGEST_LENGTH;
+ HMAC_Final(hmac, &kasme_bin[0], &kasme_len);
+ HMAC_CTX_free(hmac);
+
+ /*
+ * Add reply attributes XRES, AUTN and KASME (RAND we added earlier)
+ *
+ * Note that we can't call fr_pair_find_by_num(), as
+ * these attributes are buried deep inside of the WiMAX
+ * hierarchy.
+ */
+ xres = fr_pair_find_by_da(request->reply->vps, inst->xres, TAG_ANY);
+ if (!xres) {
+ MEM(xres = pair_make_reply("WiMAX-E-UTRAN-Vector-XRES", NULL, T_OP_SET));
+ fr_pair_value_memcpy(xres, xres_bin, WIMAX_EPSAKA_XRES_SIZE);
+ }
+
+ autn = fr_pair_find_by_da(request->reply->vps, inst->autn, TAG_ANY);
+ if (!autn) {
+ MEM(autn = pair_make_reply("WiMAX-E-UTRAN-Vector-AUTN", NULL, T_OP_SET));
+ fr_pair_value_memcpy(autn, autn_bin, WIMAX_EPSAKA_AUTN_SIZE);
+ }
+
+ kasme = fr_pair_find_by_da(request->reply->vps, inst->kasme, TAG_ANY);
+ if (!kasme) {
+ MEM(kasme = pair_make_reply("WiMAX-E-UTRAN-Vector-KASME", NULL, T_OP_SET));
+ fr_pair_value_memcpy(kasme, kasme_bin, WIMAX_EPSAKA_KASME_SIZE);
+ }
+
+ /* Print keys to log for debugging */
+ if (rad_debug_lvl) {
+ RDEBUG("-------- Milenage in --------");
+ RDEBUG_HEX(request, "OPc ", opc->vp_octets, opc->vp_length);
+ RDEBUG_HEX(request, "Ki ", ki->vp_octets, ki->vp_length);
+ RDEBUG_HEX(request, "RAND ", rand->vp_octets, rand->vp_length);
+ RDEBUG_HEX(request, "SQN ", sqn->vp_octets, sqn->vp_length);
+ RDEBUG_HEX(request, "AMF ", amf->vp_octets, amf->vp_length);
+ RDEBUG("-------- Milenage out -------");
+ RDEBUG_HEX(request, "XRES ", xres->vp_octets, xres->vp_length);
+ RDEBUG_HEX(request, "Ck ", ck_bin, sizeof(ck_bin));
+ RDEBUG_HEX(request, "Ik ", ik_bin, sizeof(ik_bin));
+ RDEBUG_HEX(request, "Ak ", ak_bin, sizeof(ak_bin));
+ RDEBUG_HEX(request, "AUTN ", autn->vp_octets, autn->vp_length);
+ RDEBUG("-----------------------------");
+ RDEBUG_HEX(request, "Kk ", kk_bin, sizeof(kk_bin));
+ RDEBUG_HEX(request, "Ks ", ks_bin, sizeof(ks_bin));
+ RDEBUG_HEX(request, "KASME ", kasme->vp_octets, kasme->vp_length);
+ }
+
+ return RLM_MODULE_UPDATED;
+}
+
+/*
+ * Generate the keys after the user has been authenticated.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
+{
+ VALUE_PAIR *msk, *emsk, *ki, *opc, *amf, *sqn, *plmn;
+
+ /*
+ * If we have MSK and EMSK then assume we want MIP keys
+ * Else if we have the SIM keys then we want the EPS-AKA vector
+ */
+
+ msk = fr_pair_find_by_num(request->reply->vps, PW_EAP_MSK, 0, TAG_ANY);
+ emsk = fr_pair_find_by_num(request->reply->vps, PW_EAP_EMSK, 0, TAG_ANY);
+
+ if (msk && emsk) {
+ RDEBUG("MSK and EMSK found. Generating MIP keys");
+ return mip_keys_generate(instance, request, msk, emsk);
+ }
+
+ ki = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_KI, 0, TAG_ANY);
+ opc = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_OPC, 0, TAG_ANY);
+ amf = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_AMF, 0, TAG_ANY);
+ sqn = fr_pair_find_by_num(request->config, PW_WIMAX_SIM_SQN, 0, TAG_ANY);
+ plmn = fr_pair_find_by_num(request->packet->vps, 146, VENDORPEC_WIMAX, TAG_ANY);
+
+ if (ki && opc && amf && sqn && plmn) {
+ RDEBUG("AKA attributes found. Generating AKA keys.");
+ return aka_keys_generate(request, instance, ki, opc, amf, sqn, plmn);
+ }
+
+ RDEBUG("Input keys not found. Cannot create WiMAX keys");
+ return RLM_MODULE_NOOP;
+}
+
+
+static int mod_instantiate(UNUSED CONF_SECTION *conf, void *instance)
+{
+ rlm_wimax_t *inst = instance;
+
+ inst->resync_info = dict_attrbyname("WiMAX-Re-synchronization-Info");
+ inst->xres = dict_attrbyname("WiMAX-E-UTRAN-Vector-XRES");
+ inst->autn = dict_attrbyname("WiMAX-E-UTRAN-Vector-AUTN");
+ inst->kasme = dict_attrbyname("WiMAX-E-UTRAN-Vector-KASME");
+
+ 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_wimax;
+module_t rlm_wimax = {
+ .magic = RLM_MODULE_INIT,
+ .name = "wimax",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_wimax_t),
+ .config = module_config,
+ .instantiate = mod_instantiate,
+ .methods = {
+ [MOD_AUTHORIZE] = mod_authorize,
+ [MOD_PREACCT] = mod_preacct,
+ [MOD_POST_AUTH] = mod_post_auth
+ },
+};
diff --git a/src/modules/rlm_yubikey/.gitignore b/src/modules/rlm_yubikey/.gitignore
new file mode 100644
index 0000000..01a5daa
--- /dev/null
+++ b/src/modules/rlm_yubikey/.gitignore
@@ -0,0 +1 @@
+all.mk
diff --git a/src/modules/rlm_yubikey/README.md b/src/modules/rlm_yubikey/README.md
new file mode 100644
index 0000000..6fbfafc
--- /dev/null
+++ b/src/modules/rlm_yubikey/README.md
@@ -0,0 +1,11 @@
+# rlm_yubikey
+## Metadata
+<dl>
+ <dt>category</dt><dd>authentication</dd>
+</dl>
+
+## Summary
+
+Supports authentication of yubikey tokens where the PSK is known
+to FreeRADIUS, and integrates with the Yubico cloud-based
+authentication service.
diff --git a/src/modules/rlm_yubikey/all.mk.in b/src/modules/rlm_yubikey/all.mk.in
new file mode 100644
index 0000000..45e05cc
--- /dev/null
+++ b/src/modules/rlm_yubikey/all.mk.in
@@ -0,0 +1,23 @@
+#######################################################################
+#
+# TARGET should be set by autoconf only. Don't touch it.
+#
+# The SOURCES definition should list ALL source files.
+#
+# SRC_CFLAGS defines addition C compiler flags. You usually don't
+# want to modify this, though. Get it from autoconf.
+#
+# The TGT_LDLIBS definition should list ALL required libraries.
+#
+#######################################################################
+
+TARGETNAME := @targetname@
+
+ifneq "$(TARGETNAME)" ""
+TARGET := $(TARGETNAME).a
+endif
+
+SOURCES := $(TARGETNAME).c validate.c decrypt.c
+
+SRC_CFLAGS := @mod_cflags@
+TGT_LDLIBS := @mod_ldflags@
diff --git a/src/modules/rlm_yubikey/config.h.in b/src/modules/rlm_yubikey/config.h.in
new file mode 100644
index 0000000..99f8113
--- /dev/null
+++ b/src/modules/rlm_yubikey/config.h.in
@@ -0,0 +1,7 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Build with yubicloud support from ykclient */
+#undef HAVE_YKCLIENT
+
+/* Build with yubikey token decryption support support from yubikey */
+#undef HAVE_YUBIKEY
diff --git a/src/modules/rlm_yubikey/configure b/src/modules/rlm_yubikey/configure
new file mode 100755
index 0000000..7c345f2
--- /dev/null
+++ b/src/modules/rlm_yubikey/configure
@@ -0,0 +1,4864 @@
+#! /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_yubikey.c"
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mod_ldflags
+mod_cflags
+targetname
+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_yubikey
+with_yubikey_include_dir
+with_yubikey_lib_dir
+with_yubikey_dir
+with_ykclient_include_dir
+with_ykclient_lib_dir
+with_ykclient_dir
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --without-rlm_yubikey build without Yubikey support
+ --with-yubikey-include-dir=DIR
+ Directory where the yubikey includes may be found
+ --with-yubikey-lib-dir=DIR
+ Directory where the yubikey libraries may be found
+ --with-yubikey-dir=DIR Base directory where yubikey is installed
+ --with-ykclient-include-dir=DIR
+ Directory where the ykclient includes may be found
+ --with-ykclient-lib-dir=DIR
+ Directory where the ykclient libraries may be found
+ --with-ykclient-dir=DIR Base directory where ykclient is installed
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+echo
+echo Running tests for rlm_yubikey
+echo
+
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+# Check whether --with-rlm_yubikey was given.
+if test "${with_rlm_yubikey+set}" = set; then :
+ withval=$with_rlm_yubikey;
+fi
+
+
+
+
+fail=
+fr_status=
+fr_features=
+: > "config.report"
+: > "config.report.tmp"
+
+
+
+if test x"$with_rlm_yubikey" != xno; then
+
+
+
+
+yubikey_include_dir=
+
+# Check whether --with-yubikey-include-dir was given.
+if test "${with_yubikey_include_dir+set}" = set; then :
+ withval=$with_yubikey_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need yubikey-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+yubikey_lib_dir=
+
+# Check whether --with-yubikey-lib-dir was given.
+if test "${with_yubikey_lib_dir+set}" = set; then :
+ withval=$with_yubikey_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need yubikey-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-yubikey-dir was given.
+if test "${with_yubikey_dir+set}" = set; then :
+ withval=$with_yubikey_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need yubikey-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_lib_dir="$withval/lib"
+ yubikey_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+ykclient_include_dir=
+
+# Check whether --with-ykclient-include-dir was given.
+if test "${with_ykclient_include_dir+set}" = set; then :
+ withval=$with_ykclient_include_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ykclient-include-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_include_dir="$withval"
+ ;;
+ esac
+fi
+
+
+ykclient_lib_dir=
+
+# Check whether --with-ykclient-lib-dir was given.
+if test "${with_ykclient_lib_dir+set}" = set; then :
+ withval=$with_ykclient_lib_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ykclient-lib-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_lib_dir="$withval"
+ ;;
+ esac
+fi
+
+
+
+# Check whether --with-ykclient-dir was given.
+if test "${with_ykclient_dir+set}" = set; then :
+ withval=$with_ykclient_dir; case "$withval" in
+ no)
+ as_fn_error $? "Need ykclient-dir" "$LINENO" 5
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_lib_dir="$withval/lib"
+ ykclient_include_dir="$withval/include"
+ ;;
+ esac
+fi
+
+
+
+have_yubikey="yes"
+smart_try_dir="$yubikey_include_dir"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+ac_safe=`echo "yubikey.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 yubikey.h in $try" >&5
+$as_echo_n "checking for yubikey.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <yubikey.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}/yubikey.h" >&5
+$as_echo_n "checking for ${_prefix}/yubikey.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <yubikey.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 yubikey.h" >&5
+$as_echo_n "checking for yubikey.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <yubikey.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 yubikey.h in $try" >&5
+$as_echo_n "checking for yubikey.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <yubikey.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_yubikey_h" != "xyes"; then
+ have_ykclient="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey headers not found. Use --with-yubikey-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: yubikey headers not found. Use --with-yubikey-include-dir=<path>." >&2;}
+fi
+
+
+smart_try_dir="$yubikey_lib_dir"
+
+
+sm_lib_safe=`echo "yubikey" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "yubikey_aes_decrypt" | 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 yubikey_aes_decrypt in -lyubikey in $try" >&5
+$as_echo_n "checking for yubikey_aes_decrypt in -lyubikey in $try... " >&6; }
+ LIBS="-lyubikey $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char yubikey_aes_decrypt();
+int
+main ()
+{
+yubikey_aes_decrypt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lyubikey"
+ 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 yubikey_aes_decrypt in -lyubikey" >&5
+$as_echo_n "checking for yubikey_aes_decrypt in -lyubikey... " >&6; }
+ LIBS="-lyubikey $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char yubikey_aes_decrypt();
+int
+main ()
+{
+yubikey_aes_decrypt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lyubikey"
+ { $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 yubikey_aes_decrypt in -lyubikey in $try" >&5
+$as_echo_n "checking for yubikey_aes_decrypt in -lyubikey in $try... " >&6; }
+ LIBS="-lyubikey $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char yubikey_aes_decrypt();
+int
+main ()
+{
+yubikey_aes_decrypt()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lyubikey"
+ 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_yubikey_yubikey_aes_decrypt" != "xyes"; then
+ have_yubikey="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: yubikey libraries not found. Use --with-yubikey-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: yubikey libraries not found. Use --with-yubikey-lib-dir=<path>." >&2;}
+fi
+
+if test "x$have_yubikey" = "xyes"; then
+
+$as_echo "#define HAVE_YUBIKEY 1" >>confdefs.h
+
+
+if echo "$fr_features" | grep -q "+yubikey+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with yubikey token decryption support" >> config.report.tmp
+ fr_features="$fr_features +yubikey+"
+fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without yubikey token decryption support. requires: yubikey" >&5
+$as_echo "$as_me: WARNING: silently building without yubikey token decryption support. requires: yubikey" >&2;}
+
+if echo "$fr_features" | grep -q "+yubikey+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without yubikey token decryption support" >> config.report.tmp
+ fr_features="$fr_features +yubikey+"
+fi
+
+fi
+
+
+have_ykclient="yes"
+smart_try_dir="$ykclient_include_dir"
+
+
+ac_safe=`echo "ykclient.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 ykclient.h in $try" >&5
+$as_echo_n "checking for ykclient.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ykclient.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}/ykclient.h" >&5
+$as_echo_n "checking for ${_prefix}/ykclient.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ykclient.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 ykclient.h" >&5
+$as_echo_n "checking for ykclient.h... " >&6; }
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ykclient.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 ykclient.h in $try" >&5
+$as_echo_n "checking for ykclient.h in $try... " >&6; }
+ CPPFLAGS="-isystem $try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <ykclient.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_ykclient_h" != "xyes"; then
+ have_ykclient="no"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient headers not found. Use --with-ykclient-include-dir=<path>." >&5
+$as_echo "$as_me: WARNING: ykclient headers not found. Use --with-ykclient-include-dir=<path>." >&2;}
+fi
+
+
+smart_try_dir="$ykclient_lib_dir"
+
+
+sm_lib_safe=`echo "ykclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ykclient_request_process" | 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 ykclient_request_process in -lykclient in $try" >&5
+$as_echo_n "checking for ykclient_request_process in -lykclient in $try... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request_process();
+int
+main ()
+{
+ykclient_request_process()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ 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 ykclient_request_process in -lykclient" >&5
+$as_echo_n "checking for ykclient_request_process in -lykclient... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request_process();
+int
+main ()
+{
+ykclient_request_process()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ { $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 ykclient_request_process in -lykclient in $try" >&5
+$as_echo_n "checking for ykclient_request_process in -lykclient in $try... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request_process();
+int
+main ()
+{
+ykclient_request_process()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ 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_ykclient_ykclient_request_process" != "xyes"; then
+ have_ykclient="no"
+
+
+sm_lib_safe=`echo "ykclient" | sed 'y%./+-%__p_%'`
+sm_func_safe=`echo "ykclient_request" | 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 ykclient_request in -lykclient in $try" >&5
+$as_echo_n "checking for ykclient_request in -lykclient in $try... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request();
+int
+main ()
+{
+ykclient_request()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ 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 ykclient_request in -lykclient" >&5
+$as_echo_n "checking for ykclient_request in -lykclient... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request();
+int
+main ()
+{
+ykclient_request()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ { $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 ykclient_request in -lykclient in $try" >&5
+$as_echo_n "checking for ykclient_request in -lykclient in $try... " >&6; }
+ LIBS="-lykclient $old_LIBS"
+ CPPFLAGS="-L$try -Wl,-rpath,$try $old_CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+extern char ykclient_request();
+int
+main ()
+{
+ykclient_request()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ smart_lib="-lykclient"
+ 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_ykclient_ykclient_request" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libykclient missing ykclient_request_process. A later version of libykclient is required." >&5
+$as_echo "$as_me: WARNING: libykclient missing ykclient_request_process. A later version of libykclient is required." >&2;}
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ykclient libraries not found. Use --with-ykclient-lib-dir=<path>." >&5
+$as_echo "$as_me: WARNING: ykclient libraries not found. Use --with-ykclient-lib-dir=<path>." >&2;}
+ fi
+fi
+
+if test "x$have_ykclient" = "xyes"; then
+
+$as_echo "#define HAVE_YKCLIENT 1" >>confdefs.h
+
+
+if echo "$fr_features" | grep -q "+ykclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""with yubicloud support" >> config.report.tmp
+ fr_features="$fr_features +ykclient+"
+fi
+
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently building without yubicloud support. requires: ykclient" >&5
+$as_echo "$as_me: WARNING: silently building without yubicloud support. requires: ykclient" >&2;}
+
+if echo "$fr_features" | grep -q "+ykclient+"; then :
+else :
+ fr_report_prefix=""
+ if test x"$fr_features" != x""; then
+ fr_report_prefix=" "
+ fi
+ $as_echo "$fr_report_prefix""without yubicloud support" >> config.report.tmp
+ fr_features="$fr_features +ykclient+"
+fi
+
+fi
+
+
+ targetname=rlm_yubikey
+else
+ targetname=
+ echo \*\*\* module rlm_yubikey is disabled.
+
+
+fr_status="disabled"
+
+fi
+
+if test x"$fail" != x""; then
+ targetname=""
+
+
+ if test x"${enable_strict_dependencies}" = x"yes"; then
+ as_fn_error $? "set --without-rlm_yubikey to disable it explicitly." "$LINENO" 5
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: silently not building rlm_yubikey." >&5
+$as_echo "$as_me: WARNING: silently not building rlm_yubikey." >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FAILURE: rlm_yubikey requires: $fail." >&5
+$as_echo "$as_me: WARNING: FAILURE: rlm_yubikey requires: $fail." >&2;};
+ fail="$(echo $fail)"
+
+
+fr_status="skipping (requires $fail)"
+
+ fr_features=
+
+ fi
+
+else
+
+
+fr_status="OK"
+
+fi
+
+if test x"$fr_features" = x""; then
+ $as_echo "$fr_status" > "config.report"
+else
+ $as_echo_n "$fr_status ... " > "config.report"
+ cat "config.report.tmp" >> "config.report"
+fi
+
+rm "config.report.tmp"
+
+
+
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files all.mk"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "all.mk") CONFIG_FILES="$CONFIG_FILES all.mk" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ 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_yubikey/configure.ac b/src/modules/rlm_yubikey/configure.ac
new file mode 100644
index 0000000..1d641e6
--- /dev/null
+++ b/src/modules/rlm_yubikey/configure.ac
@@ -0,0 +1,196 @@
+AC_PREREQ([2.69])
+AC_INIT
+AC_CONFIG_SRCDIR([rlm_yubikey.c])
+AC_REVISION($Revision$)
+FR_INIT_MODULE([rlm_yubikey], [Yubikey support])
+
+FR_MODULE_START_TESTS
+
+dnl ############################################################
+dnl # Check for command line options
+dnl ############################################################
+
+dnl ############################################################
+dnl # Yubikey options
+dnl ############################################################
+
+dnl extra argument: --with-yubikey-include-dir=DIR
+yubikey_include_dir=
+AC_ARG_WITH(yubikey-include-dir,
+ [AS_HELP_STRING([--with-yubikey-include-dir=DIR],
+ [Directory where the yubikey includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need yubikey-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-yubikey-lib-dir=DIR
+yubikey_lib_dir=
+AC_ARG_WITH(yubikey-lib-dir,
+ [AS_HELP_STRING([--with-yubikey-lib-dir=DIR],
+ [Directory where the yubikey libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need yubikey-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-yubikey-dir=DIR
+AC_ARG_WITH(yubikey-dir,
+ [AS_HELP_STRING([--with-yubikey-dir=DIR],
+ [Base directory where yubikey is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need yubikey-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ yubikey_lib_dir="$withval/lib"
+ yubikey_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Ykclient options
+dnl ############################################################
+
+dnl extra argument: --with-ykclient-include-dir=DIR
+ykclient_include_dir=
+AC_ARG_WITH(ykclient-include-dir,
+ [AS_HELP_STRING([--with-ykclient-include-dir=DIR],
+ [Directory where the ykclient includes may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ykclient-include-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_include_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-ykclient-lib-dir=DIR
+ykclient_lib_dir=
+AC_ARG_WITH(ykclient-lib-dir,
+ [AS_HELP_STRING([--with-ykclient-lib-dir=DIR],
+ [Directory where the ykclient libraries may be found])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ykclient-lib-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_lib_dir="$withval"
+ ;;
+ esac])
+
+dnl extra argument: --with-ykclient-dir=DIR
+AC_ARG_WITH(ykclient-dir,
+ [AS_HELP_STRING([--with-ykclient-dir=DIR],
+ [Base directory where ykclient is installed])],
+ [case "$withval" in
+ no)
+ AC_MSG_ERROR(Need ykclient-dir)
+ ;;
+ yes)
+ ;;
+ *)
+ ykclient_lib_dir="$withval/lib"
+ ykclient_include_dir="$withval/include"
+ ;;
+ esac])
+
+dnl ############################################################
+dnl # Check for yubikey header files (optional)
+dnl ############################################################
+
+have_yubikey="yes"
+smart_try_dir="$yubikey_include_dir"
+FR_SMART_CHECK_INCLUDE(yubikey.h)
+if test "x$ac_cv_header_yubikey_h" != "xyes"; then
+ have_ykclient="no"
+ AC_MSG_WARN([yubikey headers not found. Use --with-yubikey-include-dir=<path>.])
+fi
+
+dnl ############################################################
+dnl # Check for yubikey libraries (optional)
+dnl ############################################################
+
+dnl try to link to yubikey
+smart_try_dir="$yubikey_lib_dir"
+FR_SMART_CHECK_LIB(yubikey, yubikey_aes_decrypt)
+if test "x$ac_cv_lib_yubikey_yubikey_aes_decrypt" != "xyes"; then
+ have_yubikey="no"
+ AC_MSG_WARN([yubikey libraries not found. Use --with-yubikey-lib-dir=<path>.])
+fi
+
+if test "x$have_yubikey" = "xyes"; then
+ AC_DEFINE([HAVE_YUBIKEY],[1],[Build with yubikey token decryption support support from yubikey])
+ FR_MODULE_FEATURE([yubikey], [with yubikey token decryption support])
+else
+ AC_MSG_WARN([silently building without yubikey token decryption support. requires: yubikey])
+ FR_MODULE_FEATURE([yubikey], [without yubikey token decryption support])
+fi
+
+dnl ############################################################
+dnl # Check for ykclient header files (optional)
+dnl ############################################################
+
+have_ykclient="yes"
+smart_try_dir="$ykclient_include_dir"
+FR_SMART_CHECK_INCLUDE([ykclient.h])
+if test "x$ac_cv_header_ykclient_h" != "xyes"; then
+ have_ykclient="no"
+ AC_MSG_WARN([ykclient headers not found. Use --with-ykclient-include-dir=<path>.])
+fi
+
+dnl ############################################################
+dnl # Check for ykclient libraries (optional)
+dnl ############################################################
+
+smart_try_dir="$ykclient_lib_dir"
+FR_SMART_CHECK_LIB([ykclient], [ykclient_request_process])
+if test "x$ac_cv_lib_ykclient_ykclient_request_process" != "xyes"; then
+ have_ykclient="no"
+ FR_SMART_CHECK_LIB([ykclient], [ykclient_request])
+ if test "x$ac_cv_lib_ykclient_ykclient_request" = "xyes"; then
+ AC_MSG_WARN([libykclient missing ykclient_request_process. A later version of libykclient is required.])
+ else
+ AC_MSG_WARN([ykclient libraries not found. Use --with-ykclient-lib-dir=<path>.])
+ fi
+fi
+
+if test "x$have_ykclient" = "xyes"; then
+ AC_DEFINE([HAVE_YKCLIENT],[1],[Build with yubicloud support from ykclient])
+ FR_MODULE_FEATURE([ykclient], [with yubicloud support])
+
+else
+ AC_MSG_WARN([silently building without yubicloud support. requires: ykclient])
+ FR_MODULE_FEATURE([ykclient], [without yubicloud support])
+fi
+
+FR_MODULE_END_TESTS
+
+mod_ldflags="$SMART_LIBS"
+mod_cflags="$SMART_CPPFLAGS"
+
+AC_SUBST(mod_cflags)
+AC_SUBST(mod_ldflags)
+
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_FILES([all.mk])
+AC_OUTPUT
diff --git a/src/modules/rlm_yubikey/decrypt.c b/src/modules/rlm_yubikey/decrypt.c
new file mode 100644
index 0000000..20b6df8
--- /dev/null
+++ b/src/modules/rlm_yubikey/decrypt.c
@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ * @file decrypt.c
+ * @brief Authentication for yubikey OTP tokens using the yubikey library.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@networkradius.com>
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Network RADIUS <info@networkradius.com>
+ */
+#include "rlm_yubikey.h"
+
+#ifdef HAVE_YUBIKEY
+/** Decrypt a Yubikey OTP AES block
+ *
+ * @param inst Module configuration.
+ * @param request The current request.
+ * @param passcode string to decrypt.
+ * @return one of the RLM_RCODE_* constants.
+ */
+rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
+{
+ uint32_t counter;
+ yubikey_token_st token;
+
+ DICT_ATTR const *da;
+
+ char private_id[(YUBIKEY_UID_SIZE * 2) + 1];
+ VALUE_PAIR *key, *vp;
+
+ da = dict_attrbyname("Yubikey-Key");
+ if (!da) {
+ REDEBUG("Dictionary missing entry for 'Yubikey-Key'");
+ return RLM_MODULE_FAIL;
+ }
+
+ key = fr_pair_find_by_da(request->config, da, TAG_ANY);
+ if (!key) {
+ REDEBUG("Yubikey-Key attribute not found in control list, can't decrypt OTP data");
+ return RLM_MODULE_INVALID;
+ }
+
+ if (key->vp_length != YUBIKEY_KEY_SIZE) {
+ REDEBUG("Yubikey-Key length incorrect, expected %u got %zu", YUBIKEY_KEY_SIZE, key->vp_length);
+ return RLM_MODULE_INVALID;
+ }
+
+ yubikey_parse((uint8_t const *) passcode + inst->id_len, key->vp_octets, &token);
+
+ /*
+ * Apparently this just uses byte offsets...
+ */
+ if (!yubikey_crc_ok_p((uint8_t *) &token)) {
+ REDEBUG("Decrypting OTP token data failed, rejecting");
+ return RLM_MODULE_REJECT;
+ }
+
+ RDEBUG("Token data decrypted successfully");
+
+ if (RDEBUG_ENABLED2) {
+ (void) fr_bin2hex((char *) &private_id, (uint8_t*) &token.uid, YUBIKEY_UID_SIZE);
+ RDEBUG2("Private ID : 0x%s", private_id);
+ RDEBUG2("Session counter : %u", yubikey_counter(token.ctr));
+ RDEBUG2("# used in session : %u", token.use);
+ RDEBUG2("Token timestamp : %u",
+ (token.tstph << 16) | token.tstpl);
+ RDEBUG2("Random data : %u", token.rnd);
+ RDEBUG2("CRC data : 0x%x", token.crc);
+ }
+
+ /*
+ * Private ID used for validation purposes
+ */
+ vp = fr_pair_make(request->packet, &request->packet->vps, "Yubikey-Private-ID", NULL, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating Yubikey-Private-ID");
+
+ return RLM_MODULE_FAIL;
+ }
+ fr_pair_value_memcpy(vp, token.uid, YUBIKEY_UID_SIZE);
+
+ /*
+ * Token timestamp
+ */
+ vp = fr_pair_make(request->packet, &request->packet->vps, "Yubikey-Timestamp", NULL, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating Yubikey-Timestamp");
+
+ return RLM_MODULE_FAIL;
+ }
+ vp->vp_integer = (token.tstph << 16) | token.tstpl;
+ vp->vp_length = 4;
+
+ /*
+ * Token random
+ */
+ vp = fr_pair_make(request->packet, &request->packet->vps, "Yubikey-Random", NULL, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating Yubikey-Random");
+
+ return RLM_MODULE_FAIL;
+ }
+ vp->vp_integer = token.rnd;
+ vp->vp_length = 4;
+
+ /*
+ * Combine the two counter fields together so we can do
+ * replay attack checks.
+ */
+ counter = (yubikey_counter(token.ctr) << 16) | token.use;
+
+ vp = fr_pair_make(request->packet, &request->packet->vps, "Yubikey-Counter", NULL, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating Yubikey-Counter");
+
+ return RLM_MODULE_FAIL;
+ }
+ vp->vp_integer = counter;
+ vp->vp_length = 4;
+
+ /*
+ * Now we check for replay attacks
+ */
+ vp = fr_pair_find_by_da(request->config, vp->da, TAG_ANY);
+ if (!vp) {
+ RWDEBUG("Yubikey-Counter not found in control list, skipping replay attack checks");
+ return RLM_MODULE_OK;
+ }
+
+ if (counter <= vp->vp_integer) {
+ REDEBUG("Replay attack detected! Counter value %u, is lt or eq to last known counter value %u",
+ counter, vp->vp_integer);
+ return RLM_MODULE_REJECT;
+ }
+
+ return RLM_MODULE_OK;
+}
+#endif
diff --git a/src/modules/rlm_yubikey/rlm_yubikey.c b/src/modules/rlm_yubikey/rlm_yubikey.c
new file mode 100644
index 0000000..83b7655
--- /dev/null
+++ b/src/modules/rlm_yubikey/rlm_yubikey.c
@@ -0,0 +1,455 @@
+/*
+ * 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_yubikey.c
+ * @brief Authentication for yubikey OTP tokens.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@networkradius.com>
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Network RADIUS <info@networkradius.com>
+ */
+RCSID("$Id$")
+
+#include "rlm_yubikey.h"
+
+/*
+ * 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.
+ */
+
+#ifdef HAVE_YKCLIENT
+static const CONF_PARSER validation_config[] = {
+ { "client_id", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_yubikey_t, client_id), 0 },
+ { "api_key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, rlm_yubikey_t, api_key), NULL },
+ CONF_PARSER_TERMINATOR
+};
+#endif
+
+static const CONF_PARSER module_config[] = {
+ { "id_length", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_yubikey_t, id_len), "12" },
+ { "split", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, split), "yes" },
+ { "decrypt", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, decrypt), "no" },
+ { "validate", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_yubikey_t, validate), "no" },
+#ifdef HAVE_YKCLIENT
+ { "validation", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) validation_config },
+#endif
+ CONF_PARSER_TERMINATOR
+};
+
+static char const modhextab[] = "cbdefghijklnrtuv";
+static char const hextab[] = "0123456789abcdef";
+
+#define is_modhex(x) (memchr(modhextab, tolower(x), 16))
+
+/** Convert yubikey modhex to normal hex
+ *
+ * The same buffer may be passed as modhex and hex to convert the modhex in place.
+ *
+ * Modhex and hex must be the same size.
+ *
+ * @param[in] modhex data.
+ * @param[in] len of input and output buffers.
+ * @param[out] hex where to write the standard hexits.
+ * @return The number of bytes written to the output buffer, or -1 on error.
+ */
+static ssize_t modhex2hex(char const *modhex, uint8_t *hex, size_t len)
+{
+ size_t i;
+ char *c1, *c2;
+
+ for (i = 0; i < len; i++) {
+ if (modhex[i << 1] == '\0') {
+ break;
+ }
+
+ /*
+ * We only deal with whole bytes
+ */
+ if (modhex[(i << 1) + 1] == '\0')
+ return -1;
+
+ if (!(c1 = memchr(modhextab, tolower((uint8_t) modhex[i << 1]), 16)) ||
+ !(c2 = memchr(modhextab, tolower((uint8_t) modhex[(i << 1) + 1]), 16)))
+ return -1;
+
+ hex[i] = hextab[c1 - modhextab];
+ hex[i + 1] = hextab[c2 - modhextab];
+ }
+
+ return i;
+}
+
+/**
+ * @brief Convert Yubikey modhex to standard hex
+ *
+ * Example: "%{modhextohex:vvrbuctetdhc}" == "ffc1e0d3d260"
+ */
+static ssize_t modhex_to_hex_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char *out, size_t outlen)
+{
+ ssize_t len;
+
+ if (outlen < strlen(fmt)) {
+ *out = '\0';
+ return 0;
+ }
+
+ /*
+ * mod2hex allows conversions in place
+ */
+ len = modhex2hex(fmt, (uint8_t *) out, strlen(fmt));
+ if (len <= 0) {
+ *out = '\0';
+ REDEBUG("Modhex string invalid");
+
+ return -1;
+ }
+
+ return len;
+}
+
+
+static int mod_bootstrap(CONF_SECTION *conf, void *instance)
+{
+ rlm_yubikey_t *inst = instance;
+
+ inst->name = cf_section_name2(conf);
+ if (!inst->name) inst->name = cf_section_name1(conf);
+
+#ifndef HAVE_YUBIKEY
+ if (inst->decrypt) {
+ cf_log_err_cs(conf, "Requires libyubikey for OTP decryption");
+ return -1;
+ }
+#endif
+
+ if (!cf_section_name2(conf)) return 0;
+
+ xlat_register("modhextohex", modhex_to_hex_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_yubikey_t *inst = instance;
+
+ if (inst->validate) {
+#ifdef HAVE_YKCLIENT
+ CONF_SECTION *cs;
+
+ cs = cf_section_sub_find(conf, "validation");
+ if (!cs) {
+ cf_log_err_cs(conf, "Missing validation section");
+ return -1;
+ }
+
+ if (rlm_yubikey_ykclient_init(cs, inst) < 0) {
+ return -1;
+ }
+#else
+ cf_log_err_cs(conf, "Requires libykclient for OTP validation against Yubicloud servers");
+ return -1;
+#endif
+ }
+
+ return 0;
+}
+
+/*
+ * Only free memory we allocated. The strings allocated via
+ * cf_section_parse() do not need to be freed.
+ */
+#ifdef HAVE_YKCLIENT
+static int mod_detach(void *instance)
+{
+ rlm_yubikey_ykclient_detach((rlm_yubikey_t *) instance);
+ return 0;
+}
+#endif
+
+static int CC_HINT(nonnull) otp_string_valid(rlm_yubikey_t *inst, char const *otp, size_t len)
+{
+ size_t i;
+
+ for (i = inst->id_len; i < len; i++) {
+ if (!is_modhex(otp[i])) return -i;
+ }
+
+ return 1;
+}
+
+
+/*
+ * Find the named user in this modules database. Create the set
+ * of attribute-value pairs to check and reply with for this user
+ * from the database. The authentication code only needs to check
+ * the password, the rest is done here.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
+{
+ rlm_yubikey_t *inst = instance;
+
+ DICT_VALUE *dval;
+ char const *passcode;
+ size_t len;
+ VALUE_PAIR *vp;
+
+ /*
+ * Can't do yubikey auth if there's no password.
+ */
+ if (!request->password || (request->password->da->attr != PW_USER_PASSWORD)) {
+ /*
+ * Don't print out debugging messages if we know
+ * they're useless.
+ */
+ if (request->packet->code == PW_CODE_ACCESS_CHALLENGE) {
+ return RLM_MODULE_NOOP;
+ }
+
+ RDEBUG2("No cleartext password in the request. Can't do Yubikey authentication");
+
+ return RLM_MODULE_NOOP;
+ }
+
+ passcode = request->password->vp_strvalue;
+ len = request->password->vp_length;
+
+ /*
+ * Now see if the passcode is the correct length (in its raw
+ * modhex encoded form).
+ *
+ * <public_id (6-16 bytes)> + <aes-block (32 bytes)>
+ *
+ */
+ if (len > (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ /* May be a concatenation, check the last 32 bytes are modhex */
+ if (inst->split) {
+ char const *otp;
+ char *password;
+ size_t password_len;
+ int ret;
+
+ password_len = (len - (inst->id_len + YUBIKEY_TOKEN_LEN));
+ otp = passcode + password_len;
+ ret = otp_string_valid(inst, otp, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ RDMARKER(otp, -ret, "User-Password (aes-block) value contains non modhex chars");
+ } else {
+ RDEBUG("User-Password (aes-block) value contains non modhex chars");
+ }
+ return RLM_MODULE_NOOP;
+ }
+
+ /*
+ * Insert a new request attribute just containing the OTP
+ * portion.
+ */
+ vp = pair_make_request("Yubikey-OTP", otp, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating 'Yubikey-OTP' attribute");
+ return RLM_MODULE_FAIL;
+ }
+
+ /*
+ * Replace the existing string buffer for the password
+ * attribute with one just containing the password portion.
+ */
+ MEM(password = talloc_array(request->password, char, password_len + 1));
+ strlcpy(password, passcode, password_len + 1);
+ fr_pair_value_strsteal(request->password, password);
+
+ RINDENT();
+ if (RDEBUG_ENABLED3) {
+ RDEBUG3("&request:Yubikey-OTP := '%s'", vp->vp_strvalue);
+ RDEBUG3("&request:User-Password := '%s'", request->password->vp_strvalue);
+ } else {
+ RDEBUG2("&request:Yubikey-OTP := <<< secret >>>");
+ RDEBUG2("&request:User-Password := <<< secret >>>");
+ }
+ REXDENT();
+ /*
+ * So the ID split code works on the non password portion.
+ */
+ passcode = vp->vp_strvalue;
+ }
+ } else if (len < (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ RDEBUG2("User-Password value is not the correct length, expected at least %u bytes, got %zu bytes",
+ inst->id_len + YUBIKEY_TOKEN_LEN, len);
+ return RLM_MODULE_NOOP;
+ } else {
+ int ret;
+
+ ret = otp_string_valid(inst, passcode, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ RDMARKER(passcode, -ret, "User-Password (aes-block) value contains non modhex chars");
+ } else {
+ RDEBUG("User-Password (aes-block) value contains non modhex chars");
+ }
+ return RLM_MODULE_NOOP;
+ }
+ }
+
+ dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->name);
+ if (dval) {
+ vp = radius_pair_create(request, &request->config, PW_AUTH_TYPE, 0);
+ vp->vp_integer = dval->value;
+ }
+
+ /*
+ * Split out the Public ID in case another module in authorize
+ * needs to verify it's associated with the user.
+ *
+ * It's left up to the user if they want to decode it or not.
+ */
+ if (inst->id_len) {
+ vp = fr_pair_make(request->packet, &request->packet->vps, "Yubikey-Public-ID", NULL, T_OP_SET);
+ if (!vp) {
+ REDEBUG("Failed creating Yubikey-Public-ID");
+
+ return RLM_MODULE_FAIL;
+ }
+
+ fr_pair_value_bstrncpy(vp, passcode, inst->id_len);
+ }
+
+ return RLM_MODULE_OK;
+}
+
+
+/*
+ * Authenticate the user with the given password.
+ */
+static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
+{
+ rlm_rcode_t rcode = RLM_MODULE_NOOP;
+ rlm_yubikey_t *inst = instance;
+ char const *passcode = NULL;
+ DICT_ATTR const *da;
+ VALUE_PAIR const *vp;
+ size_t len;
+ int ret;
+
+ da = dict_attrbyname("Yubikey-OTP");
+ if (!da) {
+ RDEBUG2("No Yubikey-OTP attribute defined, falling back to User-Password");
+ goto user_password;
+ }
+
+ vp = fr_pair_find_by_da(request->packet->vps, da, TAG_ANY);
+ if (vp) {
+ passcode = vp->vp_strvalue;
+ len = vp->vp_length;
+ } else {
+ RDEBUG2("No Yubikey-OTP attribute found, falling back to User-Password");
+ user_password:
+ /*
+ * Can't do yubikey auth if there's no password.
+ */
+ if (!request->password || (request->password->da->attr != PW_USER_PASSWORD)) {
+ REDEBUG("No User-Password in the request. Can't do Yubikey authentication");
+ return RLM_MODULE_INVALID;
+ }
+
+ vp = request->password;
+ passcode = request->password->vp_strvalue;
+ len = request->password->vp_length;
+ }
+
+ /*
+ * Verify the passcode is the correct length (in its raw
+ * modhex encoded form).
+ *
+ * <public_id (6-16 bytes)> + <aes-block (32 bytes)>
+ */
+ if (len != (inst->id_len + YUBIKEY_TOKEN_LEN)) {
+ REDEBUG("%s value is not the correct length, expected bytes %u, got bytes %zu",
+ vp->da->name, inst->id_len + YUBIKEY_TOKEN_LEN, len);
+ return RLM_MODULE_INVALID;
+ }
+
+ ret = otp_string_valid(inst, passcode, (inst->id_len + YUBIKEY_TOKEN_LEN));
+ if (ret <= 0) {
+ if (RDEBUG_ENABLED3) {
+ REMARKER(passcode, -ret, "Passcode (aes-block) value contains non modhex chars");
+ } else {
+ RERROR("Passcode (aes-block) value contains non modhex chars");
+ }
+ return RLM_MODULE_INVALID;
+ }
+
+#ifdef HAVE_YUBIKEY
+ if (inst->decrypt) {
+ rcode = rlm_yubikey_decrypt(inst, request, passcode);
+ if (rcode != RLM_MODULE_OK) {
+ return rcode;
+ }
+ /* Fall-Through to doing ykclient auth in addition to local auth */
+ }
+#endif
+
+#ifdef HAVE_YKCLIENT
+ if (inst->validate) {
+ return rlm_yubikey_validate(inst, request, passcode);
+ }
+#endif
+ return rcode;
+}
+
+/*
+ * 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_yubikey;
+module_t rlm_yubikey = {
+ .magic = RLM_MODULE_INIT,
+ .name = "yubikey",
+ .type = RLM_TYPE_THREAD_SAFE,
+ .inst_size = sizeof(rlm_yubikey_t),
+ .config = module_config,
+ .bootstrap = mod_bootstrap,
+ .instantiate = mod_instantiate,
+#ifdef HAVE_YKCLIENT
+ .detach = mod_detach,
+#endif
+ .methods = {
+ [MOD_AUTHENTICATE] = mod_authenticate,
+ [MOD_AUTHORIZE] = mod_authorize
+ },
+};
diff --git a/src/modules/rlm_yubikey/rlm_yubikey.h b/src/modules/rlm_yubikey/rlm_yubikey.h
new file mode 100644
index 0000000..6b8a151
--- /dev/null
+++ b/src/modules/rlm_yubikey/rlm_yubikey.h
@@ -0,0 +1,54 @@
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+#include <ctype.h>
+
+#include "config.h"
+
+#ifdef HAVE_YKCLIENT
+#include <ykclient.h>
+#endif
+
+#ifdef HAVE_YUBIKEY
+#include <yubikey.h>
+#endif
+
+#define YUBIKEY_TOKEN_LEN 32
+
+/*
+ * Define a structure for our module configuration.
+ *
+ * These variables do not need to be in a structure, but it's
+ * a lot cleaner to do so, and a pointer to the structure can
+ * be used as the instance handle.
+ */
+typedef struct rlm_yubikey_t {
+ char const *name; //!< Instance name.
+ int auth_type; //!< Our Auth-Type.
+ unsigned int id_len; //!< The length of the Public ID portion of the OTP string.
+ bool split; //!< Split password string into components.
+ bool decrypt; //!< Decrypt the OTP string using the yubikey library.
+ bool validate; //!< Validate the OTP string using the ykclient library.
+ char const **uris; //!< Yubicloud URLs to validate the token against.
+
+#ifdef HAVE_YKCLIENT
+ unsigned int client_id; //!< Validation API client ID.
+ char const *api_key; //!< Validation API signing key.
+ ykclient_t *ykc; //!< ykclient configuration.
+ fr_connection_pool_t *pool; //!< Connection pool instance.
+#endif
+} rlm_yubikey_t;
+
+
+/*
+ * decrypt.c - Decryption functions
+ */
+rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode);
+
+/*
+ * validate.c - Connection pool and validation functions
+ */
+int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst);
+
+int rlm_yubikey_ykclient_detach(rlm_yubikey_t *inst);
+
+rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, char const *passcode);
diff --git a/src/modules/rlm_yubikey/validate.c b/src/modules/rlm_yubikey/validate.c
new file mode 100644
index 0000000..7dc13d8
--- /dev/null
+++ b/src/modules/rlm_yubikey/validate.c
@@ -0,0 +1,201 @@
+/**
+ * $Id$
+ * @file validate.c
+ * @brief Authentication for yubikey OTP tokens using the ykclient library.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@networkradius.com>
+ * @copyright 2013 The FreeRADIUS server project
+ * @copyright 2013 Network RADIUS <info@networkradius.com>
+ */
+#include "rlm_yubikey.h"
+
+#ifdef HAVE_YKCLIENT
+#include <freeradius-devel/connection.h>
+
+/** Frees a ykclient handle
+ *
+ * @param[in] yandle rlm_yubikey_handle_t to close and free.
+ * @return returns 0.
+ */
+static int _mod_conn_free(ykclient_handle_t **yandle)
+{
+ ykclient_handle_done(yandle);
+
+ 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.
+ *
+ * @see fr_connection_pool_init
+ * @see fr_connection_create_t
+ * @see connection.c
+ */
+static void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
+{
+ rlm_yubikey_t *inst = instance;
+ ykclient_rc status;
+ ykclient_handle_t *yandle, **marker;
+
+ status = ykclient_handle_init(inst->ykc, &yandle);
+ if (status != YKCLIENT_OK) {
+ ERROR("rlm_yubikey (%s): %s", inst->name, ykclient_strerror(status));
+
+ return NULL;
+ }
+ marker = talloc(ctx, ykclient_handle_t *);
+ talloc_set_destructor(marker, _mod_conn_free);
+ *marker = yandle;
+
+ return yandle;
+}
+
+int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst)
+{
+ ykclient_rc status;
+ CONF_SECTION *servers;
+
+ char prefix[100];
+
+ int count = 0;
+
+ if (!inst->client_id) {
+ ERROR("rlm_yubikey (%s): validation.client_id must be set (to a valid id) when validation is enabled",
+ inst->name);
+
+ return -1;
+ }
+
+ if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) {
+ ERROR("rlm_yubikey (%s): validation.api_key must be set (to a valid key) when validation is enabled",
+ inst->name);
+
+ return -1;
+ }
+
+ DEBUG("rlm_yubikey (%s): Initialising ykclient", inst->name);
+
+ status = ykclient_global_init();
+ if (status != YKCLIENT_OK) {
+yk_error:
+ ERROR("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name);
+
+ return -1;
+ }
+
+ status = ykclient_init(&inst->ykc);
+ if (status != YKCLIENT_OK) {
+ goto yk_error;
+ }
+
+ servers = cf_section_sub_find(conf, "servers");
+ if (servers) {
+ CONF_PAIR *uri, *first;
+ /*
+ * If there were no uris configured we just use the default
+ * ykclient uris which point to the yubico servers.
+ */
+ first = uri = cf_pair_find(servers, "uri");
+ if (!uri) {
+ goto init;
+ }
+
+ while (uri) {
+ count++;
+ uri = cf_pair_find_next(servers, uri, "uri");
+ }
+ inst->uris = talloc_zero_array(inst, char const *, count);
+
+ uri = first;
+ count = 0;
+ while (uri) {
+ inst->uris[count++] = cf_pair_value(uri);
+ uri = cf_pair_find_next(servers, uri, "uri");
+ }
+ if (count) {
+ status = ykclient_set_url_templates(inst->ykc, count, inst->uris);
+ if (status != YKCLIENT_OK) {
+ goto yk_error;
+ }
+ }
+ }
+
+init:
+ status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key);
+ if (status != YKCLIENT_OK) {
+ ERROR("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name);
+
+ return -1;
+ }
+
+ snprintf(prefix, sizeof(prefix), "rlm_yubikey (%s)", inst->name);
+ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, NULL, prefix);
+ if (!inst->pool) {
+ ykclient_done(&inst->ykc);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int rlm_yubikey_ykclient_detach(rlm_yubikey_t *inst)
+{
+ fr_connection_pool_free(inst->pool);
+ ykclient_done(&inst->ykc);
+ ykclient_global_done();
+
+ return 0;
+}
+
+rlm_rcode_t rlm_yubikey_validate(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
+{
+ rlm_rcode_t rcode = RLM_MODULE_OK;
+ ykclient_rc status;
+ ykclient_handle_t *yandle;
+
+ yandle = fr_connection_get(inst->pool);
+ if (!yandle) return RLM_MODULE_FAIL;
+
+ /*
+ * The libcurl multi-handle interface will tear down the TCP sockets for any partially completed
+ * requests when their easy handle is removed from the multistack.
+ *
+ * For performance reasons ykclient will stop processing the request immediately after receiving
+ * a response from one of the servers. If we then immediately call ykclient_handle_cleanup
+ * the connections are destroyed and will need to be re-established the next time the handle
+ * is used.
+ *
+ * To try and prevent this from happening, we leave cleanup until the *next* time
+ * the handle is used, by which time the requests will of hopefully completed and the connections
+ * can be re-used.
+ *
+ */
+ ykclient_handle_cleanup(yandle);
+
+ status = ykclient_request_process(inst->ykc, yandle, passcode);
+ if (status != YKCLIENT_OK) {
+ REDEBUG("%s", ykclient_strerror(status));
+ switch (status) {
+ case YKCLIENT_BAD_OTP:
+ case YKCLIENT_REPLAYED_OTP:
+ rcode = RLM_MODULE_REJECT;
+ break;
+
+ case YKCLIENT_NO_SUCH_CLIENT:
+ rcode = RLM_MODULE_NOTFOUND;
+ break;
+
+ default:
+ rcode = RLM_MODULE_FAIL;
+ }
+ }
+
+ fr_connection_release(inst->pool, yandle);
+
+ return rcode;
+}
+#endif
diff --git a/src/modules/stable b/src/modules/stable
new file mode 100644
index 0000000..8abe0fe
--- /dev/null
+++ b/src/modules/stable
@@ -0,0 +1,46 @@
+rlm_always
+rlm_attr_filter
+rlm_cache
+rlm_chap
+rlm_counter
+rlm_detail
+rlm_dhcp
+rlm_digest
+rlm_dynamic_clients
+rlm_eap
+rlm_exec
+rlm_expiration
+rlm_expr
+rlm_files
+rlm_ippool
+rlm_json
+rlm_krb5
+rlm_ldap
+rlm_linelog
+rlm_logintime
+rlm_mschap
+rlm_pam
+rlm_pap
+rlm_passwd
+rlm_perl
+rlm_preprocess
+rlm_python
+rlm_python3
+rlm_radutmp
+rlm_realm
+rlm_rest
+rlm_replicate
+rlm_soh
+rlm_sql
+rlm_sqlcounter
+rlm_sqlippool
+rlm_sql_map
+rlm_test
+rlm_totp
+rlm_unix
+rlm_sometimes
+rlm_wimax
+rlm_unbound
+rlm_yubikey
+rlm_redis
+rlm_rediswho
diff --git a/src/tests/.gitignore b/src/tests/.gitignore
new file mode 100644
index 0000000..a019664
--- /dev/null
+++ b/src/tests/.gitignore
@@ -0,0 +1,12 @@
+.cache
+.foo
+.bar
+.request
+dictionary
+test.conf
+radius.log
+radiusd.pid
+eapol_test
+tlscache
+config/eap-test
+config/eap-test-inner-tunnel
diff --git a/src/tests/Makefile b/src/tests/Makefile
new file mode 100644
index 0000000..2dab5b1
--- /dev/null
+++ b/src/tests/Makefile
@@ -0,0 +1,328 @@
+# -*- makefile -*-
+##
+## Makefile -- Build and run tests for the server.
+##
+## http://www.freeradius.org/
+## $Id$
+##
+#
+include ../../Make.inc
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+BUILD_PATH := $(top_builddir)/build
+
+#
+# Build eapol_test if requested to.
+#
+.PHONY: eapol_test
+eapol_test: $(BUILD_PATH)/tests/eapol_test/eapol_test.mk
+ ${Q}echo EAPOL_TEST=$(EAPOL_TEST)
+
+#
+# If we're doing anything resembling EAP, then make sure that
+# EAPOL_TEST is defined.
+#
+ifneq "(findstring eap,$(MAKECMDGOALS))" ""
+$(BUILD_PATH)/tests/eapol_test:
+ ${Q}mkdir -p $@
+
+TEST_PATH := $(top_builddir)/src/tests
+DICT_PATH := $(TEST_PATH)
+BIN_PATH := $(BUILD_PATH)/bin/local
+RADIUSD_BIN := $(BIN_PATH)/radiusd
+
+ifeq "$(DICT_PATH)" "$(TEST_PATH)"
+LIB_PATH := $(BUILD_PATH)/lib/local/.libs/
+DYLD_LIBRARY_PATH := $(DYLD_LIBRARY_PATH):$(LIB_PATH)
+export DYLD_LIBRARY_PATH
+endif
+
+ifneq "$(OPENSSL_LIBS)" ""
+#
+# Build eapol_test, and cache its output. Note that EAPOL_TEST may not be
+# defined, so we have to run the shell script for the second line, too.
+#
+# Normal expansion will still run the script if EAPOL_TEST_BIN is
+# set but empty, which we don't want.
+#
+ifeq "$(EAPOL_TEST_BIN)" ""
+override EAPOL_TEST_BIN := $(shell $(top_builddir)/scripts/ci/eapol_test-build.sh)
+endif
+
+$(BUILD_PATH)/tests/eapol_test/eapol_test.mk: | $(BUILD_PATH)/tests/eapol_test
+ ${Q}echo "EAPOL_TEST=$(EAPOL_TEST_BIN)" > $@
+ ${Q}echo "TLS1_3=$(shell openssl ciphers -s -v 'ECDHE:!COMPLEMENTOFDEFAULT'| grep -q 'TLSv1.3' && echo yes)" >> $@
+ ${Q}echo "OPENSSL_OK=$(shell openssl version | grep -v ' 1\.0' >/dev/null && echo yes)" >> $@
+ ${Q}echo "OPENSSL3_OK=$(shell openssl version | grep -q ' OpenSSL 3\.0' && echo yes)" >> $@
+else
+#
+# No OpenSSL means that we don't even try to build eapol_test
+#
+.PHONY: $(BUILD_PATH)/tests/eapol_test/eapol_test.mk
+$(BUILD_PATH)/tests/eapol_test/eapol_test.mk: | $(BUILD_PATH)/tests/eapol_test
+ ${Q}touch $@
+endif
+
+-include $(BUILD_PATH)/tests/eapol_test/eapol_test.mk
+endif
+
+#
+# OpenSSL 1.0.x doesn't support cipher_list="DEFAULT@SECLEVEL=1"
+#
+# If the variable is empty, then OpenSSL isn't OK.
+#
+ifeq "$(OPENSSL_OK)" ""
+SECLEVEL=
+else
+SECLEVEL=@SECLEVEL=1
+endif
+
+#
+# For OpenSSL 3.0.x, as described in https://github.com/openssl/openssl/blob/master/doc/man7/migration_guide.pod
+#
+# "The security strength of SHA1 and MD5 based signatures in TLS has been reduced.
+# This results in SSL 3, TLS 1.0, TLS 1.1 and DTLS 1.0 no longer working at the
+# default security level of 1 and instead requires security level 0."
+#
+ifeq "$(OPENSSL3_OK)" "yes"
+SECLEVEL=@SECLEVEL=0
+endif
+
+RADDB_PATH := $(top_builddir)/raddb/
+
+TESTS = mschapv1 digest-01/digest* \
+ test.example.com
+
+PORT = 12340
+ACCTPORT = $(shell expr $(PORT) + 1)
+
+# example.com stripped.example.com
+
+SECRET = testing123
+
+.PHONY: all eap dictionary clean
+
+#
+# Build the directory for testing the server
+#
+all: tests
+
+clean:
+ @rm -f test.conf dictionary *.ok *.log $(BUILD_DIR)/tests/eap
+
+dictionary:
+ @echo "# test dictionary. Do not install. Delete at any time." > dictionary; \
+ echo '$$INCLUDE ' $(top_builddir)/share/dictionary >> dictionary; \
+ echo '$$INCLUDE ' $(top_builddir)/src/tests/dictionary.test >> dictionary; \
+ if [ "$(DICT_PATH)" = "$(TEST_PATH)" ]; then \
+ echo '$$INCLUDE ' $(top_builddir)/share/dictionary.dhcp >> dictionary; \
+ echo '$$INCLUDE ' $(top_builddir)/share/dictionary.vqp >> dictionary; \
+ fi
+
+test.conf: dictionary config/eap-test
+ @echo "# test configuration file. Do not install. Delete at any time." > $@
+ ${Q}if [ -n "$(LIB_PATH)" ]; then \
+ echo "libdir =" $(LIB_PATH) >> $@; \
+ fi
+ ${Q}echo "testdir =" $(TEST_PATH) >> $@
+ ${Q}echo 'logdir = $${testdir}' >> $@
+ ${Q}echo "maindir =" $(RADDB_PATH) >> $@
+ ${Q}echo 'radacctdir = $${testdir}' >> $@
+ ${Q}echo 'pidfile = $${testdir}/radiusd.pid' >> $@
+ ${Q}echo 'panic_action = "gdb -batch -x $${testdir}/panic.gdb %e %p > $${testdir}/gdb.log 2>&1; cat $${testdir}/gdb.log"' >> $@
+ ${Q}echo 'security {' >> $@
+ ${Q}echo ' allow_vulnerable_openssl = yes' >> $@
+ ${Q}echo '}' >> $@
+ ${Q}echo >> $@
+ ${Q}echo 'modconfdir = $${maindir}mods-config' >> $@
+ ${Q}echo 'certdir = $${maindir}/certs' >> $@
+ ${Q}echo 'cadir = $${maindir}/certs' >> $@
+ ${Q}echo '$$INCLUDE $${testdir}/config/' >> $@
+ ${Q}echo '$$INCLUDE $${maindir}/radiusd.conf' >> $@
+
+#
+# Rename "inner-tunnel", and ensure that it only uses the "eap-test" module.
+#
+config/eap-test-inner-tunnel: $(RADDB_PATH)sites-available/inner-tunnel
+ ${Q}sed 's/eap/eap-test/;s/server inner-tunnel/server eap-test-inner-tunnel/' < $< > $@
+
+#
+# * Same renames as above
+# * enable caching
+# * uncomment caching directory
+# * set the minimum TLS version to 1.0 for testing
+# * set the maximum TLS version to 1.2 or 1.3, depending if 1.3 is available
+# * always enable TLS 1.3 for the tests, via the super-secret magic flag.
+# * tell OpenSSL to enable insecure ciphers TLS 1.0 and TLS 1.1
+#
+config/eap-test: $(RADDB_PATH)mods-available/eap config/eap-test-inner-tunnel
+ ${Q}sed -e 's/eap {/eap eap-test {/' \
+ -e 's/= inner-tunnel/= eap-test-inner-tunnel/;s/use_tunneled_reply = no/use_tunneled_reply = yes/' \
+ -e 's/enable = no/enable = yes/' \
+ -e 's/^\(.*\)persist_dir =/ persist_dir =/' \
+ -e 's/tls_min_version = "1.2"/tls_min_version = "1.0"/' \
+ -e '$(if $(TLS1_3),s/tls_max_version = "1.2"/tls_max_version = "1.3"/)' \
+ -e 's/cipher_list = "DEFAULT"/cipher_list = "DEFAULT${SECLEVEL}"/' \
+ < $< > $@
+
+radiusd.pid: test.conf
+ ${Q}rm -rf $(TEST_PATH)/gdb.log $(TEST_PATH)/radius.log $(TEST_PATH)/tlscache
+ ${Q}mkdir -p $(TEST_PATH)/tlscache
+ ${Q}printf "Starting server... "
+ ${Q}if ! $(RADIUSD_BIN) -Pxxxxml $(TEST_PATH)/radius.log -d ${top_builddir}/src/tests -n test -i 127.0.0.1 -p $(PORT) -D $(DICT_PATH); then \
+ echo "failed"; \
+ echo "Last log entries were:"; \
+ tail -n 20 "$(TEST_PATH)/radius.log"; \
+ fi
+ ${Q}echo "ok"
+
+# We can't make this depend on radiusd.pid, because then make will create
+# radiusd.pid when we make radiusd.kill, which we don't want.
+.PHONY: radiusd.kill
+radiusd.kill:
+ ${Q}if [ -f radiusd.pid ]; then \
+ ret=0; \
+ if ! ps `cat $(TEST_PATH)/radiusd.pid` >/dev/null 2>&1; then \
+ rm -f radiusd.pid; \
+ echo "FreeRADIUS terminated during test"; \
+ echo "GDB output was:"; \
+ cat "$(TEST_PATH)/gdb.log"; \
+ echo "Last log entries were:"; \
+ tail -n 20 $(TEST_PATH)/radius.log; \
+ ret=1; \
+ fi; \
+ if ! kill -TERM `cat $(TEST_PATH)/radiusd.pid` >/dev/null 2>&1; then \
+ ret=1; \
+ fi; \
+ exit $$ret; \
+ fi
+ ${Q}rm -f radiusd.pid
+
+#
+# Run eapol_test if it exists and we built with openssl support.
+# Otherwise do nothing.
+#
+ifneq "$(EAPOL_TEST)" ""
+EAP_FILES = eap-md5.conf
+EAP_TLS_FILES = eap-ttls-pap.conf eap-ttls-mschapv2.conf peap-mschapv2.conf
+EAP_TLS_VERSIONS = 1.1 1.2
+EAP_TLS_DISABLE_STRING = tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1
+
+ifneq "$(TLS1_3)" ""
+EAP_TLS_VERSIONS += 1.3
+EAP_TLS_DISABLE_STRING += tls_disable_tlsv1_3=1
+endif
+
+.PHONY: $(BUILD_PATH)/tests/eap
+$(BUILD_PATH)/tests/eap:
+ ${Q}mkdir -p $@
+
+.PHONY: clean.tests.eap
+clean.tests.eap:
+ ${Q}rm -rf $(BUILD_PATH)/tests/eap config/tlscache config/eap-test config/eap-test-inner-tunnel
+
+#
+# Set target-specific variables, so that the later shell scripts are rather more understandable.
+#
+# MD5 doesn't use MPPE keys
+#
+$(BUILD_PATH)/tests/eap/%.ok: NO_MPPE = $(filter eap-md5,$(basename $(notdir $@)))
+$(BUILD_PATH)/tests/eap/%.ok: CMD = $(EAPOL_TEST) -c $< -p $(PORT) -s $(SECRET) $(if $(NO_MPPE),-n)
+$(BUILD_PATH)/tests/eap/%.ok: LOG = $(patsubst %.ok,%,$@).log
+
+$(BUILD_PATH)/tests/eap/%.ok: $(top_builddir)/src/tests/%.conf | radiusd.kill $(BUILD_PATH)/tests/eap radiusd.pid radiusd.kill
+ ${Q}printf 'EAPOL_TEST %s ' $(notdir $(patsubst %.conf,%,$<))
+ ${Q}if ! $(CMD) > $(LOG) 2>&1; then \
+ echo " - " FAILED - command failed; \
+ echo ">>> cmd -" $(CMD); \
+ echo ">>> log -" $(LOG); \
+ echo "===================="; \
+ tail -10 $(LOG); \
+ echo "===================="; \
+ $(MAKE) radiusd.kill; \
+ exit 1; \
+ fi
+ @echo
+ ${Q}touch $@
+
+#
+# Don't run the full TLS version tests for CI post-install.
+#
+ifneq "$(prefix)" ""
+#
+# ${1} is the config file
+# ${2} is the TLS version to use.
+#
+# Update the phase1 configuration to enable/disable various TLS versions
+# insert an OpenSSL cipher configuration line by cloning "password" and editing it.
+#
+define EAP_TLS_CONFIG
+$(BUILD_PATH)/tests/eap/${1}-${2}.conf: $(top_builddir)/src/tests/${1}.conf
+ ${Q}sed -e 's/phase1="/phase1="$(subst $(subst .,_,${2})=1,$(subst .,_,${2})=0,$(EAP_TLS_DISABLE_STRING)) /' \
+ -e '/password/s/^//p; /password/s/^.*/ openssl_ciphers="DEFAULT${SECLEVEL}"/' \
+ < $$< > $$@
+
+$(BUILD_PATH)/tests/eap/${1}-${2}.ok: $(BUILD_PATH)/tests/eap/${1}-${2}.conf
+ ${Q}printf 'EAPOL_TEST %s' $$(notdir $$(patsubst %.ok,%,$$@))
+ ${Q}if ! $$(CMD) -r 1 > $$(LOG) 2>&1; then \
+ echo " - " FAILED - command failed; \
+ echo ">>> cmd -" $$(CMD) -r 1; \
+ echo ">>> log -" $$(LOG); \
+ echo "===================="; \
+ tail -10 $$(LOG); \
+ echo "===================="; \
+ $(MAKE) radiusd.kill; \
+ exit 1; \
+ elif ! grep -q '^SSL: Using TLS version TLSv${2}$$$$' $$(patsubst %.ok,%,$$@).log; then \
+ echo " - " FAILED - not using TLS version ${2}; \
+ echo ">>> cmd -" $$(CMD) -r 1; \
+ echo ">>> log -" $$(LOG); \
+ $(MAKE) radiusd.kill; \
+ exit 1; \
+ elif ! grep -q '^OpenSSL: Handshake finished - resumed=1$$$$' $$(patsubst %.ok,%,$$@).log; then \
+ echo " - " FAILED - did not use resumption; \
+ echo ">>> cmd -" $$(CMD) -r 1; \
+ echo ">>> log -" $$(LOG); \
+ $(MAKE) radiusd.kill; \
+ exit 1; \
+ fi
+ @echo
+ ${Q}touch $$@
+
+# EAP-FAST doesn't do TLS 1.3
+ifneq "${1}-${2}" "eap-fast-1.3"
+EAP_TLS_VERSION_FILES += $(BUILD_PATH)/tests/eap/${1}-${2}.ok
+endif
+endef
+
+$(foreach FILE,$(patsubst %.conf,%,$(EAP_TLS_FILES)),$(foreach TLS,$(EAP_TLS_VERSIONS),$(eval $(call EAP_TLS_CONFIG,${FILE},${TLS}))))
+endif # there's no "prefix", so we don't run the full EAP tests
+
+EAPOL_OK_FILES := $(sort $(addprefix $(BUILD_PATH)/tests/eap/,$(patsubst %.conf,%.ok, $(notdir $(EAP_TLS_FILES) $(EAP_FILES)))) $(EAP_TLS_VERSION_FILES))
+
+tests.eap: $(EAPOL_OK_FILES) | radiusd.kill radiusd.pid
+else
+tests.eap:
+ ${Q}echo "EAPOL Tests is disabled"
+endif # we have eapol_test built
+
+# kill the server (if it's running)
+# start the server
+# run the tests (ignoring any failures)
+# kill the server
+# remove the changes to raddb/
+tests.runtests: test.conf | radiusd.kill radiusd.pid
+ ${Q}chmod a+x runtests.sh
+ ${Q}BIN_PATH="$(BIN_PATH)" PORT="$(PORT)" ./runtests.sh $(TESTS)
+
+tests: tests.runtests tests.eap
diff --git a/src/tests/README b/src/tests/README
new file mode 100644
index 0000000..4055d5d
--- /dev/null
+++ b/src/tests/README
@@ -0,0 +1,29 @@
+ This is a preliminary test harness for the server.
+
+$ make tests
+
+ makes all of the tests
+
+config/*
+
+ virtual server configuration that is used for the tests
+
+unit/*
+ unit tests. Mostly parsing tests, to see if we can parse
+ conditions, xlat expansions, RADIUS attributes, etc.
+
+xlat/*
+ dynamic expansions. All stand-alone ones.
+ e.g. can we turn %{md5:fooo} into the MD5 hash?
+
+keywords/*
+ tests of "unlang" keywords. Both parsing and functionality.
+
+auth/*
+ tests of authentication methods.
+
+modules/*
+ tests for individual modules
+
+In general, just placing files of the correct format in a directory
+will cause them to be picked up by the test harness. \ No newline at end of file
diff --git a/src/tests/all.mk b/src/tests/all.mk
new file mode 100644
index 0000000..142772b
--- /dev/null
+++ b/src/tests/all.mk
@@ -0,0 +1,78 @@
+SUBMAKEFILES := rbmonkey.mk unit/all.mk map/all.mk xlat/all.mk keywords/all.mk auth/all.mk modules/all.mk sql_nas_table/all.mk
+PORT := 12340
+SECRET := testing123
+DICT_PATH := $(top_srcdir)/share
+
+#
+# Include all of the autoconf definitions into the Make variable space
+#
+-include $(BUILD_DIR)/tests/keywords/autoconf.h.mk
+
+#
+# Pull all of the autoconf stuff into here.
+#
+$(BUILD_DIR)/tests/keywords/autoconf.h.mk: src/include/autoconf.h
+ @grep '^#define' $^ | sed 's/#define /AC_/;s/ / := /' > $@
+
+######################################################################
+#
+# Generic rules to set up the tests
+#
+# Use $(eval $(call TEST_BOOTSTRAP))
+#
+######################################################################
+define TEST_BOOTSTRAP
+
+#
+# The test files are files without extensions.
+#
+OUTPUT.$(TEST) := $(patsubst %/,%,$(subst $(top_srcdir)/src,$(BUILD_DIR),$(abspath $(DIR))))
+OUTPUT := $$(OUTPUT.$(TEST))
+
+#
+# Create the output directory
+#
+$$(OUTPUT.$(TEST)):
+ $${Q}mkdir -p $$@
+
+#
+# All of the output files depend on the input files
+#
+FILES.$(TEST) := $(addprefix $$(OUTPUT.$(TEST))/,$(sort $(FILES)))
+
+#
+# The output files also depend on the directory
+# and on the previous test.
+#
+$$(FILES.$(TEST)): | $$(OUTPUT.$(TEST))
+
+#
+# Make sure that the output files depend on the input.
+# This way if the input file doesn't exist, we get a
+# build error. Without this rule, the test target
+# would just get re-built every time, no matter what.
+#
+$(foreach x, $(FILES), $(eval $$(OUTPUT.$(TEST))/$x: $(DIR)/$x))
+
+#
+# We have a real file that's created if all of the tests pass.
+#
+$(BUILD_DIR)/tests/$(TEST): $$(FILES.$(TEST))
+ $${Q}touch $$@
+
+#
+# For simplicity, we create a phony target so that the poor developer
+# doesn't need to remember path names
+#
+$(TEST): $(BUILD_DIR)/tests/$(TEST)
+
+#
+# Clean the output directory and files.
+#
+.PHONY: clean.$(TEST)
+clean.$(TEST):
+ $${Q}rm -rf $$(OUTPUT.$(TEST))
+ $${Q}rm -f $$(BUILD_DIR)/tests/$(TEST)
+
+clean.test: clean.$(TEST)
+endef
diff --git a/src/tests/auth/all.mk b/src/tests/auth/all.mk
new file mode 100644
index 0000000..284033f
--- /dev/null
+++ b/src/tests/auth/all.mk
@@ -0,0 +1,119 @@
+#
+# Unit tests for authentication
+#
+
+#
+# The test files are files without extensions.
+# The list is unordered. The order is added in the next step by looking
+# at precursors.
+#
+AUTH_FILES := $(filter-out %.conf %.md %.attrs %.mk %~ %.rej,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
+
+#
+# Create the output directory
+#
+.PHONY: $(BUILD_DIR)/tests/auth
+$(BUILD_DIR)/tests/auth:
+ @mkdir -p $@
+
+#
+# Find which input files are needed by the tests
+# strip out the ones which exist
+# move the filenames to the build directory.
+#
+AUTH_EXISTS := $(addprefix $(DIR)/,$(addsuffix .attrs,$(AUTH_FILES)))
+AUTH_NEEDS := $(filter-out $(wildcard $(AUTH_EXISTS)),$(AUTH_EXISTS))
+AUTH := $(subst $(DIR),$(BUILD_DIR)/tests/auth,$(AUTH_NEEDS))
+
+AUTH_HAS := $(filter $(wildcard $(AUTH_EXISTS)),$(AUTH_EXISTS))
+AUTH_COPY := $(subst $(DIR),$(BUILD_DIR)/tests/auth,$(AUTH_NEEDS))
+
+#
+# For each file, look for precursor test.
+# Ensure that each test depends on its precursors.
+#
+-include $(BUILD_DIR)/tests/auth/depends.mk
+
+$(BUILD_DIR)/tests/auth/depends.mk: $(addprefix $(DIR)/,$(AUTH_FILES)) | $(BUILD_DIR)/tests/auth
+ @rm -f $@
+ @for x in $^; do \
+ y=`grep 'PRE: ' $$x | sed 's/.*://;s/ / /g;s, , $(BUILD_DIR)/tests/auth/,g'`; \
+ if [ "$$y" != "" ]; then \
+ z=`echo $$x | sed 's,src/,$(BUILD_DIR)/',`; \
+ echo "$$z: $$y" >> $@; \
+ echo "" >> $@; \
+ fi \
+ done
+#
+# These ones get copied over from the default input
+#
+$(AUTH): $(DIR)/default-input.attrs | $(BUILD_DIR)/tests/auth
+ @cp $< $@
+
+#
+# These ones get copied over from their original files
+#
+$(BUILD_DIR)/tests/auth/%.attrs: $(DIR)/%.attrs | $(BUILD_DIR)/tests/auth
+ @cp $< $@
+
+#
+# Don't auto-remove the files copied by the rule just above.
+# It's unnecessary, and it clutters the output with crap.
+#
+.PRECIOUS: $(BUILD_DIR)/tests/auth/%.attrs raddb/mods-enabled/wimax
+
+AUTH_MODULES := $(shell grep -- mods-enabled src/tests/auth/radiusd.conf | sed 's,.*/,,')
+AUTH_RADDB := $(addprefix raddb/mods-enabled/,$(AUTH_MODULES))
+AUTH_LIBS := $(addsuffix .la,$(addprefix rlm_,$(AUTH_MODULES)))
+
+#
+# Files in the output dir depend on the unit tests
+#
+# src/tests/auth/FOO unlang for the test
+# src/tests/auth/FOO.attrs input RADIUS and output filter
+# build/tests/auth/FOO updated if the test succeeds
+# build/tests/auth/FOO.log debug output for the test
+#
+# Auto-depend on modules via $(shell grep INCLUDE $(DIR)/radiusd.conf | grep mods-enabled | sed 's/.*}/raddb/'))
+#
+# If the test fails, then look for ERROR in the input. No error
+# means it's unexpected, so we die.
+#
+# Otherwise, check the log file for a parse error which matches the
+# ERROR line in the input.
+#
+$(BUILD_DIR)/tests/auth/%: $(DIR)/% $(BUILD_DIR)/tests/auth/%.attrs $(TESTBINDIR)/unittest | $(BUILD_DIR)/tests/auth $(AUTH_RADDB) $(AUTH_LIBS) build.raddb
+ @echo UNIT-TEST $(notdir $@)
+ @if ! TESTDIR=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/auth/ -i $@.attrs -f $@.attrs -xxx > $@.log 2>&1; then \
+ if ! grep ERROR $< 2>&1 > /dev/null; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo "TESTDIR=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/auth/ -i $@.attrs -f $@.attrs -xxx > $@.log 2>&1"; \
+ exit 1; \
+ fi; \
+ FOUND=$$(grep ^$< $@.log | head -1 | sed 's/:.*//;s/.*\[//;s/\].*//'); \
+ EXPECTED=$$(grep -n ERROR $< | sed 's/:.*//'); \
+ if [ "$$EXPECTED" != "$$FOUND" ]; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo "TESTDIR=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/auth/ -i $@.attrs -f $@.attrs -xxx > $@.log 2>&1"; \
+ exit 1; \
+ fi \
+ fi
+ @touch $@
+
+#
+# Get all of the unit test output files
+#
+TESTS.AUTH_FILES := $(addprefix $(BUILD_DIR)/tests/auth/,$(AUTH_FILES))
+
+#
+# Depend on the output files, and create the directory first.
+#
+tests.auth: $(TESTS.AUTH_FILES)
+
+$(TESTS.AUTH_FILES): $(TESTS.KEYWORDS_FILES)
+
+.PHONY: clean.tests.auth
+clean.tests.auth:
+ @rm -rf $(BUILD_DIR)/tests/auth/
diff --git a/src/tests/auth/chap b/src/tests/auth/chap
new file mode 100644
index 0000000..648546a
--- /dev/null
+++ b/src/tests/auth/chap
@@ -0,0 +1,3 @@
+#
+# Password is already set in radiusd.conf
+#
diff --git a/src/tests/auth/chap.attrs b/src/tests/auth/chap.attrs
new file mode 100644
index 0000000..04df463
--- /dev/null
+++ b/src/tests/auth/chap.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob",
+CHAP-Password := "hello"
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/chap_header b/src/tests/auth/chap_header
new file mode 100644
index 0000000..13c3c9b
--- /dev/null
+++ b/src/tests/auth/chap_header
@@ -0,0 +1,7 @@
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := 'oracle01'
+}
diff --git a/src/tests/auth/chap_header.attrs b/src/tests/auth/chap_header.attrs
new file mode 100644
index 0000000..9f815c7
--- /dev/null
+++ b/src/tests/auth/chap_header.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob"
+CHAP-Password = 'oracle01'
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/digest b/src/tests/auth/digest
new file mode 100644
index 0000000..4858977
--- /dev/null
+++ b/src/tests/auth/digest
@@ -0,0 +1,3 @@
+update control {
+ Cleartext-Password := "zanzibar"
+}
diff --git a/src/tests/auth/digest.attrs b/src/tests/auth/digest.attrs
new file mode 100644
index 0000000..2d32aa0
--- /dev/null
+++ b/src/tests/auth/digest.attrs
@@ -0,0 +1,25 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# 3.5.2
+#
+#
+# In the "users" file: bob Cleartext-Password := "zanzibar"
+#
+# TESTS 1
+#
+User-Name = "bob",
+Digest-Response = "bdbeebb2da6adb6bca02599c2239e192"
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-Algorithm = "MD5",
+Digest-User-Name = "bob",
+Digest-QOP = "auth-int",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
+Digest-Body-Digest = "c1ed018b8ec4a3b170c0921f5b564e48",
+Message-Authenticator = ""
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/md5_password b/src/tests/auth/md5_password
new file mode 100644
index 0000000..4376056
--- /dev/null
+++ b/src/tests/auth/md5_password
@@ -0,0 +1,7 @@
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= ANY
+ Password-With-Header := '{md5}5d41402abc4b2a76b9719d911017c592'
+}
diff --git a/src/tests/auth/md5_password.attrs b/src/tests/auth/md5_password.attrs
new file mode 100644
index 0000000..65b967b
--- /dev/null
+++ b/src/tests/auth/md5_password.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/password_with_header b/src/tests/auth/password_with_header
new file mode 100644
index 0000000..08993ab
--- /dev/null
+++ b/src/tests/auth/password_with_header
@@ -0,0 +1,7 @@
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := '{clear}hello'
+}
diff --git a/src/tests/auth/password_with_header.attrs b/src/tests/auth/password_with_header.attrs
new file mode 100644
index 0000000..65b967b
--- /dev/null
+++ b/src/tests/auth/password_with_header.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/password_without_header b/src/tests/auth/password_without_header
new file mode 100644
index 0000000..6fab6b3
--- /dev/null
+++ b/src/tests/auth/password_without_header
@@ -0,0 +1,7 @@
+#
+# over-ride password set in radiusd.conf
+#
+update control {
+ Cleartext-Password -= 'hello'
+ Password-With-Header := 'hello'
+}
diff --git a/src/tests/auth/password_without_header.attrs b/src/tests/auth/password_without_header.attrs
new file mode 100644
index 0000000..65b967b
--- /dev/null
+++ b/src/tests/auth/password_without_header.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/radiusd.conf b/src/tests/auth/radiusd.conf
new file mode 100644
index 0000000..2d822e7
--- /dev/null
+++ b/src/tests/auth/radiusd.conf
@@ -0,0 +1,50 @@
+#
+# Minimal radiusd.conf for testing keywords
+#
+
+raddb = raddb
+testdir = src/tests/auth
+
+modconfdir = ${raddb}/mods-config
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+modules {
+ $INCLUDE ${raddb}/mods-enabled/always
+
+ $INCLUDE ${raddb}/mods-enabled/pap
+
+ $INCLUDE ${raddb}/mods-enabled/chap
+
+ $INCLUDE ${raddb}/mods-enabled/expr
+
+ $INCLUDE ${raddb}/mods-enabled/digest
+}
+
+server default {
+ authorize {
+ update control {
+ Cleartext-Password := 'hello'
+ }
+
+ #
+ # Include the test file specified by the
+ # KEYWORD environment variable.
+ #
+ $INCLUDE ${testdir}/$ENV{TESTDIR}
+
+ digest
+ chap
+ pap
+ }
+
+ authenticate {
+ digest
+ pap
+ chap
+ }
+}
diff --git a/src/tests/auth/user_password b/src/tests/auth/user_password
new file mode 100644
index 0000000..648546a
--- /dev/null
+++ b/src/tests/auth/user_password
@@ -0,0 +1,3 @@
+#
+# Password is already set in radiusd.conf
+#
diff --git a/src/tests/auth/user_password.attrs b/src/tests/auth/user_password.attrs
new file mode 100644
index 0000000..65b967b
--- /dev/null
+++ b/src/tests/auth/user_password.attrs
@@ -0,0 +1,4 @@
+User-Name = "bob"
+User-Password = "hello"
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/auth/wimax b/src/tests/auth/wimax
new file mode 100644
index 0000000..648546a
--- /dev/null
+++ b/src/tests/auth/wimax
@@ -0,0 +1,3 @@
+#
+# Password is already set in radiusd.conf
+#
diff --git a/src/tests/auth/wimax.attrs b/src/tests/auth/wimax.attrs
new file mode 100644
index 0000000..38ec09a
--- /dev/null
+++ b/src/tests/auth/wimax.attrs
@@ -0,0 +1,30 @@
+#
+# Tests for WiMAX attributes
+#
+# TESTS 1
+#
+User-Name = "bob"
+User-Password = "hello"
+WiMAX-GMT-Timezone-offset = -1
+WiMAX-AAA-Session-Id = 0x01020304
+WiMAX-hHA-IP-MIP4 = 192.0.2.1
+#
+# Manually encoded capability
+#
+WiMAX-Capability = 0x01ff45454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545040301
+#
+# Automatically encoded capability
+#
+WiMAX-Accounting-Capabilities = 2
+WiMAX-Release = "1.0"
+WiMAX-Packet-Data-Flow-Id = 1
+#
+# Long string
+#
+WiMAX-Hotline-Indicator = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxaaaaaaaaaabbbbbbbbbbcccccccccc123"
+WiMAX-Service-Data-Flow-Id = 2
+WiMAX-hHA-IP-MIP4 = 192.0.2.2
+
+
+# and the response
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/bob b/src/tests/bob
new file mode 100644
index 0000000..f9398ad
--- /dev/null
+++ b/src/tests/bob
@@ -0,0 +1,2 @@
+User-Name = "bob"
+User-Password = "bob"
diff --git a/src/tests/comp128-1vectors b/src/tests/comp128-1vectors
new file mode 100644
index 0000000..47178ed
--- /dev/null
+++ b/src/tests/comp128-1vectors
@@ -0,0 +1,1024 @@
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00000000000000000000000000000000,0E9FF8FF24119D2D4ED18C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00102030405060708090A0B0C0D0E0F0,A9D961ADC7633CE8768C4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,C0AED303A34148CBBFA06C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,000102030405060708090A0B0C0D0E0F,5D2A043E67B7C5C7C3356C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC40BAAD8DC6C2ABF2FC5A37199CACFC,69A197C79ECD0880B4FA4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77E0979917EF8AB46623627304D4FDB0,F06210B51F2B2840B5B9BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D4098AE8B464C6EF8CFFDF8091966D32,40CE18CB876EC6E1117EE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A9844D086BDB6F3466520C65C1DED96,1A7D588387F00CA0D16E8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E9AC39114CFAD5DB1AF451CD4925C6B,EDF6CF7142ED0CA258A35400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7DFE76CA758728499049922D9999F3AF,8E5C547A5E075CB7450A7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41BA2412C0A0757F207C76E4BD1C087E,84E634B4AAF7218FCEF62C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47B768859A5C4B74ACCEF8034C05C14D,582002FDFE5A21E5324F3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,649DFCE8376E5D387358EFEB3BC26420,5CB28C9696F57A5DEDE9B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7E1E3DF0017D23C4B7BD6741FFDAE7FB,CC427CDD4FF449DE836D6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4CC4819EE8EBEBB77082003130437D26,D70813EF55034FD892A30400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,184CA804BBF60010DBA18A0CA67A1140,91915ABA811DACDB3C63B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36322EC763D3EF2524FA010827AB4985,DCF8CC8E39D352D893B4F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A6818AC118827B49F0052A00285A264,9B18B467AEE55F507C2F0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F1D98A1E9F7B24A014857A885201C2E,C60C37B6115385CB1B06A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,437DFD43130B6DFE4F966C65CB4FC2FB,71CC9B531B3962E345259400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8EDCB9698F072904907BD54A38EB1BC8,D184E6EEF6CAA297DAC18C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D3FD8F3572797889F67E3A1D514F497F,5709C69BD0E9DDDF548AFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96E4A40675892C8DC56B43A0EC8D01A5,329E4182ECDD71496EA36000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1CE5E775FB44A8E69C20B41FB50EF2D,F8B015A9EE2CD767DF8C1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BCCBF4CF67883B274932C5153F5DBB47,04818B54332E3DB7C425AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D2BE79D308E612C6560DF304DE6714C6,655D7AC7F912EF41A61E6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DBC53E6F3533AB92B40A4475FEC6926D,2AD30CF0D317AC66FBB58C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,914677C71251C24D0817BEE04D62F160,1C6A028C89509ECAD23E0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68184B14C236E1902B8BA7D55A2C4802,08020BC1869B99426317B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB92831C5582DE547C365A1FD0DB10FF,7D4990DAEC7C78F649256C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B9F471D0BF3488E979CA32A9B0CEDAED,9EB85CA06490DCFCF3E81C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57C6A34EE6F4094E45F592F4A2E91A42,74BFF2650C1E7224C50F7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48EB9924EA123F5551D7808033252D0A,BCAABA24B488514B6B64B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E3DA0CCA62877FAE90D46B3D46821B2,5FCF387BAC1F0BB3A32BB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8B169F83205DC67ED400C76EF13CBEE,9590280673C10EB6813D9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,622AFB53FD779E2E5B7BA1948BA6E0ED,A0F227CFB0675C2B7D49C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,928BB857020EDE6A455E4C29CFB2F3F7,A0174B9864C18A544D14A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B4C4273C2AC3B5F736AE5E38E0B3BDD,1DE7570907B7F7D463F57C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F6E444BF0108B3DFC3C345B1753AD4CC,B27188972C9EB3EDED04E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B99D79D041C45ADE9DF566C7E917A45,4F97851A31C0027130527400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A60313DEB989CCE02A1DE3F9F998E3A5,02FDCA64A58DF99A9329B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6FE696DAB580697FBAC3372171B966F,3A1CF01528BF7F62E9858400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B83B757200FBA3F2FC3E716BB17D279B,603E583982951DF901896800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0A72FB3E2F34FEAA42BA088BC65CD1F,F8D4AFDCF0A58ACA2E4FDC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB808D16DF8F0433589205F94E4426DD,6BAD345C95356B42CB012400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EDEA4ED36D797C45ED846631C9BE6689,EF518A2581ED200804BD4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,365648888E5060E74BDF2D0E80808D81,2428AA249B7D99D7E8E3B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F5B73E278E21F78F6905479699B38C7,E842741E2F010248304F4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,27F33379F46FA6B79A8FCB3BE272B203,205D4882650E55576E8F0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D750388464F723D5DF5DC529D3283E4,B63569746D455BC2DD6E7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42DF5BC8EE095DDA5876CE2DA1115F17,D18E9C5D768BA02AC4DE9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,67308B554C4AE8B47E73AE5DBA99E0D5,AFB2548347F7156B2CF51C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AFBDEA2C397126A19123C74CC128D93,6A3A83DDE0F3EC903D0FFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9531239AAA0A92A028928DF2534B5E2F,828CB170F682351F8B12F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B81109133236BB1766F9382C5079AEBC,0E8B6C96AB146429DA0BB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9585D18C8B51865F34D993EDDCFD060C,7FB814F9D11A71889F98B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99C2ED37A50F4BFA55C3337F3423B2F7,E5D6C5185D36E3580F65A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B848670F782B3D6E602227DD5AA2CECA,98665AAEFC034B3CBD0E0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,065D815DFFC12FE9AFDFFF9C18D7B2CD,E75104250C17A09B49251800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC66ABA966FC847CDA806849A3756894,382DA8392ED16008E4955C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F055F2334857BE9BEF0CC91D951A15E7,CE55A765C01AD634C84E0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5EECBC15306DD047FB81D93C56E494C5,32BE31BE3BBC2B65D153C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22DF1FCE06AE53574265BCF27457D19C,071F37C9E6292165A838F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13285484F075311FAB14A161428780D5,4559832C31EF85E69D274000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,147AC147195A638DA3AC6943747B13F0,3BE416AF4EBDED1E394D6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0176166D0B478308D40672FD319EDBC7,D169CF01446B750BE3BBF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B87C0832954FA9FB0B2D4D3E598D65D6,B2FACF9EDA52A08F728C1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39C3780BD8C80162F501F9FB054EDEB2,E5CC8C96ED0A128174097C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,93917101570BA3BA1BFA7DBCD69E6C1D,8908AC2FCCB8A07513E51C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8B260CE5C93997B3C2F25E2357248C7,7348E29D60AD1D96F6EE5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DE59942143B23D07D4557F84E3E3963,36E03DE0B4586214299F6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,43817BC21197B07CD1D3EABEB9A07DBA,680D0BBB17CAE8529813FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BEDA13A0BD90BEA122F2C418C1321062,5003676AABA367BE767B3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,92F3B8C11949E0815CD9DC672A47DE91,08F7BA4E3080B206068A3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D03B447FAA0861B9E5E118BEC2073D9C,2710726FA8FF6A3803037800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B89A9B8EB7FBCD86B3FBD1F2B86F2B2,63D988615E9112BE8D7CE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5EB9756CC95B90A03C43758C1401900C,D76784339661137160199C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E187CA6B643251ECB4F10DEA1F767E3,5E173C4AC2408481D90BB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,80D04BCDB7CBCEC3115537FE85145328,F1EB7D9BA62D4895E9983800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A4698EC2A871ED36053E56308D71798,FAF015C6DDE2A1826A0EC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,667CBB8B0F868872637EBED8C6E289F4,678198B9179DE9AB98A2EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C689482AF142439B75A91B7165ECC4C,37D8DB63C76B7B2C8E3FEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B07A66BAE751E06884F791303CD9FD69,9EC1BCE089388D8FC00DCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7BEE476315DEE169046A713073338CC,42EAFBD4BAF6C0ED5EA0F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18DBC0A8B049C880EA48D146A62AD0E8,69C445AF5EA400BFD64E3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B461A2898079028CFB527520217BA0D,12179D15353140E1810DAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47FE5DBECDE438E5298248B5704420A7,3F1774546CDC1569AFBF7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3634B628DE0287DCB87B21C8084DF43C,345F6EFA1C457B7C56037C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71DB88176E8890CD6E0493424A00FA8C,01079AC45A0D984972BAEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,073FCFBFFACA47395734C54C8C476E11,218323C292CAC44089A44800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,19645F973B4B29F0228CB4427E65D894,C321F36C0A3A563A6ED89000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,83563B002DA2721008A75CFDDF36D82C,6DF9FBB17FC44848D1696800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D6DA0BD7178D13E9FCEF132E9AAE39B,F91E3DD46BFDC0C801DBC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C50C2C1352905704F2CA4DF172DA003D,E275EE5E9C189FDC4805B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DFD1188C409EAB1CF875A2DAB46F003A,30ED76B8B8D98FFC73D2B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA249F66D539B76CFF6A10A38B98C9B3,E76C07BA833CDB9981010000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41164FCCFF44634967586B797EA6487E,75F98006562C775397BDC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,161305517807E4A4ABBEF8FBB3044C15,F393E6417AA099E7821C4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A43220311334360FD5DF3E5A8CBE057,CAD7D1AABA924B87FE447C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,188FD0FEA7A740DD5E7D60CB433D853E,BDD09A5FE431237C31A90000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,649FEB547DA8C8969EB42BB4EFE33378,6FC2615D7A22A2E896B5C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE5391FC6660ED178EE077AC2B6BC1F7,CBAB6F451612429F260F4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD0D3721DDCB2BE59FBAACC278F920CF,EDBC9EC4A4FDA07F6FCBB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49945330B249F1EC10F00E11D314350F,8E67AE3A3554310A3C8CD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B47155CD8AD25E5D2F004EFEA0F72E70,5D669582C339BA9D32B60000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3F6FD204AD680436733AF549D5313196,0DFEA155575A9C8CA4F57000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,09B3BE30B7ECF8481BF7AB7D28FC1BD2,124A222E0C6C4C3A9C282400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,04D11DB975883C574DBD7774DAB904C4,E243465E4022DDE576021800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA8C7850F0308A1D2650CDE5B29C1B66,AF3CCBFC787056562D522C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8EB99DBBE8520EF4A86988E9B933143,55A7FAFAF4D8E539E4115000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD0658FBFA69E77F373BA04E79619E58,0DC5FA323C84A04CF0BA6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7652A528236DDA50C8D82737EB9B90E3,2E3F7C8CE1AFCA609B62D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8170037C74AE45C24EC09E41B4D2464F,55C9EC14FD56BFAC16A05000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84FE114A18B4BDAC82DA6F5BA2DADE4F,3B33A37444DBB76D805C9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,09D893A12772B3F9455514E3A50BB905,8575EC3C79BEA7A753DEF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6194277687F3F79E9E48614ADA0DFB7,05F2CFF1A0DEB7D166C26400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8E52FA06585D1CE6BC29E6F9483A622,489E29F51F79A2DC2EA46800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B4A722DA80ED01444A003039A9197FA,84AF1D967FAE2F7F34677400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,276AE82AF0EC1F9478FBB68B457E1DA6,88D6EBBAB9E8C84B55BFD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CBD2A4CE843B952FFD80E3C9F21034C0,79CE4C2DA0045CF7D1C23400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99F284D22F72F788D3F4129746503A3D,AF91784EEE542A871995A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FAD8B5FD7B889C3F36A267400DBFB131,91165950063D39DDEA796000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E9707B9D713F062DD2AF8FCE011CEFCE,7CE7B9040D0B5954274C5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1A8ACBAF0DECF6813478CFFEF342408,CF8DC0AC814C2AAAD477B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1ED877F777C197F60E55318211897293,E449AD57A0C77F2D35B53C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,28EE90BB4F37F5D300B1E5BCB89B4FDE,C7D81EF8E8DC7DDE34E1D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B57B9568F799BD75BEAB79DAD833265,F8AC59252E4AB1F469225000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EB34FE1C38595A82888A4753ADE0FD80,FAE3BAB54718A74E5A6E4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2F1C922230840AB370211FB4C6CDE27,AF432068508846BB05B35000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EB2BF57BB399741608E33CA070818E1,FE95822EB8561B5F9DC8D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A91138BD3801BE38A8E18B470D1FAF0B,D20AA5C2450BA956C4196000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,555871767F65C440A556F01171F43E8A,BF13C406EB3E0D21470D6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9710002398B71C7F19480141835DB207,1428A58AD5BE14D21843E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5D49EF6EF84356623664E7A5A44B289,081D6A1378B3BE718B569000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E74D2CFB728666A8DE0152D6F5F1767,2A496945D2EA8F5C6FCEEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8FF3FEE077290D92A82850F7442365FE,8DA7B3E1D781E85F9D7A9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E9E877BA791A4AF7365E3AFF4AA0DE8,CF8517FA1B5269E553942800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0EC139E142A3B9CFBD610B1E0BB00ED2,3BB88451DA999BDABCFC9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EAD301F96A4F0D354E3C5CC836C1039,D113F34A1A13B74AB6AA3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5636CAF8C382546DAA5780FDAD296800,2E377EC555884D9AD7CE8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2476AC17FD5332046CF0BBC80FFAA766,E215C786E939C5A3F4D21000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EF96A0306FFD72A0B0869E4E5ED0A4A1,615631AE931D404E3BF93400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C09D609EDF571B1863505C5D65D26CA9,D54DF4BDA4AAE73CA7BFF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1A8C6545EBB37EAFF6CFCA054AC1EAC,19D432959633D7CD4ED93400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26E334FEFD60E9C5BFE2204CC8CB01EC,891CE41D1B8280F6973B9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5808E12CB8BBB95FE7D47B1CEA43AC72,7D801C0E0A2B66139B044800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EF8D125A481566594E34D8532DF416C7,30DBCC499221A8A6E871E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7483D4EABCE5DEC707E177A81EF1F1A6,84C07BE8412B33B2C19F4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C9288F1597B409FE379A218E21297777,D4B3E78C08453CFE9C000000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8303FAD2A86DF3FE7F68E79CF18E5B7B,2BC30881291A723EFF5A0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EB96D3BCED1CABB35F8566323B9E7124,C637E2FF86FEE93BCEAD1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AE59A69F2808EE1B4211E1E77BDB654,8E518878B361082CF1267400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,948E3231F2AEBCD5D70DBC8CEC2FA000,A74C0FCCDD15F545FF44E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,213F6E332F2E74B6CFF792718713F6E5,F0AC582F9F1E81CAF2F11800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,822D13B3EEE04CBC9C59A19FC077BF4C,B661ECA5719465CBCB14D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22D07AF183C33D9A7EEAB36211F853B1,60843547E8A027A1943F7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A30220376D80D728F3A5DEAC5C1D8C3,0C68D00D0A8D848A76517000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C9EEAD19FCC2767BAE7FC689E152E9A,30164343516A0A6CCFFB4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5682E9663D37F80532742F0D895D9E3,C82518A5F8D502FB3397FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,296BF0D43CA901E0AAD35B518C00084D,3C6F4B6F7921281C6EF9C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE11EAF7E8E14A71DCC31ED072BC111A,2300B5EB4368C09530D03C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,897A26D60B5F3C924C973CFD92099792,07BFB9AD600A6F1D5D26A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0EB7E92C28C07453711C712208EA590,A3717B4C776007A446D9D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81023ABDE598612DE71519D2B9C63A24,4602A9ED205DD7A2ECD32800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F3E8BD8CBF53F016EE4EB00AE83D4920,E7A2D4E1CA7C49956A3C9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26F7C827FDCC3176E87F119834D4B53B,95A75369165D6286763B9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,704098ED590876D47D7FB9819B4AF98A,7F066B8959754DAA571CD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBE7CC6254B8122112C6CB0FDE8C364A,28334373ED0F1853843AB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03904F78B55EAD92BF5DC50BC1A9F39D,3BB4CA0F29FB0672A9784C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F459EADEE2D0EB4A55E0C36308A63AF2,43FF3300C374CBAAD8028000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52AF9DB388B23F6FA74356A29BF4B732,9FC8199C5F8EB4D758360000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D855AD7AFDD44ABD84585C3864ECA1C1,9069CDE31AD036C790295400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AA660FD307D56EE038043DCB9929E6F9,EA388366D578EDB605EC4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0E54AE3FE4444AACE332DAC7A929C9C,221230927E0AE42C7B42B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8BE801918B64B94116AD7AA68195C3B2,BB5B34E1D9947779D8E09400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B612A5F7CB7CB5D0E99BB2EDDCFE548B,812EDCC8B038D73F2B542800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,786983EB5AE4433D69F095AD831FF114,C26CB10613A8AA8251133400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,099E770F15C696CFDF524D664D72DA0F,F8709AADD870573D692B7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF5AC99C606C009909E53CC35A189B45,5E892BCED45CA3567FF31C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06099CD46C22639D0772FFB31EFF23C5,8DB982A8C70F838BEAB80C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBA047D917B57C94A9672AB0DF38E61D,B9B06F0BAAECC986306FFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,411665C7BF534CA2A0C7D5E9D7226496,38AD2C60F63D797726948400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0618B2AB97CA8B35E4BBE86B0E4117F7,503A8A7A498BDA8DB57B0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72C36F2A86A3CE233D2069460A461E1B,2E5727AC9EC2268F6A91C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8282380BBCEF8A400CC57664464ABFBE,17F5613CFA97F0809867A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,047045DBCEDE8DB595EBE7B49BD2CC22,5F7F207639DF0513F7BBC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B320FD047FA0D10C12EE410060A36BC,FB9FD72243690ABB840E7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB2CFBC1F0A6306895C40E5ABBD5FC4E,5BBFBF1700E67071610B5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B540AAB41A2605210F8692B84A6056E7,EA7D118636B1AEDC88555400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33338E1F721FD08B28221864346672DD,55C519E2884947DBF7CADC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B1227506EE577601CAE6FDB8560C3714,BA2C2B744DB37954C2A27400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD68B66CD27F228827E1D81D1BD18965,3C209AAAAEA085BF8D89C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8618DE016FAEA99C3B4EDA224F92F008,52A92A58FC80FA4C238D8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0B136695B67AC610D884B10EA0FA91D,B959070045CD802F504A3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6BD4F77DFF589FBDBDCBD709C0722EB5,F05861F9688B9B437CD38C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CCEA499C750A2BE5D572497AE3C42B45,FD8072A32652BB6624D39C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21086C88705EB412DD348CAAF3E9477B,D3C78ECD5D669D924B7FBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,955EFEE1D729A8E8A81B65456B60ECE1,A4A5FEA37064F0E7A9EE3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49CE6392F5F7E42B8778A385542CE9BA,E5C0197447F7A380C194D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D59A64A00283C3D684446BBD5203ED77,0E20987E3D59D24D96B13C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9EC7CB569F8F822308EFC4F9667058A0,7AA573410D4CE7805A971400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,631184C7DFE39F17501100987EBEEEB3,7E0435EFA49196BDD162EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5DB2A97EA52772F4FBE6EBFF6B0BA41F,027DF7FE2157C137C966B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E070F316F73D196F56FEB995DE1B112,660065D8EBD54B7B86849C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48342C9F13562F518F2A69E426201EF0,18876000621EECAD97DF8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D447EF42099C09F389049A87F9F8820,C92920E59F351664F7C79000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5612ECBE66133D8EF8AD9B85C9DF9F89,4268B479FF738DF714F64C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4479D5694B9AED0F44AA36ECC4B70D34,6F2467A3B64CAE1E89625C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A85CAA9B29F28BCA024D16AFF481012C,BC18CD6B0CAC773A0CCD5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2D8EE169F13CE527C75833395926474,360AC1DA86A569FD1C4CB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9367387612A62FC0DADDEACA88946938,99078BAAE7D907DBE29B6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,12374AF4213D4B18BAFFF164B3FD93AF,E12A21A0C882F6C8B12AD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7777D20DA4C2805FB672F2E7B6BD70DF,C6BBBC2EDC99EC77C2FA8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF87B8268C91C2D0CA99B6A73DE942DF,858C22D7D549ADB1BC060C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D880189E1CD7D91A77165BBBFE752828,671E94443799AB38DBDA1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2525084E0E318561A42F4E983B920E6,D430AE973C352DB68640A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FB997C519995347B1A6125330A90BF5F,089C7083E5ECFAD7DAA11400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B182E694FDF17FD7CFC726DE1AAA80B1,18683615DCACDC4B79D44400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1553F3A28DD03B4DEB84ABD9D0A3F2B,DD91A1D1C71FEAD0A2595C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,38DDCC7056DF77C9EEF380A723A8AD83,DADCEC05DC82CDD74BE91C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF6CDCC3D89ECC0475F759622B328F57,C0F75E2253F6774EB8425000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0735EB4A365CF9B00BB85DA566021059,C1DE8D6497EAB4A2CF7AF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C93FE9E30F98903DE52C0581032FACD,0B3BDCB34E07641B36985800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCB9D086B0E46508D0C1FE2E1AD6623D,212B147796DD9E304F8C1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ADA34F00A2A985B0744DA24E138A6AD6,3D77D6C13B6738C782B3E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DF71DE337AE2787FA6AFC405FA58D434,7372CF2B02715B600EFD8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2F4DACA111B16ADA44323552A973563,12DE30EDE1D36C67FCAE5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9247F0B48A4D5194113F964C07DD831B,76565FCA75F3A1B064419C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39A8CC4F8255046F206D767C8117B9BF,E219AAE9DAD7B37E7EDE0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A4FB62150860AE93943C6359E4B4C2E7,7C0C164480A44A4DD7DD5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA98B46B10F9259B2774613CFEBBF7BA,C7336D60F25BC80A9A54AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6134D5747E08C4197AA825C67CD09A64,37BAF4A3E83A2A615592F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02B67B24FB4855F490F119A8ED4BDCEC,E95290ADEC013547BAA66800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C028EBBFE824D1FB9B093B86EB051A08,4626EDA51BAED0AC9532E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B98956E8C4FC8FF2230F41089B9B55E4,E6AF4B55C6DA8C40DDFCE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1759F0517314526EF0F084155E9D24D6,F88275D77D48785075CE2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,818F3F03006190218122A2A29BE76EA1,872820D68AC8C488B87A3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82C39BDD7EF771B9945D7B398517DE0D,C90CC93C31F8AB01ABB09800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA539F773D7AD125AEAFB99FE0D2741D,F00769FE8F4B138DF5C9A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71424D509E2E622EDFD3996BCB518F35,72BADB1920B5920CD44C4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,69C294ADF010BB06EFA05E2F54310F1F,B29B249C2EC8BBCF01B22400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,08558A4D279984C75B9553DC9E3D2556,B94A6CE01E9844AAF61F7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F8FDF96D481A9BDE05A2FDEC2A321E5,187358184836E42DF6ADEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4363F070C9252D5A07683432F3970E9E,4853CF0C1D4AE424F6F9DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36090CAC4DC5B58EFB5A1FFAFEEC48D3,551213305EF13C71137C2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,111DA689819D635FE3A658460AE136A4,28A3D5EF7A99071D0949B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB283743E81082E8134E3E537873DA82,698447E19E464D548BECB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23F2C78A3DB7C54022B827BBEB2FDEDD,3D4FCE9E534CF42AB3C1BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0DFC63065CDD59FF97BDB43DDCE9967,4471E003AE9D6F331416A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87ED4CCC8B6E94684953184537CC1A52,26E9D421C1A8F6687A1C1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D39173448EDFA2F4F1C4E59587BB263E,FFE059647FF0C8699A791800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30EE2A8D2E7AF20C1B9826E774FB16E1,E4B6BDE3F842E79C6A41E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F16A4867C3316CF0A9C09FD50C5ACF71,E52581AAFEAF943A7E130400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0610D1FD0164D1352338E0FEA351E2CB,8D7E4DB5CA64B590F446B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EECC5EDAC58AA8CF020D2D83D86E38E8,CFE185A93812CC2A08F73400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CED8E1CD712F4760587335F5FF164ED8,23112CD5BFF1558A17C90C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61EB7F4DD16AAB1D27D7B12728ECFF09,359617BC1B8612B341AA5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5FE10BCADA993532EA7AB1238B6B0ACD,78257D016158BA82CDDE3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D5940C92AAB7BB89E8BEEFCEF34FAD63,E3D6758A0178F38E72BB9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BEA9E235C5B7ECE309E3CAE8AF151BD,5BA81B9D417CDA46946CA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DAAFB30B99E309579A38227B16FE5C0F,5328067F6C6210A43E411000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C81434FEE82C124912D2F5F4A0022D7,7AA28F178B99D93C668AD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F57CC7A65EB4369E0D457C8F79CA4114,6F8EEF679DF8DDD24D2A2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,790C8BB19A93A4EDDFCEFF96EB1DA357,57ADBE7CB987956666326000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03B2E33A8396ACC7EEACC882AED71E7A,98FC326CA7FC657BB131E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C0975C6BF224A734047B28185528D2F,61AB5628359F92BA7AB09C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,873C693B10236468C4A142074911F111,6C7AD95B726CD0C902C3AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF8DDD2F2634A51D08FDF6F90107BD04,97F17A2D7349E3B872B57800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7E8BF02547F38C95643897D5D575F6B9,7BF6276405AE0317D23D5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A2BAEB93E90D9313E794BC106853294,A517B8E019812C7F42EC4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A29A413D8420CFE4A0399946FAA6D1F4,BA1614FEF80C9A567C6C6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB8DBD4022734A5BB00E50F7A86F9568,231874E4F79C03FB60AE1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B94FD66004111947B6FC02E70F82F5B0,961014A6B1EEC0750EF6BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8E33AA731F8B530E2CB6B4B6DED38D9,1425EBA776ABD3C6C4688000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A1C4F081597FC7A88E3461DC643F9AE,2C56ECBDF4360ADC9BA4E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CFA44ECF817B55295E8F60FDA3D5912,624C50C6536EE49D6C3A4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,298A9667CB620C32BFFE8F70D0350363,99AFF69080619D9DBDE1C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,65BE0781E67A46F434EA21F6F38E4E0E,E0D3D6849A17D52D9F497400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68F24E0C77777E7D39CD542BDAA5EDC1,7CB1BFC29BE8E273AA8C7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6069C7334582DA4C3273E0ADCAE8E480,975DB219B89280E427B87C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8DA7AFD6C226AA61055384D3B2BE7E87,5A3603B2E209E6C34F8CB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8E8D9D3622A34DEA88BA8D6E7F81C401,B13A3E6AC4CB0D5CEEEFD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,542024F443086C123567A12E681B4BC2,E0E35FDC94F0A066C77B4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72F63EB6B53171079F98C1A3F6417ECD,6D4932E9FC8C2CCC80674C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C699BAA060ABA8086ED2582138F25A1A,7742C66D4B3FC700623A3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC1A5E8A32566A560777CAA60EA4DAE0,05572877BF34525CA402A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,630E0A65FD189DDE95CE1C5BEA7B79E4,222256AEA87BC488CEBE3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FB0F5F6B96A2CD1C6314BEFD33E3461,7D6641842923CFB68BA25C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A30BECB3742AFF6EF82D4864DA6DA432,6EDFE93F5BF4A8BE7520F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68C392DFEB34243DC45CA5112C7B1E3F,231D86C30824AA03A6B94C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C1B3CB650742498D73CB633F1BC1EACF,D54AAC27C4D26C05487E4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6326E055E883D4BAE9AA4C2C150255EF,3F71A7EE677099AE6EB32400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81AFF35D10DD0122DDD8A08A0A173EFA,E68AF50EBE86863868EFFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A39F138FE330BFBCB7E6A9B67D00C7DF,FEBCE30B861BDD29C095B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A0E15800C2086E341BD9BE00770F860,BB46EAEF62348E952A3AF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D05D0C0DC0A8D3D128D6E18EB5C0A3DF,F96E8E1EDA080CA1A7D61800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F5F056A9041BD41A00F0E7CEFB4A612,B7557C98F0DA32E59CCAD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3747E9BCE992A392460CEB6F01BFA975,8A1DD67538586E7FD411B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF92F06EC27968491D4EB46DC83FF644,5C4DB60C5A3E1BCFF6C6FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,765AC73AD7834792BF3A18A56D51932B,5652F0557D4F4C5F33305800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0FB2D27F274247E88666E03048739FA,7BE3F59F5A14AF8E25EAE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6358FD3EC378FE155594E8CB85CF4D6,2C216B03B8EE640B7827A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B06649CAC926D9F0E2308D70115AE1C6,288BE7C8D092A199D71C2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76274A06460DBF5E2E4646BB9816B44F,3DC7F6DAB19EF29B7EDFC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BED6BB15E97F9E777836EEE92E8FBAB8,E4DE3040F51A034DB42A5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F2AC88BCD5192DD8871223FA5D002C7,29D9A9F1C7CD8DA75DDCE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BEBB8AD82610C4962604967718C6E4C,095B0A65995FDB444FA51400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B22BD1AB07FD4DF3EA6C94D421B2BDC0,77969D457D8B3B324C447800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E75844E4BCC1465B38BCDB854FE147B,F7D399019EC2855DDBB6AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F02E5CEAEE0745683A75DE33E9E79BE8,2DAAD1213DCBFF4241F23000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1ADE7A15E36B2271E618E35824003BCE,72168E07C397F5631FD42800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07A2681347106106A1D416C3EB20B79C,6E11DD36D3BCE4CA2ACAEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36EBA429004EB96ABBE0F14572446AD2,A996965C2361869954C62800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA5B91005468214844E0E2A7F5B7AAD4,0A5AB72D7605640AD277D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC2315A4749E01A924721216F803977F,5D4852D8A3E7DACB583C2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C03E17FD332001D28D394F1B40D3546D,939968E673F5AC7A1F78B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6FA3F958542A795C72CBBBC3FD334F01,C4E3E994D191899E0024CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7ACAB3D0CC89E5679B6C745ACD3D1822,4B7507876A82AE89250F5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41BD9F89D46496A85F8D2855B0313844,96AADFCDB942515831CE7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,885714B0574F319A71948831C90B0889,16463275ED381B8B033CB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBEC83CF9D10C6BD5FD6AB6931C2DF44,26C14B7EC005AEB83BD2D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F602DAAF79101BE2838642065DAE18A,3D828E60798F6877A6CD0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD9BD8C74457B15617063D6525ECB6AB,B42DF8D97E39F4609E822800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,479C04ADF27FE0B28B760375F86A3100,FF284A00A7053BF526170000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1836CA02DB03EF6163874415520C636,C669AA3EEBB3E76833A46000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CF4B6B1905F2B4B2A24DEAF39DE2D96,357AAEE48666AAB9E6389000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8DCCB8D29BCB3E1F6C0019D491DAFFF6,4160CE94AB7D912F9AF6C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A15AE2663BBAFDF1F969BDE8C84D3BBB,A59DB40FD499792BEBBCD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,892C6E166C6D11FE1C42D20F86404A0E,9D0B328B83BEF9F874968000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31C3BBE4B06E87C231E5F734111CC661,50EB14E7F07852431D608800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A6B48C7070F1E64881B61A4B6EF9F8F,99F1EDF56EB873C810914400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A2930F6688CDD9D37849C3B2B0856E7,B8BABF3B94E49B426DF6C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF0AB32F219D7ABD3BA7ED5C1FBAB869,BC4460DFC7C6C98DB6F4D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40A2055D8738BDDE940503885D11EDA6,8F7B813DAE73B8D7A0DA3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D4213EE3E46820B1E7808B782EFF1E6B,8492C81C1E616AE5AF699400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1EBAC09FD03B944E405A2767CC52271B,F23A7C4E82532EF97161FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A199A02D1A11E43FA042185253F7DAA2,799C343425A9AB9D10698800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8EFFF1BF4695138FA35857ACE9287997,C9C4CEEEDF47434881201000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC4E4B603D4682CC8FA804E6AAD65CCD,AFBC13D658BA6B0993C5D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E026413D8A32FEFD5F3CB77AD74CBBB3,507DDC432EF1DFCD95713C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B73F664DA00B2D1D3946F3A58AB1D93,C6A1E344E333AF7EE0211000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E867FFF55682259400BCBCAF3ADB8CE8,E29A1CA488DE57D02B4E9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3242CD109B2DE38BC582FEB1E5E2BBD6,CFAA6F0ADE0A1496D250A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B755D3ACE3B389010CCAB8310738E084,E77BFA25EC55F9F35B67D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8714E5D1CEB605098C3DC3DC5D01D69C,C710A159C4BE312E6DD12400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A23264F26EB6D899265E6B21B40D849,87F1114B6C50427E40AFB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B124EE3F6D923E6A4E1580953FB773C,8C97D67E177C4C1011A94400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B31AC9479956A491400AE50E2682C238,DF553F80727F1888DAECBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1909431199EE7A44296DD7C68431ED2D,BF839D489ACD726E0C964C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9401C211D054F35300A80EF9A0DE775,C86CCEF18CB393E2D1080800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E57000D7D7FCE91D84D803C14A9EA9B6,1F818D301438528E44689C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CAB835272DFD4259DD6E5AA0FFB7CFC,014A371AF4C12A534463E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B013CB4FC14DFA049B76C6E1C1F35A9,F75C8E77A029F715ACBC7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E11FEE1A070A1E8887BD8652E924070,B3E80ACB16B415D3A4B27400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5035CD99EE98F84839DCDFEAA3FF60A2,2A30B018C91925824A033400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,869559F9E084CB43FD29BA04010DF774,1B80A1592103CCE0333ADC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26B1EA7E2650A73F28FC35A403635466,FA9A9E1A2B5A90C4B7295400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CBE67FCDF468291A9907193F0897F265,C03CBAFCEE43CC200658F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0348D66B461D5BCE79B46A373453DD3A,CCBE7E66D7ACAEF1F0B55000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,518AA0D4085C9847707500B24197B6A8,F7DB9D47F3BD3C60FB397C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50AC5F40DE8259EEFA2F50AC1DAABDFB,96932C47CC67DE1623967400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,552FB592DF830F4888CDA466B2A927C0,C2C1D6D4E18C0DC604EFE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2BB10A14F5BE16D7D7F2E947AF4333F,5BA229B1795B0A123AD22800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9233F9C1736AEBC3C174E515EAE36107,7C82371F4F6EC44152366000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4AD6C86685F605B99ECFAD1D55D0535F,DC34A617B98D52B318C35800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,449916D9A1DA7E291F48B07452064593,D12D11519E617795BE2DC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77605ACD7148D2C3636D6A782300FB95,9239B6F7AD0468E1B8B5B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F740355FDDFCEBDA6E3535D8A219D3FA,B049B7550A441FE345347C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C1A813B24BA270D433EFE9A6EC935C70,1C7759BBA563FA66C4D9B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0D475FA3BA4CBC732151AF1C1AB55954,A34BBEB09F64827B927AD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DBFB33671579E69C54CC90741ADAE794,5940EF1C4B8020F4A5DE9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,434B3CF7B020D9EE6E5829B87C15F776,9342353443059BC7BBB0C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40F2E0CAF7F693DDD605AE21E629A99C,8E8CE97A05F4E936330ED400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C863F8254231D458116A0E78DE82DCD5,2F78C563E6AB4474A470E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89BA7605A3B7A8CB0B60A93F00926F9F,BD73B0C1FD24DA1D9A78EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B40A3534EFF09BBB4E1674F6CD686583,A489F380A749D2C99CEF2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE6ABB547A80164584F19BB81D5B5985,736995CE7725C99F4A55CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,744255C89986091DF9223DF6BDA31F13,DAB16E6FC8908F2B10652000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E106C07F8AD119AA4EA7D2A0D9C22C30,4C9403ACDA17A0733AD70000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5398CCED5DD6A335D8AC924A730701E5,D54A777CBCB2F42E2E480400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA4BCAA8D9D13A04D89CCE7D5E80C0D9,DAD82F5062584E29E09B9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C1164BAE09775E74A1D6499ADB2259FE,103058A5996C13EB573A8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E0D3228E5A7CB033F32FA785F9EE6B18,E1795497A53A2DF98F7E1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BDD19B8096384D186B36151FF21F5365,0318AD041D484894D6372C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A08B3C2D17E0606A49034974C336EEEF,0EB0D91837B25881C95E0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B8E4E36C3742615D63F2E397146EB73,891FCCCAA5CC9BFC8E927800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E818C06F8F7B2E6F6B32304EB477822B,64F16D8259A5AC6A43CEE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7109C9D5C62A64D58ECF6FD23C6B0340,85237EE4D438354692EE0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,592E8CFC156A61778B3D0E4240849EE9,0D29A236335E8AA9B622BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEE768188A1318CE04D91AC8B8FF8862,EA9AC41E17F1F5DDE88A3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A0A0B1F35EF34520D86E09BA894A677,F4D8AC77FB3C4859A2BF5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A668C8A9B94DBF27340937095C3E759,1427C39FD52D1949BB485000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57E730905D26E9617981474A51BA9D8B,49276A2EC63351B7CDD3AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B361D566F88DA2B6B75F18B5032A696,1A6158CDBC7A79FB57FE2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16E07D0C1B67B176BA2FE4EAB0BEA590,3EB4FB87472864E8F8EF7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84E31AB35D3D2B79657E4A604E1CB1B4,8D0C3E2DFC864A897876C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3F8242FE1750D3C6546F1FA9B8C70E7,FE202F834DAB7D1B91190000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5AE8532AC676006FC919E9AF6355D00C,9516F98C444443E655352400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9509E7B74D2D49F1BC88DC311AB55C0,925551FEFFB8C4127047F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3E113DF2F79D6E7199B6E323C27AC27,3B1BAF967BA8A79303E20800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F80302F5E2E3490E5BF6B14C2A82FFB,E943F301AF257E7A2265A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E255DA8EE7EAC5C8F469905644166A0,23A53176B4E0115360D1C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,870B59B5A8AD858BD9E8AF222EC2B2BE,5BB9AD7462713852484CF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,46D2662F936324893426FE52C96052B2,BE34A735E3A557C17F330400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7822EC77044045B9A19DB793D3F50E6D,2B42F40E208FC3E700DF8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E7C6102BE479FAB7135005749582556F,1998B5A4F8BE6BF7FDE1F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1E6F6BB3A7F3511E13E28C70B31F30A,2DE010A3EB3E12E8635A0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4226FB50B2205E8E1B0FCE9C5FCF9F87,454537140131FB1AECE00000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14DAE2893E5DEE46E9BC32420487D083,64404B7FB3839466C65D0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82B85B0C3EC123A5CE60F2E0A293DF44,2F8CB911404FCB5A50742800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49BDA1CB7DFA102F46514A381A002570,5524C9FB7F55FBD4D6330000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,56FD653DD3708EE5EFF295FA2F206CE2,EE127E16883B3E65F4A4A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F98A948E3FCE5E5409ECB724C7507199,3ACF16C679FAE5B121CD8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ECCA2D5D97C4A7B908512664ABBC579F,B4E22BE1BE385B4B1307AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5BE7160B02F0CA8C20B887663ED0F605,C7EFF71D2B44CB10E9428C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D74AD239D11A06F9591E366D7C15937F,D60F219AA40D44F4C55AA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE536AA01092A82012ECA3A22007D478,431696D2FFE08EECB4D9A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD465A20768B32011D00DDD5B4C86B5A,1447818D2AD72F9B6A018800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,731A3E85A3EAF95E4EE205BE06209162,50F499B6DBD107D582C67000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B6EC21FE5E59EE3203813614A753FCD,BACAA7FE68367944264D2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5E1699FF99C2263D352ED394D9E61B5,1BFB5EB2D1037F5EB9E95400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,085036B1587164DDDB7A15D38B3B7727,4E739226C3528DE3DAC0BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B3295F3945CD4E3A5A07610986B0E7C7,C4EF694963D801AA40671400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2518F37AC7124F41562A52D6D7ABB113,B8EDE2D5CBF8ACCF1342C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91050DF8DCB43D2659CDC70E78D13E5A,C290CD4978BD1267093B2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7C18666F49FF1075E46EFFEACA9FFDD,E9499E7F110771B569054C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DEF71CC9437573D166764D7F9E216EA9,B83E9B48194B43DB7937A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C923CD7AD3DAD1BB3FF5B376978F622C,77F2AD8926487A80D785C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,078DFA9BF3697BA52C5FE0AB29CF31D3,757AEF05130E3548AE8DE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA750184CBF8ACE84A5A3DD63FB0E820,68C4EAD165D5FAE44A9EB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C1AEB6C1322903EE5EC13F935EC95F8,996700760C40CE6BA6164C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF096BA843214BA16011A3B4D45C4F5A,1FD24181BA1DECF441218C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A82812F0BEEC054FA2809FAC0F64B570,ECCD419B3BDCE8E9F6A50000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,539D30EFEA7B949821334B87BBCA78A9,48B4D30B1EF623792801D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4AFFE94260AC58BB1DA39998D2451A0B,880E8243A6FB4F3C9547FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8104D4FA54F766E2C84E7D381F9100E5,7D5600114B1506CD0B1BA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A4A97705548D19BEF2C0842A42C60A0,8593038543A80B0AFC790000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26ABBA139E866BD2CE6BFFB197E8C0D0,C5CEB7378AEF12A1D6A41800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AB0AA185E7ECF37CCB2C6EF04DB4F3C,EA1B76E9B763C4256E21DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DF812538FCE077057224B85ABDAD113,08D89B0B14CD51A459E1B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9B7D016441230D11217ADC999873DD9,59603D45E3C8F77D79CD4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A2366A935C097B272914A05299D9793,722126643278038F1B1E5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,64CDF5C0CD70F5B72E8A246709DD8FD9,78829F65E09A51EC92B6C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0D3CD841D24FC1698A20337D11448AE8,36DC921D1FDD637EBFA03400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D44B55312926BF14D6AA11AA07EEAAEE,CC4E2F51987ACC47A9FA3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E9051EC096D4595B5EA72AA10CB050D,268B8F75749FE37776341000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,043C11E52AC74B30B09DA3172839DCCE,FFA615AE41A2B10416992000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39717B75F15055CD964DDC49108E0DE7,271D6737E21890510DE9E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D66BD55543E7560F9ADC1D28859D457,7060CC2D162CC9BA481A2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,839A1A33E3D416E138B235A294ABB86E,C2B784275267037A60FFEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,67A9C7F1E4D2CBA5AE5B42A1FF81F49C,E774EC8A7227015D2F1E5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,46C4533742AA6CE9BA0262E932891758,D67AA5488DDE1BEE99E9A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AEC3F4523959382BD115CCE442B035A4,2D18094C4967705887C5A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,46E6E616E09CB7E55DD39394A5DC3761,1957DF25DF612BD4B53EC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8072491CB20007BA6CC7E24A4FC23A2D,A84FFCB88DF8E54030774000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,700384AE8C942CA60C9A615E0FB93C30,4B8142C4954953A8D13B6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9951C3E75C5ECF9FFC7566AA9D0031F7,809B1DCBEB889A1FB9E73400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6F610E49FC29DD5EA3A445F304085CDF,822CC2F7447B2E62C2579800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A4CE86DAAEA928FB124EC3DA5CA3EBB,EDE83ACEB36404FFEFB76C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7D6EFED35F071D2F2462160CAED7F19,E575EED6081EA7B77FF6C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29DD5372BEDC0236BD8ED88ADDD0C02B,45153BCDDB552C6F666CC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,54F41A2C39E1D9B01BF950D5CA208166,1AD31A927B0C6D38B620AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DAB9695550243EAB561253A7C907959A,3BE487266A9ADAF6FA2A9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B209462A12C58C787B0706BDC6E071FF,571445F58FE2B1E49F6A0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,885264A8B2BA53283791FCC17BED5776,E6431B1E31B01187581D3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CB3743A2F7DB26C8F025865EB42FA4D,08B8DF66B2B00CC064AF2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4BCFF07D51A538D69A1BD5D1BD46800F,1128215EBD7FCB32AE078800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,64A07031848C50B7A455919202D920DC,B67A7909187BA6B7DEA1A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,000F68298F34759CAB5F8BA364593FC5,8B70B69633E3756CD5A22800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE8782A3BFE932D19D6C028FE65938E0,874B9B39689E36259BA12400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5FBD8DE9DB7E7378BC32417528417345,30DA2A8928EE101E49859400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEB9C37A35F9E331241078CB35A2056F,0F20CB8D72AB7ECDD6A1CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,12BC5563EEF599DE3FC325CF7B7FA3B7,AEDDD76C2932016DB66BF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EBA08765670A1137D8D1876F115BEA06,2E830A587D43AB1AB1FB9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,435C0F9B79DEF7A007DF1177FF846394,DA7F625720EBFDF1EB8F4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0843767FA1549B0850D51AD8BE3488A,C65EC97D459BA53821677800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,67BBEF0293C80DB85A2E5316D2E266A9,E8FC816A328F80CE1CBC6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E0CE1586E32A187F9A825A28EE3D5A1,BC595580C882523D332C1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E63F86CC94FBCF1E5B013108F5E1E95,EEE860FA5FA7BFB372D1E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E7D53F55D07D935E2BC91636A00A8D4,B0FF535B497CDE59E244F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BA09096F5B0145242F8542D9BF1DF2C,3756FB796F8D771B42977C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A9C6694C964B25FB8DFD93C3B9F46D6,D3769FEFC8A2EA673C502800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D06567B86C6CDBF5D47DEC7A8F6C6731,AE631A624BA4DC2F594D7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7928E74CA1EDC169BDAA19ED05D67F0F,B2CDB710887C45154C093000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88DB7A8B9956FEFCE812FCC84D07CA2D,6DF91317548F4064908BF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14E0A13922478E323B00B93E642FE73D,7E7815BCC48D0C82F7219800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58BB7507A0AEE3197BEB8530588FAA99,F71C10995E59E39439344C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F6752C2E43C8C1FD5ADEF1FDF5F2E0D,FB1CC235B949996895079800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76759ED260D948F7E00063B3DBF8BC4D,B4F96FC1DBF0375BBC740400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E7F5FE64A5BD9CA55231204C5F6C83D,98D40A3B7F6764618E72A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F760DA49107FAEBF8A8B814074678EE,A03E72AC97B2F8EE2808B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,097141EA7B38A481AB72103FE96F978F,6475FE67A94CF3660E18D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13D724201521ECD7F0B5D63907AF3DFF,0B6A33B2C9D0BE2D7A638800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8F3126186456611FFA524FA250CC1A77,5C5E9D11C6ADD407ACF68400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1B6B5A60FC228BB38E51AB14F696C42,273E6EF03CABF21EC12CE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,10981549EBDA3223E8D820CAC9169A26,B5C389CF85BAF5F062AC9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C9C6E50E1C0A703F51511A7B6CFEA28,23DEB00140BAA6B3379A8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF75FB5E7877446089C27EC1A62EB922,04E38D6813864C5FB85FD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F735791998CB0AF5F52A65E60A8B5C96,831E4825135C99143BCA4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCE0F36E9BF4A6F9345490F0B6CACFD1,8794B636018607C7BB901000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F9D41DB085ADDF8FADAB0DF687513C9B,120215A9948729BC5C1E6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1331BF559F492A317E5950A8F7F7AD78,229F583637B4C17DE9380400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,678800573C8219DBD720BF0161848962,2F579B45B8368F88AE19D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF6441B4CB4FB1ECF042EB6D61EF9285,0E653124AE23AACB626DE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3708063897CA8A1F36BB6CD36836528E,9AFD7A2CC10934D5A7337800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D91D9DBD32EFE0A16B9B112E941C7567,FCFD143039A3A167DC878C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB7CFAA8A86B47A4D3D1F6A727CB76DC,B4AF398DB4DE17A5AF00A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD5D71BF49107DEBDD94576C8E4E1869,D9367B9C59A080AC95C66C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F228A9A66DA0602188A72171A3DF008,930DDC0BECFF7D99DACF4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,01A0F2374215A532E3ABC5FFD6CC951B,BDB55A3E93BC6099A3545C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D3770E3A7867FA05020037EAD52E23D2,31BCD31C93EE77B1CA5D5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F98A68F3C5C5076CC908EF36EF41C438,463BA41C3683DD974FDEEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,51C9B75E2AFCDC3392122D6B9C57DF91,CB1A46457B9A64DA0D97D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8467B23766BB51982A1378B4C2973A6B,76D6A09C5D35F0B51DEA5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A33A014149C8472F04C7B546F35506CE,2475B8089D2497E764532C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D8EC57C97246E24B6D631040BCA1939,DEE3FF6970851AD21422FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39D756DEFB4B005ACEE292C396D74B58,6F3FF477D18954D1863D1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D14C6D8641E7436D3534AADE2907AB1C,256F2874813E19140D865000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,275154585B5D49A9DE635124DAF16F2E,EAD982C122C47FE01088E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2919B272EB6933E0F6111ED30F7CB49C,E55E2F5D0DFB3A6201419400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D826E72C9CD9200418707FE58F0712F2,5F4DB5348AB8734712FE3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,702D868C60837D32C415C02DCA5E92A7,846679260D71291DF3D83C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D45A204033D99A424C794011586869C0,B45C84D24D0B3EE3F1BE9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E2B9A5D424B8EB8788208642C0D9325,1587161E9729C59F48E36400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,215245679D97996331CEDE6C6BA812C5,E763DAD3BC40C2B2B5A13C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA33695C843B2BC13A05D0FDF53E8AE6,4B61EFA3570EEA3213B92400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A7EC9ED67E2CF1681D66291271E4AB7,4B98A3DCCBBBB0F20669EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C366BD09AE8419BABB3A1DF026B826B6,D8974D2E5421CC65F1532C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A20FD98582782E2467A64F4582C6FFA,08B88181628EAE2E94F33C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91961EDA843915E90E24DBC2EDDF2B99,55EC4785C219C49B07A7F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3114A2B04AB507BFB1F2064EF4D46807,AE20B2539DC263383EF48C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF0200DEB592D09F9828D205F7BF3522,B57F0C011EE7BF1B16514C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C18282D779F5F8854CB407443D8A23C5,18F5CF7BC9F9F448DA358400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AD7CCE70A6778AA86D63EF43143854E,356192FF2F5B9C560BB06000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F147FFB56F664D8A2587D8F8BA338246,9BAD90BCB877572D1B258800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3ACF8A37EC96B1125AA54EBD1B6CD804,8CE5FCF8031EB8C6EC1A5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F4C93664DB8E72ADB0E578F14E3B92A7,102EAE991DCA6637C331E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6984BD91AEB7413902C478D5DB6BE14D,679D8A7CE0B34ED219432C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCD8184D03278915FDE4BD63B943B954,01181DA58C2739AC1D800400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E2EEC6C03258D817EB65EB2C60BF80D,896667EC0AB4B79EF744A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,707E87CC60B31BAB981AC7FB6BBD6100,812115149198B2653D7F8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,37E7F27C19223C0BF4A46974F72CD221,B3EDF0F63CF9C42C33327000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7C272423B0336C9A72BCDF4F6028617,51717330C0812799C3060400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D4D311D218A0DC45B84936C6F4F08A2,C96008F90673970556634000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DFBF17DAB39CC5F2E8CB34D43DE46B34,DB52DDB44FAAF20B44482000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5B897581DC42C93F688C6F2F595BB49,4D3F63DC19CB8644F39FE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B49596D0E69308390858414C49A950A4,8A820754E33C95E4B612C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B611FD6DD1BB62638939447C16B8D93E,FC7441F7E49561F317C00000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E59DD928BAB2FC9C637AC15FC8E0B85E,227CC47074FFD676EFDC4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FE1F8C8D7361B139B5BB339A8743386,26F1B3CBC7A4F1AA7E3F6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A52AB013AEA6AB771B129ACE61538B66,34B834857D32B40B56E4A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1EF42894FC1CFA402BDE02BC63DD3414,27336F3A6A03CD844AFB4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F675AE5D40B508470DEA22C2FEBF5F92,FF892595BA5778DC0F9BB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD3963E2A83FCF9BFC35070D9DFBEF7B,F13262FD09B13B6C5C9A3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD3D8E0EAD4694D27D053C02A16F45F4,07BA12021F3E3A194AC6B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F29222F9683359A965DFF368D37B51FF,B7B1C5C506CC44F3C4485400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC74FE5763AEC95F6A5116B09A103DD5,4EAB8703F75261F275353000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D5C7CC3C0651B7C7B590EA93F1F99E87,06B64422EC2EF03E4C989800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E3E18F946CD52E5584557FFDCF9DB39,B34C74616450993462222C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9244B53E99AF01CFFDF48AE1827ECC52,1C8DACBD94BEF8882DCF8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8ADF54EC31A84CFA1C9C85BA7DAC5987,F0769F9571F363F8A9AE6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1C0155307746E33656D84F1C6874216A,3B24753DD4871CB2B9D8E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,572776074B2ABF9D474A1E90BE3D4282,0B18859500C77987E51B5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,530B25F37BAB56582E93D7CA49BC29C6,0973DCFE0827721BAA3E0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF7D2196EDFFDD0102F87BC73E736647,BF29D98555DF5294E4754C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3F62ED8028BB9326C7B352D1BDCC2E3E,FBE9C7A4C80FA177D2D86000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D4E5FD7028BE3A1A2E6317D8914B5DE0,7D8EE0F3F6E6855579A60800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FB3930B4E6145ECF7D9A1D1795EB97EB,37F8240A0381D6B9CE73DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,682BA717279864F9D69A0DAB66309BC7,4D52F954B8A35A692B378000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,171FCE31DF97AADF7BC8493BF62EA86B,B615010CBF2A027D4A339C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7E4959E557C3FA3CCE5086E899008942,2A3518C0E04528F3EEECB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F507773FB6BA07E47C38EC65AF4383C0,53016AF6C302AEB44752DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,695D6FE782777103621CC4839A53541C,44CCA8780CE27A3D09F9DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6EB3DB8AF175499640AD17205535EC4,1D67DA38C8FB1DBA40515800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C9E6AB88664A3A4484416CBE2B6EE949,EB3D0289B8CF2D0A83558800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F7A74C7EB58F951BFAF9298E1443D83,785ED07D2CD8A61F0566AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEF8E1CE329497FB7BD85D563BBE6BCB,41E2A6F93E425714E42DAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2FFE06996CFA3E20587292A057655B4C,DD387EBA7CCEFEF871866800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0717F68DB23B333C77C94BF4186D80E0,394CB35755B97C69D2A7D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03A4141A41E464C133BC5F14AC2913CA,E0EAA20C0F3F4D87B7235000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6077B034845B4256457E83B664A74CA8,0CE359E4114FC0A803D1D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68FCF6C5DB5652ABC69FD422A726D433,C24AA6ABE418FE0A60E67800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40277E59AA7BA0E34D15D319949890A2,18A153DEAB2EBA2B767EFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,511D2A6A97DC190350BEAC49CA985029,9CB1773E34708EADB1C1D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B56006DB8F26BFE637FC23707BE420B,BFFE0C23A994AA0CBEF03400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,521CD0CE210A03345901F362CB1F986C,6944936261F98CF9ABE2C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF7D43D1B7EFA2C53CC441D24BAECB14,E44046764E65634D42E44400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D86EDDA6B38C68CA72442D8387D2583,75ECBEFF42E7DB42CA865400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB459EBE37BBE976ECE0C4E3802616F2,D96C3C8BA204BC6FD63F2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C06373086CEF4472426AD6B5B2E2FA2A,BDF4C22C5CC2CF26D8DDC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A66CE48F4A404587EB7E89E4F860BC84,47C3D89877180AEC4C6A7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21F4E49CA39F7055CB48B4823EB60B3A,BC2167B0C50AFCFA1BE6F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BE307147B80BBC470A4EE967197DE9D,7496873601D14DB5C2478000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,005DE6083AE188A9D439F822DD91E276,6071EADC41997021B64AAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BECBBEC3D9904615659398F0D10A37AD,474C529A92B020F450016000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,54D2238C5A49876C5BFFE2A40CBC1A9D,F6D12C50F2E0017FDF843800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7372C7A89131767CF0212ECF024E7B7E,E4AAEFA2950A3051BE6F2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,610E52FF15507BA26BD65CB9D0D4E3C8,8FE60B0263BE14B2F9C22000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B9567760B977B8098C11E1FE7327D0D,3CB229AF10E7A1BCCCF44C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,489D7EDD44A94F7181B77229B54B300E,E0A662E1E544275C163B2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1C7FDD0042BEEAC4F81D4078E7D49684,DF3FABD2A77D7A38B12D3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B89805DCA011CEF194D9BC04E600DF8A,2809BF985F423E17D5226C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F69BFB96B5DA8EA19624ADC9214D07E1,3FFB94087F5371C97E71BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E815D34509F9E7F5B17CA9183715AF3,F7631C95DEB4E06D93B4D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0180208C1424F65A3E14669F47D613A,F2B1D81E4DE0F12F6CB4C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E09FEA06947ECA5FC976D87591F2407D,883EF20CCCD5798235C6A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E3E936B2185A5D41D4B60C3F60103F7,2D7558E040DCC3E416F6D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91A782D36FA443B0A55E994F2985D575,AE21774C32D634AF2DD6C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,656B1598FDA639EA759A30E493215A63,DCA5B8DBC5F9D3AD06243400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D68E1C70480D6F432983FA46950B0C2,E2E90ACF8F3FA04C8F2F3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD9C4B27B6EB1149D7B085F4212D0E29,AAB9A8E82E9D321DFDF15C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D72A0E8CDD5895CD0186AE81672DA156,D763625C8AE8803D42F6EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7BC002176E2443396926FB46CE765E31,4F107FE42A13EE45CBE1F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F5A7DD615BCE9ABF8B8C4C18DAF3362,5480BD66256E4D220C265400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9251A19FE41CB4D412470F6BFA32594F,C12429A97C548C5D5C736000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ADF090518F75202F8C857DF5F67E977D,B1B2AA978F65BE9679673000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BCA17276CDEEAD058D7E81402CBC5C1,FA6A82608DDDB93A253CA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9A5679904E6C5BEC951D7ACD820F2E1,F8BE9E7706EFCF25FC611400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D86F518E58B52001BDE85856AF7CD0AA,55422D987556CD82926AF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC7868C9100C79E2B3881C384CA53D96,9558B50239B91FBBD6975000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C1B8F86FD31CD5AF76883B10B72CCF1,E60CA6EF142C1460C889E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,28B6D8DADD3B4B3EEE8E621418581BB3,23F88A84D08A65011D399000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,390324C804995A305DBF491ABB8688C8,793C4846BADEDE452720B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,520B67DEF9F337D1D308F6F061C02C9C,F723F0299B214C0A078FD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71645B154FCBE3651D1CDE8C7CF796D1,1278C555355F61C26C42F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,98D733A8D5B85CB86F6B77E4A1100AA8,AE9E9A20CA2DDEC396D11000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96B9EFFF2554579915EAA550CF286282,8722ED19BFB98E2B02596C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0A7AA237867FC0A6EDEC4EA924F0E76,43DE54F954EC06730AB7E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2537DFE6BE739991E00F01A91C14AB3,8ECABB5CE3C850D98AB35C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,239DC2BC8D0FC8496D1D144E776FDBF7,728F074A77A2BAFDEC446800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E05E050CBD1FBA7E47F5516CD629CCB,CEBE1841EBC48571D47E2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99EB8B1C74AD8EF6CF437A3F449ABD82,4C8CAAB0C8DB3F3B83169800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5030C866A721D7F572682A3F4BC0E0E,5A7EDF1309B160CC094D8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A9CC5E01B3E0B9367D61906A98A8E36,9E9C0DA2F4875275063BDC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5EFED823C5C56635464AF5D77D1EA7A,5CA79206290A4215ADA1F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17537A5411BE7B9D3BE694F0A00CB003,97DBE50AAB9E002325660000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1553DEC3F5D7437F931A7E3FFD2D3895,720564A61EF48C79C7060800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,80389F9463503F6D7BC84FEE369B3441,7FFC982DCEDAB72846277000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91731582928DD18742BA511C8A69D96C,AF84A1CBCD7F562D82079000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD162A3B971CC81DA240792EC494CA61,AD67C7E4DE3A1184C7D05400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,616CB3A22573F18BA4B3195CBED514D0,F621DFB8E16745C9D2FA9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0627642E6A047D17A484C389F02759F6,671092182F8E066311FFD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1A8BF8A390F007FA74AB0C906A04424,96910363C1AEB39F2C900800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A20ECD8792D687E6DB8A9C15804C1E28,512536CC6F779446C7781000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68437AD4CF4B415A62D91E1715383460,AC5944DEF8E834A5FF584000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34B144A234CC6D88DABBFBFD3BF0D641,0607F2FBC96FCF993C02F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F6B9CD1B07A45DA011B186A9A49D955,9DBE594329CDE953436AB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9894F828ECCA7C552079C9AAE88D9B9A,F811F54BC2C4C25465F90000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34D08C7BA29FB2769B6976908587ED2B,98B2F0558B98A1E82904BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B920FCF9AC6CE5287253EE1B5A494298,667D8BD0FE5ECBDFE5EB3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6E2575D1808FD3EEB1998C3C7081578,B8DDEAEC9B7EE402217DD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C110AB32005A4529AE28C513508746DD,32A6F986809F82322D150C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E8AAE52AE48C4D086E101D4E41AF83C,A1C8B39F74229E7ED303C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8576446856AF5AAF2971B3A07BA4D4E,95B199FD57B55E23032F9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,490A65C2382350CA352D6B635390E523,C5126E4AFE2ABD865C220C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,560F1B8F7E2A4DBE23074E00502E9AA0,1B88135A06542E17C2F47C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,499A9D53933F23775FD61D2DFAACCDD7,7D4082DE2537462B02F15400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5E7FFB677243810C4803256599D4241,530B0E0BD87EDD716E153C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC15DBB314B0CD7506004914E043F197,368892055BF4C3C5A2FFF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02389CE3320403735EDF37B2900E9C1D,6B08D52290AC82AEBD093400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F604FC5F56E05FCADAFA7A5669D82B4,432BA76333EF9B1478694400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,406F17386B826A696E5A8621B4C64C89,CEBC3E39E68D1B32D5897000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,479ABC18F6D16B0F7978D4638EF73A45,307CDDD712924E63A1604000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B30687C4213B0BAD2DA74555E5367DDF,ED1BBD009A424EB868743800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A181D5E15070BD7AF14D9FFD438B3B32,2F970EF02DBDCBCE7A190C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66FF86200758B8A9A482F0FE70D915A5,47F72F255F9325BC3D0A6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0DF1DE28AD3D61B91C931E5FF8E3F8FD,51CA1FC9D919ED3B3AAD5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F08BF58595FE0B5CB7BF3E5A41218A6E,C949FB245F5C658E0BC94C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82D5768A2BDE39F46D1D5DEAAB5BC7F8,E296D7A4DCE9ECC5E31ED000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14D57135B4E0271887B55F21186E18FD,89628738B1EF82D8E1337800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,948BEC877348E7E2E31809E05CDF5820,FF0ED6732FDFFF1C806DD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1F8493DF7A794583AA8349A6F1EFE60,61AF0321F23AF53ED07FBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5EEF0BA46587DB2FA26B6E98D8B70FF,EB09CB2A3282DE77C2617400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A405F323FECD92761D28595CE51452B6,6269C86B54930F7E44CE8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BB3261A20BD9240D869AF801B835026,9694EE49A2FB6EB720319800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5672886C169F6E6031B255F365A4D0A1,4C858BA479E037BF6717AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,457968CF1C8368F5DEC7C4F5587F751E,D0A5F466F249D242AB913400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4969F1CC1C3BF44EDA2A562A2A23B49D,12204C89DFDD613AFC7F6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5212E266A3C77E8A53A6BB6874E2C60C,FAEB70C36410349A97107800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,038B136CC82B6B42C119935062E4A261,0477BA0D961A3C86ACDB6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B8C70223689BC1BDDF9301DEEB735F8,6AB5841AA9C8361BA8D8B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,817BA76F795465AA2B84B41568CACCC9,7BDB894633548CDC295F1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC3394BA708D35F36FB7B418EE82663A,3526F2B1D0D626E69C359C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22830ACF5C70D6185B65DD4997CB5B97,8308B10D37DA0816FA480400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB14AF8263324A4877D168BE38A11EBF,7C909A2034ABF14520172400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F221FA4767A827000039281E2F0B623,05D4E1D1B316AD965B0F8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E33F7CE6359780A5B781AD215AC04225,0C20FBE9688A08D5A4AFC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD23B02BDFEB88895CB0D777AB18F345,4DE5BA94E859BDDE79707C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,223BA98DB77F1626EF6EC92CFE960192,1CC629F32F8A3C8C651CE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE306E78099F816287D71F3FA11B56DF,4E11CC726B804F906BEFB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72C611D0DCC5D2F9A50BCE28457E0A45,BBC45738032A40FAFE2D3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15CC6B6797BFADA19F2594AE921FB59A,B91B68D15D4CB4B1F6B81400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5D2DB764E7B7AAA92C357D12742462C,5F0D2A79A730E47464303800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,213195ACFE845F0C93166A631DF49487,777D5706979E2DF50B87F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,63E24B12DE2CB25ECB5E29C12E37B23D,2E14C4CD4D545C3845B3D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5CB0F5D2197CB8AB853A4B4A445744D0,8A1CB38FBB7B7864D34C0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2CE903C3134ECABBE8EE2C64C3B97708,627F02569E66F7745A408C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EA8FE58201AD8EC836D6857CD2067F6C,3A3FFA2D4BD6B3AEA2457000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8D41275DF89DD183F0B197D03631D91,F46167B49B652589D09B0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3CC77CB1F3531657711B9AFE5A2DE496,FDA30B4A453BC0A64F545400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EB3302AB5736F9F6263D208F7B156DE,16E3E2881889EDAECE661400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CA7BC43A7ED76CDD9F1B5D604681F36,9A78C7D867967E438C82C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66A1412F61A52D5DC5B5E75C25DE320E,83134957B95983C900965400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8788F948A75EFEA809BBC88485F42C6,3E0B59E31A7301B5DAA91400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03D1DBA98E61ADB76A2220CAF0B3B65E,E890AFED9844B8E585E42800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,54E139044195600843E4F5BE24B6F94C,5CAE0DC4017FA09193E75400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,335FA06290E50E22BA6FE18659A33E8E,61728763E21154C63A774400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AAC3EA583360E5AAE4ABE89544A7FC95,68267B6CA1F4FC14FBBE0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30E32E729F6F642AEF4F8D60D14D5A3C,11FE5C0791B39824AF7D0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD956CF0CBAB6371688B79DC03CC6A4C,735D2BC22F4BCF7C997F3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0423A8252D20DD174AA12315521CF7E2,E79960B97245596EB85F1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBC5D937BCA0C80344DCF1ADCF5418B7,641039C40F7D88B4F80A9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EECF953EE957E1AEC36C333D96C4B79D,863270F7C46B5368715F3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20EAEBA061FBF323C97A9576F5B98823,056407E1F0F39CA05C9EE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3FCA5A7ED535ADC2975B0AC8BF3C33E4,8FD8F9E15C99ED3E447C5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0D0B816E086CC3EA3D43120784787D8,0F3BEBC2239E37F7CD3A8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E589F677639F03501C626FFCB66DBF24,CCB15E8AFC80F0C47405B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,285C1F14D941F891CDD764C99F74A194,59B7284F9C34C1D0AADA5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A100BC6B2ED37CE78590A68DF5FD1E80,B62567A9C4B173E9484F1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,277E707A632759DF2E91A7CF9DD8239E,6EE6CFC460CF8B9A72B62800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,402298E5140D9CAF7A2EF0A93645B3F7,F24528D20569BD1B0A899400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9D70DFC32D6FD29FA8D59D9B2DB3728C,0DA1A2EEA64F163CBCAA1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03D12BEDE33CE608992001A74A5F635D,BC5444F7CDE90291DA579000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA4264789EFD43E18B42A91C0E7F0EA4,4D9D225C5ADFB5F935F8B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,44F0B60206FC2F63C509F39314945F6B,162A33E151A57F946EEBC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5A8262D4D61908E0A351E9FACFF2598,29170C989D1635558A2AB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F10746C8B3C354EC9C6AD89160A8CEC,9221BD0BEDDCDD876A8B2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B8FA87477A8355D4E6B466875259A0C,A9D47FF8B26F8D850DA42000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,139D34702695F7F899D4277F976C4DB2,D0894A14604E1A119AED4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F37E60C2DE408D0713D7F440F1A83D5F,2B510C7C054D520AE17FA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,01612C3477433ABCAF80F1EA10FEF447,C63E5660871DC933954BA000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4B6BA348510101A88441C0FC598E1A2,4C557C4D91C42CB1F6DE8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14AF8D19C6A6843220DE463DD1F4040C,5DF913F98AB001E257562400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CD5E50611433EA1D7518D586B0340DE,9CC76EFFDDAFA5BE93956C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,438FDCC8CE3353C7FA6DC4AE551245B2,8AA23A7F909799E1A48B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2643BC18643B60879735A7269D7A987D,B20311DCB8250460671B7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C1C7D1AE5DDB83D3FB416F123FA8479,0556F88B3B2380EA17F2AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,908E8B49B17E4D326F0EF9F2FA78E9E0,73AA4D65F48EE6701DA5D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A99572093A23F95F6F156055A3BF203,F7C15FE541421D63CB43E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B08DB4290BB9D0626D42F40640008681,A1FC07C0F9C9E9BAF82B0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D33CABEE42647A28791D7835A5117F7D,98D2BDB8B0CE56FF0A894800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CF607B09D5CF5648A5760BD989610C9,74497807105D4DE16315F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A79D44E3CC21609D11F76E1886F96A40,0749DB4851E2DADAD3558800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,51D6A4620DD7CC555FD3E4F747372E95,0EE5EE0883CE6C487F2C3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,362ACBAF2C62995783EDE6E59BFF20CE,95C52F28543431597B575C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5132B79FA67FF47EF4A4833E386D824,4B6C9DDBF7F7CAB3FC6F2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85CE93A1D0F99CC8643B2677A4D7FA86,6838227C63559D72F44A0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22DE20DE6E49773C57CAC9C656B829EC,D10A413DFD6091FD5860AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6821F332FEC94BA3FDFC5A28E00798DA,2EC42120EB8A00F280ABC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,121D37973388925EB5E2EFC823364F76,CD6EF47B7E1A977D7AD12800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,08E99209A84B799EBA03D41F90AE6CFE,451988D9FBF0F56AE1E4D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9CCD9AB7B846A5D131EA3101ED7C0C53,50A09516683D11B0FDEF4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5E0EA76C92046E29DC279AFDA1A322E,B294359F547F3600C5388000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78CFB7FC779B3EB22851DA5F62E744A7,07CC6B3182E2F5B4702BC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C63763E26E9C8522E6B7F9289FC7D698,6C734634305C25448525CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E29F892D23A70DF6B8508DBEA91D9136,83DDB4B393695E2533512800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B35F94865F655C238C3D9F66475FDC32,704192C30D69066BAF661C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,45CCDF4039F895685118FED30C06AEAE,363AB01A5A7241E22F8B5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB3169DE2F4DDF04026BD0ACD2E3451D,C0AC072DFAE2EC32C2999800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A14DBDADB21AAB6A4003C7AC01D7125,5F834BC537A730AB0EEB8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,617F61AC87D671863E362AEACA2BED3A,3C1E23A8E2B7EEEF33C91000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5CCF9E16ABCEB48A69DBD47A2FEE8672,2969D626F8420DB0BF69A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6599362E11E40AC1A88066222A558B73,2D00FD820B0C7B7989117800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,80EA0F12F82D2DD7EEF81E049D37DC65,DC8F89B7A5E2AF4DE4806400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E2FAED83F035D661FE77BC67543A049,84195BF5DFDB89C1B4BAC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1FB738D838DCC4BF409E6E1D56DD99F7,F1689606C624FEFFFB0A7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E0EDD907FB98168CFAD52D5808DDD37,8AABE70745D44A883440C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C501F7A7540ABDC4EB9EDB0FED7E057,1C33E9180596D96109807C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0BF880A9D8E4EB1EB2F7E247B232F74,8E7D30368A91BEFC889B7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,013256BE8A64ECA0C38B9A8C75DBDDDA,019878985319AE79A9415C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,69AEA9AEC878E38BD7F6B578C29B378C,0EF6E7E3B0CFDF4836FB9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1B6919926246CCA1772026E06C0118B,9790275EF92C9E5237E55800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,56AD747544BE89B96E3C019E3BCFB816,807845368088630A09E6CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,407212D0EC94C39EEE6827F01A2C36E9,65A4B46B47E6F9F57709DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B9FD2AF36D032C2991B3484D05B8670D,022B158A362CBB5961F82C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C45319D93B49A80B4C5CAF4D103C4E78,D3560CD730F10ED5A68EB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55D91D1D0CA6D2B8EEB0BFA39D580ADD,385482EA7FD09919766B9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB11070876E8ED38788C0DF9C6402593,31EBD1645D48C8093E625C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB49D9350BD6A5376CD56D7F00216D5D,F083D58403D218D829958800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D40873B3A9E3DBA1D6CF0D0C65EA07F1,57A134B56E18C3CA535C4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36BA58B48BF81CFDA44935D5706F9471,BEA90DC973B3B9622A54B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78BF252E31F76C743E1A971CA702E346,B61CA967FFB8D341FDF4A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F7F83D2D484580E8E64E8420DADE3B0,7FE00E37C99029A79FC09400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF116FE8B95E674F722938B93995345B,0632A6B77B739705E58E9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57AA9B1142E72573AE6702118BDCC5B3,A997A317FEA200A1BF17C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26A312470472B997C50D6C2AFA39822C,566586A7B4A9C4B04E947400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06E8CC2E32C5AB23375735C1D2A9F38F,B07A1E6B1A1487FD1EF35400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50C57DA189F9DEF15F4FB0CD4B9367D0,B7E3F20B6A83D4DF00291C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4675E3E185C5A2D9A35A35563781D4D7,A7CE1ED6968E6808EE2B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C79AE9CCE6754C73AFFC48F3F8D3BD0,E6D686E63824A2F14AC3D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4BBB2B496FFD177FA57CA441D308129,1AF150442D8695156841B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B1A154C651756BB5716C454444574E7,B36458807808C000DFBB8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B320C674D7BFE9FE97D648BCDD05E7C,D2FFF90A6C9514E69B2E8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,475CC377554E9BC27F3F519942A91C14,452FDF7EB7007DB022391C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E00CE4A90F93475BF1FCECFF48467B7A,60CB8ECD24A6EE06D57F8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,815178A0C659B18945639C4B07EB0881,6A8192E5D3B693C59C483000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC17646BC2F358901FB26E4E43675920,5B0B39552E99A25B5DA35C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F18F45FBCEC63FFA649513806CE900B3,7187DA52E1B11801CBFF9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F75C41529E232A43FC926C70E5D5FF63,E9FD91449755E2EC5BBCE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D52BA065FF224D2F8F07D40319A50370,D852250AB403426CF8DDB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1D2E56B09E4BCEC51BF417A4C372779,A3E804521A96B079E58A1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7058BA383C163C684C6C505B73091FF9,F79BFFD0A222CDAC8AF9D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,464E181491382AFF807712047648C94E,79A87B43D7DF0D925B844800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2104EC03923F8FAD45AD1E0993A5D87,7E1781F3283B2F6A881E3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4AC0C77D93E0CF377031647CA3EF7183,FD17B7555745CB85E67E7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8BA33423199B92D0B8BEDB68321067D,D88C3C98B96CEE6FD7073C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B719D887EC6A78D24E03725D73B8C95,CD7B4AD85CDC4460C5850C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2357B769EFC0A4BF1764630CB7E8CCD,2781A4EBC32671EDB7D11400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6BAA811BDC5A84AD77F89D0C1CA38E73,6EA0886076F38D7F7E5DB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E256E3F599C5D59E5CE419047E45A475,7A5E2D93E70C0DE9E24BFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,448D90B6D0728D6A8C709364659B285B,3A1BA05A8ADC9D9A9406F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48AEB674DAE14A861C1ED47E106E1F09,1D179FAD2440BE476484F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4ADFBEB3D17620818F10A2CFF5A2C685,90FAC65A6510EE987BBE7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,97F5994BB37BC1B109E8F85612A9EB71,AC0E414EF10CA9E6EC12B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5B58A750CAA75DB6F7DB327D33C7029,4AC405C9508DD4AD0D2D1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A9FC980135340C2148F7EA1397E0A3A,E490CC8B50EFD553525E5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C654B096CEE17996842D414ADAB0F65,5E202941D3B94A97F801F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BFD42E6AF05531E36472ACECEDCABB01,105900508885332F7AB27400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F1D6FCA47D9614EDBEB3C7BBD0F3FBF,D56F3C13E6E5A823AF345400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CFCB9E4A854AFAB012A3773659D3497,E2A8D0A7CDD8208BDFDB8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0EB2F1479B898574FD5A005BAE2469ED,FDFB5EC18859067F746E3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DDE3DD627701D3C82E231BD8E6D3B9A,C1D1AAD8ADD808A3531C4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,83C59B2CCA5852317B0CDE7DD7271839,0C921E18ADA831C196F4C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F15C1D01CAEAABB0F3BE6F9F945009D,0B5D77E367E003B2E9B57000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D643477293F78185BC9BB8CF56618B68,0D2D4C255FAFECC099C98800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0133D361C9C3F74659D49017CA4688A1,87E097A69DEAC904FCFBC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4BD21978E31D1A932F52D1CA52BA51C1,D69E4C5478984C99E36D2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E7A3119A8A14EB0176450391EAB94BE4,DCFEDA85A75B49C6AB08D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A602B0877A593FCA1E6ABD00D6E577A,51D275F3D93C3663FD457400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DC13BB009B7D17955912233A638CC40,DD5585D4D69C6308668B1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0DAF5353573B8D7BA15EE778D10C5B96,AA61BA1FDEE572BF3991B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,561FAF93B17A26208F5C25563F89CEB3,16886D3D2E82D27F07206C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E8477F09EF1EF1467422355C9D7A5F4,8EC6BB8B18B4F0ABF7E80C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,344CA2A796654AD2120F2C8DF91E398A,D8426EB27CADF76A1343B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,62B925E165726437836A148714266725,F9C2F257432181710C074400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40D9F437C6B977D4905EE57051219409,032DD9FD9672471482AA0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,704164C86890924F54FC23C80780D43E,C6AEF0A6161616D7E369FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C50859A7E4B893CF0152540D662AF6F5,8455EBF400BE39D837EC0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,45678BD0518687ACE0382776502063CF,6D078470B0A19D4F11483C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87BF9B0EB9C4C02733B2A70235FEF789,3C7E311DA59EE7194C1B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,417AB0CF8C02E4F88A48595F037612C7,9863ED9CDB97E9858E59B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EDB9E22D193705D5B296A1E5208A543E,970D6DF96335F191FF096000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8CEE30C5B579DE823EF219572C580C14,BB8CE2D7396C694C2000B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FB2DD7777D14FA51725B84E2ECCC25D6,608BF57DFCDCF781BB81CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B80BF5CC2BB2257EE7AA0E3389A311A,5ABF98CB0FCA9AB95180EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DF3CA5DE617D1A3D8AED5D3FC35A5F4,62597C3ACC2A14FAFD627C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F42124E89A2BB0750289A4D309483D85,4975BE2A554B9AF2127A6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,467423D8CDA747D5D8FE6176A8D4C3D6,B2BBBA88E0573F00D2317C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6AF7F5B6F08B68B634571E2F98DF77BB,36BAD2C7F49D0B5F41D8E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7ADC92106ABFB875E218C86116F338D7,0FD01030AEE5744760059400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B9D359A4859A227A18E95DF83A54CDDE,19CD5BF3D090E55029D4C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,79A726C514C2F388828D95637C68C9B9,FF505A95CF143009E4963000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B718DD87A174CD9D97C1D44866543D69,2E70D35BE3F4B667ED283C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33E0321C0110429FCF617D2047C41392,9762E08AD5AEAA8B22572400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1E72B0717BCA40E8207B235ED337F98,E0808C7A299F7CA6DCB62400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70BCA904F49B289684D72B21234D158E,5BEAE8368903EC2C83024C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8CA2F03DA9FA62C87D75B1ADBA601CE,627D983FDE0091839D772C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6695765D71EA944A33BD8A24BD2BBC5,9E10BCDDED967DD8E5BB6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E28036071370022361A292C6FF0346DA,11C94697FF0322B813332C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C304A0719C863BF255FB766A34CAF6D5,987F746AF4BE1B5EEBDB4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E6D0DA456CACFFCAC1763F513C780E8,02DC9C8664003C31E81B8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D87DC287D64CE316AF1FF5D22CE6403,7C7ED05AB3FFAB5BA46B2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B93E2C36F43B75F7759F1856158A0C81,195F8C4631C7F5827A12AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0BA82A946103A44B59AED9E1BC99D964,2C8ECBBF4E05CCE5CACE9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,386543B2FBFC04636770631E42992CAA,643B71AD00861745ADF29C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4127B8924B007BE05A1870E623BE0EF,73556CA9245832D5B30FE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1DE95ECE729F864307D8F5863D092FC,BB3FCBF94116C640D0CDB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8A1F1E112909D704F71B0A3D48BAEB0,D18D8B60803CCC7502C4D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,25C76F0AB71C9E65AB99665DD8DA3BAD,33B8951FE810F71564DB6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E5DDAFE67E23B856D1E46A5B27A7DE4,C7AD38CFF61BC5FB6E2EE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52F4B4C77A10F819DD8874C18EA7438D,668E45DE6168820CF57E4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,54CD69AB3026B3E74752904CBAC11A02,D8D074AC1BEBC91C6BEAD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0813F4A8DDDE2BF0E5B68B00EAA6F30E,DA326497C3DE92A4E085B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36A30D53982D5D85BA13190315AD58AC,F32AF63EAC691B345BA92400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B63D3E9052CB3CC5F2C3FF2837EEA5F2,CC27BCAABE8F8142BA484000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,879F9AF719FE477E14B3EB0BD77B3E43,F4B2F1CB81A170610AEF6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C054F0CD7C31B847AB7175439A458178,86C839BF0E031ED064908C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,79C74644F0C6602375F08868AFFBD268,06CB29729A358897B3FCCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8498EB5B4FC739BF5FC50B616406DC4,1D639210EC64B69D3F8D0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9CF9A35D8621E232FBC13045589B2E8F,E7C76E017BCEF9269F2A9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A18C21324C93123FE7D9CAD2A1E9A559,11CBC47301F850DF3596A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C765FAFFEFF8A17DE76C687A72EDCF8,71853FB74D540B83AFD52000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DF8807494703ADDFFFEDE81D4F3FBB1,B61A4D177B172354FB810C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B66F399537C587B74FEA82BB015D19A,76356D3B5F027674C6672800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D73AE14411A2C7B935A9D507F5BA68C,80151CE2F0D60D694150CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A29D56B89D350DD4D9F841F0EBC8BD91,9D9361719374D3F972E79000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED9E597AC0D022A3CF8EB6920EFEB2E0,9488F7AB56E42346AFEC7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7299CAAD6C44A24111BD8B94456C322,ADAAAE15F05A4F697DA29000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CAF5329EBC9A22F39181985473DEF108,47E4B7D7B82F7DB5AF04D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7538BDF5E86F3529A0384446EA8D1EF4,4EF96C48D339F2B15226B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07F5D01354A04BA9273CFC82D483B86B,E4A07AA41947F5F230582800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E0083C5FC227C3B612C6BED4C5A332D,63108DD54C79331CE2992400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2683E60D1405F0866B833E7FC83E915,B84678DF144CD28DAAE14800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8D8698128890BAC2B82D5B418199ADA,E46F5C5CB48D6E5597D24800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81EE1065B330FB2C21039D8779FC7C75,3351A55C82A76D1ED1E1A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47B5ADB0550E2ECC4CE6874AF2E6418F,91B69B1470354B6526073000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13E38B62E73CCBDF5D7242C08D2A89F5,85EC66414C029772FBDE6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70235F0E7337C84322AB96446FC1A833,D8E94765B1CFC78F829EE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8237581EB1ECD66A8BF30AA3E35D4F3E,32E73E377DBA84E7D4B52800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6F441642D4A71FD69ECC6FCED8BB068,A890FD9C9FCC796DADC97000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40F87D956379B82554DB7DBC26D71D5D,D141EC8AA94E5946EAB2C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E88727F888CD6A47E59B29ECF8569CEE,C158C34537B52903F9AE0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1DAC3F3A141E99F953BABA2CAC38A87,9943AC9F705789775289A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,502D8301980BB00F04D7E5F6CEEDC373,5DCAA4B437C8B14C0E45B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,100488093CB374C14B49608936D33DB1,EAFA1391EECEC311171E4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5EE4EBA9C0E79F25CC2A5F6F84603AB,CEE1079CEF85234D879E0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B90106F8F0D039F5315A3700BA690960,697CDF0D338C49FC6A048C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A63875F2FE66C8BB50398A4904DD3404,C0CEF845910957FCC6FF6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD5D01A15B8C285C55778253D39BD134,8340DA915B2194E9F1B80400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7DB1C19BE6C2F2A50ECCD76376307BB1,88CADD268FC87AFDC061A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,256A9046143884EB2F67AB14850175D2,DF413B7B297755E841789000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ECAB0399732B45954989A362CBA0813C,5139BCF5B900F6229764A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC402D3C33D0138FE69E8E9F8F6506B4,36313C1C57A3D5A0E051E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A5AF91FD7F5CD1737564E0751280729,AE070C1E5A14535629EF1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,95995007FF5EA7F154152F3C23799DF8,E984C168AFE2954852384400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EF782AA97A03CA95FF486CF6F78B32E,6630B29A9777970BB7930800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5C2906DC49A264B7EDEF71B2C8FBBE3,8406FFCBE4D0CD1738D46000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D8CB8FCB97763EBF582B0F95F002AD7,577F959095EA213D7EE47C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5834BF4F437366625F452E94261CFCA,3769CD4D6616561D0F241800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,772B4CDF899FFBF9DB9EA0B97A7D2DD8,B4580063FDBF1DD3133A6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91929148C60545B3F745CF6A56D41C27,30547EB2AF6A55D5FA6AD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E932DD627A9466F58E252394D5D04901,6307C0244560E2EAC34AA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0E3394DE2E75CB2BCD3DD4BB13C194E,153C8946A3A747E6D3690400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F28A7D1B8156803234B4E37F42CA737A,9942F6D5B52517A6E7ECAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0BF0A68F6E43F56DE7B99FD0C9996FE1,D813A8A1C33DC3AD9D9E2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E9EA7EBAB43E8B6162A9F17E5B70323,B62C69C63EC30374212B8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B384329A87DC6F129E4EF6D0E68C2301,14BB46A6BA52828796C20C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6BCF32F418AEFA69610B2C4094269CB5,EC1DD1ACBB3ED4D568E65C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C03029166C297966572C62861BB8F33,98328BF8D1F41B4DEADF1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0529B36F238288BE3EC577E3B0D1C13F,2A2444BF54404D080F7F4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A41C97D2C33749FDB1C42122948B81E,C0CC4F6902D81E7A63AD9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C5D4556093D3320B02C80C100685F74,4113BFDFB09C3748A6292800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B3BBA35D7A5CF7C6D449AFFE93F0A50,91CDEB2BBDE6AB9166797800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2CFA1C03AD05C6DCD97B74A9D5281F5,B4256C9DEEE49675ABCB0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EE3BA1ACCB7420FB7CBC03496EDA075C,5BE80F2FDAE1AA9C3FBD5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6CEA40CCDBBF40EFD818F246A23BAF49,AA6F04E7EF961C5C1A541800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87593AF0C2AFD9FB1578F47853492BF2,A7682DFE1623709AEE063800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8A639319C14F1C89B0ABB64D136BF9A,29514A6DE21DEB47B6301400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F08E8ED904F99242ED85964F7A95F831,2BF2009F485BEC2D798AB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0485854AFA9A042C61A572D1F73C0410,8FA71A3E177267E955474C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,237D5850161F65F6CE1420D4EBD0B28E,7A210D3999C5CB711E241C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C31EBB62770179203514FBDDAC77D7D,7C17F19E8BE20EB76E377400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8FFF12A2CE3BDF4B7F9E620B548CAF0,522CA15B72EF64BBE4A40C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50BF459B3924B07E86AEF6CA47565754,EE64879FDAA0FBFB1CFED000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F04BA9D7DD3D5166495C802E6500D69,6298C400A3E7FAF2A82FD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7BA0CB4AC96C1128CDE8F341CE06B047,9133D5BF5B17D7B431887800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,621D834BE928B3AA065B709F69AA56D8,953881D2A2AFD50BBEDF1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78C27AB36F475466FB70160194D686C3,63ECB79DA075E9B878094000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9BE76B1C0303CC8B952CA8629D175501,8C9B8A40631A160DF30F3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8DC6F2C6DE887B8F9B15080959534E47,C0BBB3320D464F854B6B4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E542B7C86F2FF2F3BB95DB61FBC62DEB,850FEDBCED96F8BA42975C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,271A9EE3C4A98425E1D13EF0A2BF8273,7146E8F7627885F6AD611000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07824A66771D764DC131E363CA9AAC5A,10A20AB726F6006363C36C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B2AFB87CDCFB8A28F01FC12BC0B0527,ACC2A8320B12002C9E4D4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8196A5C8F15421B49DC08FCF11FBB647,C0A1622EA312CC03175B6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D231C176472B07E38E0BE3C61FA7C2F,290F0F22E828A4FE264D5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52B4CE41BD869756BC1263BECDABA56A,74255DFA0AA6776B9BC87800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,391FB21E6ABEBA5B3CB77ED2DD8F6533,186CCDD8573F3D7AF2565C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9EC0E3582BAD0C0B43B31D3BC33811F8,EE6820780F53A730BB586000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47F1CFCA01E1E5FA976ED5F26E24D8C2,B5F12C39244D2D4093305400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,09B3752125A129F41A84094DA47F4CE0,7788E20F4FAC8E370C4F3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21C5BD892C7E1DD2DA55A3DA45467715,D73214EA4B34C5DBAFD59800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5BCE233AA9565E3D27A21F2B7546E20,13CC2525B05358D8ED654C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33BBDEEB22FA51437A27E6E0544CF0E1,19F94C1807DA37BB6B1C9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCCBDE2E5168DC0D0FEDCA996D77AD68,482D6B562A13AB4C1B67E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,783BBA207619F1CBB9044EAE5BAE2E10,BB61051A9C9DEF0F1DBFF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C0E1361E509CA0004A420A41E1D4849,16038E532CFAC7AA80048000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7AA6E63449724DCC8DE68E8D5AFA5301,73BABF62AE9E467A4D867C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D07B9311627AF8F541BBE37E593F7D61,7A9C8872C238B5C2DC8C4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A195A7F22246F5389492B1D0631B6A67,0B17240185622BCCEB6D8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,97ECEEF59A9483051A945B6EED4C78F2,E97F75B682E889ABE2294400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B9D254F1523FA70CE4BBFB5544C4BEF,A08C4FEEEFA9238722AAD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B9F4375D97DD4078504EE625364CF8B3,CDCE8299491D913D7BB8D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,696BFCC93CC4CC64B2EB5E826C8C2219,09835434E7139BF0B90D2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B77A6C4A0F884C434F4A6E4FDA14276E,A6AEFF174AFA09654D14B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C6DA8FCE206CC03FA59EFAACD0BD907,6CB2E37A215DAD381A787400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1CA7C35309FB7ECE5D5219E176B50BD6,7B2008A5489593D7BA70E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C388FC5D8BAEC91F29005CB86695E682,46952E2042FD4BA728BB1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC2DBAAD2F34798AAC7D6BE151DC0A69,7B56F0DB0ADA555E3CBBE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1B2A9F3482BB5F7C4884A021E072128,D11EC8DADC1E76064D794C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB9437BC42C29EF5EA57F5738AE7A629,ACDC6CC57CF7E950C5FEC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A779F9F9247D0F86CA92F36EB3D428A9,63707C9FB8BF67C7BC68D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8102941773B0B7D0B69B63CD55E81501,6C6A24096571C1CF59BBA000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9A6F2E81D56C4BB6E73E2E508558889,D083A100B004B33198152C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20EBD97079542ACE342699F03004242B,D7A46BFB9150D08712629000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC5E3DA672DEE281AD27E32122B9B36D,86E78B56EADD64C2A54F6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E9F77D590ACEAD911C0D11EEC7FC2C8,606B827B6D73312287D9F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,05440E31DEB3885973ABA57B59343041,D175AD1E110F9457575E6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AF82442372F760DA698E78909810CCF,094CEBA17CEA543968351400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B231C433B53C9EE33FE1B4544631161,920A60F7EDAAC3AF94963800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2DA294961B34299A5CF7F83F58B6A06,6D5BCE65DF1B786765FD4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9EEE58193DA40E3ACA6427F53210C456,6CCA116693779FBE108BF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91893F03898BB4893837EDA553AFCEE3,446395A9D20D15EC20546800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FD56A37A515E98523EE17593BFDA8DA,4386D1476506EFA5D67D7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A57EBE1E2500B892E31681023A931DC,94A83A69B6087F355241E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,62C0673D8DF88A630BABD27D89DAEF9C,41863287B5A85F9F29648800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BDB6CD049C2B27D6F56BF1FF602407E,6499BEECA5277FED7B616C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16402A54957BAEB151703031790B88B8,CDB52ABF00EA032B9261BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A317167BA191CECA41534D6FA504AFB,FB27A373B24DF6955A0DC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F140B40C1559E82231122649271B3C0B,4630E6390D0833A29A2E1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0DA9978679975EF89FEC8DD578B75DE7,B172798D19F1270657081000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5E0A8C4B055F3437044E355476F3AB4,449528393C21EDFD77DBBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48833CA3136C59F16A35D53D373A44D0,3CC0E89847E648210C501C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6233C40196F570765EB55E159D8E5F80,B974B4B9410C682D04BEE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A4199A244B9AB048A65F2C5AA4228D2,A8DDEB16790C84D4B6CD2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1468A20CFE51B3CE82359D4F2AF6941C,BA10D23CA1874A38FE2A1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A3CB47062BFBE36FCD6257EE7D72F88,A2A9149381F57E10C9545C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5A5363DEE1BDA47986041C41C8E34AA,6CD228F7E612AE9F8241E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,944956CA8654D73D294421DA6EA62C51,987C0884830A27B7C10F1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14F62C203D2627EE9093FDEA95BCABE2,52FC66E7FCB74AC837FAF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50C11C4253D2DAB982CF8711104412CB,6DEEA62B0D68F378006FE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8DC47A4D50019F1CD5DEC362D2ED9A2,7461F7817B8FC81E5BD2A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CEB6BD0BFB463953A646FFB41B1AADAE,21CA435081939219D163B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13A2DA5D51A79E03A0E1EE945870DF4F,AC77A6CA0E2C0D6D39C7B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,990AF9AE967A25B431EC263897441315,92BD9D744C43028DA5395000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B6D77887C93ECD7EA31CF77EE405DDD,8FAEC162B88C9B7AC0507400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,65AC3F7C936506792B81399D617C4B01,633653B209F9D44D2D805800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A06050078CCEBAC82FF4E6C70C3C7E66,37DDEEBC33A3EBEFB9080400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,209D949802205B077CBE94D11666254F,D90C1F730DCD5A0851461800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96E1732AD1EEC3849E86F2EF1896BB6F,E15CFB24B0DF81A7DCE1FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C46CFF71BC7C0649C57B66B11BC791B,0BEC49EE8AD752847955F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A38AD60A6CF2B1F19327E145EDF31A03,2C065B8EEF112FB3D641FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A36EAC16FE6DF1D04F03921D429DA125,DA932D16F576FBD408B37000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AD321016CBFF532341C3126C84A4F31,476572A6736CA32E0F5EDC00
diff --git a/src/tests/comp128-2vectors b/src/tests/comp128-2vectors
new file mode 100644
index 0000000..13438e7
--- /dev/null
+++ b/src/tests/comp128-2vectors
@@ -0,0 +1,1024 @@
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00000000000000000000000000000000,34B4225BF16B96E118A85800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00102030405060708090A0B0C0D0E0F0,A892A8EFD6D33E3650372C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,F699F0BABA87114F0350BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,000102030405060708090A0B0C0D0E0F,A5B4C7CA0514C4E1B25CBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F918FB140A2D63E10B9B3354C93D5816,C1AD6FE372383E0D6AAC7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CBFE7E4156F94F1E6ECA59C194A9BED4,3DEF079216A74B97B4ADC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B65CB9DDC667BBDA3F493FB4BA2CA2E9,A846E7EA48C2E85F1C115800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23E0F6ED14ED2596A3B11453786E7C2C,73280CD483E7DCDE26F94400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB5CD183A1D26D1CF75D5987D20CAE75,055DF715899926BD0D6A0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E99C6D07A0914E101FC2094406FB46F,0A500680A860B1678C749400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F9213F7452CC291C6B64F990DFC219CE,6273439D25CA01E321505C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21C5CCC4CDDF8D016F82788BF2863718,404F028B1F31A67A71734400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1561F279CC3FC8D7FDF7703C3755003B,7081294CCCF3AF9D87CBBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,360EBBC222F116936F55772663FE0131,D30CD39641B7771E2CDA2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D7FDC4BEFF3E172607BCAFD0FFB8414E,656222C3E481A1AE7B42BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D832114007244CEB3B05AA50F60A1DC3,EAE9BC2A4D1DD802E9ADF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CCB8CAA7DC27AF527F75385BC9CC943A,2A43B559362A6DDED82E4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48BD98472929D5D66FDEF005FD1B67D5,0EA9FCAF684D3416C187C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,97A67270ABC7807CF3F7D2D668D9EF2C,510DA1D26FA933C86D0D2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5CF1FC3916B9631D04E763003CB0AFB1,EE2E83CF08A00B0A1966C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18F91C80B5CDC5A5A95A187EF66AB0C0,0182E8AFDC4092FEE382F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,248B68303F09476AE2E72342636E6D9E,D78DF0808D19FBF8B703D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,340D4544F8559C61EDF7F4216E70C576,2480A75BF304AC7AC73F3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CCFE030B6436D949082ACA45077C9193,85A18AEA5B9BC2B7A376F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D0754700F6A1D2C704921EC67AF3ED2,2D337465329B474F67975800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9165BF37C63326F8CE9CD03F9A1378BC,DCAEA3C710D0D67DD5B3F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DCFA432DFC4F1FF19A441F32A5D8597,F010B99B63B7E6F75DE6C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DE9D2AC71DF86E5A599017A692CB4B8,EB93C952E8C616D6C2979400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,261326154E44C794F5A91935182CFF40,B27DE0650A1FC35AB045EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3F299BB3EE46BBB4ADB5493B4A2CBE5E,67838DEDAA2242B6BB237800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFD033BE76FE261250042457B40445A2,863CA702CF08A47B3CBD5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCCF9EE60A80EC9F7BE413A50CE60869,14D1B0D8254D474C999CC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A966B4A739358CFD6EF22A9A660785DF,6894BA1EF235BFA46A0E7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C1F8AD801A7441908B0597E186EBF2C0,C4E9F13F0C19A76F7EC9CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACDF541A969C68703E5DE37ED0B7CA09,832463CBF662B2A72D4BF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,274F7ECBD2AF639D9479FF4C73815E1E,D1D5AA0F491ED442716D4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E4FC9C886E4E5A8EE89AF61231857CB,323C4D161E55610BCB0CCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E0F4130624669860131BD80D85A3F1F2,07DAEF70D14DFB9988C5D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD8C39429A107F263B2A5F596A501905,1417946345034965053FB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A95D7E54A42604BAB557A0BDA4F50CC1,D1683BA6DF50CAC2508CA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,140C6662233AD66D5AC825D80A9A8272,A0FAA92970DC0E98AB406000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEA61DDED13D0E0F2DCCB71ADD551B7B,7240AF352D215FE4B4762C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4C84D1860B03C3DC2010FB6AB3E4C47,30576C1054878023B505D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,747AF0FE3B3E903AEB6191EA01DC9F4E,4CBAD22E8500464CFD7E4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E607B88BE14E5CEE43594EF51A0725BB,1D79DBF69D7E2350225D9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4002BDDC83EF54ABAE5442B0A8E976B9,6CB6D7673428D2D2E84BC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB8B27FE3F278CFDAE085F236A0A28E5,06407FCB02EBF61123C57000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6883B190F8EC18305BAAF6429E817BC4,C17A6B9AB444C1A9DD448800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18DC6B25398F64FAA4A740C617E9D591,F88F9FA28DE0500403AC6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2735F287D3AEDDD35C204628322D3899,00F5692A5F350599985AC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5FD7E3F81F3671F547B94D9F6BE7A348,FC9DCBBB4FD0580F9D196C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A316F08F912FC534D8E204129C78974,855C814274800A5C45B3B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,960CB8BE1B5025F3EBBB55EB0D79890E,E1CAF3B52DDA529D0B694000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,282461C3FEF2ACC7F53E640AAA8279FA,52F8D1327B2A1B5319025800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BA4DF10402E2E5956DE8DA1886CF14E3,DB2D97F66B679B4D12661800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33B82F56356D44D6A790ADD4F4CE9FDC,694EF7DB3E35F50726159800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,01FDE145E42A4A0F7CC97B8CF4A216C1,4391900FCA30173E63A39C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61259899F937B7403B2EC70ED9D32384,F51BAF50F8CE1A64DCD25000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E6F0DC32693A7EF677C37BC44CE8600,C110634B037031745F401800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1283E739566C46FC1041C2EDF46ACA63,4C74EFAB8A6522A010F09C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE7B368B575950EE69D82D3CEEF59E7D,FE9FF88A94F0A490335EFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB0D3AE84486ED465CFD507F6B321E2F,76D1679FAABBBF1FD3E79000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBA5E23EED1E43EB3AFCE2ABC5FDF71F,022E2C5CFE2B4C3EBDC41000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0B9EDB4BB979E3CA9630F8CCC3FCAA2,1775CD2F9C4A6DCE9503C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A68C3FBD3A74468D486308DD1412D31,77249441DF2502778FF3E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9AB0D6DCD8251E4BBB78BFACF5823C7A,E7499452B5C45C1A7D15BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B62C6CD3A87425B29DA8E226B28C3617,D4A1FC8107EFFD9ABDB01400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A094A045959D9A589F3BBD28D908CBAE,A20ADDC80477942E1B390800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C76356D4AB3CDEB6AF36AE27653676F,F192C4B354CFDC97186CD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,04ADB833E08A91A26BA932A9BE9DC4FE,A86826C01F6B291290F21C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CD25169C9CE123475F394ED818CDACC,F0219A28F767E219F029D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,758F9B775D80F66C2F46F45C13D14EA6,A20754DA43C43FC4C387D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,501418ED3CFC481399ABE1522CE9FB1E,42764FF7641AB6D55C796000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D7333EFC9B3DB86C43ED4A440BB02D3,9AE0F630A52EE42058852C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BEE9E64A0165F7EDEDED06BB7AC0D11C,B436CC2DA8B4E083D0967400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A342BA3D24D7CE59E44C5F1E6F3F28AB,47BC33CA9A6D94596C8B0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,423580E3B8B42BE68E2FCF0805A369A7,34A0F45FE614F578B9504400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C81DF1E755DCA874A97FE2C8A2030A45,2B5D9AE2B659D2920CAF9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00B065F6BBD7142C0D810D81348143E1,0CB323266C1993A44D335000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D0DE9876CCA615D16BE541659FD8E0A8,F313600462BC4C2BC056DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1C02F9836A1C0C334AC68873C1A95DE2,E913C4B6BEDC8F011042CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC2686858921BD2A970F3364C1BD8154,CD6AB5F8BE1967E637F11C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC5A44CE58F654A751AD1F87C7468E22,E5B372CDD142BA7523ADE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F7B93A2ECA12B2F0A7AD2B550781A311,AC1D56004C3DB4248A2B9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,95A26343BDAE219F9A77E2D68B8D9715,B8E2274BA75A01A1B844FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9EF207AF47750EBF69E81669A0D7168,90BE7292A33AFF976AF50000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB095420C757A88E23E845F90010CE60,5D5267614E4868BC9019EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,43DA2FBE69364674ABE7A67EA1079F7A,11602A06755795316CC2D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F3145932F5712D7767278650BF038C3,62F7DA68B860F0EAC85AF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6AC7C8825DE45A64EE61E175A4212CA2,1564273CFC0D44D3AA813000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A81B3F8E35F3B77A681E581E81992245,DEE4D4C1C210AD3A88208400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA6EDF93A83A4F3390C7A74448F3EA58,DADEFCC4C903978B5D968000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEABCD9A4566FAB5CCC225649A9B51E8,990248308A158336AD8CB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5A9320721897F9C4010CC26806DCC6C,4E9483834C11A3258B735400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A3BD4D5FC62586DA382EEB13EC5B98B,C0BC1F742AF062B2C57F6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,657502B51422A9DF5D02215A3211720D,ACD94B7C1B42B827ABB4B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E601807D685AC33884F10BEE2B0F7155,8E555A2E5483666FF8E9EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D081597E0807CDCC345E64EE06A656EE,252F83F942D3CBF225A5BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE911B26A2AAAE1690541AD7C4AEC12C,C09DFAD45B847939AA6F5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D32460B8EA2DE870AEEF9591E2B945E0,415F30A507DFB65D21E92C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3EF290EAC6ED5506430691F6652AD256,BFDA7F8A4AA126AD5D832C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96E50BC3013669B9453CECED3379BB9E,3127EBB45E2170FF88B6B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50CD8707C942E07374A604419F328627,997A146971E7F9F173930000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F5D436A55F52CF178EC755D9B851C2A5,526DA1545DB57E300BD2AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,59D00634939E1296D628D762D098359B,29CB71E3C1D6D8F598FCC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A50B3BB3252C3C9E16C12396F3894607,A1107E2B8910AAD9F4098400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89F8344B973576425ABDFE3466A7C99F,3335275BFB59F6DD11903C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17095FF0861CCDBBE7EC9DDD97CF9FD8,1952EB05C39002CB2533F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00319ECA71633B48AF1CF6050FF612EC,8DD0BD48A4287D3987225800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE2BC8ECEC5406BAD2992A903A516162,4DF20DADD02875F1F6DB8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2719B57237F55AA6F967EFAFFAB491D3,E9584869A08303981DDF3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E9895484AC5350C6020D47BECFE5FB53,183CE56373954D52E0BFF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E4CCA78B5FD8FEAE8F593DA046F7D39,B2EAAA3360B2AABD8923C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F3B1A9F9D5F83540037EA0EA78A8DE90,12147C976D7BB13BFE9BCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD32C4C62D3CE942B5FFBEB6D4A5F2F8,45407DABB4B14DDFC8FA5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B34F7F0BD6B2D777C0817F82E3052AC3,FDC03BCD2DBD999561344800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,83780E5C93048E6A2A060346ED2BC544,6AF2A4F18731A281B75B5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B64A86EE50BB1C02134F11CB431C5069,36AC5A0B2CB95F686E3F1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCFEB28D9732B937496FE96CD11B24B1,E23CB44D586FE9FD19FCF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61664DE891B324D7C1402E7B80C68B17,EE3A9940C7A09853F8D9FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B173E8CA34CF9DA56DBE336196941EA,F703154C9730C5AA58FBD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D21217A48E9EFE24B4704EC10B85C6D,D56C16F7F97B8CEC06BEF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFC69A387F0435BD58C13FCB913F60DB,5F63F9197F0028ABC70F4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AEDEB9AEF7408837DD4BE51498ECA4AC,1216B27EBE081A8B58880000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14A053B1F95E86448F73D2FFEFC7FE3B,2B9BD41CABF325CB93BD8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6881901AF0FE3333627FEE84795A70FA,651BD7D5B6DB33C5D1B0EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,196577B50A4C9BF7A208E4533219D468,5E251C34B40822FCC476C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2ED5196DC635F8603196BE9549BED8AF,BA9B3440ABEF67B108421C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE09F4C92966BA06163AA644D6CE5D7D,E07AA3D335E25B9303671000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18A117FDE347F64B3CA01F0F10659596,4059BD729905578A62A29000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6877CF2C157251B5A97904F8EB337B8B,2B1A0A31984ED54C1D3E4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4236F749801A93FE1FD95324A24CE1C8,2092ADDFF5D50EE60E4ADC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B9A4020F7EFDA03BCFB46FE31200708E,80685309ED5215AD37C5C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,574B8C41C4594499D037D3BF5084F167,218AF13232BA26852E95B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D7E99E0D35742E0D80A85F243606F28,1B54FEDD20031F7C11533000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40EB7A728783CFB17363744C8960C966,ABBD5EC9F78951FC73C11C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C7826A1F1B40323CF57C7909A83E2D2,91C94F666B08EBA4EF7E0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61E2456FB48EFBDB946DF0A3F298BF41,9E39FFDC1C8573E4DF224800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B3BE969A08BF4CE4BE98D6CC0BC7309,152512315F2CD6A3EC1D3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6C41AB03860DD83608098111AAEB4E9,57A99A60C2B9DA9E26C85C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6CD88694601229E809C13775C4E761E5,18017C263C41817B9ED6A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,53F16F6A6B6D2513CBBD0D63CBCFF990,115CC0B613458C1F17DA3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FAC9C89DEAD012D875350CCCD6DF9B0,3CA402F00396AE4AE375F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61C960DAE03E40FC1F56BC1C71D37E06,4E5128E99E89BC59D51BE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4DD845C43A81DF92E90B83504E159B85,35C382EFF558E66A0822F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2315D98737F65C690EE46743434DC239,36A2E24DC3B5834D198F2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A63680047A7750B42313F2D3B878662A,C3D10EB4D222A75C63383800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3934F208F33EB583661F36869C73FBA8,890536E7B8FEB54E97526400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A9F494AE875A5314FC40DEEB9DB9985,A14AE3B8501B7B5885947800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6BC8770CA7ADC109185683CF4666D9F,69748080DBE0959AACCDBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D2EBF8E248B694CFFD41BA7428668159,1401C448FD719A421363C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7AF83C2D4448241547B3425A8CD34C0,5A8B14DBC9E50CD5C3616000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D95594E46451C524B586913F80965237,830C1CF57919CF7C3CDC2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C00B2713CC2E4E2355DA502E1B521001,FDDFA77D186A5B4BDBD12400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B8D598E6F13F1236DACC84E456F0E01,B471887B4A040637264DE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C652FDF2912983742E177C0EA30F2E61,C42F84FD9CD6E7FC37536400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B655E5F7B56B51D7E254A9AE69E44C8,48721AE298AF66D7CDCC9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A900B611A5B17D82D4A2EC8E6544090,F4A51C7F4E896653E5140000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,554C91377E43AD28215056E8AEA5DF4C,B566C947F785B9B830080400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,54725198690B36F0C6A4DE05B0E79E47,BBBBDA64D8B739E6D5038C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0BF03AF40DED5898A8D1C657846ECDE3,4EE99919522D100349F9F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,971B0989CDE6313ACE7690BD2C2BEE09,590684B1A33F255BB9D40400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,32E1BE35019575931694A33B7B0AA049,BAA62EC15FCD29F7BCC9A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B601512FB8D061C1B6F7FA423733F8C,82C1C97CC83A920346C47800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0A3B5BDC514E4F20060D83A61A9C711,684138DD3D04B3B15E11CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F2F20EEE54D82CBA6FA087B242CA6A8,7F445E9AF2735B2C29E33000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8F357399AAD7B59AD790D55C55FBE3CC,86DB5E7D9F1E83A870067000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,511141F30BE586D039080ECD3822F2EA,D358B8FFEBE9FF38F0EF6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B62E2C043BDCC5A1741ECE60DDE598CC,D5E1BBBA61272C8E9375E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F0F950D094BF35F9657D68E5018B9A8,BD37BD448CF9A5DDD7E87000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE30802335604EDE8F943169A72E6A68,EC184C8434883302B00D1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DBB9938C7C4B14E1D5D07DD616B4E0E,AC5A0D23DA694B6128547C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D26257D4C9CE19B09774A9E0C86E335A,4C8C3DA2D021243593C7EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7CD31F340EE67C49D651E1C3042D2C1,A20D985A6C900427C48CB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D763E4A31FCD50F595E4666BD91B8EA1,3BAD6E389FF168688284A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41DEF6924472D84434CE2C7D96881F3A,B0EE0C304599D3AC58018800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CDEFB71C93D7B5EBBD6CFD85EDF9C12,7C225B5EE5301B2F71E1B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2A41CBC63F2F8D34FF1E47FC9B7660C,DF4D16A7EFB8B8BB68450000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F490D52DF1330100CC6D4EEAF8253EF,C501BF91F2BFF6B811393400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,124A768E3593AF51297D2740AD0200A9,4CE1215F737876BD5E89C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39B8F95D2406756066A53C4E705F5190,017D2D2F27C605B783B7E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F4511450C91823B333BF3372B1616CB,7EDE3A2F55D86D2692B00800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0762815735FF7B22BB73A35F2B98BCF3,C5F15A6612CE3312682BF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E3A81D6C95B5BE0866EA8E077241131,0F8E225A21CEE88570BF8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CDC633D112AB14B86799836799589EE0,41D8946A92C3F5DD4D4F5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1655B3EADFAD31AD5A077A22DF28AFC,16D609AEE5FC4A24CCDD4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C73E501E952DD572189853B6BB173A4D,A9E890D3DC0B1D4A0B295C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1D2F09DF9A48878D0124C469BD7F413,35DF82BD4899DC7437B6D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BE1CA7C52223B34080503DDD9F84FB7E,8449AFF4E3C8F31BD76DFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,44D343E09285E36C1ACC9494753A8584,624DB556732775366D708C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61D91B4E360F4F5C7EA25DFFDB081AA7,8276AF99F7EF234573014400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDC7AD732965351CEC95D5AF89254921,7E1DB73398B30B957DF8CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A944BAAFE83C95B9349782F5974B663,5A51D44FBD0A2BAE38195400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2941043DC4CD9975CCD5B57B11055787,5A506CD76E9E008F4141C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5547C0BE6192FDC79A0E77EC8E7D726,6CCCCB1940F444EBD2FDCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A53F937180266161BEFF102A4AF616C5,5287128B3152083765EA9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A15EFCB21BF0E8002FEDADF8542D8B9,4EFF43E5E4F8FEE77F8FFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99F84D1074D0E4A89AB99E79894D990E,01A6BEC2FB1491F16AD90800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C09FC1D74F44970D826CD75BD76E4C6,4AB57C72DE6516B54FDFA000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34C365219A6CB004FFAC21098E9BF4F8,E8DACB225DA9120AE8B7F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,64938FBDE2C7C8BD27DE7DE71D936F8F,EE4AE4535176DB9BF2B7D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6F53EF3D8213BD92E370F9565119A36,D3F4E0550CA140F329096000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A3728A2E35B9109737BF41A7CE3BA88E,AD7857ACE57489FCE8475400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5A46566E17F20CBB22ACBA0829B3A35,53188D1D79B9AC71E12B7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49C327A37B243C502211059ADC2B928E,92D49AE27BAF11CD61DF3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C013269FB730DD9B4B87867F285692E,7F977070217337C997B27C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C08BDB2794795CFA4AB1626D23AA49EB,4248294453FCAC270C119400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6650F32A56DB39C02711D06D361AE5A2,AC1869DD89ECFC26E19C9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD10CB3DEA808A7D0C1F666AA3FDBED7,15CBA9F20FCA32D7F03C8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C088FC4AABC5D08B3B842E90883EF20C,B64B2FB41EB4CEA224AAD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C3658205884DDE93389FC595DA95F3F,A9C1907D30E26D51BA496C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D386F98BEC1386870DD353EF8BEFD0EC,9F2DAB5417E2537C78DF1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,32D13296BD30E931C2EF187B9C07E676,099E66F116225F2E5FCA5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B3F10C760DB7647994D6C1AB8B0E27C,88B59F43AB9F746C3AC3D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F56EFEA97E53ADBD8A28E6784D4454C,A3A64F72AD0A3D1414876800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC15015AF77CA3472D9C722ED2C6765D,202ECCA412CA0903D2E46C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5DF5D4D07734814F50D24C28D4D133D6,75445158435F68E6138F0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0AA8ECCADE7C3DDE1E33CCCA904F87A4,7C36F6063668D0871E35C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D5DA6CFA0EA9C893E0C31EAB8F07C265,A4B70423146ED051AB678C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA0DAB9743D4641EDA047DDCE7AECCA3,43B666DCFFAF925608CA3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8B74AC8B6096E5884601F4E1DDBD174,1E8E15E0F1743837DB3CC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F60A4B2AC4B3FE14259CFF7B9B9B9DA,6EB7E1212271898211BB8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3CD19D5573DFFD6E493C4DD7337758F,13130B7A1E66FF00ADD89C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9836A1AD51EE33A05C1AB926D13177F3,803B815E3D4A015D69AE0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A96EE958A39E9F57FD81B873F32F0C6,82825219B94D4148364CEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DEF7C00F0ED8BFA5E29FB0316BA10293,C1599BCEA9E04812F33B3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF8A6B0BCC3285827DB9D471479A515A,60236043F506676EE874A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4332F66E5C8FE9B2A374A807ADD3489C,E76B4BD39247441C69731800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6B1A9D4F4B82AC72D820EF143F52BF1,BFCE82DD74C8ABF9F4C3F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41955313F015B3E391555E7EFD20D94A,CFAE1992CBAFDC38113E1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99F3AF88D90DA2AB226EEDA86816B73C,385E9AABC4B633422F7F4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E497BC27A587261123B53562665A0421,EA6B9CAF5418DEE2B0C48C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A881F3D91DFBBB74427980D76B6331B2,E1258AFE12F8EFE020B58C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A5FB6205C5BBA89FE76DF2D32C9667D,04608F77B0B37BC1645E1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E282B8E50A4C89F996967FE3C97D4376,A34FA42A7429F439A09F7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BEA1A3C719CFF988D49FEB1E66BD4C5,58095EA3DFF0E4F55C649400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D21207460046447600836E81933C2987,5D3B6182D866461F597F5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,86DC003A1E7352404118C4A6BDF522D2,522B03EB0142EB27B813C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFF92D1920F3AAAB2ECE380817DB739C,8D193BADBFAB72BF8AB02800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D169D93541BDE4543214B3905A573F9,3026B85156E7E48078DD4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E8B626C2461A81224E29EE751E578E4,DCEC75A33337B20D084DB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5DF990790E1F9D245F0840E90C845F9,5D43D9C00D5DFEEDA9632400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F1733D5BDDB0FC3BCFF3A095EA63FAD,C3190679E66A34EF6A7FB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47E6B7544D18B2FE7A6910368080CF69,8AFAC9EA29F6FD5EF3CBF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A015E3BC2CC8B20D1F9BD245BE00D935,6F8DDCB4C9CECC28493E8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,850745B3A941130D04F76F07BB7DBD2D,CE82AA1D16E2D020A1BE0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F9EE213796256B136B6503C06FECB90E,BCB277A4EF1AA561D1341000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,326CD7C58707E7D934772FA1A14E16FA,B8DE63537B49F9985ACFCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D495E6E54EEDDDF0EEF870FE4952568,CC5F16CD030F0E8CD1A58800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74E8879783B60C994471D29F7D06168B,376BC13CA72BB41E5C3DDC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9EC9382241ED63D96B4D1C32344E1AE0,D83B4BECB683510AB6948400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F35E046CB410739F29DDBE66DD5F37D5,1A5A5308BA48B041DB62D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,286C8D04A4E136AD2871F6173640D84A,7A89F034584E9F8550028C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A16B18F2C459C143EEFF761842BB578F,484459E01603A7A52320AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8188E3D3E1C1BB3193E45E3D300FDE2,C1B8C534338CF19DE6EC4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C04D2F4663E98094BBF664207CA5AD8,35187E89549EBFCC31894800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21637583D2915E0AC78C44BF8D6B8529,73D4A069B4EBE3A7F9B3C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7D30DF857DAED4EBC23AEFF59558B1B1,1905B164D13A1493F43E7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0761A9113C550E71D4A001D6F2651E62,191662FEB0B15243BAB64000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DF95FF090CAF75AC07F888E70F60BCD,58EB8C5A5CECAAF234DDB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A4E9F6AAE94DE7A282FE59371E75034,14B519C690ACA88942B1A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50A4BA3A673775C82A273690ED2FE960,92EB9C62BF57A3462A081400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89E484024EF1C40A108D261A39298AFD,2F2903D5DC9FFC4AAA17DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,10DCA6BDA94F80E7239120EDF9231AC7,67B830467AA2C76B8A83B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70A961DF5CCF1C45D26AF50541C3ECCB,B19AC7232C7E7ACEDFF6F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B338E1357DBAF14CB0D1AB035928F71,83EE66B91C1CFAFBE8C5A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F68F8CB5C1EAD184564C0B518D2DF608,35E056CBD8D692CB54555400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0B4F049C406ED5FCC1AE8FC690BD520,9556CEF79B478627D5D4E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E8F808AAC6301867025A4C7B247FBD8,58950816A5768A4FCCCFFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC5DAB1E100A506A6114696EDE6A064F,94A4116760CE7D8897D08400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8601AA0166D16DBE7320C9158D0700EF,F4E00766FA137211703F6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7D0E95EBA4BD16E3C6B538FB723FAB93,3D231451211EACBA3DD42800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EB41290ABEDE397978C898B02219908D,5EB704A737FD1C97848CC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,230DAD3A95D90EC20EBC8EC573781B06,CC0A164A00B54DBF2BA99400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0769460FA069E0DE021693AF2B923CB3,4AD863E830BE2F6013FD8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCF8186B27A4D60588375B514EE8217B,6BA6F69D924AB5B806C22400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E17C33D2F1B42CC9CC4BB68C372B86AB,A315B3B4BBF2AFACF82EB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C74127FCD69A7DEDAF3EC080DD794C2B,A288120EC5E5D774E60EE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D148DEDDC094E552A75B362858807E76,037A7E48A6E230437E1AE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,91F0824B24B3190318CB89B0758B6821,D608EA0088C201318F3A4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F5D92535D449D7412E16856C9A9CC83,8C126E8E0155CAF47607AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22D7AFB76E71CF4AA209B7B5B8711551,7C7707A33EB1CAC94FE51C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8848CEADDCF76EC13D5D5309594E7A58,7E141BD3C032FAAADDF1C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76D1736CF997CBD643A242F805917ADE,4A422DED87839DE4F8639800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96B7E7197A05CBDDE68CD566E833F907,62E205A674974554C7F5A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,928AFCA1A1DB27340BC5689F9ADCC3FD,9A7A16C8AAA1A89D28CBAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,566561B80926991BC84FF3D782C43533,4C67249BE59008455BAD8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD7CCE408FE4D908234C4B9B7AD4586F,54FF6E91AEFCACE32C6B0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,270BE9B26BFD8E8F399D63CE342C3AD6,BD3B66DBED973FD195CA9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B09662F3C200C2079B15CCA03EE8550,BAA793152333F7B78DE07400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52A0DE611C43E8A2AA08C73B79122EF0,8B619DFBFDCA21ED3246A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,089249127245C7364E2DA1F4B12B4174,1BB9BECD4723DAB665D9B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78A4E8D674E7A9BAF1A2EEC2BCA52C83,1F4A8220DC3B790194AB3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D69D8E89A9DB9FDF5008A490DCA35932,97F23433085310FEF92B0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,303EC59372B82FEEF9776A77B89AD1EF,D62B685B0469F2DCB8431000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF25B6FBA7D5B955F81A196F603DB6DD,9EEF5B576A0D5904CFE16400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A034EDBF71F3789C7AD0B7DD3E2983B7,F3955289B3B925D317E41C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F64D014BCA2B53B1FB6C5267C6AA869,176AD9DFEF9FD87C1B26FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8A8E6665D25A32DEFED1BBFE032178D,635E89FD4FAAFAEE81A6E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D61E52FB7BDDB6B08D79E5727701E327,1A8FC1CFEAC2D83C73BEE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F526D40E8A4791776F76B754BCB6002E,42230C725900932FEEB32C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33274BEAE8FCC71C0547FCD8370F53D1,A647CFBD2B6015A5071F2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71B260044E7818F625536196647D609D,9F6CAE8F4BA7E18167D1F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,494D5B1DD29C4CE82825A0DE60D75B28,747D3A2FD2456A63434BB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D57BC3C7180DC541ABFE858D10462A05,171FA63B591C6B7002CB9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75CDED92F2DA05D5F5A180371FE51F0C,8D6064E886661C7493535400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A188392250D0CDB92FD3E224332F7B0,788924D7FA3700DBC29A5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15D4AC837FC73BA6C4A0FE899D09718F,7CCF880D84106A31F5F07400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC453FA3FDB5BF207156144B24AD1E7B,F9DEC85BC2B8D3996D094800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71F2AD4E06BB7F988C5004A0357F6970,DF76F1CA8D1203DCFB8F5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9ACF6CF19BB44FEB4D95541AFC4A14A0,261B9A333A06FCCEA0D19000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E26329310742282F2B9D1E3DC25033A,15020ADE64D319AA40610000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6DDCDBA584140D229FB839D398F78A7,3073F2C778550F75EC707000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D3AD058E5268095511BEA6976BA94D02,6C2CC3C6B0325705D3393800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4F0FF1E5296A93BDC84A3B0E03CD043,5DF3547DC840423AD633F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC5F59D24CD8961B0872CD4264F240E3,4038666247DF1CBE432D0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BC9CE92196AEFEDB4A9C93D9CA8A006C,3EA4747DE9A8B930EC780C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7FDBBF43164D9C679C09F010ED57120,A0D97A4D4B329DAC3C1D9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,885F62DAEC03DC5C7C3B6D2985F1989F,8E8C3BB5767DEB1A84B8AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2BF7BCEA0DAEEFED5F1B9BF67C59C42F,3E83E6A4BDA567C0C1C37C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A90204CA9EBEDDB0E8E270C232430F4,FE65162A4E81EAD4C0FAF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,983A16E1E9F06C1E16CA66D0024295A8,A31960B3BCA0409A77D76400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,894A65F0863621F6F4B0F7D2DB52AF61,EABDE0292515ACBA40C8E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F12067DCF27C55BBEE33B0856124CD88,82F1FFC3EB594F53CDF39400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81821C13A89580DAEFA775D37D75C58E,6DE6DC3F4AA7EBCF3BF69400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,296F16BACCB5B66E5316A21A82E603AC,CC5D42E68A362BC4EB60E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5AD7081575AB7E65BA8DF2DE3B6B7909,CEC011CC38CA5ED64CB93000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84AB79B6A3A1F005563210592BE8604B,63D53A5C888A72E5A18E0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06DB39540FFAFC31D275F3E56EB15824,88AEDFAFE13E7632EA7CC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E38292FDB67242052D0A445014910D0,41BBF707586B1FCCCDE90400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A371E96FAD96E1545D8E8808A07E07E3,6A58E0D91F95F6DBB18CCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB10FDDCFD8C047EB0B51E96048CE459,2DC85575F29CA4F11FC36C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B4307D70E43F25A9CFFFD56370BBC94,9F3DD6CE52DAA89234550C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42FA4C38D32C541EC2F1AD27DECA6C67,13D083584650096DF3789C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8FDEDEDCB6E23CF14E6EEA25DC419F7,09F8ED29BB3C6C40A9196800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F83B170565F4977A89E3E09477CA1B3,E1053E83AD4F056439AF0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C2EC5FEA03C78F65D7D711DE30D76A6,CC39D08EBE81752FB84A6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1EE80FBE225CD938D1800459985B61EA,688E5F40E8C20BCD7E90AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F3D06972170FCE7CE9C7511293846D9,D90B439D68E4F9229AF30000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B15AAFD4778B30CBEBA6123A2DCF242D,416073391C2A09D498896000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F39B05FDE23CD3513FC1F9426CFFF0C0,C833CCF0BA49B3417F93C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D778CA42BBA1BF18D77DFF99BBEC939B,F3878F86134C23289EFE4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E54F1991A18C175859242DB288BC581D,589458131E50C6D50B946400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C5BEB096F9D117872C665B719EE1477,C39175020428B806D442F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9412AB06825CA3411BBE178480A7D1EB,70B4716B4A43ADD6217EA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06EBAED1B90E8A2D25C3AB1973905D5D,ECB251D81D64096720ABA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD229FC2ABD4D5CB1E24FD63EA77AD66,4E74DCC86725C9249311E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D87E8FE1157A93AC00DD5D2948ECCAA3,4EB7C5F4A40577BA424F0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30884DEB37B796F54A3C04F3A86F010D,3A2F6B2DB3E7387C9B85F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BAC80F40908D0C03313C33CAE26F5DC,9646ED009469732EC3EBCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD302E7008E2683A7244AADB9417E501,7839F2AE68BC906AFC06E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1348D0CD2910306D9118E9796E303C1E,FED0DE5F032BB902E4354C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70C3FB8FB3CA6942BD7C1DF5EDB10180,7E9B37DB18F1AFC4D28BB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A4150041B47229B850660FDB84B65828,D8A37D0FB9B2675AAFB9DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D67CF90EB0C63FB4951C40B5F91259E,7CFDC3D570F1E7C38BBE5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88017172C4612F91C89EC43868C6FDF8,4E838FF2E0008654C5CF0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23B4A866497F2C4A67353B396936CFC1,3FA08D495D5063E30EB6F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED2550ACBCC9821894FBDF3DBDC93297,A45019C0B1E78F60BA837C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,43C6573D014B23C691BB0DFD2040E9C9,2901DE457C41F792D77D2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD204E6AF70B423ED521A4B3AEBF3358,AF6620C0D42EC71B29135000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EBF14EDEEC94BE21F6E2521841B71B4F,C32B0095A611EE1FCF8A0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4354B7F94D37F8974E8912FE63E65ED,A8844009E0A67032FCB39C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F5F2AD08E071C324A2A0A6FFC77B441,61BB6EBDFFEA61A3DA29E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FAA048F624863639327522D41B31D392,971B2475B2806A4741497400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E98C633FB91EE72FC4F0CB18119A67E1,FBDAE08872C1CCEC77EA8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A8815193A45732FF6CC06AFD49F9316,F26191BB253A328C7567B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC8FF54ABE8958DB01DBE87E8178A69C,E691DDCFEF1AB2B6B069A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,027469E5A3803DC4C2876D95C1C678C6,2438B8CBCA2A88A931EB9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5159283F05722548C74A737741CD6509,D46ADFFFCB068AF092F12000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6AC3B272DD8CC8BB745A8D0B36C211A1,DDFF97F3223A4B6BC232F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AA83372D1D5EC88F72ED111E27A448E,2E229F0F997B25213222F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3E7608319DCB2A0E65EC9AE2084EA982,C8B76DFD9A01A240E1B5AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2841232946DE470D2FF755C70C19905E,DDAA67B52DCB035E9A2CF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A944542DF2373E12823C99DEA8DF170B,0808D4ECBC4D77A0158FD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2138146A6A0E2E642053DFDAA9E16BC,74EF1291ADB07C95E02E3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0DDFDD1D9A82399E61C371CEA1F9CE38,B58BFCFC24A6D75BCB169800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9FB3D625B946962B54E2C17B20C42D45,D7D987D5BF9DEDA710CA8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B55779FB61B29B8BD86771D0BF16D63,3686F4642D1F419AF0698C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39E34A86EC6FFB7055E7FAC2E0C974C4,D271890EA753A7883B0D3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4A93386400F4CA3FDCA51846BE80335,457CB81CF3489FE6AE1BA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A313371F69544947FCC573B943DD9183,9F548C3892CFF8A485074C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2012EFE25DC9AF67C46C0CBCF2EC7591,4E80A17F41BD8EA8C55F1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,486BD31661FFCE74A65CE0D558850D9F,B613B59771B8352D12C27C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2186CAAECA47991101726EC2C6F6E67A,BEDAEA0EA1943FE1FF221400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D42D4D87D70821014D0CD86BC38DA4D,A2D95578B1FA0E16B0C3B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4DA30AC34F7EE91EFBBDC6DF5555B76D,6937A53FF44D36E61351DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,795C15464D421AF29BBA1907DD10F028,629184CDABC11E3CA0C56400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B3CE0E7908B649E875005DE7E7FD1FD0,24C51AEF24FF49A4A4747000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D957396D9E3C4AF53C89E45C54DC0A5B,17161024C0F22E10A7430400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,43B416FD921D9BA3CDA47EA123386302,9810CA384A6F6647E51EEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B03AE1B7D664FC5B96E2A914C633D89,DC3FCC1CB0099F7414302C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A6BEE40BA96A40B7CE9E6844DFA73AC,E9EA864579D55C68B4B9D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70FDC71A73F676D9C4EA330754B901C7,049ECEC4A332DF7B51D98800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7E61A21AF6B328C26E1D7325DFA25B36,D7D91E06B4C43EDB795A8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C666E78CA92F658FA60C350504BC09C6,4445B12A7082935CBEF71C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55020E9C0982E00235CE187B034B8591,3B0A8F08523A46377BB9B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED046D0B7B672F496ABF1C835EAA3C84,64C19D9FA085AE2270B45C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,175A73A9CA9507BC08465DFFA9B8A496,59D1449FB47C046EEF89A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07C70D392BD451EE506780DFBD5DC83F,12B436EB13A2F5EE6F3B2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F91C460017B34AA789A219167F5224B4,D4557BAA009D10CF37E70400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DA7C45EA6A64514FFA689538ED5ED53,4C6C7DB8436151A89E15D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E87DC47A13D472C5DB246BC2F8D2DB72,F587FF0ADB6832FBD5257800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC7EA44A9CE859DD79E3D01FCFEDE8DF,7A8E075D75CEC76E2E79D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A03EA7604753B3C008D3DB463A7442B,47CCC2AB07276A6A9BF0C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0017953B084C3B7424D0687D9C02A837,4A0117D0F840E0A91E2C6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEF338BCB48C15A37795C69AFC7C570E,EB007C6F30EFF093E499D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,53A6A76FED38FF6D62777B449E5B548C,F00CDCCCC10ECB062682A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C70D559D6F8B8DD99751D56C418FA35,E3C5F362FF9ACACA40A3A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9CA9F9FEFE37D57BF633754AF7B3634C,2534834DE550FC11D9268000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C23013C1C3C0954638F9414DF49E0B8,A51D6BD87F72607CF707E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76D341F1D8D1C65514A96277AA457C54,8900B6FD332891AFE38D5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,647466BE40774C458ACE1760FB2CBFFC,EB85994EA6C7F2A785620000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB0CC7E41AC5D78A9A09184DF4F90553,21A4C2684DA076CDC5F05C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,582C3F28F5E1380932C65D3544B7BDDA,2006B84F9FD789AB7EF88000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F823650EEE1F31CEC3AADEFC452E429,80C0352D91A88126384F8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7D0288577305FB4CF1979056E527E0B2,F37749459DF1409694865C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,45566B3BCE18DA92823C95C1D28BC600,63290D3ABC575FFE70B0E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BC54B44285B1123AF6D3EDA43A5446A7,0787BD187870B36B47403C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFF23EA0922CAA395D87CE8F71E686FF,EA9A6507116E59F885954800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81406FA900C3787CEFA83332ECE83ADD,B9A1B23CF74881FA72F13400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17ED1CA689D152C83DDE7C21298B1621,B9DF2AD19F79E00D39BC7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD24FA43CF93AB8F615A2CB55205954E,8FB777F02793A4A9E96BF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A60A9D4076A4668ABDC434CFF4F4BF1,3874A5322A30FC61EE2EFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4A18EC0063E6B403DE774801F83366A,ED58E3518559614FF3CDC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B4F77B27473E3E9E9F37A270B85AF0C,3BE0FBEDB313262BC0BFD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB88BAA258597D5459F9B1279809543E,67E5E4AE690246C0D9E9A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2951495A11BADAC3A91F653349FDB05,3E6FBD4969707A42327F8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF7D610513988261234BFDCA9174D852,7D1721E9A2057DBDFFC78000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACC7B916F1D53C75BBB5EAC0C0C9155F,5B50D39BE87E86DB3FF7C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,463C7145B20B01098C16142DCD76F3E8,9D4B45528F381B44F58C8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E5E028DDFA0A3C0C879FA07C9FE0B11,366B62B32BB6DBA922F9C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,131524709A0F2C72CF897E34BF7AD533,8B444B299DE38B10C9931C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B2BD87BFF31207E0584989577E010E25,58798AFBADD4F313CD4E4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,878C4B8B7047A04F24B85A039CF1CA08,134AAC5663497B78E9ED6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4372DFCE989ADEAF69B3CE5541F2D44B,5A4EAC4D5B411199843EC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F4FFEF059262212C6A9440F4BBA67303,2147ADD96FADA5C3B0A82C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ECAF923AE9D823A2B5AA234584FA1956,A7345726E548029DE8C13800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF988D41A1D5C109D0706B2068ADFE14,C3CF7CD2693FFD82DCDF1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,449990955002E4111D56E0C20946C6BC,63437E1008262606709BAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2EE20958580CE4F8A8BFEFFCB1D28D0A,C5F9DBA0853C4B619979B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6AB470BD27B24DFCE750B3EC08EE38F,2E4FF932B76DC48617597C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AC1D7BB4F58B97A4973F3BE4AFDE91C,5E1785F6777316F60EA67400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,495AC23A71E47B790E70823F557301A7,97A06E87B1351A61E82E4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F62F24627A42462892EF3AEDFBD86BCE,FAAB2671E38D5F25CC2DF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,60372B92D3EE37510355F7CA2FF1AD89,248B52F48F946258FEBB3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A6CF14AE01A0CA1562D639A97AE49C7,31F7D19EAB76B3A4015E7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D0FCAFC71D9A145F839F11688295A8C8,7772C8610A17D87744943400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,842DD75BB5B1E7E201E248663A83CF62,4C43DDCC9F35ECB2ECBAF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,45AC11764243D64DFCDF35443F498A11,CA15ECFAD53D0E487DA51000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0A05481CCC3E9759495DDF4D061F7FF,5284304B591163CF2AA35400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCAB0F4F0DC5DDB74F6F45C3DE45A890,1430B0D94E51B3F0970B2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96705A918F3F7DC4779EEE959DF56DDC,11CD9894491DBACE093D5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3324BCE404ABB6FFA1B815FCE3653504,10B5BF4FAD33E64AA1446400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,69C0EC0F65DB292E47D77861648220C1,BF307A6E2EAAC31C03ACD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2CD92262C563D16CDA7076A3916B025D,C3DC96C3F8982607CB34F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3874E5B8CA16D381A0B33E8846EF7678,826BF9A7CE95C140A965CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3368842420F16B5476313F02B16B3CDF,0C34B5F2BBD5B6D336B5A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,669E584D4DDB2E1EAE7E914C8541F311,B9246D668912C36EBCD2D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D428F26986A1C746CCA262426C7C0B2,7BDB274C86342B7068033C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02B97CAD06351C5C3CF86D396020026D,CB2BE5BC456ED73635071C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4696D369884E4941D0E087B32E09D2B,2BB0A12257D862AAA55E0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4EAB87DA796EC3488C342BDF311AEF22,23A0BCDE4B0DCC2C8D89F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCEBEE5F1C4C7A4E8A83B6D4CB236AEA,84C90910A45004A63EEA0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55855957EB252F0C59A6B1EC4506B9A3,9C693CF049FE93DD6D755400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDE4AE6CCA16EF7FBC9AFE8067FD4E16,1E9A9CEDCA101D2193375000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3600B73545F54A51BFFF6ADF932AEBAE,7CC316918A7AFFCA973BEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,202D67833ED8B105BDF66722B7E64F7F,540ECE8E6B38E99DF7FBB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1868360A46FACED93D287EB937EED141,EBDFE734375B0DAEE15E8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F65A50219A711BA33E5227885C5BD27C,E87D7741411E095602402400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCD82A0A445AC9373D96BB9CE8AF6B61,517805CE2B3DD5310B6DE000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC6AC085B92AB68E52620E350E1BB3F0,758E969F192A9B2B20B20C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5A32C2C398BE819497923869A8D3316,97FC978698E4FF67A0F0DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7BC59BE121995B4AEB0332CED5A1198,B5CC69159E1C6047190D4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,827E9C6B80997F053AE704994119544A,C073B256DE3FBBEB72696400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7702362250B6F5F6F323230C598F9051,1BE3AB6CA52CB8A98041E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00E5A0BD996A84C310238A05A5AE7495,A31D2FDB0196FA415CD15000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D9CC3F666512DF3DB2056CBE7F62684,1026ED1657B49F41317A5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BDFA3EF9D36448BAE383A49FD6A977E1,BB2F552110C1F5872EDD6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18D87AA310A0CB9B3CC8EF54439FFCC4,FC770426413A7100746FCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,992813CB979D33BFBAC54D55CEB4B73C,D0148FCED4882E99B5550C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,833856A2E8B0EE42A5EFDFE505A2A98E,C21F2CA3950B24C3D5718000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D16805B6CFAC637A2A39924114036E5D,322B554745D2B0DC386FAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E627A1B378BDD2A3ACC7486963D69C1,00B201FDFC3C4AB6C6633000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,86F68E8A8FD9FE2457E9E1FE47D2523A,E4FC49F68FFEF7ECBF3F2400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F72BF5374387A730D780174FFFCF41EF,80396F47B01D853208C4E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07A2299E7A5F5D56C0070412811B02BB,EC7B17DB8911F53B2F97BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EE2F57A690134B89D2E4B1C219CD7E03,F492970E081E648CD3366000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B2DB578B1D559A2778CBCB0216EE5144,B3253ED8496B17C05D7B7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C80254249001719EA40C51F2C4BCD4C,36E4172968201F89069D3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1C28E94E15762073DBEB812F5F1BEE2,DBED6738EA5E202530C78800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F784B5CAF051C4FE137D2FE59A28C00,D6008F9F45FB8CC50677F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39B71CEAC0104DBA6743E2EC285BF7DE,01FAF3FD3A79579778F7BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,261756F9DB55FDFC1116091B8D6BD58D,50FCAC1DD42FE079AF7BB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57E47170F70AB261FA998017D838199F,88EE9756212F1BDA4E12BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02DE5B5F4AC153124891E768B5E3A1B6,B42185D92AAB6A18859F3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,224E9EEF82B29CF691BC9463D9FFC129,DB92040E46BAB90675E89800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,524B0B8ED727F299E59957FA271A50B5,456AE3A856C6FF5A6BFDB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,242A954E612E1F0194CE8493A4CD1C18,1F607A7E1DB1212B24A6E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A61AA82441B24BDD06AA6BB2CE77CF27,58FF4B1B3DFBB3E3726E6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E01B82CC43D3D72D8CCD60C92C62EE09,C00041D883E5BAD0BF03AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3AE3E93F044396DFBB5A529A26DA2553,DB62C24686FE8014B399EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,653A180F0F7C98B94130A5C40BD11EBE,9B9BCBC09E09E8D559ED1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB92A03B9A262683AA1A39CCF8866BA5,BA1BDB72BF6C2A94D92E4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C79C8FC1619F413BDEDA3F9F8FB7AB19,2334AFE1C799B9815C7C4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71DC6F9B718457B72CBF948304DF4168,13230113D8C0A23FD5BA9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A11D3C634DAC5379B5970D401EB6C512,CF9956024F33B4A965371400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,05B7355A6962EEB393814579339EBC53,CA1CD0788A724158BC84D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D494D03F59245A4FD88A87C4E842F8B3,C8409116E5BA783DA8B89000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA2235589D8182BF643DD68FBD3924B6,447CC4020F9F87565B5B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3537CDFE59252A2054E7EC1BC16C5061,9C8D45FB1480BE389112FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D81AC6DF80593B62E4CC6D51EBF682BE,DF6CAEF62BC536826FCD7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EF6FEDBC6F65EC72E71DD457D7F01E39,545AC9FC051774F6ECD97800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A926134D19884E0C5DFDFED7E5D43926,315E8EF19510592D48DE8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D40A68048F84E3C89159DCDC2F6CA432,4E27DD965DCF6CEB40489000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E13A16536ABEDC92A087707F6962664B,F54DF012133B0CC1D91B8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,443F8F2A487FE8CA0E4E36CB0394FA2F,FE5A205335BA7EB4F9EB1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4CBDFF21AE06C34FBCF8BCE67A33ECE0,1A80583C4CDFF82675F59400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE08B54548CDE074E31630B0C5F2545E,47904CB4205016ABEDD7FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16C810823D7C5BF3D5A7DF540BE927BE,BA3C7853EE826A7FC1E8CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,493E34068D98BE1CB0DC488E4215EB44,A10DFDCC8CF7E13AA9F48000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B16221E154B8E737705BFE4EF686EEA,FBE1504BD0786AB3CE8D5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,40067BF44F7EBEEC97866D1D2B589C0E,76C385ABD7A3198D4B2D0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AEE48475101B133756C5260C974C3CDC,B6B159E0B62A3E135CA3E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C337455E7D04CDABF9100A0DCB518C0,7FEF52780DDF19198AEB3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34509DDB0528245C753B34D0A470161E,79608012018A272CFC4FBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B82EC07003C40E7F69415CFB29090181,E31D8D19A1038B6F3D25BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,101CE5DD0A72E07C3759B23BD07CB713,13389C0B65706D05753F4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3508CC1421B61CC1829F1AC5000A3E4,F3A0E53D7E27598C99901400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BE906939FEB3D53EE5E3B3F09AF34392,44F8E711171F64FE3B7A9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58AE77015B346DC96112C7463CE44CF5,217BCBDD9A7A15E4E3B9AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,01EB1E42FA9BFECEA63771A8EC8FF608,1282EA813670CDA82B028800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0287CC4F44011FFB7BFC45C753A7E764,EDC47B4AD2F99E044B773000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFAC099B033FA5CE08C1E10751436B0D,774EB65C534D5C554A4E8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB57C444B024972E3CF20C2F885D7211,8C6F76D58DB1181A94989400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66B10CEDC32FC796527D98A4B9052E0E,48BDC529943EC0D5E66CF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9D4FC614B4A5ECBF84C40E3F2B7B3B0D,BAD7D26D697368A3931A5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7529E5C6269C75FCABA03362FFAF0BA8,4428CA3F074553B7CD193C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,290F258C9AE1A88D5DB89D1C963ED8CB,49A6A7D3EE75322C985B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A635EEB118CF0401AA539B3E78D9BC2,E75EB6229EBFCD7651869C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0A8CC5650A8C449C27358D13F5D149D,33D344289813FD1762951400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00347953F59FEE734FA747B5BBB492EC,163D84E824A58AEA21C45400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C1DB2550ABDC1D83D3C6234C1F7216D,DA743AF98691235ADBCB9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,566FFA71F19564E0334521F522D247A9,E40AB25D08CEB2A2E2961000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2BE2558950270CE4EA4F041311B700B0,9D3B8DC6DF02EE2215575000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C7CF5A9C76A34069A0086D67162CAE8,C7C27DFBC668647941BFB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6704C0DA2E47E546BF089365FBB7EEF,3EB8772558CE07528DAFBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A4789958665D25892122D9B7838A7665,E3AEA74A7E4487671C72B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0359DF86F25D1EF335EDECE2F1300D89,62C3FD4450596914203B4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34BC3AAB3035AAAA631514F56C19D85C,9C6C6F2C7BF109B71BC24000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2AE6301993E8679EE9783099EE4B74C4,5827D1C48907242EC9693000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8E688E8C19E4842AC61D673A47502BD8,E937B1C11E000FE617CD9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,635D70F76E8DD5A60C93E636555643A3,1FC3F91D21ABDB110560D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFBD75A9EF7C590502CB305E255B32B7,5AA46577C4A19E56222EAC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52017B0F5A735EB4B4195B41C5ECDDAF,141288BAA0C78E43A21F8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9B7F9780EE1DB174EB3DE3E0DCB4430B,67DFFA9CDC3456FD0ACB4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CCB9CCC90211E81ED80A3663FE9520DD,B296494F844BE19BD0BA5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,094C25D5E5F556578FEC3D09E1F18FBE,2ACF6FC60CE2E75D0A26C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8EC3B41444043CA925036ED10D358A08,5026E7548AE49E190927A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,90E7DF0DE887D9A66C7481D56918E113,4B84AF649EA0CD5F0840D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,968EE15F77994D3215AD0B3B830C8022,353867C1CAEC7F26927B1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DB07381378EFF68414A6DF0B19CFA74,2DA3CF74819513D2FA280C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,905553A290DD902F230AB5334EC3463A,013A682A7041996B08865C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C61792C1391DCBEA18157DA3A5383F7,61BE5406A149B4FF8B5E9400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C1D6A7204459D8394710449B1D13BCE,CEFE606815A3CE4E25379400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52A2764A059CED2CC46E04FACAE047AB,B9ED555DE46B9F27FA452800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,583303EC3575D11BF8340CC10F6FB42A,DA213F2F44A4DF52BFE50C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ABDB49A4B210381D9622AD5822150096,F3672C97FEFC462BDB03BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,711639E35CA2CA66EE65C4A45CDD6380,536057FBB46AA0D25803FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C8DB765506BFF298F89022E51C308B0,89EA94F579D333C66670CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EE21F43BC9268966A546FDD100C3D841,D4593228E6274177E5750000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EA1A2B1A515C72C4F4097AA555C93705,E1DDDB18724B2B66A8D08400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C9B8393D38BDF1065B162DF707D3009,B878385FDB1AFC41854B6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC0493D80DA33AF6FF5FC42D62870052,4ADA9E7AF7F353A9D9EC5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E41565124D918E28E7ED57AE770D7633,C8C8CAEB0DF9667A2D34D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6F4B3D805D5DCB5672FA617066A4B2BB,346EA70E1588E99C88A47800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A66D7FC4CF30B989EE579AA08872713,4BE79F8A52FF99AE1C710000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C901D0043F0660C0A9BC60171ABDAB8,148A92FF28DBB5CB7012DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B80E227C8575C331DA9AE0F4050D218D,4CE2F914C3EB439A03393C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9ECF1E38C9B9103C6185B00F3C4D93BD,CB38318E5B3CF543530D4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BAC15FB21C609560794F4C965685E290,46B7D216BCBA27E2A4085000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C4AA0670C7B8A667728DA0D594069C99,12D51B9D3C7909002613F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D099EF68D7E3D1D47F23AD15AEE4B5F3,93622C70D1D635CCF84E7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B33945EE00E962EEEBDE6A8FF4742E4B,509F4F51D9BEB63CF9B59000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0D473BB0B5BD4DEB25DEE36BB376C10E,3FD579DB817D8A510BAF6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A14218445FC5A8E72C96B1F27D73AB52,A3BEF92801B0252DF5DB1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,494C095A54E5CDB1A1F6095C42D760E4,15A68280AEB04086C3638400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8F90256E47BE4678036609D34B89544E,2396E34F472750F9D3524000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C0927F8F0FD2307F2C6FECE9243F06A,87AFF076277855F812670400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C636207195E46AE24C49F4F9D0B786F0,86C6671A2A8BA28EC6918400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7AD2E1B41F3761C59B29F0BFC5890F0,10574CB3947EDCD7E9595400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C9FE56B04AC1EDDB9E04E352E8199A3A,5C1ABFC9A21F5D95E1DA0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3974645E95D98E4F9274CF62B0D885E,ACCE97C26AA1DD1BB9340800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82D095C92DF409D3473ECA08A5A81B65,30BA06CE2F1AD2A3EAE8D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BFAA576B9A290496C47C3D498F8D4FE6,B43D9C5448CC3F754EA0A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,040B228CF2C6002BE385DEFD7DB55725,62D7DDCF277DDBBB84289400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1E565C0B52EB2B1E24C17AA3848652A,9F8A216B9C64DC5A03833400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E8A846052A19AF00098BF1AE1FDA9EB,2C5BF370EA47936AE4802C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACE3EC57D2DBFF11B9B8A81B4406FCB9,6689168B45E7E9084283D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7414C5D415AB5574A82668573BB04166,AFA7009AE75A5B6E1C8AF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A986D44920217FD956E7C4CBC3DE0527,F9BF62C6B3C722659717AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A08A9B02F531CB9D580DF8176A3A994E,D379914524C2ED1D1B693000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C0F9E924F063A6243865DE1123CA045,D7F6FEB5091DA38F0D1F9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D55B8C7718CF349F906071C76555C986,564E13F008AA9129A319E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0613FF46EFDEB6A663D915B86A9D6C0B,E75538CAD55D599EC6718C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B00D4FA90CD2DA85E1E220AEEFE2C5EC,ADE280F0C17C8BF566451C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD380C653CBF3A927A769324D9E00324,3DD21D2EA170DDDFD5E16000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9172812C62A2FB789825C71C23BE469,765EA88CBA94AA15DD3BB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,59FA5C6FA03F2BD23E35CAFCAF58FD46,546D5EE3655E43632DD94C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F6A4D79BF1DA9F46E41241CD2CD723FF,74ADD5456F2CD3059AAF3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,46077741E91463DCBB61F3BA88599848,24D72BDB319C6EA927B37400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,46E2AFDEF73C2242C2EDA4C690C91E1A,23B988C1308602402A4FC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C240BF323A1B10CF791397D47340B26B,F13F3AD8A00FF908FC6BD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87839B0D4AB1B531495D00751BDCB435,ADAD6944C3392006CC85E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,635EFEF876F6318332BE61BE6B4B83E5,4E763956FC5B9B2C37C09C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A4A4AAFB83EC7B93840A3DADA92F1E9,7032880172E7BCFB8C72E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,915C8330D241274251BD71B7E6D37699,E2003179F7CB405965011000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E20E7DC2DF7BAE037EC7D880B3C26E90,992AADDC12E81003488C9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEB75A96C92304E40C2E0E806E918E9A,BCA49B63865490E279409800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB1806312EF173FB73897A3D0BE6A053,F731BB08A833760754AE0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,64E576287B81C3442F95345C078D22DB,B5DEBC603B1ECE7161C95000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCB334F708467997480B458DB66356E3,CFBD2049D829D9C42D26E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39EC58A24300E932FF9258EBA374ED62,A489F81E6E16D0F436977C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52FE65AB5569A4DDC91DB5EB747AD872,712CF42C24F212EE4B80B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9401DD3CF0C494B91A3CB28A677A6F9F,6958E170DB5879834C90AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A7A70C832ACD99447B4DA063BB40A249,8C4337552EC9121D9C0CB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F777485D595BCDAED8AA529E91A161F1,97DE44F1E89882C3A91A5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D25D899D7458F37D0F26C7D5FD3C0C9,1E9604A46215B01EE4C11400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C75E9C40BBE9AC71B03E2B1A4FD8F77,BA6F3343BB0A50DFC9F54800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E2FBA59B74C51357D5944849B5D5B01,D5312B4F4774EF49E9318400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B48D0294C24464CC796F7665C639A3A5,DEF4ECF98FBCE2A4DF450000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1EE10EFABD753F49C13D0B6FFE567F1,C6CF830856A1AAB6750F1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,328BE773AB9ACABE5EBDB67A72DAB593,1246E6852A5B78EFC63F1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6FA835395102B135A0DF22ED100A30C,F7EC6507B3D8882E9F86E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42BA23DC01CE115FEE284E30D93C2EE1,85061F767191A64FB6DF3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,590C81F77828CC50FAE2322F88F2FF72,4428F98DAC165B709AF39000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD5A394D5AF47943FFFCEED795E55131,7BF03394EA112244A2E53000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4B350364A61282E9C7E109C200BB59D,22A39338B073F44ACC3A7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2EC97054F229452094AB6E95713E2B73,C7DC6BC4D8586FD0A278A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9949BBF69464815BBADB53732B830972,221299171F63C0DF3AEF7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE7021704039DB7C25139864145D2BD2,1945B987B54CB70E5D718C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31E7C45E5C16698DB87FDC4414521085,68EE8B49C4E327CD7EFF1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C9301A7630A80058E6016DF1E61F67C,22E69372E777618A21335800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8BA8B91866F892579CF8EB18BFBCD4E9,F3E2B573F70A66FB55C23C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,312372D0F65B447765758D9CAF2434D9,93609D380DFF429A870F0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA787B420C4399138BE2317A0DC94249,9D8372124BE92CCA0D06B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,27DAE7C8BAE72D001FC9002353E9B64E,4E15629B933D694F68733C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26BAA1215821CA9F90E4CD0690C10F2E,58103A993006A0C200359000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A3D6F246FB435A7FF58E1E88B434AD71,685673795E247655A1B4A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF468FF55671C17282B41DD246D2792D,26BDB78D824FF8CDBA768800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,600272165F44AF4C0E537AB5D8E66736,3C79315DB6DAAEF9EA724400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,508F035C9376D9FCC41AAA7D1CC764A8,41FD7AF4639235E4A02C1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F4D22B29DE342EEA7CD8E4E3F43A4943,CD833E80A4BF33DF3CFA2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58843C6F5856B56CA9198695EFE17CF0,5676CE8A0AE61F33C3ABF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E3C73DB4F5CC678DCC7BFDEE568E826,A247316EF8F882D42FCCBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D37AE74AD0489776723124F6CE81D42D,78355AEA1296483A3CBE8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F43BA41AD0DB41DA4F54FF5D6FEE4771,DC1D9BAFDDD5EE83C1B8AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B65FB4E50DD0050E79BAF78FD2F4B9BF,B0E291BAF797A8275AD71400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8DC778A2ADA661942266E0B86CD7DA91,B9D294C0291018F04A09E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6E293ECCA4A56F1D93C8242D5E6756C,25ED1EE23A3C11FCE7D57000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B5B86CCE2090F22424EDA2C512197C8,A365A6A867B02EE9343CD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F250AC936FDA89F1966C3D3812BFBF4,3A4AB781109515A1139EE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87CF86E273A7A8BE687D1802005D2A5E,8ED03BDAA9E92833A6727000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,98CA9A659D2C4DB1A235DD54BA36EB77,0AECFC5BE2B7C1DC6D0BC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,53EA0452158CD2DF5F5AE2DCAAC86BFF,29A163B42A2D557A70974400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74B58541693349756299EE79D408C415,56D28DFB499FDB30B87CA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16E25268D3F1498A42525626C2440505,39FCE1A8505CD73BA1DAB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,737D32452FEC46C026B249E7D77B9A80,9D515ADFCD93432FE73A8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ADD0543912E4A632AC4C0814294751F9,59D694C394485E65DADDBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F30160AF9D726612C00476DA06F2FD1,6EEBE451744257F9435F6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0198B362FF964F890256674B225AE2EF,DAB5FF67D8925B0DADD74C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F99975FC4D5AD6FDA57655CF1DC35FB3,8396623C8B44C2904815EC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,762CD396934B5E7916EB48D07E3D8383,D597556F2C650DCDAB686800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACFD433259569169FEE586564F056F31,CE6C1FC52C2CC10E886B6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0C3AA12D8EFA599621B8219AEDDB39D,F46A4FF31C0FB6ADA7FC3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88964441874790C6B1AD12C6BB907060,CC9729FDA25819796E90D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF65C58D03260691C1267E992128F675,BC7F343F69A3B6C09C114000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B13CE2B597DA27FB9DE4B9ADFF717495,87BE699F1748597BCFA46800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2680E79DC76B80EE268FEE9C1EC945D,18E19922978E90020F353800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B31B79AB27925553119466A3C845C49,041D5919C3CA2542AE91AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFCA938AC5DDF97C526941838527CE9E,FF7CAB0E892D9AD987AE2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36D5B7252A7B57BE2D4E06879E6975C4,427F72A3254D4BA24C1E6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4FEB6B8FB01025D6C479852FEA000C1,825845CFF96383778D0ED800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E138E7CD58527B7022BD1553C4E493F4,71AE9F089F8B970EA986F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0FD7F38EC52265FC33D60DC9553A5D7,140CEF85332BCDDBC3B26400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F0BDF1C4BE4A35C065EAAEFAE646A01,96E64BBB007D4761869BF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03706861BAEEF0DC1CEA996C3EA93D92,C2CF16AE93CB94D5A85FB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B1259AB7C681443C290E0C1BF5224DC1,DAD36B50AA8455AD5D6F8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E225F155FA5CA852E151B7AD3BC40394,9F480C67DF663A51B91C5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30098EF69DBBDD25FB9C87315D3020F1,51D39392BCF956FF0F34F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,749E0FD7B6ECD4B45E80C6E54A14BD0D,44F77EF7111682F411EA7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A5444F0E7E7C61CFB031F86E62EAFF6,2F65BCBA94C07D4346DF7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C9C7A48094A579C8A989B28848DED187,CB88C47F30FAB985582B0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50449C950CE2DB6E0DF22609E005E175,64EB723CBF43873DD2320000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DEEC383005D68C05C665CF484E371FE,F941903FC1062E6FB20AFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FB3BB14E175FA9172A2741E04F139B5C,4E9CD42E9C244AB3690E8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,24C01EBBC6B68F9BD4850D1BC360FEBF,BDFFBF809BA31A516463A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBF4841145F14A97DDE18D3ADE4CA794,5CF60E45C59FAEAC54A66C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B3AD72EE04894CB4B446CCB338E31656,39C9B3FA3B84200BD76B8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BFD7004020C1DE138BB6C78F2042D89,5BB03480D9B6CA5180F82000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,024D288A0F95E4633BD0B05CD5B700FA,39DFD93B2CBEBD1CBE42F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AEC0EE2B2E999AB36583974C7668FDC,68FA512A754892098A4F7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6BE0D7EC8A11ED5969386ED31F2AC1A0,37161F968FC6655AFE02E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD087BD12284E354ADA00FBD47EA0B99,B1E477DCAE13CA518EEB7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E342819ED86F7026BF73B76227A8CEE,B002DE9D67667700161BEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75D09A20C3586EC73944AB4C216D44F5,8AD9F7E3FD40F9637AA0E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E360DD744AA863F6E0341840510AA1B,478446EF066F048C82A65800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C048603EDA30D4858F8F6C48A9563B41,4D53E54088CA31C0AD9A6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,759445A6138231604DF7C13CCAE4BDEB,5CB44BCCD6460A0950CAB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A91CF2204877ED8903E7B1AC9348BB22,915775CBBD20EE58C44B0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E21BA0D598D2FC61442E32449589112F,4A83081F3332DCC326F5DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,04F3AA9BA2A1D95E8CDEA6FC34308017,D6082B73B98D161CBD653800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,594A2A8792456A71705BDC4E89E2521E,65929B7C79B8DEF106487000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,446D9EEB6FA4D645BB682CB86B8277B0,5AC860D938A44B12E17F0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C951406FF94B294E9276024B879B0661,AC12B1BC46CBCB5AF2B0DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E542E0D75649646B084DE8FB0285C77,65BB3D00B13D1EF9E5173800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1268CF4BAF41B5D12BB865F0E3D8B22,3BE83D7A359D3597AB3B2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36C3C451F2325C18FCDD73CC0FF21B18,4B6718390394E16180E97000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE257F14B53AC96792EA2CE8B4A4E58E,A519EDEB91EFC18B1256F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3F14F22F59C516912AF25CA62FA8F053,F3BA543B2C728E3FA4D30800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A4F5220261EAD5516E8C517BD2ED831,DD66EE67A690B8633E51E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,495C634F6667460C254D97B35445707A,C6F29CFA4B9CAED36E270800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66EB5313B0C83A64FD376BE02E03166C,5E895656A03CE5C83A4DC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,35889435A0DCD4B799BE7695320B69CD,ABFE28829FE27DE9E31B3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,183B1F81EE25E31AB5DAAA33D015CBA6,E80C570BEF8028830FB68000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F92B33E2BF63BF05291C09F0213FF72D,9FC5D30A549A662B0278A400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E12E30F732A3A2A206467BB3F174FF2D,FBF985953AC4308EC8678000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E66C7ADE2AB71A9DDF8BA3A18F9C1302,E2F0A7D8972CA55D5873E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,59DF68C04CB938BB9CAFF8EBBB6C6CA5,A12CE62E9B86E592D647C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5688229644E7F91AD75B47BAAE320C27,445E1ACDA1CEB5490A7B5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8B26CFC065CE0BC44A97E33A5A07345C,75F0660EB010AB40421F8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77BE38B4815AF6DFBE17DD48BA9AB1C9,A8F61F6D8CF832A592B4B800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E73AD699EEE8DE8460F2C01C2077CD6,CA6BFA4A79B9104550A07C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B546F3B274639D31AE0ECF3C378D180,5A668DBD6AE23D628EBD1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57887332BE21016DAA2200E69A5E850C,937CBB32F8A08E24E9550800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F11C61AB9A2DCF1D73D2566C07F2F90B,70BA40635D38BC070B1A0C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DFE7BFB3589E3EB3E77895EDF0130C3,7C0BF94042656E559D11C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7F9F26B1CB9C77524810B97C649137B,CC9F502181117A6015AEBC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3579A2F7B2267295B14F6A2B2F09937,FE52FA20DF09C6BAD47E9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A2C147FF0868F41FF61BD482C7E21BA,81B79CC89B3DC23A023F5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED5E4033949163C5AB820CA16C51AFF6,A82B3722F3589AC19CFA9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22AB205407EF30ECCDDA49B779ADA405,9B570A9C9E89BB11D1C04C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD5EFBC04BE376CADFE0207ACD8AF095,AB4D42353B1DA514E410AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,785180CB3BC2FE8792E424C407F12437,03BF1E622929CAA732929000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7E1DBB304169F6DE4F12151FDEA7B4E4,F74A4BA566896445694F0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A1668D9BF09C4B9087F7640A835AE9C,C467FA442E9052B1A1944400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,096E3A437ED6A342BBA60D4484EB348C,AF5684AA97791DB5F4F04000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,218223AE24CF97E6BFFFFF1F646ED3AC,912BAC5C763BAFB866356800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,32E34FC02745575D7844046B5EC92297,753BA5F36C33B0A8FF19C800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78193A44A12EF231CA47659678D49122,B812FB79D7769618FB98D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C79BDF37D02F924936515FA9191535C,3A3EAA1A02A8770D634AC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9149129D54A114706A17C92268E95788,4BAE933AF24AC862AA02C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,827123B8A0AFFF76512B9A4247F18263,4E176C62EF8993DC49BCC000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7D362E0CAB7936076570676D3B00926,F7142C9528BDE0C3410DDC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C4835D3873B027F4A04E01E09F10B567,6CBDDC9F268BB2523D371400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C71B6B495E2280B5ADA4882926012E6,6608CAED6ECE6BBF4E4C6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4DFAD94ADEFED514A8336CF78DF291E3,BC9E3927D64A5AE83FD09400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39E9E060A7A89B40951170834EB358D0,882709FBBF4C15A53ACAA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,93FA22B2882936519A894C83FB71D7CA,10CBC4E60938FF6E02BF9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D3054E4F523088E4672B051B4830D87,8C235DDFDC54AC96423FD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A9AD3AE912E007D1B7A773CE5995F5A,C7440E0B278459AAA5452000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5DE6E922819457D8A17A4495C432CC78,346894BB2BB3E5396360F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA9D461DE4EFE173DD0F70B21F0EF2E4,897F09AACA45A443DF046400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6CC4A0AD6363AA75173ECDDEF1867500,5E1369255B428A3CAFE91000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A83B7718967EC4E71FF17A13E504979D,8ED613C3B5EFDCADB43EA800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,920D2CB5A77A118740641007D01050DA,5CA75E88F9DDE10943C2E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A25AA14FAC524225CF34796E3B48D4E1,486C8EC0519E9CF7BE04BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,079234F699B3D4F4E10E81A6F6CB4AF2,953C821F1B60AFA612147400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C0FA3B7884EC1F49A1FD64D25D918CF,66B1BE35A97A35B552B54000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4809694A853437CEBC1430403F2C0AC1,8B52048DACE2B2426E64D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA0B1E50C790195CF83E867BBBA1B11F,8A7B4F4A857CBB91D743FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,750AD2FEB9321E8161BDCC3737F294CA,3AFA341A9F80B2C6DECFA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EFA25251D61F8DED93F2DD2F5C773DF0,B05617847AAD49659499E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4372D23AD9D5985A321D47FF3B94311E,2F0458EEAE7C37C9B0D28C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0E4D5FFBCC246C0B694D0BAD0C6E01AB,BB9E49591CDEA7B38E42C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2AF47D04C203797F5EC2CC841A3CEC5,58EFB4158198FF36194F6400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A7F52669369320D3CD5883FA4EA3F2B,6CCC2ECD466D42B7A4305400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C50ED70A1FCF421FE6D3E68BAF7D90A8,DB98CC5763982C52885DEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,09483A1EED2CF60CCE0DF670E077459C,17C5625B1E4B638831C73800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E8BE0C3DF99181656D71A665B2F6E78,8930954F0BEE0ECCE8FF7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E1A3948DF968DACB8B50C7BE01F7457,1AFC087AF7C3DFB650B5BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC70952E477B9CC06C507BEE1B1D0DF5,2CD73DFE8A454951F8F5B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20C31EC84115A792269692DD24318D5E,710E521A571C20908E4FDC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57EDCE38D0847365DDC3E2476AC3E1F2,9C8BA4C70BFFA8D374427800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2FE14DF7EC89DCFC40F4532DA4CD8FBF,E929007EF952A2CBCAA1E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C891106C395E6FE27CB057717252D1D0,426667B142F5B2C6DA154800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E00C2B6A32C78A39943C5C47F2662676,DFF8A3A85B25DC99325CEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEC57F0F123AD7D36B4B6F35703F64F2,0E5DD6F7FDA06422FF0C2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EA718A0C7FA4D3C942BEDBFF0E8C27F,0494E06696570FBC07B20800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5202C1B460DF93CFC147F50DF0DB8AD2,909CBBBB1234814F20B94C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5BEC24FA1715EE2A004AA64ADB891D8,79D301F620BB0AF9F434D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE558B21568C8EC4F96ED18492327DD4,20D3E5E9D2FD6C7B33644400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72CD73EC048C026C289501852295D8AE,A7BE173CBA66C90364D90C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68359A95139538BDFDA335F9766CB52F,D9153BE65D53CA5E79DFF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEED7553983FBBD1D9758393FDD5F1B7,B8CEF24E0140134FCA4E4000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A07B08315437682AFB159924B0686BD,4CAFF446C895B91BE7A06800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C326933EE7F409FF467A907DF0036F3,F80FA736C483EA30DF9A7000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,95F16978198BE120A3080E7339C4DC16,61B588B440110F1176018C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FB88DCEA84BEC2D61D59D26AAB1E5B2,63B99FB3D4828DF14A632400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99052813B4FE1DE320C9D18250D7EC0A,99B838E84079665C7AE32C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58B92356701F585C5DEF34A1867E1164,6E4C4F64265374992B89F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D4730E1A155968372A2796C007DB61C2,F24DBC3188928DD7F6DEB400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31F061BE095DD8F0CB9B12915F677513,432999E45E51F50F160E8000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8FA54FD77B174B01419DEC483C3BCFD,960214386FC602BD0B634800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B69C34EB57A1E9BAFEA2FC8BDDDACB97,D31496A364D337F21BA43400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3DEFCCF108C176B427C6D558DAB2257,FD4F744BDFF1BD5408F63400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,634413A6F936B67FB937E47831BA1744,3D2045CEBCE10C5E3945FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,761FDBAD45F01BB614C990C5DE842A48,7A29FE2AAB86F4F7BC520800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC9ED9B997C283EDFAD1D86D2B4A7164,058544343376B8BE3F87B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81627CD5C956F5B71A9C0ED4E521420D,4E313907E89F9F9B55398000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DCD0B3984C8247B8562EF6237E9545F,17BB7D71DC7324EE7C747400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6F27674CBCD953B4059F3B55F78E8795,14900F7EC6BC6B801CF05400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ABCE668D4532111068E0094A3A100E4D,A18AF444D2BDC12B60B2F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,280E9EBF56FAAD5DB2C5CF73CE296DEB,20055334D6BD65B69284B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84608515AAF1D869F9EE47B6EF48EF0C,78BA397766592C4E05A7E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1692DA2B7086E7AA8D3F3035C7107359,87194D864264ABD4CB900400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07DE064FA13210922ED16199034CA965,2ADF1D09B4ADD164B76D1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75EF82FBCC14256470722FADF3776AE5,CD3DDE9AA2529DD7A8C8F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B99DC3A08EB5341A32F8C62E4BFEE43D,F417AB93249FE05D579B5800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A4183E5E094E733AE11BDD7F6331043C,90655E9480FB2602C4D18000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,28D40D70C58A581E2BA5DB2D8312BA8B,535906A3650D559BBC8DB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13B5B284571B20D9EE9799C96BD40FC4,B71466E5B1F11AD6B8AFA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0029C96AEEAE094A86983794BD582AF6,836AAE69B149DD54877A2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DBF2EC98F31ABBA2722DBCF89EC6A44E,68343042FC4F198337C3BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,083D0ED162BF1A80574B5906CC1F4AAA,FA3ECFC6779C1AB430E4BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E1D795034EC45B8F9821D6CA8203BDB,E816931A5308C59819AC2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4EE4972E7F60987243A9799E63D662A3,B16939018348AF781859E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,849CF4F89D3233F3E584CE0C129D4BFA,D9C2178D63D98597ADCA8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57EDC728BCC2B30DA9B7BED3393C3CF9,CE8A219B97FC38CF8EB29400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A3E2A0D88F960CBB1808EE7211C6362,B4753C1822EE5832EAC3D800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,032219016ED376CF2D9CD997FB3ED6A6,9D99910AFB22549BFA59CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6465F4B9C6DBA457BE7EB0580642E4EA,349CEB847C741124EECD5400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC5EAFC6E0CA5C7811E4DBE5188454D0,FF3B8B9C7E49CAEB00BA7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC779DF1C75EC65275971CA4DDA54445,BDF0ACA83F71F5795FF91400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,97167B93AEAC688D65F5CCA5AA540628,A8934C20176826D8E9210C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6FFDE9C6396DBADD186625777F0EB1C,25D38BAB18E0B1A4561EC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBABE99B5DA9F492794D1B33F2E69306,A2F9EB555D1860FCEB90D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31336FEC645D23BFBDB2F17A7D051ACD,DFE297E427C7EBBB85125800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F4CEA98E6B5D08FFDDEF9E83F02EFF76,0793F349B87CE001C3D24000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03C233F35A8980F0167C9C01FD381026,1B936C46CFBC6210208A5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,83937A0CE40B24304B9FD30B2ADE62C8,81449A34B68F541FC0D26800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF885925FF754C3D2E0F17FEAD4AB540,FB623A02D722E99948756C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B263174AD8926BDBDEEC5E9A9E92424E,4F2D03FD412BB66F8FB45000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3493E0EE360CCA3459BAD5F44C23E804,0C327FCEC6FCD5C9BD410400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1CBE4486B6754A05800548C706835524,A5B423FCA3BC87386CBCEC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96057C428E150BBCBD9AAA18405BC04A,0683236771BBE74B4A2E1800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F2B319F79573629E56759FF5BAC67303,C89F69CBFCAFB5CB5F5BE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DB5E2D4F572F50D2DC637921E46D270,8B09544DFDD6BA2F6D8F8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8EAB71FD2C9F62866607E317946B8515,7B0C4057E9CF10535B275800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9033CFBD34995F33F7530BF78C207EB2,34D5E0DF065F9CD9373DB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55B56528FE385672E006DF3E5F15593C,71D3C14D2EEA2465AD0FC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52A4AFF178091E85625C39583A935096,7EAA20BD18083FAE1FED9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F3F6A273A8A75EEEA484F270209DE61,695C9E3DE158905DB1B9B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B607EFEFC1959FA8B32E0979F241CD7F,C3B8B80D01C9390D837DD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5D74887A6DC4F652ADC13A10D4CDD9B,19CC8430EDFC5FC268973800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A09F045DD589B5223037DFEE3519A376,E60E7F22341E66A3F3EE1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F3E0ABB2B1E4F00647F2D5C236A1B26F,7A776258F5C5649E5E201800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C47160A0897A8422C528D7BFC8D20188,D1D32C73E3DCA58B70BB3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F779D231ADDA823C8F9EE13C5CFF8327,F1D9065561B6D0591BDAF000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BAA3CD7BE838696F2F8F7161D6C8BC07,2F4835836D00DE30A77A2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29D8058453F0FB8777E0116247D1624B,D626DCE8C83BBCAEB1E60C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,962F26AB8CC6CFE7004EBB98219F6E46,3114E64D5E558C1CBBCC4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4C608BC11A358456FD44A38ABECD461,1EF6FD55FB22D74591F2DC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DBC87B90E5CC736D89A063C8E7EA12C0,69A047C836101660FA0EE800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2FB2C67E647416BF2A58284677FACC5,6995DFA7822EFFB01826D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D2FF6CD3C9A5038B9B33755C6DDB410,4A047503796C5AF0A83D7800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D20566CFBFCBED16DF8D3A0284A85E6,835C3F58AE388B93F74E4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88F65F3F649962491D3E0FA045EE23EC,9612855A987ADDA693BCCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6ABB80355AD24C621F34965507BDBB3,98603A29610E403253C30C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C37280108B16E450EEED07BA7575FEEC,2B1FC2879493BEAB8BA75C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F637E1EFDD8A8F577040337DE4817A7D,00E125367FED4AAD7277E000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EDE6AF5E598389D9BA050D5527405DE6,904AA4D51E003AD87D170400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AAEAA56781A803C19F7FD64ED2ED2DB8,EFA8298CB630D5D9C3325000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B7AC6EB7CFE9DB7CBD20B3AC8BE73F2,46DE7FDFC06B8AE2F3A4C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6A8681B7B066BA7CBC43139B22C3DDA,BA6F5DCB9895FFD2509C6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A12237D9124C39E638D56647E6A86452,D25F86768AA3E961C69C0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,07066B004388D3DFB3B04A64AD83B7F7,7650268E5DDA7BD220CF0800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55A2BA46DE50A3C16EDF3100416146F0,5FA039D0354C912D161E5000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6109A82102094EA00C2DC1F5D1458EEF,8D84E7F5DF9FBA1102E23C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F37ED30ED80B697C3C71DC8CF41CB486,AFA2019028CBC07C803FF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,80D00951B03829654F56D8577B2319DD,259B7737DEA5AC6586C9CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4ADE88B1C1450BD2C04DB298627E794D,11F7BD5CD2F0457A912F5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B8CDA8600BB3D20418AC2D6AB2BE0FB,6CB450249C7A80539ECCC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF5D6A632867A1AED9B0591504B6C52A,8976868E00E168C2BFCBD000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D7881B90D486C90EFF4389A071039F0D,F652A1C5A41ABBF0AF09BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31744AC378C3A56E2E599A052133E3A1,990811B8536A91B40FDF3000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB828FC7E2BA095663B1CAC857B1C882,991E252E53D405FA7584CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7789790E921E29D8CB10D2E90A6CFAD7,C0615EBDF99A548693DB0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,631510BEDF7A2CF31DA6E69F9AC78378,6D875FDC78C70F8BCF206000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41D1BA21CE28CB116716247CD1567A1D,94903B7659431E454569A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F98273C34B90E685BD7873383CB3BC7,0C738DC3E630AC6FDAE9C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75BCBDB5B2E23F46B6366229281E5487,68E6EF3AD2A857847D050C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2293CC54F3395A790F86AA56A95E357,B2FCBED0F540FB5ECEC9AC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E92707ADB71C3808BA4E241DF3EDCF2,D45945189B01B92C0ECBCC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B469FF0DD32AC00928D4770977EA271,C20B5CC8B92FF28E449FD400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0FC84522EECA927DFA68F9D07C70B0C,451A254F4DEDE634F514D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE996981505A918727D5BD232B0E157C,646E03E626B160D204C3B000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F388F8FFBDA93A421167BD44F368647,5F6F12C381E2E75AE300A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0086CFA9CA7E7AFE28C4497FD19AE133,928AEEB2868BEDA13F275000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4359ACB771F941FB8F52513D01CED563,393130BF04B3D914DBCFF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A19C58E94C9EF7C363A627A72EE4C57C,B1A84094A806E28A43B57800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C165902B95C0CB08ED5DC0FAF3580F2D,6CCB395862241FA3661D6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26BC352460FD073FE015A410A7CFA935,61E88484BB88EB782141E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C3F3A58186A0DB703180BE8E4AD5387,EB8671AD139925539E964400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E9CC86936DF7AECCA2B86736689DF416,ED230A13BF046D8507B77C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D90CEDC4BB18209C39572AC480BA46A,E011AF24697A323D4CD4D400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D769D834E79706D9D620286FD60B1882,35943940C4DA30A49167C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDAD1FA63E891B0D3BF81D8629FCEF99,1C2DC750B9127257FC288800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,825721F453B177BFEF0BAE758AF1AD2A,77052E1CE9499B1B7867F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F3D588F1FE8E4CA01533D4A0DD9B4DA,141618BC5D4E72E62A9F7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B8A0B4D6916EF18BAD7CADCE39D2833,AEF6463AB65B838A5109A800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B32247244EC86BEEFC52D7C2491E9D74,116F80B9090964FD599D3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BE4339301C93DED261879486C6A8D90,8E23D0F627E7802D1A3CD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C903F42E92B38595CE04FD53910EA6A1,7E92DE635B26DC6051E8F400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A24E8A73014E79FA74FBC2CF1CBAC711,0989A5AB4FA9CBD9AD0D3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F3F558FA77482A4CC9922AFFC7802BE,281A9A26975E9C768A7E1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82910421BEFAACBAEBB5EB41DC83208C,A2D604FA378CF8119DB73800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,53E78DBF2B389F15A2371DCCEE1E1DA2,8ACB8E30CDBF4AF3839FFC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,559E459FD9ECE082963014F6055E0E36,436F9DDD7F7E58599A5ABC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,719BF029031FC8D8650BC2699D5DDD18,A66649CF28F4FCEC3C4E4C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,723B50440DE3F461C4E5BB5BC9CCB5F0,B8686043FB0F1413AA938400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17D769E91662028370034FEFD2876A25,635E411815C51636EF944400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C102DA3F7A14B3A85B2A92A31CA4789,0EC89144BABEF0E7095C5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AADB189813213B480EC68B9678281753,AB74FA76105F492560E98800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5919335F3F34EB77A0D13D8790E78DE2,8B1EAD6A1613CB2D66A6E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6822677E661136749615304BC7FE951A,5C94BA4C4C4C6A1A15AB8800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2CC83DC6F20C2A7CF26E091238784A90,9AFF51719A5284B6CD051400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5729A297D31DCA3C80C1AC10AC176B22,D00E1485CBA3A95D55FE6C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C93C54A70BC96C53D439450A3FF9807,FEC899718D29F53351630400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85CDF4DB93CC4C8317EB38D365154735,091A1DD86B98DC9CC88E7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2ECDC19D1D190EE4E6AEF05FF23EEDE5,5CBE8BB86ADDEF96A8CCB000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0797E696BB2890ED056F4EB0528AE0CA,793D86F92A994DFB06BC1C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C066293DCF36C84E6B3CFE96F94F9C47,5F12425ECEF96D7AD1DE2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBF3B6F26357F2D1079ACE9DFDFC5ACF,1BBE191A388CC485ACC73C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4A0038D686FBA95824576415B778DCC,AC22616B710B0813F74BF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23D7856727E8712982B14CF92F15BEA3,C5FBA55A7DE5D2383803B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,56CA39A1C3CBFD2B69F2655FC24FE648,C483786DD70F46392ECFF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06EB61F4D242712C3DF57BEFD0CDEFE1,3F1ACAC22225021770211C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36C3122A765088E042535DD98BC9ED18,4AFE30D76B2A655E030ECC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DF71036C59630C04C024ACD193606F4E,C69F93BC5CD672FA60646400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A52F96B6B364526C5A69E166586D25A,CCB7F20B61EBFAF3A43D1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C945FFBA58D767D0D10D9F782CEE0187,C9843051992470B4CE005400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDFA26664DEC8A4924CB13A5FC20EE17,6CD559CDDB082F8DA4352800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,12A863FDE1C0EE9B6D16DE221CFCB61A,F78ABDD98DCA48EF73190C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A5F7A1CB88C2C9956749106395F96F4,34BC4920C153F06D3B7E3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,604BDD6E1FFA40CF8C6F96DFCDD62DA8,4984353CD8F24EEF1B6D7400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9587947D970D63EBFE4AD39D0E82F512,339EAC3E342374FC2A164C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A6CD41A12ADD4531D8296CECDB12374,3790B825CC997DA4B7A7D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6E632FAEB35738451AD453137E9F3BE,5EE75C98E3F881BE277A8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD3FDEFF3C7F70BD04683F6DB3418F41,BD09AC2921A2DB430D86F000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,527D3DC8958F7E48800A4061F1B4C52D,616B6E288F8484D1C5FC3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49C88A8C09113B1B20755F2BD890084F,4939E9DE1A45020E61931C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8028EC02D6E7E00021452C58B0B60C7,E5D8BED53BFDDC5D32820400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,205E4C48735F32916A0E1D3F3A0B6B21,4AD530D94EA8D498044B4800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8690268A6F86560B3C5359C6BF6FA3A,6A92D7E521805F27C5E67000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5ACCD297E16C479EF11A21BFE70358D7,FCF7BD1B1EA29CF4373EA400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74B8193542AE198C23C6031F08FF43CA,780DBFC6135777BDF9F79000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA25D7D6F552A94C5481386366D1A0F5,99547CBD65A09C3CA2985C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA5C2F5CF869E6D16ED05925CDD78840,4934C178087623626F070C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B1851E619BA5D0A36461F6267B6A9413,90A284CA11E5A5AC86EFC400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,994A371B63FE48129BCB11984A2604D9,5BDF08835EEF4D01CBE41800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0AE26AB49E6158225D94BF39FDB29EBA,83B81B517E7C54D578B5B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E64B2E37042CB00C5C9624BA2EBB6DB1,F059311F4B7EE022146C8400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCD24B6C00C5FBAAD39224D54B3FE4D2,C8B1E798A5299804F9F06C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEA2A9307DBD872BEA7C42B4517FF856,FCDB2B1870F46D34F2BD9000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6F8D8379339F4B9B6C6C7EA4941880D,B02031965E6AAD7912746800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C7D5314CD07485E80A9CBC3536E8E3C,F625C41964CFF56A0CB92800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B1B09636A93D1D6089F3E8C45939ECF,AB411511CC23630BB1068C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,60BC3B66ACCB2FD8FBA2D180C345DDD4,66ADE7E8DD5FD245FE67D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,080B4DA8017F1C8076BEAEC2ED4C23D7,67219CE095584AB1F3CE0400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36B9E1DD94CE2C7D5C50B4F4782666D7,837763889C34FFB59C0BF400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7426357487507712D1544AF62DDE03DD,E272A3916D75F94A9D18E800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3EC5110BF23B8292F7440D236070240,F98D822F01565E3F776C1400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1E12B4E8AF0B527E971E7B0F1912E6AD,8092FAAEF7EF58F4B96CE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF63EF8928F00762BD9204F407F224A2,8954E660D5557692BF693400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6063EE906F69B00C636C2FEAC781869,56EB75B9916E5DE0192A5C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,967DD337ADAE9A73E570CDCA4BDF866E,0A5806A9778A0B3E031BB800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,98D1CA43D4C21509F98120B0D6A1E7DF,4CC4B4C66ABD3A5DA0638400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D97DF816F20FF7ADD1E41D01138B49F,625867D3F8DC80B255FB2000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E3946EEF6DAFEB57B967823218D603C2,9FBD7D5310778C193D99B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8E81C1A706E1C873CF8AA371322021D3,C588BF56F7CC23581225BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20DA7808951EF3A9429114C3462F5747,30DF8359FE34CE5C0374F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0E6E1CA7B8C4E025636F5A66D09D29E,D45B3366E8740A43367BC800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,60003F3AD24A644CD2D69EE03C01EF0E,DAE6302331046B94B6741800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6E7C6E2615E1D7C356737AC52EE514F,FE3A2765EAEAFC0F938D2C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB1A6886B5DC43DD77A0261E1AFF8B2F,B98EF65CC4BA464524735400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0A0C0D4B354E14F2ABF41F602630AA1,18A96D6E34F8FD4798DA3800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,62BE756646EB90390EC21E6D21BB587D,10401EE31F4A5BF98EDA6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F2B44B17C9EC961778E1255E9B688A1,C272B7FD9ACF088ADA573800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C433B7A9DD753EDE601E7FCA21334158,3B189C41DDFE0D439C0F3400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D998A557E253D40A32DA7CF97D5A29E,EEC272A2BAD8F690B5F4CC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D1B821D9FCF2BE276D723A435F9954F,85004EEC5849D04F018DF800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8A5404B37F54719B284515CFB9B4001,4AB5D01ABC448CF3105C6800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9D3B27999D28125B877274228906EE0D,DA8C14CD5CFD377A8376BC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5F666FAE14359D65D2F6EB5EA45961E,94AA2EB983B386BCF21B2800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06F16C45CE7ED4E6201646F0C750D419,1593E4E1BCCEC056923B9C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,82FABF6D7B45CE4C64EB0C6E9DC502E8,F6487E29D164CAC32D86D000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,541F1AC3AFD74DC7C70D6575555AD55D,86D04EC42CAE37F01ACF6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C597908361D898A0413B7A66354A6065,14AD14240E876852E6226800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,200438F0979DB724420285D43B2179AD,F293B889DABDE43C1BE6B400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,739E0F37032ED78A0913D042A8C3FE4A,8DD8DBC7F999094FD4F0E400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16A8AD7D1C5631CFE5F4CB9CB9ED9163,6D3F95B914469F0ABBB81800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC81B47EAB5649E55A9F6E0B93B4BF49,2BA8B6AD2E1E2B4902330C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B0267728AD6B956D254EAD2B770FB37,C03BE3BC733D51F61B1C7C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,10B1A550E224F719E76D98ACCC2C85D5,7FC28C88085940FB0C555400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E71F7EBF5F6D8804D1C223EB722BB46C,58742C27AD8676AF08918000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C3F8FDDD8FCE4D20174F6286CDF71F1,7CFD68608E450A2D7D20A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99F18874776E15A839C2A3E7C321EDB3,58B30EF52C693A4B40BB0000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AC814B518EE9ED843E35E8EE9C25409,C0FDDF957DE317A4FF92FC00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17768D68621DA8385EF1348B274F372C,44E1FDBBAB1D9EC1E358C000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AB55D41FCAA07EC8E8C94315F698D793,5A2F087594F2156AF1DE9800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6CB52163A5B7FFE27654B0310B572B6E,98AD77BE4612570C68FD3C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CAC07183EEB34F38E70334AB594FC570,5927855548220C340D283800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,71B14D3013D7651AB586A96FDB2C55C4,CC9BF8358407E57A3B448800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6081353FC28741F50C7B103D6B2907C6,AEB5F267FC32315C39DF4400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6AF53DD62899A5F9336C3A52898EB0CE,9BA4DB7E121A278A11EAD800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B746DC2022342A402ED432B27F6B243,13305D58C682BFF823F3C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B16EAB6CF2E07F8A3AD61D2DAC6496C6,4B890108A901763F0ABB1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20E2CEA085C2CF1B0C4706E4F8CE9196,21EA802F554471BAE0D64400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D1CE68C2764772B1264B93A71E305D3A,297C675B8A2A277866A7F800
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,504B4718D7CD40663A3FA48E87AD07EC,ADAB984B10C1A3D0A14A1000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C964C6996F55F06AE5320FDE2406007E,A023AD3226510F472CCE6000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB308E478D79556474FA4E4B53FC151D,5CD9540DC7AC8A3566D90C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29EA1AC88BB26824AE83CF126990FD0A,69E85D6AD0832BEF5629A000
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,873D1B21E6080852EC53F65086D30974,0F17A7DC95E6E47C6ED51400
diff --git a/src/tests/comp128-3vectors b/src/tests/comp128-3vectors
new file mode 100644
index 0000000..e2c7112
--- /dev/null
+++ b/src/tests/comp128-3vectors
@@ -0,0 +1,1024 @@
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00000000000000000000000000000000,34B4225BF16B96E118A85986
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00102030405060708090A0B0C0D0E0F0,A892A8EFD6D33E3650372F78
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,F699F0BABA87114F0350BD8B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,000102030405060708090A0B0C0D0E0F,A5B4C7CA0514C4E1B25CBFED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2FD8EB45A807D375CEC72D3599C1E04,F123A4B0D526DA2AEB199FCC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,059BD4242157FEE159683C03B1530CF1,8CD58D5C05D24653C730F1B4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A00543B7F4AA6F5938E3915F1A04F61,9CB62587973B8079FFDDAA68
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B022CB9F45B6F2E05986825EB60ED3A2,DD465462764C701D8E07230B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C36DFE0444A53EA8D64666EEF095829,68DB77768CFA36F5D9584C2F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,65EB5166053C36EBE4149CA8E032F85B,8236AA79048BF9FD23F22CC4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE7F96A0CA6743F4FB43725B65C98CEF,C3D19C91C0BE1A8A80866991
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA93097AC1F7FAD6AB300291D7378320,47D77CC1AAAFF848FD02EBB6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7ECCE6BCB6A960BE9F347FA4BAFF9806,3F9CE85AFB1B11B747E41A1C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,537CECFE605EF84CEC6AACC26748D8DB,23AD4EFE3BBD5437ACD58FEC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77DA6AAB1D63954F7EB121F69939F087,3782AA51C410DF352D5BA4C6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E6989BE6CEE7154543770AE80B1EF0D,E3EA331104D11B0340EF41C5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA3C9311948C43A88A81F9F151218628,DCAA5F8ABAE6FD1FE3D994A9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CBAB8FBD3E6268579024BBE465A085AB,7A08AD916948AC88F285F679
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9E9545BBAB220B79C11B4268E4AF22E,76F8883C06A19A0F3AA0FD70
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F0260A9AE9FEE9D4463888C7E2B58DB,08EE26FD13A86CD1AAD5B368
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A3451F2C657E4BEDC052AC7E42A731E,A8279A6015E5935099372857
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1B858F9D05C34D05BD5D0483B037071,F31AD0315CC5E86B76B97ECD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,67E29E6639A94DE8CF774F21D5FCD211,6ACFB2184DD373148D5D582C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66287B28DA9E5A4A3674842A416580E3,0EAEDE610EB9744B2B95913A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06CB6DE4CF812D00C494C2CC088D7FA8,D41C2FB8F696C84D882DCF6E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06A7F31DE8BC76B51A3D43968930B60C,9CEA8DC24E04224753B9D218
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29D36234576AD8395163D1CC9826167C,16D467073F5958EA424A09F5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A41667DE9BA1AC860500C4ECB359EE3,22AC7CEFE26F3A4CB98E4B23
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15999866101B177430FE614EB17E76D9,A1332C1FCE97402B4A743D8F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C02AB81126B1990F77F810B82B797475,3CA34AC67EAAB7048DEC15B3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,47061308D6D2A8B4DAEE2AC7A44D6842,0282A3DF9C9A981A22572231
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8BB120BF99F7F51DBF66B7CBEF239874,3B915FC6905D571E0244A15B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2BA369767520B8C1E2CA69166546D1CF,D9FA973CBA46C79E08993ED8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E867952D2484B31C4DE74554B8CFD8DA,D2C4A14D3FF5550E776E783C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,51A70B24DB7DFC4DABC254C6CD9BA81D,FF770276E357757BF17B6A03
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D79459E2FE6E8E17510C4649E5EBBD43,DD587C63DA11D7A39B0E51AB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,992511517261548767BC3A5EA0269459,3123ADD2EBF5C4D7B3F4197C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,38112A87B58DB889B06F70A35B2BB039,EA4365FEED09E1A34304A763
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4DC4F985E69146A65C0A853EF5C307D6,57B9BE9FB46D951171CF1DBB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F08DFB812F799107F8A817C6A93504B5,5F67F38F8F729A1A34468A50
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E7AD4225A84CAF9662B79D8AA4EC60B,9CE2261C86FEC23836F8C25C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,904503A6A4B61660F24330E74C49183C,8D434E4F0B2518ABAF9C92FF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC0B25783A74FE16F97AF6EEC84799C7,E4869E47D43D385ADD6FED7B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B351F09F9FC46188103A266FA50BC54F,DA4E687A478A4C3EB77EA5EA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,453DE3EDBBC72BC9C65335B47536EB38,2CC578A40472AD4C336D3880
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,250133698D0068AAD95A2E0FA356FE47,F7BDAD3677641DC625C40A3A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,482A117B4A39F9DD842E67F376E4AC8A,C7C280868DFE252421111382
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7B435E33F800DEC7881A5AA6DC7795B,68ECFEF6FBCE86F0145B2710
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5528C93204329236879A8D0EB66EEDF6,5A3B116AD3A228DF0C148E35
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2BD00A4ABA3837E76379B9C0257CE95B,DBAE1F2F91E090C7F250A576
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,897FAEE5AD4A10D443E1E581E1FADD2A,5E0FAC279B3DB617F1D79E74
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50C13D10436296F6511294F0659346B4,6774D9611D81D2B28EF62CB8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42F5D66DDC05442E1B394FC346AFB794,AE323C87CC24BB8816555868
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23978478FFFB8DFFA9160898AA04E67B,F9E28ACDC3FEF9C732506146
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C736BC43FA36DDE8B66F9E5F5F38468,836E479A4C3F9060A5048129
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D0F54C3DF060F76A908CE871B5A15CA,2C8672011E95771FB6A01EC8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F300DF8463DCCB4D8222A7021B005E92,19243A7269EB1F75402A01DC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7177B3EC6658F41C7245E773138A0F8E,3790D6633E9FCB095F1D823B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A2FE0B12CB713888781DCE0E90B4776,CB65E9845237344F55D7AE1A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BCB63AF37AC2DF53B077E413B588001,00DB17E0FE288237A333C4A9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0A650FE37B236732D4B889CA6A6C835,7FC46A51EC2B7BE0C66E1A6F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68B09A32A5459C6F6E5472109FC164E1,C8F1AF34F21E61D9CD2E6839
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B57DD3CCEFE0F33E04EF164B25A124E,A8486968444DAFB51C552932
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3CA34C720BEB4E2FEFEA6D04BA4FD876,2B1C5B57D1249DACE613F90D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CAF61E2E3773AC8891E12638871595C9,4E03646AB273D7835417418A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B1433F3F651E0E478A12AD2163681E48,0204AEAE7AA03ED2B87985A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,907DB9ADC521BEAA511AE36FE1A8084F,96E8BC8BFA3054AE764A8BC2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBD2E95BE518C72529FC67918EF9AC4C,9461716327C1CA6ECD8E3DD5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5EFA59CB1257BCEBD7C52842485B1A7C,FA69B871271C6D3BBE9C2C0F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B170AF028368F19F26CBEE3EA04B69C,9801411E3847223CF3F6F5DF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A03489DB2DA7957AC574307457C539F,18265685F3F9FDE17DF568E9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DE46F89BE1AEEE7E08E6E6C96136B4B,948500624AA36F84F8A9144D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3502F3348EF421C546A22C60F73D82BB,3EB807C5B084B783A6ABEAA4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,266F0F71417652FDA262E209ABA9813A,1AD344CCB780727F29F539A2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F89ED91B773DB362E3B535ADE806309E,6154B2555DAA2536747C8C00
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,95898AC8F59AE30AE6C131F433609984,F4231FEE2955D325C6358E8E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCF177BED3855914164948383A7BFCD3,B013BDAFD7B01F6D12635E71
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A41287144BE0462B64F3BF9FC79AFA28,11FF56DE220314FC01D2F427
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C37A6607EB0CC90AAE0E805987BA2BFF,96AA9F8F1B82C816479F6F30
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B30688EDF5883129A3EEE07EFBD716CF,2484F97D0E207448CFFCCABC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F49EC19D30C40E62ED346BB1E973B3C5,7F3DB7AD4F1E679D1C1BA290
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AA60565959700AFA4E24383A7852F98E,40CA139963F8B07D82F93631
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72673BD9D3ECF3BC9948B6F96D44000B,A29BDBCBAA7C7DFB9ADF7DDB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F764D588E2AF04E183D9DC2008E54159,892163F30BD023B629FEEBFC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6225365E542C73635002C5D0F49D79E8,9ABE4CC8526046189A15E8DE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,578FCABE430EB1F154DB178035C87340,A08DCD277DAFEDDE2CF34B7F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,90D2277F8E73308C9FF488C22C64A371,BDC38FC4489A714E45D465AD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CCF9D01093489E9322A92CC5B45EDAF4,524D9D6323724755C3A58301
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC7AA07884338A1CA74A149C920B7113,804DF3B4AF8F2EC1EFD23E30
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B49C7B29E5DC67EE200FC77742DDEE5E,5A6B21FD6EF3D215C82D7033
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,943410D203597F271EB914B045471F9A,243BAB53856F7401082F722B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A66F889E48C971C19BB1ACE8BA14C7D1,53BC19A4C99196271B6DDCDC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C1987A822D55252A53F4C5165A9A6E0,695CA9F5FE4FB59944E42198
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E2A72A29D3E40CF17720A2EB2729F54,277189F03E8DCE092840239B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5756340ED21CCF06BD9CAB1B1B6B1F83,F514DEB77B49396051473F97
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8F4D4E3BD46C79E859EA6C4B1707115A,FA8DFF24FDDC28232DC7A86F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6133F53D525646BAEE9303FD23A6A957,4A1797DFA2F0382CE2C8A691
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4079E18FBB564363AD12F51E06CE783,367F320EA19755B931A57645
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7DE5A96E6249F511894B554941711A59,B9D48BA0539A31A9532462A8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFD50CEBA82EC1FD6EE45FF2ABE23BBE,3A1327E46668F8A9C4F703B0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0106CFA6F81EAD4369327F7064B87D16,3F432307ED0F3C057C5F2712
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE3DB3EC969DAA637C83C99083F1F8A0,7CED22DC3DC07E253C978C97
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3392F85F96A21B777F33EFD11A832A9,247BF07ADD6941713F40A327
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A815EC556143C56EA7CB787305F8EC8,BFF611BF4369FB38215FAF6A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,49ABB28EBD9106B5F204CC1AA2EEAE97,0A9E54DD9C485068CCFD153F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DEACE7DEE61E242671C0EF0E441C1B6B,B6FD390C7404DAD7D4359416
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A327503C873F7679DBC3271382093C7,189B498F1D693458BD79489C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6546D5569FDAA7E85217D87DC34C7E0C,16FE55376BD68D78B6161E58
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B695FEA192283985799C9CBD614C37A,8D71BFD1C8A1559770C77689
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,11E2A6E032B79DC02CCA50CDF257FEF1,C8E97ED1703AE1CA0CFD14B4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15C788FB019580F2EAEC04B3F074D96F,F83FCEA965FE9D0A141EE058
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,24463A9F5279C2F684EB2F17B9C0B793,10E3C959293B21D9B4293BBC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5C0D212FD189818BED2B980CD771710,21777B0F52239D696F7BEE2F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B38A49118E0A121DF29B8781E71C89F,F922FE3B5C9A2826818B51E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,100F07B6881EA8482EEAB29E695630D2,A70F52D10C35A99831518DD0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5478D20CB06C9D9EE3E5B159BAE6EFBC,CBA83BF92463F9B14A6882AA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B1EAEED654AE3FDDC35BAA926D45B0F,B2AE2D718F554D6855936C83
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,827512AB9C1C73CCB8AE1A292233C563,0B512886B3CED2AF94A54153
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,312063D0754C824DA712B64D2A6B33A2,8C3C7D5EAE0CC1BC2141AEF1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C41B044B098F5D6773229480C84D66EF,36A53378F71AA1014DDDE622
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06CA7A392F7FB360BE218ABE86020D80,0D7C440E7D4D7C36077390E9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8F4DAFA1CF388ED27662B6F234BF3B2,D755DE9D6A83D78A02EEBD2D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7451425964131EA8FDEEDC3D51ECCF9E,4FAB527C28B1F4BDB34158FC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BA511CCBC0A07FFC45233241E1224340,13683A5A03D2A1927F0ACDD8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8CB04EA4DB020D5D4EE3812B38AB84CB,26648E563AB2075E2B5C7281
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,04A2631D325386F77579CDEAA967C37A,C1DD35C987CA7918F4044197
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5BE4CC4A516147408183FDEE9DA1D65,696A0827A2FFA3C73A10404C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,36C43B5BCE7BECE6FB2DE03F4BE709E7,FFD099DE6A2C089BED7D35D2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,35EA9D9C382CB460467F8B8D1145917F,40D9401342FE480A8A009E2E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E00D2EB361732C08E2C3125DB7D2E3F2,491710E39159DBC5ADE0DBAB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F587457CAEF8E5BAFBC129641BF8EC69,CE15ACA01CD0077FDAA76A87
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BFE148C7255EAADCE3753A7CB3E1FDB2,46BF49FEB914AB4ED667E4E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8452A0CF7A80F80C4D4EB5C7E7969DC,C04AB5C52A9B1C5964B0B86B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF289490E673C0B56DB6E768B3CC0A48,856BD7044AF5997C29FC5138
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1DA9BF8EABE527222D4B7301F5F6E14A,3D61A9F9DB5C452DD7C26F95
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,036DBC1FC7537E77FA4CBDF33DFF927F,44CC56A1DC3A5408286C3EBF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A26A8816BC2735427354CD88742487B6,BBCCC740C5571A4653805B58
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FB57CEE47FB84A4CF354FFB02BD7F27E,CC74DB56925160F24B998789
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B7D14B36BEFA7AFD23BED5C89274817,7FE28DAB2C64E290FE8D8CD1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,783B2B4B5D240551B0D1C5073C86EAE3,BF879E67B031772A214137FC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5C5D0E238A3C63E36ABE8CBB8D3A755,C637492282DDADF2344C5F12
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F60AFBED2788482DCE9012B308F91018,A6D07EDAD84C22F55D578795
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF29BAAE83F0D4BDAEDF57439B240E2E,C88A6075AE55B48C41413694
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD2EE48803F736F741F7BC539143B6B7,6AF648295D9D5BB30994F0DF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8759E7150969DE74EA60E6DC6B0605FE,DCECE445325ADB93295C208C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E8A3873E185A8130171809B1C670E466,A52DC25C7BA9A8B5D35A3447
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFE9F56C387AF2EECB6C16BD73100E84,9F0AAF87BBE52A0D82B0F79C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,504D313E64F204B950E1FCBA766E6A10,2A6E346A487840A9FDC91C91
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB973244B0AB827B73463C26EABEDFF4,CAA52660E1D03128283903BB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,099D40CC50BECB4943D5417116A02A43,184B3CD556245A75AC3B2E95
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6F936FB2AEF98A81E78E4D190DF9D876,591FF4491319AE943B7E3F5A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED889EE0177981FB3054558A3D93F5D9,C3A3682BE186AC971EAE5B96
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D610FF2C9B5E26A58C3852B1CF968675,CAA5295895B7A4167F1FAE69
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,60608D5017ADBEC3DCEC4F36DC2CCADB,3850062836D6D9C342A5754F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1607142E96C20A6D55887D473E1C1ABA,57B3B068E892BCC25B81BAD0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0173C6DB9751FC3246158C2F1082842F,D24D9DE4DFF90F1862A202AB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15A4DFEECD687B26B2398404FE651E26,124DB27D43E78C9E1F22329B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C04FCE7248101CA8434190F8F3F18E7,DEDA9836E027014878678B27
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1F308C74C95344CDA356907739190DC,34E78710601E8D992F9AF14F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6CB50D780B92072B37F757ED6E63B0C6,A2AA5D1A550999067BB69BA3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5E2BFEC3FEE9ACE4CBF6B5441346F5DA,18617E4E20754E060463F495
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B28D0F02AFCB8CC20235898B355CF3A1,E1A687503828B8AF3C8EC33A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E7A8045111133E9BD905248B3E3D9E8A,98B3E202A3A5A3FA76358768
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD33375D0823C4C5B6CEB0F6B4E39F8D,92FB4EB73E56C32476604CDB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D8318B9642BAE26C791643DF0F53080,BE8371F5FB7CEEA806AA292C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DABE054F9D33BCE9795748681EE640C,CDEBCCD1A2CA52EE3907F9AB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,16AE48F67D14618AD12F93B7D5E3A74B,29D03897577684C1CC2C1A60
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D544B9110BAE6EBB3FB9BF625DC725D,4309E6F048FF37D9D21E7EDC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,563E947E114D9A470A52F05745B59B58,9EAE363902AD89A2EA744C7B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0804E1F159B228C2B549965B0628B600,7874B39866D29960E6A4EA9E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AED48B489D0D2C9E81AC8D5E6A15084A,45FAA83D1F868D1E1509A444
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FACBAF33A3409556CD177817673BBE7E,396965C351C7668CD26E734C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9919EFE9BEEC2374E74FCA514442152,9116234214E63C5C488B384B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,870EDD564454CB858A51E67D360D217E,6A159AF76162DABBD6D0DF63
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E66FBF9271A50B84A5D7AB53E7373176,30ACE630BED634AF6D1DD338
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B561ED7F3EEC916D48BE068611A49FB,47AE71282F48B4F5892F49F7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,400472731C0366CF0BE540DBFA745BD3,12EFAB1FA8A873483C53F0CA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DAE6DFAD532BABC40BB959C970D8814B,40ECC9C908605D2AD7C04044
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61F1FDE5DA854053A07508662FD5198B,56DE93DEBF9302DA18649DE2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BFF8B0D12F533A3E3C9C46BB8B73D4E3,8DB85E1EC6AF6F2720F44165
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,172A3E21168D80ECFAD1E4E122C0B1A9,60CD03545AA93CF3EE8B9A5E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F304D41493FEC89AECE06C355269D24F,BDA5728AF5174BFE8A1DE7A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7223C3B61097610DB9D86BE0E5C7425A,EF3B366F60DB819EA4CE3CC8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,73D79A145D0F20AACCFCE879398A14D9,6B90D4161C02C37583E93EC4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D2A3297B864EA9FABB396211FB8D7DC5,43BC011FDDB44128F061841D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBF84C03307C92DBF77E819748CA693A,562EFBF4DB6078A949AFF824
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70D8437A9120D5F1EECC400CB8F009F7,A3585AC211D316CA9BAF8349
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD70A2CFA9289909520AC3E442066E95,4DE9364411A3D22E18E05EA9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,200DF7FF1CA3C90B9CE7BA3E1622C243,87C54F689FAF75861A864E36
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3558987AA0E60869CCD2AAB41000171D,F88E5005DDA6A32A86B46323
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76C03334BEECF8488345EFE09AFEBA8F,7A8B21E14808D8FDE12DEC82
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6C34C7E0F992FFD107CB3C21AFD8FCF2,7223C34459BE33199E397C97
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F567B76CC9075EADFD5B1F5BB995DAD8,3A4D7CAE9189475274EB3A26
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE553460124B7240AD5927F199968901,66628D72D37687E345B5B80A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20A361BE827F77F8752324D0DF0191B7,7BF2B29BD955EE9DF8A0A462
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89E668A5719753E733E483449D26FC35,59E64E6FFA910A75BA6BBA60
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC23E756AD6C5A8EB93FE43FD1743407,296AD8FCB4BE13EB61403D22
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C78D75FAC41A829171137A924C008FD,B5B12D7F28E1C3CF0BBA182B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1582B13A55A441793F24364F4E79D70A,4FD6AA11A62B3DAEE7AD9B01
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F83F6CF2845E6049268A98937165CF46,90C14A957BDC4877443E00E8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89A39A6F6D0EFC34FB44B9D94E1FF998,B42B60ABBBC80A57030893E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,506069010FBBD8FB9B621E1E2499CFDB,E143B413238339E5F1691BA7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F05CDF287428D1F8A82F8D2B90AD2D45,97F6CA366943F4B6CE9FF71B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,250C4E224C7EEED75B5C47E9B281F038,22468D1F2D1F8BF1D39859FA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8C1F4CEDF1F26B67CE6AED5CF27346B,652F8F8149F1819CA8C863CA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,821DCF113144A74A0696107A511BDA50,3D8BB5E6B9C0F05E46D96D75
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21BB340C501240AC021FFAE616ADA466,876909CD1586AC2DF5FC7AE6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F877A1C9FD4DA1F3E375314677BD07CD,F373090EBB599E4E9EF9F429
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26845DAB23924FD243CE4BA118AFC18F,039F20C260E2A343D36182FF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0C74932F7693F4D4F7E0418E41879F5B,B7C468AD4CD5728DC6565CFA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9AF335A2CC31464188BD38CF75937FA2,1D1A99E64812A75CEF4596A9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9F5E25ECAA22CC54A2637CB8DC01FFF,A756214C3895B523FB63A378
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42FB25801DC657140C86C1C7F18F2F01,590D9B13514090C19B0000BB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFA06688034DC8F1A474C5CB230FF52B,5937F4916B9D698E3FABE3DE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C711B7789802A2E87BD9C892ADF37666,B885298A5DBA44735E11AC17
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0754A2EB8464B56CD205F6956C88869D,CE314473BF4B1E1B6C7BF179
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4EF0E8BE04D929C3AF6BF71852A72A30,E14518550A295F9866046EFE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E845124E430E41B9F7AAD910F93DC6C8,B478A5A1128ABBE224610BC3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FB474511BD214140C90B521798743A9,E8BE27301A6EF0E481A68DDC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C727D9EFB0A70769934515C95015E3FD,C33D3FBA7B6B71F7F5B1E18E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,64ED08124194B3590CAF7263A77E688E,58FB6C2A5678A5FE49C6DF04
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3384D1E460CDBA2E9306042D35C2DAF8,53249E60E0137005D6C0582F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E4E2DAA21826A569BEB3E89C3F75954,0B51B269D2EF17CC2AC97F8C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7783A5B5BBCCF29C2AD09070882EDDAA,F0365CC0D5656AB7C9EEC1D0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,362BC8026D00F70FAC9406ED186655D4,261C2E9B772917B953719AFC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DA0E8368EEE2F2946AB1D284CFB58D75,2AFF64A0A7796A645F8F6569
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1C3F461143F2E728E463F6AA04835328,98F8FB6C03A8F04E5DA6BD80
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1BFD760F78B82698E764E2F009E83A10,ADB4E618176A154B4077D28B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD4833A790171E25A3FBB40DFCA805CD,BCA4151338D53087CE12FEA2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,012135788F5DE698BA7865313D838D1F,B6E7203A49F125E0EF781021
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE3713587AD50A75828DBD3B27C4227E,F1E1EC13C4DD8F300801DFA0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8CA1F5693F9485DA47665289F9B7994C,820A5683642DC787C4E86A46
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,412A89798D2ACDFFE18E5C1E4D7316A7,D93057561BBC893843682759
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00CD5CE9424EC374FC60FB76B70EECBF,88A74D19F682E1A255932C53
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,038994C83ADEB2F74D8C8839F53437F0,A3F15A3800700FBF4036A9B6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5378C9DF92AAF716A3E3479FC93F9B6B,A1FA256354C249210CE3F4A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3201667073288CAACF46F3BEBAE0367A,345D24DCF43872214332792E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C88491C3A4AF5934C112299476F96F2,DDA8299BAFAE19127326C0E4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A09EA9002485129676578DBC2D29970E,19E2856AA1822D8C382BFCE6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0249D8409D94C899CB3211101F44E706,34F666DF84C3F4861F031B70
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,393735BBB4F295F78875118F2282FEFD,1172696A8F3AD17FF4CDC32D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,880A34A01DB11B02983984409F474598,78E946DE142861000EA71378
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D2D885D4E8D0FEDF57329B9CA684481,5C839ED7586932AF9267D4EE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9A319465292440E4EC40AD4311412BD,34C4833EAB737BB515DC3E29
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03928DA8EE9E6EF58F8BDD25383BD746,FBD0B65369592420F4AC13E7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,871B76BCCE398DA305C05583328F3D0B,10070DBD7C735D468E99FEFC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D8329DFF082425E4865ED82BEB77D2B,6891E87151FABC787888D502
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AD6B061F1E920431D52B7C4D7A6814A,1ABA71E6777298078DC34E9A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A3113748345C8D03408EC03C67AA757,C073219B699FF4EFE6BD7F20
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E78DEA79071AE8EBB147A5BA7530F6C2,7F90BBB9710C26C21B7B306D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,10A9BD1DF9BC3D57CE9878D0AFA3171C,8BA97E65B5C543E81A0968E9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,691DA2346C6D0FDB814C07F9A243DF31,14331E4947AD140A7C1A6ECB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE6961F7424C872568BB6FFA0D7C00EA,05543EA7314FB4A0012243D9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BEF85F199B780AEC2D7E75FECD14F54D,DBED42B3388D1DCB8FCCE224
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B08AF472657A3742598FB1BC3E3DC702,776AE1440D3ECC1771317076
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F585700F880CE42F2C10AA2B2D9F743,CB2B3444973841C5300DC71B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,25E7C4BF79991617715EA342FDD16E9F,A4360B1247A7112B4525966F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EE3964F72F1F85062AF2AE995B43A511,672886691D327820EA6639D6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F4DA216B41A2ED1777CBA97B4674B1B,B4A8EA97BED0613AF1C51AB8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66A36F7EC04C45F3948403E381E3D5AA,9782454E51F13175CE23C4C6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E88D31F0EB83D24F7D26371129763FBC,18DB2B166C64F39868EE8D97
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C13DE138071D1F51FCB8D6FE388E038,662291FFC942AF9D67AECE01
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F05DCF03504184FDA2616467DF5795A0,BD52678F949A9FB2B389E5E2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F4F788BEC2EE583ACF059B0ADE014CC,747EAF9274A438F5AC993B1A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C37A8A7C38765AC31CDA16786D732F1E,D3411AE9A8133D3577EB52E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E4B2DC6D7322CC108231C199330860B1,0B8183CDB4774373E772B3AB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,642BA8B13B3A34684C6D526A5FD2D752,902123CAFC2DCF346D63151B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EDB994505213703314C42A325D55A40C,83D68942220B5A33CD61FB1F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D1399046DA2D653405F1F1940E875C8,4750475855BE7402E5D1C5C1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C435B4BC5E2F9651ECE8EE13D6E25A2,D8876ABEFACB10BC3AC52E34
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D9A5A7C9CBA7A07DCFAEA0E4DAB2725,C58EB014A932C3116E65DE5D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,09A2B5AECF349CB2D56B7A39872E4163,C1FC34A7A8D16531914737B4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,28EC2B7795CD5FD29D0D88A33D0E107C,C4254A6DC983AC85BFDCC948
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BD04EB44E9025675CEEA1EE80A4EFD6,CD3F1B6EA3FDD0DE0EC87DC2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8FE9194D8EDD327E9D5EC30E09CE619,C2D257CA005B12DAB1C57E99
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9FF0A2CE81526677BECE7093E03F40B7,F639DA208C14F5D5E9B9155B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8523C03A2DE75F6421D0BC91F02359C,4E3BD1349917A5406A619CF1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,860466FE29D625755A732EF72620BF12,DB53D349D3D90BFD6C7B5097
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96DCD22792D5381A5B33392650D8FE83,64C9D371D87E92B9BAFF2BFD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4482BCC96F8D8E5FD6EE2A3A302316C2,15D4F790CE455848506F6917
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A53C321889AD33DE74846729AD0482B5,6819059E37B8BCB2CD3BB056
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB6FBE7ACE4F1F336B7535F43CE3FCE3,36FEB6CC91753307137675E5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,32323174AE66387A960E21E3E48A36C2,7941EB9CFAAF2FCF2D9D4F9D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2F01BB704E0A56C51D985BC170C2516,2DBFDD6D224B73B8E3BA0F93
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B2FD8D3C4135A5F53C9E9CB2E857C3B0,783971383699EAAB8A969788
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBFE997F54C815A9769C576DC5557918,A6EFB070C41375FA9077AD0B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A04DE27D214F2BAE0AED7427D2D57228,74A3F90EF7E7E5F9535ACB23
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E47EF035F98F3D57BC9C1CB574D6799,FCF439F7297B000610E5BC95
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F7C7310B4AE3FBEA22077FE53884CD4,D2D20CA60E5D657DF4AC1A57
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B5456E3EDE3A798519D70DA24FDC14E,8786A30EB8DFDE39EF411441
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3EB8F29B8FFCE34CFE924A4C8B412BEB,FBF694C68239868881135AB5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9112F7C42E8F86ADC612FFEF62BCF031,A9A0EC605E0B7D959D94F3C9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3B9E8C729F6BD2A647103C87B50084FF,C7C6B0CA4CF9067D70D50450
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,721720697921EEF72389D70412DC9BD2,2E3A7C1632E8038E1DF4710D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F4B192A4752141D528FDFE57403D1D29,7EC20B5FFD6D4F380EED6885
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96ABB2AD544F3B40B2302317A00AE6C9,3AACD18243723B98834DE29E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,475BC853DB0993F15E4DDA017849EAA3,E356B15F48DE8C2A841CF3DF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB6E877FDF36CD13D291111A2A52706A,20685B9CA28B27D1B267808B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF844AFF605D6CA75D32C8D76911FA5F,05FAD3B3B7DF158D73F68D46
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7BD6D23A35ADAA7A24698768989CCBB,2D4B6CE203755ED6DE54D1BD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F22358724D39699DC5F3CE252E5CB388,1362F31DED7766967CDF75FD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8DEED8937A8635D058E1D3B2937C1F14,FED61D4167F6721F3D42A96A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8F471A85DF24F8694B66679B8F3AA05,0C53F26A0AA68A554F02BFDF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FBFFD9900A7DEFA9FFAAAC445CEB9FC8,3A77E657D27C1AB33CC527EF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57D09B46F380628DC5529A22E6CBB191,FF53F69D116A083581928053
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2EC3BC236DABD021D37F1777AADD9678,AC7EB38011974A02ABEAB3F9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B79834352EA64EB93D000257045EE658,F9EAA0D8DC11FF29D6B516E9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,655B9375AC8864762424A4A0D47B7BD3,4646C2ED5F21B2EE15379E4D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E022D6981D611DB9C6E1D71BC5F3829,E9421D6DA7103E98C42BC348
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E82BC59288987CC4900809B3F93A258C,765C26D3449490E464D3A68E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D88E96E65B3E75EBEC71A167FC745022,9CE53769A506228A186ADB5D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE5DEBB9E0A8676C9AFD507CC4584B13,4011F610990EEA93D7CE122A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4285D4CFB1769D1A24E50EA2E22E9897,981AF6169C7B6C2F9D35EBBD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,662AA01C92C099B9F1E6202E196893FC,A18AC40821D530216226AF89
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02AC385F2414C82B3471B647689AB849,E94F1A9A2178C9FF103B0844
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F51172514E1CD57F69EF867599C3DC8,3982621C739ED323AAAA7C37
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F3525F3F535F4E6DF13BECC1D8FB1455,F62AFDBE83135B71413D79D3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F92792BC56E1E01FF0E02D970FAFFC4E,7BA8768FC9DE99379058D8F7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B52F1DCB4966196D138C68DD54E5919,E461FD2030A5BF5D6EE94D1D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A185CE97AFEBF1571FE5D75D3BD575C,97C86A5C1573579F9C21F2A3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B41B160321225CE25C4E33E040056747,F571B0467D59F5B9CCF118D6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F670778BBA33B3995EABDF9CE23E1F2F,7EC8E7AEB2F5F754DBF3E2C8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F01509B4208F00FE9AC5F302E913FD0,57EC36681223C3B6D4926342
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FA147D70166C6DDE3DF84175679D182B,10BBA85D4FEAD1DD02D2A997
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CC0F7F90199AA8DC130452DD284E1472,1A02ED61BFF438D4C5CA0141
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76ED3C6965EDE96C8D4E1E8ECD9F56DC,6F3A549C817F60E6DAA3EDC9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4B337D2FDC0E5FE89A8E552DC45CD4C5,ECED242B4B6A1D78DE53A425
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2E1E0773A8030D18A18B9D272425875,BA7CB02898761CDC4873BFD3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0B7D58F803E71297F445D449F7D692C,7D106558576E6F817F16B949
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F9E967729FA158B2BBADB67F03F24077,6909F02053F635627288732B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E11EE60D5050CE4C9D0B03410C5ECAE6,71C3F54E1E05B0F7DAD5C400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,02F33A269A8DC9F28CA3C370A15E8844,F1947CDB239461CA161485F5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3EAB022CAE7D0FF5171CCF46470D2B1A,EC68B69C5D6B56DB8009520A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8D4A183A00EE3AE6342CD895CC722FE,1AA84577A5A893B64CE59077
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C4AFE74025F7228BEC7F0F338143284,7D0F91326ED356A09110688B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0A42C179A055958B374DDB41CCB29EEE,0D2943530809487742DFA541
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D7ED82A3EE21516F5B5E9AC6F7C461A5,6366910A49AAAEA42C9030D7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,86D87077BC84F98E3937097EEAB02ED5,2A9ABE810CF32B7A58CA3F3C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,880C564BBCEFC7442CE047715FF7D734,0CFCFAC0132393C12C1604E3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC31B4989AD996F310386615015ACE5E,5CC175EAB000EA51A1FFE224
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,392104223345E1D18364CBEA4BC3BFD3,E264A4072A07CD9B6680274E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5F7D8CD69434C38C21342F0AA1BA95B2,A6054BD785E94219C6B13676
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0583E23F330357A0ED6C19F4B1170687,D4420333B9B73E98C9CDBEBD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BEBA72E43E8B849A8AB7DE5E384F4FFF,5C8E69DDEDACC0A2E2C53C49
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E924217A8D6DC3349F1227E479B75ED3,EE4F62ED04137D5789593131
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D816518AD87D4EFCE7596BF5CB44F4E7,05064CA57A799CC2BE53F4DA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,915D72694C6A437D7B0F426F09E052D6,D424688D264C9C6C4DF27328
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A670F35E061E9939F3BCDC59FE3713BD,6D01F2C7E14F078D905D0CC5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5C4F891E7FA9033123808EA080057854,CC073D07C363B207B01E7A92
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18179F59C553186751D81E19B525844B,5A85AB9293AA28FF5FAB717E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2B28E2A5F646D7C1D8CD149FC5CFCBC,C92B159FBE27D67E60BC4979
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B4359F02926FB5CFE5CA5A8D1CA4DD9A,3F3BE16228D0E16613464E71
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DEE387A6D3DE2596552C22CC63DE4C51,0C00FAC805524991C3279C9D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D51C0E2C76902EF329A51E1F0D7BCCD2,2B22C1C141C8048A35731F8F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D5E486BEEB5F24C1DA0E8845A9B7A814,EFC378D93A3973CC122E8D4B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5854C608946E292D53C10BB4217FFCFE,1C9F8CC7D50860B4B3A0D942
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7AF5AC0E19E193F7D8E6F39A574735B,548B1F53379D01046A6A56CC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34E91F46730F97BB9FB5EB234FD1F8EA,63AA742D508678B048EA9C39
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,341BA1C17F4B3404873D4FAA11360CFE,72FB0649FA0BF6BB586BD4D8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E3FB44A03A77C0CE5A61A6A1401D171,6CC44D57F3A12BF4EFD1A8EE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6F736586A0EEF3449DF0B60D94FDF437,9CD22D8E908B8604E50AEB38
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DD7BBAA9219A684937E01ED3C4BB765,979F4315ADAEEFEB2FA425A8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,14DA6A52901E8307A0A670AE479F86CA,2BCB1F00A750C44FD8796227
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CCFC8E22D343F1F742109B298C70B6D,8A2774F0FCA16945E112A963
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6EFFA300E7B42409B6C0AB2F7702DE10,03775D043B0E74A09DD3C682
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E32DD9C06363D3861E0CA8757F6F1E6,7A93227B2D9D42E1E9BC575D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EA9C1AE547A7A703FB9927071741BBDE,E21A228CBE7A6CB571B048A3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C02C6007B9520A2C91AD461F0D036B0,1152183D03228FA0824CB02B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D05F647A9D52588A8080FABC23C8FBE2,081E7E132E7FA762FEC9615A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C69B4F862714E7DE0F164AFB86FA749A,A6EA4793326C53FCDD068BFE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8AAA18EA7C2BF9AA2CF2FEBC67A2D237,A844FDC8F08B88FA76203076
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99EB982A955878D476D0DCF26F4F2549,4CEFC03D8877AE5A4948132D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E67E1D6202D1579CB6CE1019C356365C,359F17EFCEBBAF1871BB23B0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,51E24C6EAE298E24032801B915284529,A4D4A479C4A563C887CDAB23
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A680BBE906B789E8EABF3A2105F729BD,003D877DB7245BD9494FAA4F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B8C0B91B3E4D721C64AB693D3661F0A8,E6BD97DF792D7247ED7470A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C209970974C5FB03F13CC37DC5AB14D9,CE35FF0D37FA85538CE400E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AA776ED1EDA8F6365E7B6C309C2D14C0,44363E12F52D707C3A603CFC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,63B00CC8C764D6349953A48FA7C9257A,926B6CD0BA38598834ED10B0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCADDE2690C1A93C5E2726A62AAE2C7D,FBE1015B5DA87469EFC57492
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,37EAF2D85AFD72C0262AA7DCD7429557,33EB97675FC486E25CA4015D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD2B37FCBFF34E2A3E298C4D0E889335,F1FB1A310DE2FDF67C14D823
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,21E5FC1E51A73A330400ACE4C4620506,D5C7DEF1981B1E4777A03D0A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5715725A11F18EAF719F33AD86259A07,51A55915E4606D4BB5293F18
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3F809C472F506B2B1E857DC01069423,05206E64B7887F0DC6496ECE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,93F2E9C05B6A1C6BDC847F30C173335F,59A69CA2FF24C63F4081368D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BE45C95A8747E9AB6CA17343FCBE1EA9,2584335E68BAE8EA10F0218E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,680BA0B4E836CB3878E5D0DEF1C2E896,E62B658EEA7A6D7A43D59686
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D3653DC920D22B620131542E79336C0,F95FC2F730472BB634C51FE0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5519276EB1657216B1EC10FB4A93F56,3C425689A01D4D8029631CBD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20BCB9E98C1415A8EDF358D37539315B,BE8FC33FE00171B5785F850D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,444B9544EE15034F9B8C15E25488BBDC,192A693DB42C3C1A80AE4D59
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74838C600CAB9BED85163A7DEA529D7C,45BE629E6266098B2637BABB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BA67F869BE79821954A4C23546F5A620,8B1D92C591984DF390B34396
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BAE1A926B0C4C0F224D15BF6480BBB57,B47B558C9333834B06901440
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C5A480FBEC0C7DB36FFE0A4D0714EFE,6324B2C4EC3557EFBB6F0A3A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,79D99D9DAD7E91564058816E40216884,AE065CF21B8617F8206DF134
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,652F5B2A342B02A44BF35CE9BD99B1F1,27530B5DFE9656356422E110
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,298878C7092089346E99538E4B530732,1E99C17F976097BF59727225
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCE036213AA9AE0890D6B4C4BBE1B819,2F406CE178B194BA4223F014
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CFB133F107F8FAAF1105550EE7153B2,E9219A1A70AF922F7F6335C0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E5CAE7355EC3D5082C3AC9D2D4C1D74,111F2E0C0435C381F5F0443D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A432251736F441174D9BF11302FC8A0B,6D85327CBC7D05E5B498061D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,864C3D7719506623594FD357343FAB3A,99E9C7CE8A73118896FDFA73
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8060C76EA57A22E835FC003E36FBE134,5237739EF805E1A8B0175638
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39B499359679F3DF5F20EC816087037F,EED3A9367C317D2C93F7350F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3B125A61F19898D982A68D4747F3AB27,E4565B4CD803A7E706F7648C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,59E0CA0FC910ED47CE9541E983256AB5,86D49D08A5CF0A80AD3D5471
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1509F82B32C4D1CBD190289F2ABE2A4F,181C407D8EB4F6228F3829D2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5A1461145641E786BEBD6A7216DE8DC,94431F516F754C875F978737
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,059B3DA9442AB954CAF99206B5BE89AD,651C10359109860AF1718475
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AA9D00B5EE743F509F23AFB30D2DC459,FDB81785C720C703A71500C9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,55D1E3F5EA6945E329135BE531AE5AA2,EE17C77D4FFFCC83060A77A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6874E0DAA246D283EEBA23D56647A2D1,E7018B195236562B25504B68
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B97E607938AB98651325079D9873FC2F,7264AB0E73B77C3BCD9C59E2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,97242D0FFC2DDC9D58DCB99F47FDB54D,FFA3866BD5962ED89FEA8F43
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7105A4274D2BB5F3964D306E0B84BC00,362122F98251B36C8D265AE7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85A013070F50C8F318EA9D2C297B32B8,2DC9C0B8598E482E3419CADF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F9D1A3A528BF1503E0659C4599BAF4D,426C7085EA709094FB9E9737
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E40D0BF9B1BDB25BB8CEF5F2C6E42EEE,0A24F4C8561666FACEB3FA68
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,99F0E31E63033B10C013EBBEB5A38F25,D04FDC9CE5590DAEEC9D2071
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACED4722C9A93AA8653984D1F748AAF3,F24EA9777C8BA77D01531F9E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C24AD9258F77CD859AAD2E9929D0F86B,BCEDF6F871E3EA3157A11783
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3F2BFEAD419E0677BCCC0BBBA0F0526,B5677CC99B8ECE1CC3E6A8E5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,754FECEB3814DD16FCCB048240C569F8,DEFDCB968FE746EF38F62121
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,858D87A91898E0E017AE65A8E96E009B,13239CEC1BBA2B7080B21A45
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5420B3F002F35796CD870C9EF308E305,2AD04D7F4DEB18EBFC6380E2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75B4876D6E2469EEAD26C4CBF4AA3A74,BC66DF1BFE59D3EA4B51056E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68BAC8C22D18BBAFA5746D8BAF3919D9,E125668BA81A618FAD0A626E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61A5CB8A7FE9124A50581DE1F88B4CE3,4713490084F1061AC0D01E61
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48A114454ECCCD8F73B798AC77397379,D69DC6F8710A5DDC1C097681
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7295FAE9C0FB3EF6DCCD703EA74BFA6C,0EAC8CD8DC71849E3C8D11D7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,41EFD59DFD1E7A03F6608E0E7BD475C6,9276BF8FD0EFE2CEC453E0CD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5D1CB28DEAFD2DE2D83F9670C193867,F8C00545BEA262A59508A28F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1341091B0AAD50914EC51A0DA1E8DB6,0C1CCCA9988F7891593B5B3D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15B47603920EDDE3B34B7842547DDF58,75E90A950B489CF1B3FF84E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE9B3B9176219A4A8AC1AFEC7C152267,54212EDF5C06DD53A5360B30
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,640A58C1432588AA65E3B88E8A66326E,1864A1790FA618FC9AB896C0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBDB0C7B620366A7E9F3BB5AD634CA0F,A059B19B2641F578227C1F99
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF31F65075488B3C9C4271D31087052A,B81CD905D39B5FDA2E4A454E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33D44783AD83F85CEC49E9710B8230E7,68085BE1594AF4350BB72575
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DB70BDF5382D01D9F38D868298BBB2D4,E67ABBB646268CA0DD275928
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1ABA1A66B8F22CF69576CE375FAB4EA0,182F2FB770A7F636B2B97AAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2CCC1B002E74532B12BFCE0F75F080EF,1F298C218193E0F3ED2959D6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A2E879EB6F21E729463FF02A5367088F,CCEA2AB95BC3214EAC9E627E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5325A7BD8CD28B4C8009AFF45E545987,5BF39891DE27F5C1D971D6A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E422ACCAFEBBA23C330372593E0EDCE5,EFBD096CA871AE04B041A3FA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF4F883267B43FB627A6CED4D39D3297,3F3DE74071C3A880C23A2B12
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD49F0326311DC823D757F635197572E,907E8D9EA29C29D0DD4FAB21
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCE21FB08EF39CBE431CBE3023C4DB27,73ACE1A839774DEA18A34375
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0BAE1DF873FE7A7D9048D635F1F14EF,F3074BBA4F277FBF5A7F91D9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B37C38BB80328F3C97A977F2ED254174,AC6039F5FC06E302415DDC31
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,665CE0C255C84288F7A75A5F81926F6A,55234AC615BB3356CD0E41A1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8E7AA9F32253F42EF7F2D68EFBEB21AC,04762BF970D1F2DECF22252D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1BE05726059C3F312787A379F585DE2,094D1F7842C129B549BCEE85
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58B1B3DC7636E88130647FD67B68B08E,8486978922E8D4D23A075885
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,01DF6BC1C5CEE8C177C59CFFB4370F8E,B71D112215E3D942CC8B156B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E21294A89D9132C2DAA27BE40B719293,00DBB154E82102ECAAE060A4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,35B192D8BF541EB6EE622972AF7A640C,4137A9C7D970F4A79B0C0826
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,457C3690BCC9955B543D2147A98B8BEF,1E6860FC647A0AAB87131B5B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CBCAFB6658EDF3F504659B024251EFF,D0BE0503E3D82D3545C0FF71
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,247DA9A5A1C41600098D805C941BD8EF,0B620D456A380440F69C42B0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96C7ADF6EB63AE953A9AD69CFDEC2ECD,7B0035A1982AEECC937A9463
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4998CF82AA9184C7AAC721A14EDE612A,8B953D21C3805FCBDB26DC03
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D6C2397F816501C1C2A54026A87A891,5E4E4DA6DF8439447F40AB24
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9296C69A474A588CAA17E769F09E650E,F2454421E40AF0469806ED3F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5E72F91519E8C1676DE816B80E8ADCD,A3A9B91A7FC134B9D01551BD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7BCBBFBE158DC5930C71CA5752DB2993,20AEED525F372D089FA1A1C8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F5DAE81ABAFEB880B768EC43240DECC,AD83E8DD85824241E62C971F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A0E44698E7CFA4A85C50490D45B5D52,B10B5377EDB51812B6F29C8B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57248389353A263554EB4D9980CCC158,D1881105398CD380A6B43608
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,276F117BDD45E2A3B9E8A034CCBFAD36,31C05360EC269EDAEF5B60CF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58B44C471348805E3472F3B3CFCDF804,C6C8C30D56B10D1D9BB0C187
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B6B3A243E90EE58132A0C4E648BA8D9,741851B256F0927411A5E180
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48B2B680CDD3420DA07D8043834FFA25,8A4DE29E3AD6AFFCA0B4D62D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9AB7967D54AA825C370EB756206BD293,3F9C0A891963C81E9C98532E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,05415E6C0388DBD47BA5B90075C80AD1,FDFBB592A74BB2B7DC06605D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A16149E3963E97DE8616C5B2D5C69BCD,28A88DB95E7F29561D90AD81
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B440410CE552432A8CD1C8CFB44D4E17,9A8DC4CD1584016C16C71170
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,282F5FC1F1DB7045E95C4D2CEF993331,278540F1D12DA5AACCCCA5F2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,69CB46C66FEC0563177C54A92389B55C,266B6C7FEB0A70ED61325A02
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A996783B3ED992261F42900F14EEDE0,E09AC5B6CB1C5D8919A65CF1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0D7319B6F633463D5D2678D9535DE6A,96CF081192B489B4942226CC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9163934E4B6F027E9D1B897089E5B8E,7C33CF678EAC9D79A4B8DF71
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FA59B5C3098D6A4EA607ACE8EBDFCF6,09E20383EF90CD41BCFB9E3C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,545266A2AC95D9DC7523D9CC26811772,76E1DD1B438A449674311F7F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD404E88DD3ABACDC4B15C02F41F9DE9,2EFC6B2B406E29D1E947AF1C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,92CED35256204E31EC3549F58B15C7B0,1E212698E114E761E5B663C5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EB1F247E0D56A25EF5718ED36380EEBD,01BBF677F47C754FF502EBAC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,32083C4DBFF7FE1FA500529BEC94F689,587DE353144F1B3BA54447E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C6742A6E91A429CC202BB838BB717B8,CA7694D92FD84F2F45AA6613
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4C6A5D02313B182340FEECDB0A9CB3B2,416B5C878D90B6481EF1DDBE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,04C814633D2B0BF3B03D3B2F5CFB9C43,A9E3C68FD77D1B30D415180C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6908C7AEFB2819798F070BF57354A8C,EEAE98FAF4225799B577D6B5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8B8B932852D90A70F245B3E01E0623E,E978D99AE21FA544E0FF7750
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B2B1C9AA587FFAA004D2DE4743EB7DB6,BEA2D1F69952283D80F4CBCC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C891C1DDE6D0688136A82B79CB8DD541,E6E6CBF549BAC1BCC230DC82
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5619F847A4005AE32AA9751EB407CF8,F9AA6BB21CE75E21372A5ABB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6FE23F42B4B5FE8B333A1428E7EC789,A84BC66F58C540B8BDA0CC71
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0B784416AEABB2135791774CA7FF04FD,9AB68C5F642C64C82567E299
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42AFC9A45375E548CE1EF6E49C907FF3,A756D8B5D20EFF34C4C5D18E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61334E0DB09793458FF1E7874BD5BB56,FF1EB9D76FF1B2E49564419D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,471A3B7B06D76797970D836EF664519D,C51C2ADB60D331AE5AA94282
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,26D42F7E2DCB2C1FEB76511033C7D986,A28858C9C4E7FA2CC6F99576
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8FA6CCDCD58890BCBEDBC29EE019A002,B394C74C41F3FCA60AD2ED04
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE6B666AA3EF9CBA6094007E3F1B4F24,9246AE183103570DBB6E1AE3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A18F941E8B893C7D27D63F5F4E14985,345E27AC263C7C0585F25D06
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3E4A515BF1C087D1F3AEE498D3C9F4A,B3A6BBEAB3459BD607310A3F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE2024BDD217B94AA602EB502C9FAF4A,9104CB600FEDEFA6365F34D2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,61636EA7E19138D4BBEA213AD61543AE,90992C68472147762B9FEEE8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FAB3BFF88D340A5423E32C9596BC8B57,7FA6B3679298BB21B282A350
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D37D80ED1C7F445F73A66F59C11FCF0,110889228DE97F9AFE93A1BE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6D10F7561451F50B85255AD5BD912D3,668622414C3922D25727F3C7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6A2AC428310CAF276CB6035CB8EB9BD,8F3E6B6B0E0485B69F011B6D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68204E1B48BDB4F5D89F8A970B2CCACD,D404A42390D66EB423F42554
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,98CFEE98EDA627B7680EF7EDBB4CE14C,A3B4D01986D64F0AD563F7EB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D06325445759A1D117B09B2E8F4C94C2,F5F33FCC60A8E84325C3CF5E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,92A8B5DC09AC530E8A5CF2F38AFF22F9,2DDC1FB79A084C64EA4BE75A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5521DC9BCD55EC9CFB2158A120BAE06,D30F832834176C330CC43514
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C14B9437622D990C05C3FFCB734DA52A,D0CA95116EBF7A6261CCF2EB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75E4718349BE6677212F218679338FD8,837DC56CE8A0EB5D01903DB0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,937F3F6779B2D4EBD5B7A35E3DC89D57,A86B1F588435C042D6C7642C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,352D597B542F025B4D18A42C9B50E426,AF86E90EB92C60A7B0B942E5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,195505E0551B87975CCE1A27F0B1DE1A,7960D8F66F1D52C8623223DF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23AD7E24D5C114B17F629337C20B2267,430761488833363E43CCF38D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,258C233904FE9E5DF8E21E6F5AE217F7,5A03D16A770893B19751D022
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB9F5D69C3189F895C6D541588F6F6B1,AD173ABFA217584CF3E33648
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D41DB0E40598D7AFD4500E3B3B1934A,884D68E5EE36AA82FC277648
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A825B23D799E59BF6AC02ECEC986D308,16731DAC8BC5B9FFE165452F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A02958E967EFB560ADFAA471FBE545E,CD455E83E810D06DAC2DA40A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E0BA11F212EFD783B1B2D7C1D94CFB02,BB3D1F7CF901443C564AF018
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D2B6B980D7A84ABC255FD36D78F73C9,9A9EB3E89127EC8C59F2F219
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29F7F3DD366FD417FB27FF070C6C64D9,90A88C2971EF2519A9286ED5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,398096054AAE11F1466EC25C31EB488B,FE8C1282B3EC0BCC245DC0D4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4727E5FA42CC306C94BF5BC60BA5D04B,0979930740A16964D4E8DC9D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,00FA2643930D4CAB0B437D4538A9A5CC,D7199ABE41A62FA9A21C940D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4BA3FC019B73B6D50671AA008136D42F,632173C95CFD3E845734F21A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DCF66A88B4E29275FEAD88B7FA30432E,CAFCCD143CAE517ECED695CE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,65945975D5C9C172830BA2C9E82FBCEE,C124C3DB68DAC92C77D9D77B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88F1F56B2114A44495DD4758A27DEE2D,8AE73C7FE5A4D3AFBA04735C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,98D15F929E3C088915CF014704953670,D40859F7D1B9B0BE218DF3A0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A5CE1BDCB03D4A716F94FA058AA4A8D,3C52E2C038B420B1148FFE5A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,06E140F81908655D7EB5CAB5BA500EAB,EB33656525860992973EC912
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CA5F889F82FF6D1BC8A37EE7F4CBCD8C,5A05C0D894B353837EA89DCB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18EF57BF7CE6A833096851B002085B85,836B27AE1ACCFB7E70705D78
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03C91A567AA4F70F8FAE96090B1735EB,6A9AFF2DEF414785C740FA96
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,87A6F4595E81766503F3A69ED488CF30,1CEDAC452A7E2A8F0C6F0898
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6D2C603B63B9C2DB78C7603FBBA2E56,4D87573C92C742AD679C5F47
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,38F20E83B0B6B0ADECCD8AEEBFA0D699,174B64864AB6D9ACB49E9974
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FAC8FECBB568C411B8A026E8101EAFCB,DD1C6136805B948F8A752F88
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,444530537C31B55D744B3ECDAE7351F8,79452F3E1F9D9CAD82B87F8C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,857CC0770DCA36D9022EDAB273E28663,83392240C1AF37AE62A628EF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,57E9FAD98FEDEE806AF218277C3C5D41,7CCCC317E62BA74A9C76D519
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B5824EEB55DCD5A494FF1A90587A823B,286597939FE17FB2632AC770
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B279D4E24EB13A17401CACFEE936E04,5218F1BB472334ED7E1638FA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1EC44F30AD61EFB4E0DAF670C3B2AB70,9996814A92FCDB239CE26937
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FCF2FCBA29AB5869EA97742E1B84F36,4C4AEBEFFF5F38B19E115879
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,12690AD6A685FC5E12F9F2C8BC3B0EBC,4E637991268BBECEB730DCB7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9F82CD33E3B58A7A12CCD5CE0263795,60B29E63DDB9E1662CAB28AA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9338545BE3BC0BEBB1147A60A901D050,87A06D1628D7F632AA0B09FE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,430A9DDFFBFDCDB35CF25C2FBD5FE048,3CFDE615E8709673BBF5F81D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9142B3536CBC753D11927BE8106E06BF,7AA594617CF61D637A708F6C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3035ECECE2B602952946B25C768FFF52,790963DE796E2AD0F5609414
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,238844A8C5D4EE87E1E3DBB9730AF9E1,EBADA4E0EB87ACAE64160331
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2EE2ECCD9C8353F0DDDB3DE1FB564845,9639CD9CB0B49815D3CEBDA5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4CCF70032015B8E5DC13EE6DF5D9766C,4199007AFF50F079DD974CC9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,940EC0E6CC164B97CE7A620569BAF28D,8F4FDA8480B3DB9879680E17
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E9AE188BDDE66B3F5854C3EF4B039A52,E2C4FA22AE53E117546C6A9D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77933DBD0A5BEC33112F9984918AE86B,3BFF6F18700B52ECCE2C84C7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18B1D51FAEAD1B22B013DEACB696F70C,A60CA3558AF36179BB73000A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC8C43FFCA7B3BE74B75C4FE2161DDD2,0A94334EA63F06450687F5A2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1F89ECC18A10A50802BDA9425C04646,04D28F46E4CB41BF9A42A595
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1EF29848E8859D78699F0BC084FFBBF,FAAD7FD942FA72B031577F66
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A6E390B309FFE210B5F08E60C9A38C6,AEB7315860F4D0720BB9F041
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B574C2AA7D8F662B40A8B32502003397,1DF4B893D380E8976DD338E3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,92D42585A0375621E0CE7624BC8A9EB0,A5806E604AF5D548D7680484
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EDF884875394558E62621E8017BC4F2A,4716D1CBC44A8B3EFEAF67A9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7E1B515FE3CDC08B58C5A9954DEAC7C,4D639CF494DDFD648BB5AD8E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B7E1FD35769F032A5253E103D39C9F1,ECE54620684332950785D8BE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0679BCD97C8EEA6B4E3A6D9A6DE33835,CF055324EBBAB90814F42FBF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DC3110C86D5C7E1D4D3D545EE24FC2C,07938CAEBE1712F5AE1E3ACD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE1B1164BDBBEAAB83ABE0C419DDE545,9A5C9BA8D8F26A7CF64AF101
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B0754B5A1DD4B70D6668EC8EB4B39C10,52FB1BF1CE5FC6A231F0F05E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC45EBD7DD6E36E070B10B353CCF9D5C,B729AF7EA1195B39374B58E7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F61666A78A70D5FB48828AF5EF5AA2E7,D27EC7914E016A7FCFF71C54
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50BD44366D78AF6A69F20093BBD5E0A3,17A8D6BF04FD4962D8E160BE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,29C0FA93802FAB90949F502AF5E3F2FF,A8061D733AE08D36228A60C6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CDF57CEB499D1531687C8E6BEC30F2AD,2FE50295265CB2EE759C723D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CBE08B4E5F61E801F929658192748795,6616AA22DB8D0F9B383553F7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF1E33D1EB2364CC5EE33ACB28D96BF1,7A57FA9E969374C8E3C47BB3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A836E1719AE7E54F8A98ECAF902F587C,80938563139ED354B2C3FFA8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39BEEBBC77D4CC9FB568B738E7D02F71,34087FA85A9AAC1586847BE1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EC546393DD23CF2F2862384E8C3B146B,BB153B83A3908B4E64712AD1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,96BD017521C07684145B6F8C6A001308,854845992A4DF09576663A15
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F60B146739D623E691FFE695283958A2,D4E66CF06941040DCACA85CF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,881FF49FE99FF0FBA2ADB26C9E27276D,0ACAF775BB38337A1E344200
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3714AF1C4056F4F1A0334428E70EAE31,675C9D5C711980E4568EF851
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,76ADE089A96DC337F6DF5AA2AD9B9379,A4BB7572C86755C40F67668C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC2E67BF2FDB79D53509A1B712C3338F,A08FDFE14B6377B9593425DC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9B1BF9D0A2191C33F6D3119A057E9ECF,A40A99883EC4D2F5E66F135F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D2D20EA10C7B5E377E110CC2C471298,D771870E3342A158CF5BC565
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20DBA5BA5C7364DAF94894FA2E3133EB,D5ED6537C0B3343D2E3DB575
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B045A56105D5FB8E568F5A18107F339,DB2DB2118ED8A75AEC9F17EE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A6EC373C993C65460F60D5C2F1E2C42,AFC9C8DBB8D37070636E8A83
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78D42F93ACCE494C7C48F8B3FEB833BC,56C4A07071992807A24873FD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,877087DBDE0778182AEDF1835188A17A,A5AEBA67FD0C0053573562D1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C5D36C7B00BC21E37EE7C8BD2344A2B1,9B87A0E5CD0F142730217AAB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2848480D8E779C0190C1FAE7572E7A4A,8F1512191748CB0A91FDB205
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3863CD1CBCB481366B8B1C1F6FF8530,0766720770BE1247317F7B64
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BB71FAB97A20ED16A391A519A9EC193F,486EC0A9E17EE343578837C0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,052E5A2C31CEF3E3695A1397853D45D5,936CA82F9FE6A435C4EE4DE2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7B6306FDF353E730770E66604F8466CF,4121273261A8C8394BCE6FD5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A6FC4AFFD8C84F8818AF4AF49FDD53D,5763599BEEC27160A6AF64BD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D61D855CEBE64691EB99EB73E3758FA7,E5D9845F2515E2BD741E912C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6982C1E0C933006920542445974B0459,AD5EBEEDACF13A80488D11FB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D36A5A66DD0059C76B2C0510EC41E25,4AF22EF5C1DB27880E8F1B1F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD58C379E73A4923555FF88714E16CF4,D30AE0937D8729472D0FC3C0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E04F522692CBEE4B7F0315AD9C51D72D,D96F380954E06B17783E0391
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BBE2C80970B92F6ADC1AE1525A197DAF,9FCEBC453C0C2F496D2B7B0B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D8CC3E92B9C35D22B2FBB94706521276,BBF9E042F4E5EEDDC95EBA85
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30B4398C6A943E1FE0C3C512BD4BC788,8503AC4FEB9FDF7CAB207F62
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42176E40D3F1446A15D9AF3BAEAA97D1,FBB1A09D0DC843BAA4151147
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D9269B04D899888C4DFD9D18A14EC62,9319967214C5E69AF7CC83A5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,577A7773EDAF8B1A958F7786EAEF9777,F32957EF68CF821FE3C4C844
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,62BD892681623A3893599E5EDC068BF7,52B4A34186CA802DC7650385
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8FF2DED49942BCF15D92184DB625AEC,2B7ECBDD13D65F645A1D71BC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A375F080809C959288ECBE28177B8FE,A15C38E02FF392874C2477F3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F24A400691C85CFA11801DB8358EDB28,AED4274B44DA2CE47C646927
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2A605DD2D6CD2532034962B7B341C92F,90C1FE26F8FE8BFAA6CCDBD4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4A0EE729A82478AB404AF83758EABB77,9FB249FB258CC32EA8C2CE1A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,77E87DCD362B3011042A2D50DA174118,50FEB8FE43E76FBD9FA6DB41
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,05099369CBEF98698783BA40403A34A2,D6F60A72FB0E5B8B693A2191
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,33817E9D63C8FE1DDE0025FDE7DB2FEC,2CB474A91467A18E2A9CC760
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D237DCCFF06B1DB84E8D2BE3554FCAE9,8501DE0D5ACF9E38D7363AFB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,377F98A0C49FB4150128986DCE4E7359,25D8CAAA3EFEE5D7102D6039
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B00DBA3CC58C9C7ABF27447431B16300,9221FB5259BE9C96B161459F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,20E5A41ACB1B3853D6A31C52DB5DD12E,67928229F5693E291B98E732
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DF9CCAEC4EAEA10523ACF122D4224B0F,D6912B17D1ED650EDBFA5DA6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,030C9B40FF53EDDB9097EACF7DE5030A,931B4F1E46FD35AB1E5B0F58
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,977A5F4C3C961719DB5EB52D0B38B1FB,F8E13B7190E28876833BF22E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D726AFD1E009A57B50C7751EBCF50A3A,455B65855ACAB653892103D3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0066B204988D12934052DD78451B3C38,7A14D3B1095D6E7778043C48
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,310344BE7D063F69CE10EEE11B3D3325,D9D916E2A9E0EB1D884F8817
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BE1E399FDAC7463EC2AE1BE7CC281C15,761BD212E485B0C0FB45CD19
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BCA508E2BBE57BC3F0373052B3BC3D9,8EFE95BCDA4BD9EDB5DF843C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F2FDDB7EC0126349130702C354D9FF5C,212B7A28EBB7D9F43B25FF93
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,476582F5421F58306A3C57C8F6CDED9A,1A591D59BCEA8D9B7D10A2B8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC58FDECC86B561D6A148B4074872BE5,4BA6D4EFC468467C570168BE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFE2C743B197342B2C6E33058DCEADF5,D683B57875B63428A0523913
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D0921D159B743A3E644DD3787FC767F6,5729DB51AA3905FCF6D11CF5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22A292888CA8C313B785F970B490C261,7AB4DC3F26954848629108E5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,996E7453208FCE8F62601B741B187880,129FA10FA3D67ECE7A49E8E2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B3915B7F245EE8CA2613C5DBFA40B36B,AC6CF8265CA6021E6D28F477
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4865C31CE54C3BB99E53591AC8979198,2650D862DA70A85B9FB4503A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC16BFBF1FADDB8A3DED51D1ADD8C391,F3CD6C256753896320EC4D9A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D27C082749B362A9E079528CE462144,49BBBBF8AB5CFF59005105E9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,19308C8E873FE8D050BDDD797A029CCD,476AF62908F1421B62E0E334
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1426F94934BB10E6B4EBAD64D2A54A2B,02C6B814B58120E5F96B4107
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF1E5C627A5533D575A8CECA5B1117BB,9304DD11B97DB619F303A9C8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,58547645FA672D474940279877918D62,BA40A424762D75DD60C52373
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3A56DCC21C13902FC625643FB25C987B,57E685340A4A237414207C48
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B851E274F9E1E7545ADDEDE0DBA5D2BD,AE14288C0BD0877319194E8A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7627A495FF15D16F5DFC3BA784DCC243,5772AAE27CAB453D3F6EC374
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,34CCAF8288808B8281740C29BE6E71B7,C8CC08C9299FC6A61C92B17A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,17795498DFB7074869664325E892F88E,E0319808163DA661053AEE0D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7A4338E4C6CAED253D81CA943F266933,12FD13AE57F3492999AC0020
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C70DA6910BEDF88184ED2CC8A630A64,D13FA04CA1CEE854310D2469
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,51C87035E8757BE513382458A614D592,6643B6F05BD94565D7292AE0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,890B1AB6B918B6FB910A874F1774097E,5E8292F81CFC8D81DEC5C71E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,093495E9E1A906FF8A02BE13F27EBCAC,E4700F7002C7311ADFDD0AD3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18534EA254A6E58AD279F2E75ECD1A2A,F7CA1F8D9D942211356F15AD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1B25EA19D9FE6E6C075DD10D7178DA9,DAF3C83EE49AA9C795967BA3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3919CCE828CAA532B0D12734DE55C183,F9FCA32B5411A7A5802D8953
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,056CA833057E0B16285F753AD6FC4925,D99B2F3AEDD8CB9229BBEC0D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4E900241483908832374039E44B365DD,CFCD7BF4E9C80C302555C5E6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,434E2A4081A6AAA495F6324A27A2BEE6,546C2AE028F7324B31EAD660
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,542BB3F650D3FD2197D651F2AA3B4CB8,779CCC12B9A81203BF6E64E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85C002B4D3C22F62CA29B5A200016AEF,DBFE7A507BF3581FDBC223B3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0D62D296D3DE757A2B97313CDFDBF28,F6A883DBB001D5A06FA56A18
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,758F8139CC9EDB9E1046D5D71AC6ACFB,A11C1322F33B0C7147ACF210
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9854BB439AC95310546DDCD6AF8C9EE4,75DFC039FC4A5AC6541750D7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,162B05A3D90E4F691CF4FDA964F9D08D,BD38EC87D8FBA954372B5C2C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3B870DC087FFF1CFE1FF0E7A3E5809FF,D8926C4CE7F8A1B73803DEB8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74DC9116A986A4C5623CCFFE99151940,E384D58528BA6593998B47F8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4F0AE2A1169E2C0CA32D76222F82AFDA,D0D1CF2A17E32F33E0BC5D85
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E401FA58FAFE8C370CDD180384503D4,410C2B70E0AF9ED19AD1A655
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B600D795E20D5072AAEC3F12FED9831C,8B195E4EDDFFBEA4FD2078CD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84F03AD81AC842234924AEACBFD9E007,C4841B6926907A9ACE38F692
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A9BB6DD52A6131A6324B2200A94A4C37,6135DD345339D952D055778D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8C76285968EE5CE3C5BC053389320472,483B0678643EC1B079587398
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85CE181363376F133C27395F546810A6,9942C4C95A9803060EF4E9C5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0EF7F03976FD4F35877D81E51773F788,E07E11CCD12DECB4ECFD52F4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E051CE8CD789364F3D4514664637125,37016F051186B84AB6C0017C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3B969219C864C6EBC0E28E998E723EFD,06FDA82FD788237C82EFC648
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,941D4CA3583D84AD49E8B36043A26B3B,711A06F246EFD1CB875555EC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,42452AB4BBA8816B642A7A2B2CB32746,4963261C47864C816D91D757
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EFDC72ECFC87BAF583836B28CD402AEB,8FFA4E3012A7358F04C87DDC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6A4A1F77C1F84217AD574B06BADA8D8D,7C615CB1B0C19C1B5108B2D0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,612B7A4023CE381E2DA777DB5670EF19,0F3C0B32C0CFA19A1E371569
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F2FE60B316249CFC37FC844738B6776D,094BD3DFB26EE7787C67A768
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F16427D34518986545D6C34CE3DE0F25,E61CAA8E90A56C33E64B314E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8CC551123C8D0E5F06CE4CCC4C5CD2D6,4A12AC7EC803DE9CCE4F5BD2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CAF4FCF0116F09688F70DB5BAC4FCF7,7BB52ED93C9753BCD663B3CB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,570A449DE9CF697AD0F857BA3B4ED10A,F4D5A26EB7CFE1DB99F235B9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E7492BB6C9641FDC442007FADEE378C2,47BB8A378D5FD4618BAAD3FC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4BF5A78BEB85E6EE45587980AA8997D1,856007831C77BAEED3FB74B7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C467D3AA1E425853300115E2852A2C22,79D0A87198628A4DD0715A81
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,166E20A0937416E40585C4725A2639A9,E60A8BF1DE5F8FEF98FCAD74
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF60302DDA32C9B15B810FDFF066C3A8,066BACD0B62EE1F2DFF67E5C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0CF0CC0B334C5FD676AA5ABD29DB391C,A8C1FF13A05A3C2AFADF07B7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C6F0B6C1F4145802A9B4DAFF7595919,B21DEA3B36A10ADE95DFDA5E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,59E49926C0291B47EBAF1E08B8FC2E6A,29CB0AAFC26985131F99553C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,24A9969D2A435B8E8B8F425AAA089862,6358ED4DD9679D461F39870B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CEBF9A54B65EE526C4F5962B744BC8E9,CFBD78D18CE385CD80AE77D4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,766D7612E2649493E42E8729651E3915,B543D6DF887B827AFE7A49C4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8D9C226BDE5412DD4CDC3B82143A831D,18C01DD500E50DC6BF028E93
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC89833635DA629FB52A15D4603AED87,5865D89B38AC00FC8277D3AF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,75C5B6B1886B874B64A935443CB167A4,B71CEE0596FBA77B740403C9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A154255A2AFF8779A6E0396E3FAE226D,CCD287D9A032F1D350D3EDEC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3493696275EBF6764767DD177EBA8F68,9D0F44BEFE7C57E7A342E055
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,48B4168389CC95EF4EA289767AA4CBDF,77DC39A48A7C1944B4AFD3AD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9F1EE8FC7A3886E78B1A21338B64837D,419BC21C840CA23E21C29EC9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B1EA444B1E3E7A548FDDA7FF64D2E602,4977A7DE73FD33B1D97D58FE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,68F8AE28016004B285403B23E021BB2B,CA330C40333234E36F460166
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F4F1775A34BE9711260B1F977E152EC,7BC572ED3D38FFBA5488732D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3901121148BCE143BD22B87CB212EF88,5D3212E5298C99705B7AC932
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC61F4169C4BC0B3C54437F622977834,D4506840401DF6554635D857
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5A051696E25C5B4852D48331780441CB,BA534B6CA3EBAF8CF044826F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,841B5804EAB0F86CDE97139A2C6B180F,278FBF615BF11F7FE79EAF23
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F1488D2026FE51161531EB1966D59BAC,A3CDC43DD0FAC00FD463B36E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13913340133F4E555B5BFFADDB325BF2,6E07FFB5F8E5DFE6FF97BC2E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9111742825025FF594EFF2F058048BF2,BD0896C75C8E80FD28C0C583
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD1CB3D3F4E34057AF30029403CA3E54,3EDF25FC2A8068B3EB1DB74C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C054E12BAFDF2452238738A499CC283D,B7212228FAD9A97F935AB498
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F52B105E60C0CB09793BC8CD7AEEE955,323153E1E96C18F34AC12A74
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2FD896ADBD204A8EC457DD6AE4446DCA,78DA31F53A33D4BEA3F7A1E6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03C67D7FB9F90F3B8416249FEDE60208,3C625218B4B96297314882EC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FD0C8286A0EC5A245BBCCED275905A72,FAD0C4B702D988EF237D72DB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A93176818C64D31AE11DB44936738D59,665AE6D0A8E0E0FCF7FE4204
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7801F9B77C8EA23586FF132942D674A9,C6E394BDAEEB9F1797D9A6EA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FA3B9E855330723B00CE8E3B7FD0F2D,6C615F2A5E6E5BB3E3F4E496
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F3AAEFD08C1A3711672606593FBB55DC,916E07B07A2BECC7D73C5C7B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8A2B83CC57E49E38B3116FB032AB7C2,A4264C771ABF08AB7B9BF457
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B169A6F3D14D65AB435A411580C72BE0,91EC0B1EBCB8F77237ECE573
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0D43F218A959414940569C4F80B5F9F1,A2FCC9A9F23685617EA963CE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD5A7D67CBA2D953A064FA3F0C7B426E,9D2F2AF67DF7016C4078365B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A1F412EC7A762D4D86B524DB41A03CC5,B46893F2D972D64E0C56595D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4FEE01CAB67DB39FE9E67E62D1EAF9FC,B84477FBD1FD9217E64D21F5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2C557D29B854DC9F895D95B3D9A71C83,5FC57C5E4DDD05E6D4125643
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78BAA554D65A8E13CC4AE5F244FDFA65,05C6EC3E2A5CB9469981D932
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8026E9D238C5ABB9F3453D505358379B,0A1D29C53AC98815E7A834A5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3960A9455AAB630A81F8379CB8254B81,3ED3FD6E9716E4CD21F791D9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E9D5E86088C4798AAE8EC68FF93B8B6A,1BCD6B153FBB8C98DCFE2BB8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E27A3FAEE5ED88DB4184F48A312A955A,C0A83F05F7F5D8718FE8A810
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3ABF186BF4A9EE6DE4BDD164A9EB3CEA,0B85C14D123EB7FBEB22BC64
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2B4FEDF3F46178F97BBCB8DC4B6A7AEF,9B47E11E0BA56D68AE00ABD6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DF9DB131DD1927D7523C996A8CCC7956,AFA7F27615E6AABD484B3750
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3151C7838F64ACE68776C88E23DC26F1,7A18AA3641D5750C64165993
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFACB079853517002305BA6CB7D7876F,09851BB26A04A16B792B284C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,620666076D2D088AD2F61F4B4DEC00DB,63D6377AE4D5077130A3D5FD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,81181C3B04A2FB3E90A2ECB3A09DF44F,CB46C3E3ADC28DA7A9F12CBE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9B485FC8D34D39B84D619B0FA0B91DF1,0366966D53CB7BDE4BF394C1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE43D7FFAF046211613FAA0672781DDE,653E1665CF9679361F428A57
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78C2DFA82F4520991FD3507A142AABD2,4FBE0E4158E403B8D8AA3269
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6E11061572E6C5755F897773043DB7D4,7E654E600CEAFE38C6337807
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3FB2EF05BD30839A1F11EEA2BC4C3ACC,CAF07B3BBA6A5CD6757F0C5E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D2557CB6B0ABDAC48E074C3CF3EEA55,909EEF3E8014ABD0C3141328
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ED451E3A8E2618FAE17CF8C9C544EA12,D43D8B75C4370BD8DA08289E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1A7EF4A0F0C6F89DFA9020D69425B363,BFA698344E2EC5C260D3A3CA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,39FF53E64F2B4B8E445981EC8B04DE8F,926623ACF4217A7D4DE94C15
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FB4E8BCE634F763D8FE2CD361057705,3001951E5CDE9C320AABCBA6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,744DE4EF2893C68A63D340FE40E2C1CE,420982D52145AB5A54B5EADE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C8ECBED4C9D3639D3F1E5F4F34F682A1,24865C4F6792107A3365B515
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D00ED1D1D9CF74C256AB08C8621FA824,665B7FA2B71AEB7C2DFF7724
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,83745C78C893B3F786C728DEF6A48A57,6872F7917E0FEF0F22D5EA61
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7FBB66885417679E5970AE6B72C5BE4A,84E39E1931E4CA690551F64D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AF9D46D06E926C66835517B0155C8ECD,150A4C90CF275DA03AA0A342
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,236722E40A7FE9AF48008DA60028B057,28C9E79D9B3B9433BA2C8AE8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,374143C31BF20F54B0300181515ECCEF,028C56AE7D60DB723E0A4983
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A84BEB57AB7EFA419243F145D7B81623,4E00F03F82C080039BD00EF5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,078CFA828AAC69931B30F86E3451B81E,AE382636F9F94C763B8070A8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1F9476007304E4C4A3C1F14A27CB2EEA,476B9D26577B59CB3E1C3C16
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DBAF388DAE2EB27B76759C2CCACBE8B,263C08E1450EAEDF987EDCE7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9C2BF5F3EFC3DEA34B4EC3F633280B03,41B8D9727A5E8469EDB661F0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AC7D476A7CD104A4C4B152FE82899E39,A3B40003A9FD7894C517C8E3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,178B204DF182A0560778E5B90D1EE170,E77BF4BCA640C82BD2665C9B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9AEF8B5694B926BC4A55DED5259163A2,55A731EF32A6CA3E833F50B4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6B8D7482E2E1A96F6B776DBE6F7E5661,CC7E378D8C7AF20E8FCFA0A2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2AC44A80A5FE1003DD24AA4C6864BC61,EF7AAE0833F9C3888473EC56
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C260EAC6C71D7B7D35C5BE1CCB34212A,716DC830699958E175632ABD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5946CA2D7232076E2DBEC266E794D1A4,338283CB5CD91817A465438B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,210EAA6C850967ACCF3325487329849F,29D05D8C1655A641764CEAF0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,393C4E5602EF6301890D599C7766CA53,85EF9BF7A469BF0005D5AB2D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5ADE7491694A75A5CE0959996473031A,78A42538B39E12BED126DD63
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,670A72D60EC6606E4E798EBB1D4AEA45,3EB374EDE44B276A0B05F01D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,23916D367C0E00CF13B2BA5849293281,3BCEC47F6FF94E05EB2756D7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D37E626165E8CFDA7F3503EE96D78AF,7DB25F0039486AA1C17DEEBC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,730EC7F1A1334D7A9FA161ECB8FE839D,4DFCF9EDFE4056DAFBFDEDCC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF7A806A9945108833CB3C136032A33D,68CB935008CA401B29CDFE2C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,148D1ADC6281ED1ECEEB4C61A5D5974B,6611E49991CA4CCC35CA4BBC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5D941E9A26889E243CC7BA63356B8769,B2F69A7288ED0794C8D8F3BB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,52176D9C830733245657C8866CB3FD34,07D624B781E45E1AB2885D43
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6677C3BD296A6AF1E3D08CB803D9F29,6DA6E7C25EEFC908BC9CF2ED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,35BC2C889362E17CC46F1DC4C69DE5AE,9B632BFDC79828C2EAE40ACD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A8FE6732AC535DB718039CBB7FA0B0A1,CED6008EBFC492271022666F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9CCB764C102F715FA8F6A77B9C681A29,E63D04D6553D5A1272EC93FF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F430C9CCD6AC2C5448DFC20AEAC26B78,A268C88D3C4AAC5C3C40B971
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD2A3D23F134BCD78AD204776884DF1D,09C2DF4686D239A55FECF7C2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6CA21CE9B44435BB2DA88DD15B1E1A6,23E6DAB765FA303816298AC7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F7A993FDE676BE6063A83BCCA2F4CA7,A0C1BD80DBE3CDDF9157ED84
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,84D99115B8B2820C52546580B5A71517,EF30D73FC9C7712BC1F4E834
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8F104901412EE55AD48EC8A70C0D920A,F9758C4357FCDDCFF5D7878C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B6E970122768A8B60D6ECF3590256587,449F36D3222CBF4262F7052F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9456329E3E51725FF4306C1BF1FC84C5,47E7AF27620A89B4F646FB8D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A320F5AB902AB2DA39A19819EC3DAE64,F6BBE92D2F19DEE5593071F4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,ACF41B8B0345BB7C0611BAA2F78CE719,1FBC5EAEE93BD973D6AA6F6F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,511765C125FBEE4D4E5BA1B339214FEA,6B1389AE53C01A07793BE30D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,960398E8F44A9F26F51694BDE61DE6E8,1EBE854FECE2AB72356FF067
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,43172468FF0E5D538B047E89D9FAF128,968204B1B443C19E2E861632
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EA690D56A40B0E4810CAA7C3F48ACD9B,2B46CF65F8EE650856000B67
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CB2728D1C06FA1653325838B6786ED19,C757A09F686434C6D2AF8FBB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4ED8EFD706EC13D2D8ADB73E922BDB96,F188C54E0B4FADFEEEDA9E98
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DE4E12D86637EC29DAF8366BE5A17078,927929B7DC0C251D1B2BB0B7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E241E86614830FC4AFBC8A9B994BC11,37D46D82906800EA6197658F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FE24429FB354D1BE7F27D1220D7801EF,A3D69BDD8EB8C24A6A19BC09
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C1C835697AF1C95B77CB5D09ECBF402F,684525124857136F39ADE1DD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AE8AD487E7DD8B1D8CABB82C4B3183CB,EDED085BBF5084415D4E0205
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70BD0DB40F3D976E4907DCBA3E40FEE1,EFE6A6F67370348AE283ECCF
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B1072BA60B98806208700F6BBCB338F,4C374E86BEBA04BAF4A2E11C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,536C7B7A6D773299B839416916D78B6D,1F09C90AD9654A66EDEC86C2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,024FF49B1CA2AC1056801B2B9FF0BDF1,3CB058ECA6914AD9AB4E58F9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3F73F9C6FD5F80388DE7CD0D447E34C0,9D4EEE0478937DC2D7EFAC6E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,56C45BC9B76D6D98B674258314ABD03F,9307A97F0128F4A8A062C418
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6EEDC53430538D16AEE578433AC82C87,6BFE03DA1A89F83253866536
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15526C4A50256C554663A59AFA31E799,33F71C34F358D46AD9618212
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,31FFA6A17A8A7537CCF03A58E7F32A28,52F193B5D4238BCBA227B4C7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7EEE147EE90896BD4375E96B11D467D,712F540C52D2B47177F8087D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,218825B240C7C411F7A140834E3C6439,7659E16CBE00DBEE2C89CA18
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8A61111A6B336543BF5ECCEB68F7D15C,2E895DC6ED3A9C291F169FA4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,05582B24643BF38B4F0B95044533098F,484D01822E1106E27D0DF3C4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A209067823F038C99E35FBBCA3BDE95A,0DCD65DF9F21B41F6A1E5C8E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,62EE981575D6A3250E3BA64DC029F078,C7A87C7FA9F0372FE89BF1C4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,062C73ABD56F61A3A42DAEE0F8EFD09D,F5660C6FFCDA6350574A887B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2F4F96A5A4062B572F7BBE311ECF6492,3F67F5A619A34CE49DC41D7E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B360977080E47CD9B3ED66ED22091F4C,23822C6017E8BA385838AD0A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E6E7FBD7603CD52AC2EC8CE72041DD0A,F76BC82C5FF94A2F0B411FD0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F53314B138E7CCAFB2F7131185918AEA,7788F96D0ACEA0A2645D52A7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D6B452B402B2851C2012C30029645FBA,311CA2C5A76C27E8C7A58685
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFDAF1BA6EF954C620B12F16762B35AE,189701B5967B2D96457EC247
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,642D3D046F4F1EBD0C775B06592CDB27,D054138B51038F23BD0171D8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CDB86368F91E71CE0FC34A70F6FD65C2,74D76011A1912FA279AD1CC8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9FEDAF38BA24A6C82BBA68DA95B71176,7FE4FCFBF42536F899ED7360
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FEF1D522E84CB983A5090B4151780376,1489794A18B7CBD81B3E6E57
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,861435ACCB03FB2D1BFCA69782DC469D,4B4D585395AD649C89FE6139
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,995AD2985AD4E5A1F8802B90B7F8ECA2,993C1F391FBAEDF577E144E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,742263AF7482CE41D4EF0B03A3AD9B7E,ADB826CAEF2799A7A88DC866
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,479337DF35E98C67741FAD81CF3365B9,FCD508F6FC1ABBE522E0B691
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C7B92DE42D76D646284A2C2039F584B7,C541B2C7568E4817DFF95FAB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D0C3DDC48EC35DA67B369A9DE0CCFFCC,8AA975041C6BD0DA7586DF38
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,599B31C8C3852C1C23DD19A7ACD55C11,07D62DF63575B19B89DA071F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0F269A0EA3E8EFEF5C3C52D43D002225,A34DB9124623C3271061BAA6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6AD44C3FDCF70DD91323CC62CFB02D4E,D17293017E5E46B0F054C9F7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BFE112DD9EBF7E917C561F72750B8912,8825188DA2B08941B8089631
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B87A63D3DCAB1BAA9A185650D52F98BA,781E9ED97865B4EAEB24F256
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,15F374A04F54435C4986C3CEADE49078,3803413B6A6B7D342431E19B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9597CEB0C4C1DE570C408C732C4AAEFF,FFFCC0E7778720989F5D207B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9EA551BB7EEAB54B2CB0B7D5A4B46984,12670590F5569DF36255182B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E0A14DD9D10CA02AAB400CDD6D4CC8DF,3B8D453873F43514FBFD6E61
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6D7D889972B4415B2C4BB94147A8B0C3,9AB50F45E012C1C13DC0C123
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BD143BC0B969AB78A4C77AEF75DF577B,46BA7B2AACE2BE1EAE041BAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFA3644F3A1B2E3C949409CD1A9FD9EE,4784E15B8459FC8C31BC5A09
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F68A2E4BC14FF93B6E8AED6603681E44,08C81D5D7ACCE6421A3A83C8
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8958835A3177994FD9E234A64E8DD402,4AB52CC30160C00D0CB8149E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FC5A744BCC4C3A64731A56568F1824CD,7691B4A850CC3F520A27CAED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A0BC0414793FD7CD91C4901ED37CEFEE,50387A5169C4BEF0DFABA169
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CECD899ECEEA771F48B27ADAE869A0FA,AC47989CED4D7ECC858B3316
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,227AE04F7CD994EC2C5028C28EB91C60,2CF79C8535D09CBE08C99BC4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1EFAED76F88CB13D36D6FA9341E6F72,D0939986C168DF7A71F8692B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0BB39C124E6009D6F192BE076CE0B912,07ECF9210CD0BA6CB7D0A331
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,66B94A56E5ED1CA6D8D13B716C826EFD,AB586CD5C53D9B44AC9CF827
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,74BA0547304F65181E09067ADE3944A8,1BC03458AF15F80379307560
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5BDCE39E73DED6127D19DC0D2B07509,2AA15E6321BC75606E161299
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5FA9FB4F33B5931DFD0B608D3673CD8B,2EF8B7A870C0B16E2A2E0771
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,591C4B52914FD9906794F9B437297932,57D657E1F9EE91A75BAA281C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,88A97F10BDFC5900CE69B02CD4927D5F,49B141185B37C4BFE45770A6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B699392799957BDD5F7578F616FE052D,E9FAD536A1195A43049FD4FB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CFDE65C7EEAB7B468E5EB53B59560E56,EBDD36D040A23090DD2B7C8C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7DD1288548E9EE0F59C7AB71ED93F458,570BEE5B5B720E1C71CC4188
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F8A953657955164A202FD05D61ADDF18,ADB41A9171F3B9EE64CDA252
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8496897F262DB3DA5B1492BD910EE533,A116D7BB8E39511500CBB3C9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3143866A1BFF58CB64A6AAD00A8B98A0,88A823BB6C87C33D326F89E5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BF2FA6BFFB949B5EF935D4A70A1AD000,059EB7C4093E12A3D67AF43B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,22D61E9979690AE0F70A2097CF75617A,4CEA847615CAAB386441D6D3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8BA2EEFC875953E279A0BBFF3E40D8EF,EEB30C7A21BF5CFF8C016E76
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0054786656570CAF86CDA3E2658CBC4A,A8D77AF4C0D2968BF86F7EBC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CD789413163D67BEB5A8B4B2041AC8C3,1E8EFC2C49634EF3D3A76663
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D5C2E3294F8E3F7EDDB41D8038E8AE4F,DFB267CA183A97071445EBCD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4547BAA42EC0A2AAA5E4A51A40F508C7,D726295FDD1F03CC38C0D510
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,30675DADA51DD427E74150DAA3D08E47,D98EC07B336FF2636664CEDA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2049EFBF5A6B4DBFC1D827F7B6F4F79,8A5E61E9C25DABB569047DBB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4DAEAD6EFAFC7B2D5B7599CB572D966A,3C7F91652C4F50ECAE96E31C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,421C75DAE44E53BF661EC64716C3315F,B7C0ECAAD15C95E5A230B0BC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3DB086094870B8992C429827A41388CE,932A80FADA930997A72E765B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1AED87BACBA9546CEFD7577149B343CF,37496BAE7BAB169805B8A404
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1D4C0838314C7B2E969CA01BE86628E8,FDA25570F91EE000DF4A462D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E2CFEBC9DF035EED50D61010B97114DF,507A0EE2F0E2377E9617D79A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B7C41BDBCB3DC0D686FB4F2A246F1EBE,9A8B1932BE12002117B66C60
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F3C6DDFAAB07F2655835AD684C1EAF8,84F746F4206E7B9D70DCE400
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4BE5B436297DD7EFE78F43B50E9D83AE,6A7351376DEBD0C0045287F5
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,810A6D4C4BCC9B442FCC2D17302ABD52,BE8DFEFD0040A9171DFD1028
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70BCCBE54FA56D6C760B2A30F12DFE3C,D066D8EAE15177FB53E82557
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,685C7FF8585763703654DA98CA2ADD46,E3AA8A4EEFF90AE719F7C9A1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70EF0027B67540B854A5678C2FFDC575,58B0CE51BE4916D04D84D042
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AA3ED4404B99F8C48BC481239F470693,C7184C0EC24D703FE74FE294
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9E5EF17C6BEAA0E6B65199ED365DDAB3,9EE43A1ED3DBFD931A317464
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2E9403A2E3000BA5C4E0D27C2EC64E4C,813E15EBE8D0B17B5823E4BE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,0173781A0EB21F505712948BE75B8458,1E3CA90D5A9E8A6464C8E36D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3C088C10489234D6328F501EDBC98C00,9D7C6B66C8630DC1F3F5312D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6EE02A9C039B2D0FC48FD8A345F1892,0A822A5118F13C0B8734AF15
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BE8C4CBEAF4F1F1A9A3695894F9F2A99,CE0FCD1BC48933F43895E002
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,128432DC7C3146F692965FB0D0A3308D,770FB50A91CC47B0382B00E0
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C88C48F3C4D3EC720F01BF9C6A65265C,8F6DF2A2261D41952A2C382A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B971116F61EB90F27D34457F37AD39D9,2D33847A8C32844FDD307D51
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,227551D0863419A949DD59F36CC83C5D,829E83017A42C31FB195868D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,03234F66F921406777377B0DF204A6DE,C43127089A8D4F7250387C9D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D88DF421C6DE2284789ED5D54F45F03D,3495E7918C60F295548DB637
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C3FA2BC662694EEBEE4781F73CBB18C4,F691B5C42013705DE1C5AE33
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DDA9DD56CF3E1FA5BC6B9118623A733,469BDF4A8704D356A9A14B2F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6A403AE0667AF03479DA7D96BC52127,4996261F8E580F85B515239D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9B2F270E808E89FE9FBF7910D371A99A,7904A08879D7368E8D28AB78
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,346CF33E3A1CB2ECCBB0293B22718FE0,4A381CFA638346B0AF50A973
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DBDF0D1632047D2E033CD99585D4EF4,8D52FC66020546B7F4C0AA7D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C0C92335F55CAFA75C8F32ECC8A8382E,AAFF1231A4FF3657E2A2F050
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F98D69B9C10B8180D8CCEB6F8512EFC8,ECBAA8308702D56AB4B8042E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D18711BD38803D6528A0ACC4A2D13F44,FE40B2A809ED1B288A23EFED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,B45EB08D49D283FE8D5CD8736CFBB0BA,2DC3543A5FC96E5D77C6A8C6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E5A19F4E5A95B41A6B467A4BB61FAF6D,FDDE48FF9ABA9E1772A997F1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DEC185B0F7E9E915A245BCDFAA61B9EE,B4E8B8317BB9B202C1216D39
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CF79DD706BB5431EA0505C5A9FD02DD,B25B155F0F33758DA3E34314
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D7FB84CABA49F0DCDA6CF9BD8DC7706E,47350A6046056A36028A17EB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1552B8D34DA464D3306574792B48A3D9,E941C62F7B37C94DA75700C7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,BC7D021BCD887C891AD03F35E0A15BAF,BE126713B56707925500E8FB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9134777CBFF4D521A3BFA344F7A0B437,FDBDA66AC1D9ADAD8755DFE7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7C5F8F8A6BCE5887333A3CAD627717E6,31F970EEF6CD0EB0A2CF4916
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DF8CB343C509A1AD4F2EA7115FCCDB06,693FC7E51AEE34C25011590B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A91315BD7A33231FD527B607D84FC46E,1830B3DC10BDF6965B2C9228
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD2E8EE1869FF0D47F58E63BC83318BE,5FC704AB4A24BB4EE7D4E116
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6DEAB545F792A82A34768E828C52895D,2C2573C04319579657238F81
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,002EE13DDD62BB00513824409FCC1E3C,714637C12FBC3464601C51B9
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,1B7F26BDA08083628375BEF7D154A39D,70863DE4A86FFCBEB170F92D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,50260BE0CBC61779A3974F29E8F759AA,0977C5842CB846C0F9B7C801
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7CBE72435D57253A7F17B38DBDC91592,FE586E3BB775847DD4D53896
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AD828B0B2057DC6664ED791C5D07B0F0,2DA0521A402DB87C23EAA90F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4D15F0C7057F79CA95112266A0EC2372,C8E87F6A99CD77F1E6C52BDB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2603498B980BB24F3CE98CDCE7132DEC,3D120C7D2A0626188F107796
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7D3F0B786427ACCC65036320D6A87E0D,90EB68AFCE491FF4FC1B935C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CEF85C041E9B497E104280592B4E20A5,D7088EDD39E9441B42FA5425
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,28423C88529A282FEB63168012C7C9CA,8541314D155ED02F6180F8C4
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D00F94DF50F19EB4FABAEABCFD6D2D0,CBDC0CBBA58873A08254EBBB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2770701DD269B0577098A27093E4CBEA,D433D01C27279F7871B8CFBE
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A6196F4218B78A98B4744669E89272A4,6D9355226838299D764B92FD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C2746977B2BDFC92BFBD7B108E31888F,13349E628F46C2871403E8BD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,EEC4692F450CC83E13E2B71D59B3A3A6,8373F07A23AA5A770F09475E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C6016D020BC4C0FFB135065862E023E1,C65DD883032F002242741716
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7EC7083310F0065F3B96E8472A3B13D1,1023CB8704E3F094C4254B40
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CF0F35022BD195F113924F7FE3170685,F91BEF9CEBB0E62E17D189F1
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,13B6AB833AA9181A0D0589C321E1D641,B2393292651E5C5FAC10EEA2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,78E0922DFDD9664537CA30DE31608273,2BB017C76BEC45864CE8B5DA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,92D6133ADB98116A1A8D5233C0D82798,A638E5FB37FD99BDAE373B67
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E63DD02079DC3B5E6EB39366B31C321B,6F90B73C6489D8259C852982
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,18A08A6C828005707749B55A9B372486,D5EB1D8073248AD37B8F239D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D27A6AFDA367D22533F4A41A08E728D6,C0C1517C33F09E91EAC4779A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9DB473E798478DA64AF4ED702F4BC9F2,3022D423A1C7629E82A5A24E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D9B45909B8FB54224223494EEA6E2E30,032151B6AB3213BB7DDFD85D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,8031C87FC0B6482EE41FDAE9452ECB50,B6944CB7B74EAB9C478F1C52
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D75BDA282D511A8FDA9D2A668C9C8DAF,2C95EC0DD014289FFB35213F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CEF23CA86FACB24BC87C7A6F8E3B1C88,18A4524E271A78D2DE5E7499
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF647B9CC719F05B6FC23549E39B1357,0C865AB29E48C3C797B021D6
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,27F8DA6420EAD9D9577BB23FBC8505DF,C3C5015754C0AFA87182B618
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FF8354FB4DF2F4DCAD9810E6D6BE2701,82C123077C870F46B60D29BD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,036E56648887DBAA96FFA30E83D8AD82,B8DCA4880CAD8DB0E51FD51C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,86E00865EFAA86388A9005B52F005717,9241332752219C7BB5A5D3CD
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,C9629A55E7894963AD2EEC2468FE7DBB,E1136ACDFFD9517A555B0F27
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E09B731993F83B3F5B3870A764951ABE,9BF47B15A4384C738487A24B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2378E55D7C30DFC2977F4B1DC4F9F5E8,48EB70F03A3CCB87CD82A158
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6184EA341945118E0646CBA5D58384B4,77675FA63C5BD4A41AC05381
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3BFDF98A86FD921FB72992EC14F7BB45,F538CEDE6978E01EAACBB45B
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,4456A5A28E7312B13115462951C92AFC,72A818CF0DC16D1CF61AAB95
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDD3E2786D4F2CFD9480D66573BCFC9C,2841008AEF343BB28D103C8D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,6DD6D61B2289A9410CFD9714CCECD4C8,F59AB2D1B59D311242978F3F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F167C9441706277D09DDCDD7F7E52A64,126858DE4A4F5819448B7834
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,980FF11DA5B60F457D8AD89A85974578,379707AA8D96C5D76FA14C03
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,70AAC833D245454AE89349A7446EE506,5D79BA0B6FFD9631AF1CB4C7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,927181350C74438DE3B9E8098A617E9B,F763FBD8F7F514F54B18A736
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,CE2FC9FE401D5EEDE241E70202A918BB,6D93D8C321F8333F0AEA5D7D
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D0052E34EB985536E784846E9328E485,4AE323A62EEF67882838712A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F0258B4E9282FCC224A3D6CD3B03CBD9,91BE1348792DB54DB4CE8DED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,D14CDA342B363D1D643CA37F69459559,9B5263789B687DA01AD2408F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,3D1B125A5450D9985C1FEB85BBC60A50,36BEC97C697AA64958AC0150
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,89F95D62593A08D9C22E451C7FB8C5BA,D57A8B45E9EAA8AB3A514325
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5B1FD080E4A66D7057CFADEF6FED9146,1BCDA51E01D6A6BD34B4447F
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFA91C8D534BF172752D8A5A1E5ABF18,1171B4FE506D4A96CDDEC1A3
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,928BCB824199B826E519EADA61A4C251,EB2F19E5D73C846D8C714D3E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F53692F3FB3982697190167751544A29,7AD742D7360FA6C3D379B2B7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,35E981691DFC03F3594134BBB7666048,E80AAB73B59F47BF4EE3ACA2
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E1C591DED46E4151A2758DEE40739154,46FE19CD4CFFB3A2A20C2DED
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FDDF6A5BB92A46D2E62A4D892D62DA3E,91A0067C6F79DCDD23291EB7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2D57BDF8192CA18115B7D8475314A217,9714FD544700667211D17C04
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9B362EB227A8F692CBCAAE2A35126D4A,6A9616C6A43C428F826A47F7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,AFA7288D0D58EADB8C9786402A6E64D8,997C242B49CB8E562D648454
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DC52408D8CA5204B565EDC5A0FC1F62A,EE9CB66B77A507D22BF44138
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,FCF61DE9035595B243208EC41671C65A,2FF077600EA3FA5A0D767078
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,9A583D3FDD3982A15876623AA3030000,19A047A8A76A867653D4911C
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2DCFD0800243D3D0D713A0FE4B1C41C9,C64FC0E63E24B5990B10208E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,72213EB6319FADAE5FFE5DBD4FD3F03E,8BB15C1A20487D9F61DCBB2A
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,2895AC8B667126F52244CEC0831D2C11,179EC0708E768B387560A03E
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7091C9ABA945FF32B3CD9818DE84AEE5,2107211D6BC2DC36418D81EC
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,219370CB0713962417F979DED2342075,BF57FBAF865A8BADEA9AABE7
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,F836740255B8ECB99BA7AEE2CE8C53BB,A3A5D83BA6B66D2EC39B4035
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,E31DC4205A93AC332F96CA5E7BC9FCA7,73483A4971376226A7D00F88
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,A5128C271F394B9FF303E9D169451808,E189B4B86326531262853FCB
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,7F8AB312C58E36A6FF9B80D9FA784D4F,77BEDAC4AF6EBD00DDCA8663
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,DD6FAC2574A4358D54BF123B5B2E4D47,29D903403B472B3968A0D511
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,85CAE759E11DCD58B02C500C539C1FD2,EA65F4805AED4E612A71FB27
diff --git a/src/tests/config/test.conf b/src/tests/config/test.conf
new file mode 100644
index 0000000..832b125
--- /dev/null
+++ b/src/tests/config/test.conf
@@ -0,0 +1,114 @@
+# -*- text -*-
+##
+## test.conf -- Virtual server configuration for testing radiusd.
+##
+## $Id$
+##
+
+test_port = 10000
+
+correct_escapes = true
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+modules {
+ $INCLUDE ${maindir}/mods-enabled/
+ $INCLUDE ${testdir}/config/eap-test
+}
+
+realm test.example.com {
+ authhost = 127.0.0.1:${test_port}
+ secret = testing123
+}
+
+policy {
+ files.authorize {
+ if (User-Name == "bob") {
+ update control {
+ &Cleartext-Password := "bob"
+ }
+ }
+ }
+
+ $INCLUDE ${maindir}/policy.d/
+}
+
+
+#
+# This virtual server is chosen for processing requests when using:
+#
+# radiusd -Xd src/tests/ -i 127.0.0.1 -p 12340 -n test
+#
+server test {
+ listen {
+ ipaddr = 127.0.0.1
+ port = ${test_port}
+ type = auth
+ }
+
+authorize {
+ update reply {
+ &Test-Server-Port = "%{Packet-Dst-Port}"
+ }
+
+ if (User-Name == "bob") {
+ #
+ # Digest-* tests have a password of "zanzibar"
+ # Or, a hashed version thereof.
+ #
+ if (Digest-Response) {
+ if (&Test-Number == "1") {
+ update control {
+ &Cleartext-Password := "zanzibar"
+ }
+ }
+ elsif (Test-Number == "2") {
+ update control {
+ &Digest-HA1 := 12af60467a33e8518da5c68bbff12b11
+ }
+ }
+ }
+ else {
+ update control {
+ &Cleartext-Password := "bob"
+ }
+ }
+ }
+
+ if (User-Name =~ /^(.*)@test\.example\.com$/) {
+ update request {
+ &Stripped-User-Name := "%{1}"
+ }
+ update control {
+ &Proxy-To-Realm := test.example.com
+ }
+ }
+
+ chap
+ mschap
+ digest
+ eap-test
+ pap
+}
+
+authenticate {
+ pap
+ chap
+ mschap
+ digest
+ eap-test
+}
+
+accounting {
+ if (Packet-Src-IP-Address != 255.255.255.255) {
+ detail
+ }
+
+ ok
+}
+
+}
diff --git a/src/tests/dictionary.test b/src/tests/dictionary.test
new file mode 100644
index 0000000..1b3130f
--- /dev/null
+++ b/src/tests/dictionary.test
@@ -0,0 +1,11 @@
+#
+# Used for internal testing
+#
+VENDOR TEST 32000
+
+BEGIN-VENDOR TEST
+ATTRIBUTE Test-Name 1 string
+ATTRIBUTE Test-Number 2 integer
+ATTRIBUTE Test-Server-Port 3 integer
+ATTRIBUTE Test-Signed 4 signed
+END-VENDOR TEST
diff --git a/src/tests/digest-01/digest-auth-MD5 b/src/tests/digest-01/digest-auth-MD5
new file mode 100644
index 0000000..cdac8f7
--- /dev/null
+++ b/src/tests/digest-01/digest-auth-MD5
@@ -0,0 +1,28 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# Section 3.3
+#
+#
+# In the "users" file:
+#
+# bob Cleartext-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+#
+#
+# How many tests we have for this input file
+#
+# TESTS 1 2
+#
+User-Name = "bob",
+Digest-Response = "89eb0059246c02b2f6ee02c7961d5ea3",
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-User-Name = "bob",
+Digest-QOP = "auth",
+Digest-Algorithm = "MD5",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
diff --git a/src/tests/digest-01/digest-auth-MD5_Sess b/src/tests/digest-01/digest-auth-MD5_Sess
new file mode 100644
index 0000000..1c8d0ac
--- /dev/null
+++ b/src/tests/digest-01/digest-auth-MD5_Sess
@@ -0,0 +1,23 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+##
+# 3.4
+#
+#
+# In the "users" file:
+# bob User-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+# TESTS 1 2
+#
+User-Name = "bob",
+Digest-Response = "e4e4ea61d186d07a92c9e1f6919902e9",
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-User-Name = "bob",
+Digest-QOP = "auth",
+Digest-Algorithm = "MD5-Sess",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
diff --git a/src/tests/digest-01/digest-auth-int b/src/tests/digest-01/digest-auth-int
new file mode 100644
index 0000000..f3ea45e
--- /dev/null
+++ b/src/tests/digest-01/digest-auth-int
@@ -0,0 +1,23 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# 3.5.2
+#
+#
+# In the "users" file: bob Cleartext-Password := "zanzibar"
+#
+# TESTS 1
+#
+User-Name = "bob",
+Digest-Response = "bdbeebb2da6adb6bca02599c2239e192"
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-Algorithm = "MD5",
+Digest-User-Name = "bob",
+Digest-QOP = "auth-int",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
+Digest-Body-Digest = "c1ed018b8ec4a3b170c0921f5b564e48",
+Message-Authenticator = ""
diff --git a/src/tests/digest-01/digest-auth-noalgo b/src/tests/digest-01/digest-auth-noalgo
new file mode 100644
index 0000000..1ab6ba6
--- /dev/null
+++ b/src/tests/digest-01/digest-auth-noalgo
@@ -0,0 +1,21 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# 3.2
+#
+# In the "users" file:
+# bob User-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+# TESTS 1
+#
+User-Name = "bob",
+Digest-Response = "89eb0059246c02b2f6ee02c7961d5ea3",
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-User-Name = "bob",
+Digest-QOP = "auth",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
diff --git a/src/tests/digest-01/digest-auth_int-MD5 b/src/tests/digest-01/digest-auth_int-MD5
new file mode 100644
index 0000000..30e1c48
--- /dev/null
+++ b/src/tests/digest-01/digest-auth_int-MD5
@@ -0,0 +1,23 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# 3.5.2
+#
+# In the "users" file:
+# bob User-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+# TESTS 1 2
+#
+User-Name = "bob",
+Digest-Response = "bdbeebb2da6adb6bca02599c2239e192"
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-Algorithm = "MD5",
+Digest-User-Name = "bob",
+Digest-QOP = "auth-int",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
+Digest-Body-Digest = "c1ed018b8ec4a3b170c0921f5b564e48",
diff --git a/src/tests/digest-01/digest-auth_int-MD5_Sess b/src/tests/digest-01/digest-auth_int-MD5_Sess
new file mode 100644
index 0000000..7665bc0
--- /dev/null
+++ b/src/tests/digest-01/digest-auth_int-MD5_Sess
@@ -0,0 +1,24 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+##
+# 3.6
+#
+# In the "users" file:
+# bob User-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+#
+# TESTS 1 2
+#
+User-Name = "bob",
+Digest-Response = "91984da2d8663716e91554859c22ca70",
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-User-Name = "bob",
+Digest-QOP = "auth-int",
+Digest-Algorithm = "MD5-Sess",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
+Digest-Body-Digest = "c1ed018b8ec4a3b170c0921f5b564e48",
diff --git a/src/tests/digest-01/digest-auth_int-noalgo b/src/tests/digest-01/digest-auth_int-noalgo
new file mode 100644
index 0000000..83675d8
--- /dev/null
+++ b/src/tests/digest-01/digest-auth_int-noalgo
@@ -0,0 +1,22 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# 3.5.2
+#
+# In the "users" file:
+# bob User-Password := "zanzibar"
+# Or bob Digest-HA1 := "12af60467a33e8518da5c68bbff12b11"
+#
+# TESTS 1 2
+#
+User-Name = "bob",
+Digest-Response = "bdbeebb2da6adb6bca02599c2239e192"
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-User-Name = "bob",
+Digest-QOP = "auth-int",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b",
+Digest-Body-Digest = "c1ed018b8ec4a3b170c0921f5b564e48",
diff --git a/src/tests/digest-01/digest-md5-sess b/src/tests/digest-01/digest-md5-sess
new file mode 100644
index 0000000..a77cbab
--- /dev/null
+++ b/src/tests/digest-01/digest-md5-sess
@@ -0,0 +1,21 @@
+#
+# http://ftp6.us.freebsd.org/pub/rfc/internet-drafts/draft-smith-sipping-auth-examples-01.txt
+#
+# ??
+#
+#
+# In the "users" file: bob Cleartext-Password := "zanzibar"
+#
+# TESTS 1
+#
+User-name = "bob",
+Digest-Response = "e4e4ea61d186d07a92c9e1f6919902e9",
+Digest-Realm = "biloxi.com",
+Digest-Nonce = "dcd98b7102dd2f0e8b11d0f600bfb0c093",
+Digest-Method = "INVITE",
+Digest-URI = "sip:bob@biloxi.com",
+Digest-Algorithm = "MD5-sess",
+Digest-User-Name = "bob",
+Digest-QOP = "auth",
+Digest-Nonce-Count = "00000001",
+Digest-CNonce = "0a4f113b"
diff --git a/src/tests/eap-fast.conf b/src/tests/eap-fast.conf
new file mode 100644
index 0000000..b80f270
--- /dev/null
+++ b/src/tests/eap-fast.conf
@@ -0,0 +1,15 @@
+network={
+ key_mgmt=IEEE8021X
+ eap=FAST
+
+ anonymous_identity="anonymous"
+
+ identity="bob"
+ password="bob"
+
+ phase1="tls_disable_session_ticket=0 fast_provisioning=2"
+
+ pac_file="blob://eap-fast-pac"
+
+ ca_cert="../../raddb/certs/ca.pem"
+}
diff --git a/src/tests/eap-md5.conf b/src/tests/eap-md5.conf
new file mode 100644
index 0000000..9e2eca6
--- /dev/null
+++ b/src/tests/eap-md5.conf
@@ -0,0 +1,10 @@
+#
+# eapol_test -c eap-md5.conf -s testing123 -n
+#
+network={
+ key_mgmt=NONE
+ eap=MD5
+
+ identity="bob"
+ password="bob"
+}
diff --git a/src/tests/eap-mschapv2.conf b/src/tests/eap-mschapv2.conf
new file mode 100644
index 0000000..4afcfd0
--- /dev/null
+++ b/src/tests/eap-mschapv2.conf
@@ -0,0 +1,10 @@
+#
+# eapol_test -c eap-mschapv2.conf -s testing123
+#
+network={
+ key_mgmt=IEEE8021X
+ eap=MSCHAPV2
+
+ identity="bob"
+ password="bob"
+}
diff --git a/src/tests/eap-pwd.conf b/src/tests/eap-pwd.conf
new file mode 100644
index 0000000..a756cc1
--- /dev/null
+++ b/src/tests/eap-pwd.conf
@@ -0,0 +1,11 @@
+network={
+ key_mgmt=IEEE8021X
+ eap=PWD
+
+ identity="bob"
+ password="bob"
+
+ pairwise=CCMP
+ group=CCMP
+ priority=1
+}
diff --git a/src/tests/eap-tls.conf b/src/tests/eap-tls.conf
new file mode 100644
index 0000000..c88a559
--- /dev/null
+++ b/src/tests/eap-tls.conf
@@ -0,0 +1,19 @@
+#
+# eapol_test -c eap-tls.conf -s testing123
+#
+# Set also "nostrip" in raddb/proxy.conf, realm "example.com"
+# And make it a LOCAL realm.
+#
+network={
+ key_mgmt=IEEE8021X
+ eap=TLS
+
+ identity="user@example.org"
+
+ phase1=""
+
+ ca_cert="../../raddb/certs/ca.pem"
+ client_cert="../../raddb/certs/client.crt"
+ private_key="../../raddb/certs/client.key"
+ private_key_passwd="whatever"
+}
diff --git a/src/tests/eap-ttls-eap-mschapv2.conf b/src/tests/eap-ttls-eap-mschapv2.conf
new file mode 100644
index 0000000..abe5d33
--- /dev/null
+++ b/src/tests/eap-ttls-eap-mschapv2.conf
@@ -0,0 +1,17 @@
+#
+# eapol_test -c eap-ttls-eap-mschapv2.conf -s testing123
+#
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+
+ anonymous_identity="anonymous"
+
+ identity="bob"
+ password="bob"
+
+ phase1=""
+ phase2="autheap=MSCHAPV2"
+
+ ca_cert="../../raddb/certs/ca.pem"
+}
diff --git a/src/tests/eap-ttls-eap-tls.conf b/src/tests/eap-ttls-eap-tls.conf
new file mode 100644
index 0000000..0937473
--- /dev/null
+++ b/src/tests/eap-ttls-eap-tls.conf
@@ -0,0 +1,15 @@
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+ identity="user@example.org"
+
+ phase1=""
+ phase2="autheap=TLS"
+
+ ca_cert="../../raddb/certs/ca.pem"
+
+ ca_cert2="../../raddb/certs/ca.pem"
+ client_cert2="../../raddb/certs/client.crt"
+ private_key2="../../raddb/certs/client.key"
+ private_key2_passwd="whatever"
+}
diff --git a/src/tests/eap-ttls-mschapv2.conf b/src/tests/eap-ttls-mschapv2.conf
new file mode 100644
index 0000000..7901ac8
--- /dev/null
+++ b/src/tests/eap-ttls-mschapv2.conf
@@ -0,0 +1,12 @@
+#
+# eapol_test -c eap-ttls-mschapv2.conf -s testing123
+#
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+ anonymous_identity="anonymous"
+ identity="bob"
+ password="bob"
+ phase1=""
+ phase2="auth=MSCHAPV2"
+}
diff --git a/src/tests/eap-ttls-pap.conf b/src/tests/eap-ttls-pap.conf
new file mode 100644
index 0000000..19fd752
--- /dev/null
+++ b/src/tests/eap-ttls-pap.conf
@@ -0,0 +1,12 @@
+#
+# eapol_test -c eap-ttls-pap.conf -s testing123
+#
+network={
+ key_mgmt=IEEE8021X
+ eap=TTLS
+ anonymous_identity="anonymous"
+ identity="bob"
+ password="bob"
+ phase1=""
+ phase2="auth=PAP"
+}
diff --git a/src/tests/eapcrypto-01/eapcrypto-out.txt b/src/tests/eapcrypto-01/eapcrypto-out.txt
new file mode 100644
index 0000000..3b12512
--- /dev/null
+++ b/src/tests/eapcrypto-01/eapcrypto-out.txt
@@ -0,0 +1,63 @@
+SHA1buffer was: 65617073_696d0011_22334455_66771021_32435465_
+ 76873041_52637485_96a74d6c_40de483a_dd995090_
+ 2c4024ce_765e0002_00010001
+Input was:
+ identity: (len=6)65617073696d
+ nonce_mt: 4d6c40de483add9950902c4024ce765e
+ rand0: 89abcdef89abcdef89abcdef89abcdef
+ rand1: 9abcdef89abcdef89abcdef89abcdef8
+ rand2: abcdef89abcdef89abcdef89abcdef89
+ sres0: 1234abcd
+ sres1: 1234abcd
+ sres2: 234abcd1
+ Kc0: 0011223344556677
+ Kc1: 1021324354657687
+ Kc2: 30415263748596a7
+ versionlist[4]: 00020001
+ select 00 01
+
+
+Output
+mk: d1cdd6d3_574ef82e_c1e83879_559e89f8_de8e6e90
+K_aut: 54323970_481b5159_48d00a34_422bbe3c
+K_encr: 72469fd8_bb6c2a4a_93ac42e5_b4668acb
+msk: 0a572a3f_2baeea10_640598c9_41901995_f842097a
+ cbb13272_bc949b66_8fb4f5a3_deefed09_3947fe64
+ c88f7df8_dadcab5f_8d003913_8e9bcff7_1a810316
+ 11eeb959
+emsk: 207256b3_9ada49ef_c1850c12_30461921_d700f9f7
+ 83a0f5a9_cff155bd_6c8f1aa5_072b7530_af44f515
+ 3cb983b0_8343effa_2eb161e2_7d3543bc_5bd6db22
+ 993af27b
+SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
+ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
+ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
+ dcba9876_54321000_010001
+Input was:
+ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
+ nonce_mt: 0123456789abcdeffedcba9876543210
+ rand0: 101112131415161718191a1b1c1d1e1f
+ rand1: 202122232425262728292a2b2c2d2e2f
+ rand2: 303132333435363738393a3b3c3d3e3f
+ sres0: d1d2d3d4
+ sres1: e1e2e3e4
+ sres2: f1f2f3f4
+ Kc0: a0a1a2a3a4a5a6a7
+ Kc1: b0b1b2b3b4b5b6b7
+ Kc2: c0c1c2c3c4c5c6c7
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: e576d5ca_332e9930_018bf1ba_ee2763c7_95b3c712
+K_aut: 25af1942_efcbf4bc_72b39434_21f2a974
+K_encr: 536e5ebc_4465582a_a6a8ec99_86ebb620
+msk: 39d45aea_f4e30601_983e972b_6cfd46d1_c3637733
+ 65690d09_cd44976b_525f47d3_a60a985e_955c53b0
+ 90b2e4b7_3719196a_40254296_8fd14a88_8f46b9a7
+ 886e4488
+emsk: 5949eab0_fff69d52_315c6c63_4fd14a7f_0d52023d
+ 56f79698_fa6596ab_eed4f93f_bb48eb53_4d985414
+ ceed0d9a_8ed33c38_7c9dfdab_92ffbdf2_40fcecf6
+ 5a2c93b9
diff --git a/src/tests/eapmd5-01/client.gdb b/src/tests/eapmd5-01/client.gdb
new file mode 100644
index 0000000..b77a269
--- /dev/null
+++ b/src/tests/eapmd5-01/client.gdb
@@ -0,0 +1,5 @@
+file ../../main/radeapclient
+set args -s -x localhost auth testing123 <req.txt
+
+
+
diff --git a/src/tests/eapmd5-01/client.sh b/src/tests/eapmd5-01/client.sh
new file mode 100644
index 0000000..53f84b1
--- /dev/null
+++ b/src/tests/eapmd5-01/client.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+#( echo 'User-Name = "eapmd5"';
+# echo 'Cleartext-Password = "md5md5"';
+# echo 'NAS-IP-Address = marajade.sandelman.ottawa.on.ca';
+# echo 'EAP-Code = Response';
+# echo 'EAP-Id = 210';
+# echo 'EAP-Type-Identity = "eapsim';
+# echo 'Message-Authenticator = 0';
+# echo 'NAS-Port = 0' ) >req.txt
+
+../../modules/rlm_eap/radeapclient -s -x localhost auth testing123 <req.txt
+
+
diff --git a/src/tests/eapmd5-01/req.txt b/src/tests/eapmd5-01/req.txt
new file mode 100644
index 0000000..d0de5e1
--- /dev/null
+++ b/src/tests/eapmd5-01/req.txt
@@ -0,0 +1,8 @@
+User-Name = "eapmd5"
+Cleartext-Password = "md5md5"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Id = 210
+EAP-Type-Identity = "eapsim"
+Message-Authenticator = 0
+NAS-Port = 0
diff --git a/src/tests/eapsim-02/check.gdb b/src/tests/eapsim-02/check.gdb
new file mode 100644
index 0000000..72da283
--- /dev/null
+++ b/src/tests/eapsim-02/check.gdb
@@ -0,0 +1,3 @@
+# $Id$
+file ./eapsimlibtest
+set args <eapsim-in.txt
diff --git a/src/tests/eapsim-02/client.sh b/src/tests/eapsim-02/client.sh
new file mode 100644
index 0000000..32c5aff
--- /dev/null
+++ b/src/tests/eapsim-02/client.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+( echo 'User-Name = "eapsim"';
+ echo 'Cleartext-Password = "md5md5"';
+ echo 'NAS-IP-Address = marajade.sandelman.ottawa.on.ca';
+ echo 'EAP-Code = Response';
+ echo 'EAP-Id = 210';
+ echo 'EAP-Type-Identify = "eapsim';
+ echo 'Message-Authenticator = 0';
+ echo 'NAS-Port = 0' ) >req.txt
+
+../../main/radeapclient -x localhost auth testing123 <req.txt
+
+
diff --git a/src/tests/eapsim-02/eapsim-in.txt b/src/tests/eapsim-02/eapsim-in.txt
new file mode 100644
index 0000000..b138c64
--- /dev/null
+++ b/src/tests/eapsim-02/eapsim-in.txt
@@ -0,0 +1,59 @@
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Id = 210
+EAP-Type-Identity = "eapmd5"
+Message-Authenticator = 0
+NAS-Port = 0
+
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Request
+EAP-Id = 211
+EAP-Sim-Subtype = Start
+EAP-Sim-ANY_ID_REQ = 0x0000
+EAP-Sim-VERSION_LIST = 0x000100010000
+Message-Authenticator = 0
+NAS-Port = 0
+
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Id = 211
+EAP-Sim-Subtype = Start
+EAP-Sim-NONCE_MT = 0x00004d6c40de483add9950902c4024ce765e
+EAP-Sim-IDENTITY = 0x000c456170536572766572477579
+EAP-Sim-SELECTED_VERSION = 0x0001
+Message-Authenticator = 0
+NAS-Port = 0
+
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Request
+EAP-Id = 212
+EAP-Sim-Subtype = Challenge
+EAP-Sim-RAND = 0x00000123456789abcdef123456789abcdeff23456789abcdefff
+EAP-Sim-MAC = 0x4d6c40de483add9950902c4024ce765e
+EAP-Sim-KEY = 0x0123456789abcdef0123456789abcdef
+EAP-Sim-EXTRA = 0x4d6c40de483add9950902c4024ce765e
+Message-Authenticator = 0
+NAS-Port = 0
+
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Request
+EAP-Id = 212
+EAP-Sim-Subtype = Challenge
+EAP-Sim-Identity = 0x001a323134343730313030303030303031306540706169732e6d6f66
+EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+EAP-Sim-SRES1 = 0xd1d2d3d4
+EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+EAP-Sim-SRES2 = 0xe1e2e3e4
+EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+EAP-Sim-SRES3 = 0xf1f2f3f4
+EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+
+
+
+
diff --git a/src/tests/eapsim-02/eapsim-out.txt b/src/tests/eapsim-02/eapsim-out.txt
new file mode 100644
index 0000000..c582c51
--- /dev/null
+++ b/src/tests/eapsim-02/eapsim-out.txt
@@ -0,0 +1,161 @@
+
+Read:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Id = 210
+ EAP-Type-Identity = "eapmd5"
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+Mapped to:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Id = 210
+ EAP-Type-Identity = "eapmd5"
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Message = 0x02d2000b016561706d6435
+Unmapped to:
+ EAP-Message = 0x02d2000b016561706d6435
+ EAP-Id = 210
+ EAP-Code = Response
+ EAP-Type-Identity = "eapmd5"
+
+Read:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 211
+ EAP-Sim-Subtype = Start
+ EAP-Sim-ANY_ID_REQ = 0x0000
+ EAP-Sim-VERSION_LIST = 0x000100010000
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+Mapped to:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 211
+ EAP-Sim-Subtype = Start
+ EAP-Sim-ANY_ID_REQ = 0x0000
+ EAP-Sim-VERSION_LIST = 0x000100010000
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Message = 0x01d30014120a00000d0100000f02000100010000
+Unmapped to:
+ EAP-Message = 0x01d30014120a00000d0100000f02000100010000
+ EAP-Id = 211
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000d0100000f02000100010000
+ EAP-Sim-Subtype = Start
+ EAP-Sim-ANY_ID_REQ = 0x0000
+ EAP-Sim-VERSION_LIST = 0x000100010000
+
+Read:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Id = 211
+ EAP-Sim-Subtype = Start
+ EAP-Sim-NONCE_MT = 0x00004d6c40de483add9950902c4024ce765e
+ EAP-Sim-IDENTITY = 0x000c456170536572766572477579
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+Mapped to:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Id = 211
+ EAP-Sim-Subtype = Start
+ EAP-Sim-NONCE_MT = 0x00004d6c40de483add9950902c4024ce765e
+ EAP-Sim-IDENTITY = 0x000c456170536572766572477579
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Message = 0x02d30030120a0000070500004d6c40de483add9950902c4024ce765e0e04000c45617053657276657247757910010001
+Unmapped to:
+ EAP-Message = 0x02d30030120a0000070500004d6c40de483add9950902c4024ce765e0e04000c45617053657276657247757910010001
+ EAP-Id = 211
+ EAP-Code = Response
+ EAP-Type-SIM = 0x0a0000070500004d6c40de483add9950902c4024ce765e0e04000c45617053657276657247757910010001
+ EAP-Sim-Subtype = Start
+ EAP-Sim-NONCE_MT = 0x00004d6c40de483add9950902c4024ce765e
+ EAP-Sim-IDENTITY = 0x000c456170536572766572477579
+ EAP-Sim-SELECTED_VERSION = 0x0001
+
+Read:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 212
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x00000123456789abcdef123456789abcdeff23456789abcdefff
+ EAP-Sim-MAC = 0x4d6c40de483add9950902c4024ce765e
+ EAP-Sim-KEY = 0x0123456789abcdef0123456789abcdef
+ EAP-Sim-EXTRA = 0x4d6c40de483add9950902c4024ce765e
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+Mapped to:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 212
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x00000123456789abcdef123456789abcdeff23456789abcdefff
+ EAP-Sim-MAC = 0x4d6c40de483add9950902c4024ce765e
+ EAP-Sim-KEY = 0x0123456789abcdef0123456789abcdef
+ EAP-Sim-EXTRA = 0x4d6c40de483add9950902c4024ce765e
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Message = 0x01d40038120b0000010700000123456789abcdef123456789abcdeff23456789abcdefff0b05000013ff4927cdce9e996d7dd44d860802e8
+Unmapped to:
+ EAP-Message = 0x01d40038120b0000010700000123456789abcdef123456789abcdeff23456789abcdefff0b05000013ff4927cdce9e996d7dd44d860802e8
+ EAP-Id = 212
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010700000123456789abcdef123456789abcdeff23456789abcdefff0b05000013ff4927cdce9e996d7dd44d860802e8
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x00000123456789abcdef123456789abcdeff23456789abcdefff
+ EAP-Sim-MAC = 0x000013ff4927cdce9e996d7dd44d860802e8
+Confirming MAC...succeed
+
+Read:
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 212
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-IDENTITY = 0x001a323134343730313030303030303031306540706169732e6d6f66
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+ EAP-Sim-SRES1 = 0xd1d2d3d4
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+ EAP-Sim-SRES2 = 0xe1e2e3e4
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+ EAP-Sim-SRES3 = 0xf1f2f3f4
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+Mapped to:
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Request
+ EAP-Id = 212
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-IDENTITY = 0x001a323134343730313030303030303031306540706169732e6d6f66
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+ EAP-Sim-SRES1 = 0xd1d2d3d4
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+ EAP-Sim-SRES2 = 0xe1e2e3e4
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+ EAP-Sim-SRES3 = 0xf1f2f3f4
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+ EAP-Message = 0x01d40028120b00000e08001a323134343730313030303030303031306540706169732e6d6f660000
+ Message-Authenticator = 0x00000000000000000000000000000000
+Unmapped to:
+ EAP-Message = 0x01d40028120b00000e08001a323134343730313030303030303031306540706169732e6d6f660000
+ EAP-Id = 212
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b00000e08001a323134343730313030303030303031306540706169732e6d6f660000
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-IDENTITY = 0x001a323134343730313030303030303031306540706169732e6d6f660000
diff --git a/src/tests/eapsim-02/req.txt b/src/tests/eapsim-02/req.txt
new file mode 100644
index 0000000..28226e7
--- /dev/null
+++ b/src/tests/eapsim-02/req.txt
@@ -0,0 +1,8 @@
+User-Name = "eapsim"
+Cleartext-Password = "md5md5"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Id = 210
+EAP-Type-Identity = "eapsim"
+Message-Authenticator = 0
+NAS-Port = 0
diff --git a/src/tests/eapsim-03/check.gdb b/src/tests/eapsim-03/check.gdb
new file mode 100644
index 0000000..8418d96
--- /dev/null
+++ b/src/tests/eapsim-03/check.gdb
@@ -0,0 +1,2 @@
+file ../../main/radeapclient
+set args -x localhost auth testing123 <eapsim-in.txt \ No newline at end of file
diff --git a/src/tests/eapsim-03/client.sh b/src/tests/eapsim-03/client.sh
new file mode 100644
index 0000000..2ae1747
--- /dev/null
+++ b/src/tests/eapsim-03/client.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+../../main/radeapclient -x localhost auth testing123 <eapsim-in.txt
+
+
+
diff --git a/src/tests/eapsim-03/eapsim-cooked.txt b/src/tests/eapsim-03/eapsim-cooked.txt
new file mode 100644
index 0000000..caed4d8
--- /dev/null
+++ b/src/tests/eapsim-03/eapsim-cooked.txt
@@ -0,0 +1,169 @@
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "eapsim"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+Input was:
+ identity: (len=6)65617073696d
+ nonce_mt: 00a3f6b4e832cf46b4d3e0d090623e22
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: 1234abcd
+ sres1: 234abcd1
+ sres2: 34abcd12
+ Kc0: 0011223344556677
+ Kc1: 1021324354657687
+ Kc2: 30415263748596a7
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: 85153a7d_7dfe0a4f_f3bf72f3_3521ff76_b048dbb2
+K_aut: 72cd7e8c_f2086e24_a98c1780_bc3d745b
+K_encr: be789668_329769c3_73c0b64b_beffd665
+msk: 9be9fbc9_5415fa9e_f9d52563_bddd9758_65a3fadb
+ 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
+ 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
+ f7fd9956
+emsk: 5dd5a779_65415b21_69aa1300_09dc6ba4_96433d1e
+ 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
+ cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
+ 279c3f66
+MAC check succeed
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Sim-MAC = 0x1234abcd234abcd134abcd12
+ EAP-Sim-KEY = 0x72cd7e8cf2086e24a98c1780bc3d745b
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=999, length=168
+ MS-MPPE-Recv-Key = 0x9be9fbc95415fa9ef9d52563bddd975865a3fadb47a5815a7310cf3f10123d4e
+ MS-MPPE-Send-Key = 0xccaf9d4b30b13c804dd130e5117f35aea0e50b439a08b80ddd15922cf7fd9956
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "eapsim"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0x9be9fbc95415fa9ef9d52563bddd975865a3fadb47a5815a7310cf3f10123d4e
+ MS-MPPE-Send-Key = 0xccaf9d4b30b13c804dd130e5117f35aea0e50b439a08b80ddd15922cf7fd9956
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "eapsim"
+ EAP-Id = YY
+ EAP-Code = Success
diff --git a/src/tests/eapsim-03/eapsim-in.txt b/src/tests/eapsim-03/eapsim-in.txt
new file mode 100644
index 0000000..ffc3f84
--- /dev/null
+++ b/src/tests/eapsim-03/eapsim-in.txt
@@ -0,0 +1,17 @@
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Type-Identity = "eapsim"
+Message-Authenticator = 0
+NAS-Port = 0
+EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+EAP-Sim-Sres1 = 0x1234abcd
+EAP-Sim-Sres2 = 0x234abcd1
+EAP-Sim-Sres3 = 0x34abcd12
+EAP-Sim-KC1 = 0x0011223344556677
+EAP-Sim-KC2 = 0x1021324354657687
+EAP-Sim-KC3 = 0x30415263748596a7
+
+
diff --git a/src/tests/eapsim-03/eapsim-out.txt b/src/tests/eapsim-03/eapsim-out.txt
new file mode 100644
index 0000000..caed4d8
--- /dev/null
+++ b/src/tests/eapsim-03/eapsim-out.txt
@@ -0,0 +1,169 @@
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "eapsim"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+Input was:
+ identity: (len=6)65617073696d
+ nonce_mt: 00a3f6b4e832cf46b4d3e0d090623e22
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: 1234abcd
+ sres1: 234abcd1
+ sres2: 34abcd12
+ Kc0: 0011223344556677
+ Kc1: 1021324354657687
+ Kc2: 30415263748596a7
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: 85153a7d_7dfe0a4f_f3bf72f3_3521ff76_b048dbb2
+K_aut: 72cd7e8c_f2086e24_a98c1780_bc3d745b
+K_encr: be789668_329769c3_73c0b64b_beffd665
+msk: 9be9fbc9_5415fa9e_f9d52563_bddd9758_65a3fadb
+ 47a5815a_7310cf3f_10123d4e_ccaf9d4b_30b13c80
+ 4dd130e5_117f35ae_a0e50b43_9a08b80d_dd15922c
+ f7fd9956
+emsk: 5dd5a779_65415b21_69aa1300_09dc6ba4_96433d1e
+ 72065983_cbe8bc1d_6d744c99_dc76f16f_24324709
+ cb731af2_fbe69c6a_dd302662_a083d7e2_7c05c7cd
+ 279c3f66
+MAC check succeed
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Sim-MAC = 0x1234abcd234abcd134abcd12
+ EAP-Sim-KEY = 0x72cd7e8cf2086e24a98c1780bc3d745b
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=999, length=168
+ MS-MPPE-Recv-Key = 0x9be9fbc95415fa9ef9d52563bddd975865a3fadb47a5815a7310cf3f10123d4e
+ MS-MPPE-Send-Key = 0xccaf9d4b30b13c804dd130e5117f35aea0e50b439a08b80ddd15922cf7fd9956
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "eapsim"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0x9be9fbc95415fa9ef9d52563bddd975865a3fadb47a5815a7310cf3f10123d4e
+ MS-MPPE-Send-Key = 0xccaf9d4b30b13c804dd130e5117f35aea0e50b439a08b80ddd15922cf7fd9956
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "eapsim"
+ EAP-Id = YY
+ EAP-Code = Success
diff --git a/src/tests/eapsim-03/eapsim-sanitize.sed b/src/tests/eapsim-03/eapsim-sanitize.sed
new file mode 100644
index 0000000..1cde2b6
--- /dev/null
+++ b/src/tests/eapsim-03/eapsim-sanitize.sed
@@ -0,0 +1,21 @@
+s/\(Sending Access-Request of id\).*\(to 127.0.0.1:1812\)/\1 999 \2/
+s/\(Message-Authenticator = 0x\).*/\1ABCDABCDABCDABCDABCDABCDABCDABCD/
+s/\(State = 0x\).*/\1ABCDABCDABCDABCDABCDABCDABCDABCD/
+s/\(rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id\)=.*,\( length=.*\)/\1=999,\2/
+s/\(rad_recv: Access-Accept packet from host 127.0.0.1:1812, id\)=.*,\( length=.*\)/\1=999,\2/
+s/\(EAP-Message = 0x..\)\(.*\)/\1XX/
+s/\(EAP-Id = \).*/\1YY/
+s/\(EAP-Type-MD5 = \).*/\1MD5/
+s/\(EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000\)................................/\1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/
+s/\(EAP-Type-SIM = 0x0b0000010d0000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f0b050000\)................................/\1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/
+s/\(EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000\)................................/\1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/
+
+s/\(EAP-Sim-MAC = 0x\)..................................../\1YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY/
+s/DATA: (96) 01../DATA: (96) 01YY/
+s/DATA: (40) 02../DATA: (40) 02YY/
+s/hmac-sha1 mac(20): ........_........_........_........_......../hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX/
+
+
+
+
+
diff --git a/src/tests/eapsim-03/radiusd-example.txt b/src/tests/eapsim-03/radiusd-example.txt
new file mode 100644
index 0000000..c261cbe
--- /dev/null
+++ b/src/tests/eapsim-03/radiusd-example.txt
@@ -0,0 +1,1506 @@
+##
+## radiusd.conf -- FreeRADIUS server configuration file.
+##
+## http://www.freeradius.org/
+## $Id$
+##
+
+# This is the radiusd.conf file used for testing EAP-SIM stuff.
+#
+#
+
+# The location of other config files and
+# logfiles are declared in this file
+#
+# Also general configuration for modules can be done
+# in this file, it is exported through the API to
+# modules that ask for it.
+#
+# The configuration variables defined here are of the form ${foo}
+# They are local to this file, and do not change from request to
+# request.
+#
+# The per-request variables are of the form %{Attribute-Name}, and
+# are taken from the values of the attribute in the incoming
+# request. See 'doc/configuration/variables.rst' for more information.
+
+prefix = /elros/mcr/root
+exec_prefix = ${prefix}
+sysconfdir = ${prefix}/etc
+localstatedir = ${prefix}/var
+sbindir = ${exec_prefix}/sbin
+logdir = ${localstatedir}/log/radius
+raddbdir = ${sysconfdir}/raddb
+radacctdir = ${logdir}/radacct
+
+# Location of config and logfiles.
+confdir = ${raddbdir}
+run_dir = ${localstatedir}/run/radiusd
+
+#
+# The logging messages for the server are appended to the
+# tail of this file.
+#
+log_file = ${logdir}/radius.log
+
+#
+# libdir: Where to find the rlm_* modules.
+#
+# This should be automatically set at configuration time.
+#
+# If the server builds and installs, but fails at execution time
+# with an 'undefined symbol' error, then you can use the libdir
+# directive to work around the problem.
+#
+# The cause is usually that a library has been installed on your
+# system in a place where the dynamic linker CANNOT find it. When
+# executing as root (or another user), your personal environment MAY
+# be set up to allow the dynamic linker to find the library. When
+# executing as a daemon, FreeRADIUS MAY NOT have the same
+# personalized configuration.
+#
+# To work around the problem, find out which library contains that symbol,
+# and add the directory containing that library to the end of 'libdir',
+# with a colon separating the directory names. NO spaces are allowed.
+#
+# e.g. libdir = /usr/local/lib:/opt/package/lib
+#
+# You can also try setting the LD_LIBRARY_PATH environment variable
+# in a script which starts the server.
+#
+# If that does not work, then you can re-configure and re-build the
+# server to NOT use shared libraries, via:
+#
+# ./configure --disable-shared
+# make
+# make install
+#
+libdir = ${exec_prefix}/lib
+
+# pidfile: Where to place the PID of the RADIUS server.
+#
+# The server may be signalled while it's running by using this
+# file.
+#
+# This file is written when ONLY running in daemon mode.
+#
+# e.g.: kill -HUP `cat /var/run/radiusd/radiusd.pid`
+#
+pidfile = ${run_dir}/radiusd.pid
+
+
+# user/group: The name (or #number) of the user/group to run radiusd as.
+#
+# If these are commented out, the server will run as the user/group
+# that started it. In order to change to a different user/group, you
+# MUST be root ( or have root privleges ) to start the server.
+#
+# We STRONGLY recommend that you run the server with as few permissions
+# as possible. That is, if you're not using shadow passwords, the
+# user and group items below should be set to 'nobody'.
+#
+# On SCO (ODT 3) use "user = nouser" and "group = nogroup".
+#
+# NOTE that some kernels refuse to setgid(group) when the value of
+# (unsigned)group is above 60000; don't use group nobody on these systems!
+#
+# On systems with shadow passwords, you might have to set 'group = shadow'
+# for the server to be able to read the shadow password file. If you can
+# authenticate users while in debug mode, but not in daemon mode, it may be
+# that the debugging mode server is running as a user that can read the
+# shadow info, and the user listed below can not.
+#
+#user = nobody
+#group = nobody
+
+# max_request_time: The maximum time (in seconds) to handle a request.
+#
+# Requests which take more time than this to process may be killed, and
+# a REJECT message is returned.
+#
+# WARNING: If you notice that requests take a long time to be handled,
+# then this MAY INDICATE a bug in the server, in one of the modules
+# used to handle a request, OR in your local configuration.
+#
+# This problem is most often seen when using an SQL database. If it takes
+# more than a second or two to receive an answer from the SQL database,
+# then it probably means that you haven't indexed the database. See your
+# SQL server documentation for more information.
+#
+# Useful range of values: 5 to 120
+#
+max_request_time = 30
+
+# cleanup_delay: The time to wait (in seconds) before cleaning up
+# a reply which was sent to the NAS.
+#
+# The RADIUS request is normally cached internally for a short period
+# of time, after the reply is sent to the NAS. The reply packet may be
+# lost in the network, and the NAS will not see it. The NAS will then
+# re-send the request, and the server will respond quickly with the
+# cached reply.
+#
+# If this value is set too low, then duplicate requests from the NAS
+# MAY NOT be detected, and will instead be handled as separate requests.
+#
+# If this value is set too high, then the server will cache too many
+# requests, and some new requests may get blocked. (See 'max_requests'.)
+#
+# Useful range of values: 2 to 10
+#
+cleanup_delay = 5
+
+# max_requests: The maximum number of requests which the server keeps
+# track of. This should be 256 multiplied by the number of clients.
+# e.g. With 4 clients, this number should be 1024.
+#
+# If this number is too low, then when the server becomes busy,
+# it will not respond to any new requests, until the 'cleanup_delay'
+# time has passed, and it has removed the old requests.
+#
+# If this number is set too high, then the server will use a bit more
+# memory for no real benefit.
+#
+# If you aren't sure what it should be set to, it's better to set it
+# too high than too low. Setting it to 1000 per client is probably
+# the highest it should be.
+#
+# Useful range of values: 256 to infinity
+#
+max_requests = 1024
+
+# bind_address: Make the server listen on a particular IP address, and
+# send replies out from that address. This directive is most useful
+# for machines with multiple IP addresses on one interface.
+#
+# It can either contain "*", or an IP address, or a fully qualified
+# Internet domain name. The default is "*"
+#
+bind_address = *
+
+# port: Allows you to bind FreeRADIUS to a specific port.
+#
+# The default port that most NAS boxes use is 1645, which is historical.
+# RFC 2138 defines 1812 to be the new port. Many new servers and
+# NAS boxes use 1812, which can create interoperability problems.
+#
+# The port is defined here to be 0 so that the server will pick up
+# the machine's local configuration for the radius port, as defined
+# in /etc/services.
+#
+# If you want to use the default RADIUS port as defined on your server,
+# (usually through 'grep radius /etc/services') set this to 0 (zero).
+#
+# A port given on the command-line via '-p' over-rides this one.
+#
+port = 0
+
+# hostname_lookups: Log the names of clients or just their IP addresses
+# e.g., www.freeradius.org (on) or 206.47.27.232 (off).
+#
+# The default is 'off' because it would be overall better for the net
+# if people had to knowingly turn this feature on, since enabling it
+# means that each client request will result in AT LEAST one lookup
+# request to the nameserver. Enabling hostname_lookups will also
+# mean that your server may stop randomly for 30 seconds from time
+# to time, if the DNS requests take too long.
+#
+# Turning hostname lookups off also means that the server won't block
+# for 30 seconds, if it sees an IP address which has no name associated
+# with it.
+#
+# allowed values: {no, yes}
+#
+hostname_lookups = no
+
+# Core dumps are a bad thing. This should only be set to 'yes'
+# if you're debugging a problem with the server.
+#
+# allowed values: {no, yes}
+#
+allow_core_dumps = yes
+
+# Log the full User-Name attribute, as it was found in the request.
+#
+# allowed values: {no, yes}
+#
+log_stripped_names = no
+
+# Log authentication requests to the log file.
+#
+# allowed values: {no, yes}
+#
+log_auth = no
+
+# Log passwords with the authentication requests.
+# log_auth_badpass - logs password if it's rejected
+# log_auth_goodpass - logs password if it's correct
+#
+# allowed values: {no, yes}
+#
+log_auth_badpass = no
+log_auth_goodpass = no
+
+# usercollide: Turn "username collision" code on and off. See the
+# "doc/duplicate-users" file
+#
+usercollide = no
+
+# lower_user / lower_pass:
+# Lower case the username/password "before" or "after"
+# attempting to authenticate.
+#
+# If "before", the server will first modify the request and then try
+# to auth the user. If "after", the server will first auth using the
+# values provided by the user. If that fails it will reprocess the
+# request after modifying it as you specify below.
+#
+# This is as close as we can get to case insensitivity. It is the
+# admin's job to ensure that the username on the auth db side is
+# *also* lowercase to make this work
+#
+# Default is 'no' (don't lowercase values)
+# Valid values = "before" / "after" / "no"
+#
+lower_user = no
+lower_pass = no
+
+# nospace_user / nospace_pass:
+#
+# Some users like to enter spaces in their username or password
+# incorrectly. To save yourself the tech support call, you can
+# eliminate those spaces here:
+#
+# Default is 'no' (don't remove spaces)
+# Valid values = "before" / "after" / "no" (explanation above)
+#
+nospace_user = no
+nospace_pass = no
+
+# The program to execute to do concurrency checks.
+checkrad = ${sbindir}/checkrad
+
+# SECURITY CONFIGURATION
+#
+# There may be multiple methods of attacking on the server. This
+# section holds the configuration items which minimize the impact
+# of those attacks
+#
+security {
+ #
+ # max_attributes: The maximum number of attributes
+ # permitted in a RADIUS packet. Packets which have MORE
+ # than this number of attributes in them will be dropped.
+ #
+ # If this number is set too low, then no RADIUS packets
+ # will be accepted.
+ #
+ # If this number is set too high, then an attacker may be
+ # able to send a small number of packets which will cause
+ # the server to use all available memory on the machine.
+ #
+ # Setting this number to 0 means "allow any number of attributes"
+ max_attributes = 200
+
+ #
+ # reject_delay: When sending an Access-Reject, it can be
+ # delayed for a few seconds. This may help slow down a DoS
+ # attack. It also helps to slow down people trying to brute-force
+ # crack a users password.
+ #
+ # Setting this number to 0 means "send rejects immediately"
+ #
+ # If this number is set higher than 'cleanup_delay', then the
+ # rejects will be sent at 'cleanup_delay' time, when the request
+ # is deleted from the internal cache of requests.
+ #
+ # Useful ranges: 1 to 5
+ reject_delay = 1
+
+ #
+ # status_server: Whether or not the server will respond
+ # to Status-Server requests.
+ #
+ # Normally this should be set to "no", because they're useless.
+ # See: http://www.freeradius.org/rfc/rfc2865.html#Keep-Alives
+ #
+ # However, certain NAS boxes may require them.
+ #
+ # When sent a Status-Server message, the server responds with
+ # and Access-Accept packet, containing a Reply-Message attribute,
+ # which is a string describing how long the server has been
+ # running.
+ #
+ status_server = no
+}
+
+# PROXY CONFIGURATION
+#
+# proxy_requests: Turns proxying of RADIUS requests on or off.
+#
+# The server has proxying turned on by default. If your system is NOT
+# set up to proxy requests to another server, then you can turn proxying
+# off here. This will save a small amount of resources on the server.
+#
+# If you have proxying turned off, and your configuration files say
+# to proxy a request, then an error message will be logged.
+#
+# To disable proxying, change the "yes" to "no", and comment the
+# $INCLUDE line.
+#
+# allowed values: {no, yes}
+#
+proxy_requests = yes
+$INCLUDE ${confdir}/proxy.conf
+
+
+# CLIENTS CONFIGURATION
+#
+# Client configuration is defined in "clients.conf".
+#
+
+# The 'clients.conf' file contains all of the information from the old
+# 'clients' and 'naslist' configuration files. We recommend that you
+# do NOT use 'client's or 'naslist', although they are still
+# supported.
+#
+# Anything listed in 'clients.conf' will take precedence over the
+# information from the old-style configuration files.
+#
+$INCLUDE ${confdir}/clients.conf
+
+
+# SNMP CONFIGURATION
+#
+# Snmp configuration is only valid if SNMP support was enabled
+# at compile time.
+#
+# To enable SNMP querying of the server, set the value of the
+# 'snmp' attribute to 'yes'
+#
+snmp = no
+$INCLUDE ${confdir}/snmp.conf
+
+
+# THREAD POOL CONFIGURATION
+#
+# The thread pool is a long-lived group of threads which
+# take turns (round-robin) handling any incoming requests.
+#
+# You probably want to have a few spare threads around,
+# so that high-load situations can be handled immediately. If you
+# don't have any spare threads, then the request handling will
+# be delayed while a new thread is created, and added to the pool.
+#
+# You probably don't want too many spare threads around,
+# otherwise they'll be sitting there taking up resources, and
+# not doing anything productive.
+#
+# The numbers given below should be adequate for most situations.
+#
+thread pool {
+ # Number of servers to start initially --- should be a reasonable
+ # ballpark figure.
+ start_servers = 5
+
+ # Limit on the total number of servers running.
+ #
+ # If this limit is ever reached, clients will be LOCKED OUT, so it
+ # should NOT BE SET TOO LOW. It is intended mainly as a brake to
+ # keep a runaway server from taking the system with it as it spirals
+ # down...
+ #
+ # You may find that the server is regularly reaching the
+ # 'max_servers' number of threads, and that increasing
+ # 'max_servers' doesn't seem to make much difference.
+ #
+ # If this is the case, then the problem is MOST LIKELY that
+ # your back-end databases are taking too long to respond, and
+ # are preventing the server from responding in a timely manner.
+ #
+ # The solution is NOT do keep increasing the 'max_servers'
+ # value, but instead to fix the underlying cause of the
+ # problem: slow database, or 'hostname_lookups=yes'.
+ #
+ # For more information, see 'max_request_time', above.
+ #
+ max_servers = 32
+
+ # Server-pool size regulation. Rather than making you guess
+ # how many servers you need, FreeRADIUS dynamically adapts to
+ # the load it sees, that is, it tries to maintain enough
+ # servers to handle the current load, plus a few spare
+ # servers to handle transient load spikes.
+ #
+ # It does this by periodically checking how many servers are
+ # waiting for a request. If there are fewer than
+ # min_spare_servers, it creates a new spare. If there are
+ # more than max_spare_servers, some of the spares die off.
+ # The default values are probably OK for most sites.
+ #
+ min_spare_servers = 3
+ max_spare_servers = 10
+
+ # There may be memory leaks or resource allocation problems with
+ # the server. If so, set this value to 300 or so, so that the
+ # resources will be cleaned up periodically.
+ #
+ # This should only be necessary if there are serious bugs in the
+ # server which have not yet been fixed.
+ #
+ # '0' is a special value meaning 'infinity', or 'the servers never
+ # exit'
+ max_requests_per_server = 0
+}
+
+# MODULE CONFIGURATION
+#
+# The names and configuration of each module is located in this section.
+#
+# After the modules are defined here, they may be referred to by name,
+# in other sections of this configuration file.
+#
+modules {
+ #
+ # Each module has a configuration as follows:
+ #
+ # name [ instance ] {
+ # config_item = value
+ # ...
+ # }
+ #
+ # The 'name' is used to load the 'rlm_name' library
+ # which implements the functionality of the module.
+ #
+ # The 'instance' is optional. To have two different instances
+ # of a module, it first must be referred to by 'name'.
+ # The different copies of the module are then created by
+ # inventing two 'instance' names, e.g. 'instance1' and 'instance2'
+ #
+ # The instance names can then be used in later configuration
+ # INSTEAD of the original 'name'. See the 'radutmp' configuration
+ # below for an example.
+ #
+
+ # PAP module to authenticate users based on their stored password
+ #
+ # Supports multiple encryption schemes
+ # clear: Clear text
+ # crypt: Unix crypt
+ # md5: MD5 ecnryption
+ # sha1: SHA1 encryption.
+ # DEFAULT: crypt
+ pap {
+ encryption_scheme = crypt
+ }
+
+ # CHAP module
+ #
+ # To authenticate requests containing a CHAP-Password attribute.
+ #
+ chap {
+ authtype = CHAP
+ }
+
+ # Pluggable Authentication Modules
+ #
+ # For Linux, see:
+ # http://www.kernel.org/pub/linux/libs/pam/index.html
+ #
+ pam {
+ #
+ # The name to use for PAM authentication.
+ # PAM looks in /etc/pam.d/${pam_auth_name}
+ # for it's configuration. See 'redhat/radiusd-pam'
+ # for a sample PAM configuration file.
+ #
+ # Note that any Pam-Auth attribute set in the 'authorize'
+ # section will over-ride this one.
+ #
+ pam_auth = radiusd
+ }
+
+ # Unix /etc/passwd style authentication
+ #
+ unix {
+ #
+ # Cache /etc/passwd, /etc/shadow, and /etc/group
+ #
+ # The default is to NOT cache them.
+ #
+ # For FreeBSD, you do NOT want to enable the cache,
+ # as it's password lookups are done via a database, so
+ # set this value to 'no'.
+ #
+ # Some systems (e.g. RedHat Linux with pam_pwbd) can
+ # take *seconds* to check a password, from a passwd
+ # file containing 1000's of entries. For those systems,
+ # you should set the cache value to 'yes', and set
+ # the locations of the 'passwd', 'shadow', and 'group'
+ # files, below.
+ #
+ # allowed values: {no, yes}
+ cache = no
+
+ # Reload the cache every 600 seconds (10mins). 0 to disable.
+ cache_reload = 600
+
+ #
+ # Define the locations of the normal passwd, shadow, and
+ # group files.
+ #
+ # 'shadow' is commented out by default, because not all
+ # systems have shadow passwords.
+ #
+ # To force the module to use the system password functions,
+ # instead of reading the files, leave the following entries
+ # commented out.
+ #
+ # This is required for some systems, like FreeBSD,
+ # and Mac OSX.
+ #
+ # passwd = /etc/passwd
+ # shadow = /etc/shadow
+ # group = /etc/group
+
+
+ #
+ # Where the 'wtmp' file is located.
+ # This should be moved to it's own module soon.
+ #
+ # The only use for 'radlast'. If you don't use
+ # 'radlast', then you can comment out this item.
+ #
+ radwtmp = ${logdir}/radwtmp
+ }
+
+ # Extensible Authentication Protocol
+ #
+ # For all EAP related authentications
+ eap {
+ # Invoke the default supported EAP type when
+ # EAP-Identity response is received.
+ #
+ # The incoming EAP messages MAY NOT specify which EAP
+ # type they will be using, so it MUST be set here.
+ #
+ # For now, only one default EAP type may be used at a time.
+ #
+ default_eap_type = md5
+
+ # Default expiry time to clean the EAP list,
+ # It is maintained to correlate the
+ # EAP-response for each EAP-request sent.
+ timer_expire = 60
+
+ # Supported EAP-types
+ md5 {
+ }
+
+ sim {
+ }
+
+ # Cisco LEAP
+ #
+ # Cisco LEAP uses the MS-CHAP algorithm (but not
+ # the MS-CHAP attributes) to perform it's authentication.
+ #
+ # As a result, LEAP *requires* access to the plain-text
+ # User-Password, or the NT-Password attributes.
+ # 'System' authentication is impossible with LEAP.
+ #
+ leap {
+ }
+
+ ## EAP-TLS is highly experimental EAP-Type at the moment.
+ # Please give feedback on the mailing list.
+ #tls {
+ # private_key_password = password
+ # private_key_file = /path/filename
+
+ # If Private key & Certificate are located in the
+ # same file, then private_key_file & certificate_file
+ # must contain the same file name.
+ # certificate_file = /path/filename
+
+ # Trusted Root CA list
+ #ca_file = /path/filename
+
+ # dh_file = /path/filename
+ #random_file = /path/filename
+ #
+ # This can never exceed MAX_RADIUS_LEN (4096)
+ # preferably half the MAX_RADIUS_LEN, to
+ # accomodate other attributes in RADIUS packet.
+ # On most APs the MAX packet length is configured
+ # between 1500 - 1600. In these cases, fragment
+ # size should be <= 1024.
+ #
+ # fragment_size = 1024
+
+ # include_length is a flag which is by default set to yes
+ # If set to yes, Total Length of the message is included
+ # in EVERY packet we send.
+ # If set to no, Total Length of the message is included
+ # ONLY in the First packet of a fragment series.
+ #
+ # include_length = yes
+ #}
+ }
+
+ # Microsoft CHAP authentication
+ #
+ # This module supports MS-CHAP and MS-CHAPv2 authentication.
+ # It also enforces the SMB-Account-Ctrl attribute.
+ #
+ mschap {
+ #
+ # As of 0.9, the mschap module does NOT support
+ # reading from /etc/smbpasswd.
+ #
+ # If you are using /etc/smbpasswd, see the 'passwd'
+ # module for an example of how to use /etc/smbpasswd
+
+ # authtype value, if present, will be used
+ # to overwrite (or add) Auth-Type during
+ # authorization. Normally should be MS-CHAP
+ authtype = MS-CHAP
+
+ # if use_mppe is not set to no mschap will
+ # add MS-CHAP-MPPE-Keys for MS-CHAPv1 and
+ # MS-MPPE-Recv-Key/MS-MPPE-Send-Key for MS-CHAPv2
+ # use_mppe = no
+
+ # if mppe is enabled require_encryption makes
+ # encryption moderate
+ # require_encryption = yes
+
+ # require_strong always requires 128 bit key
+ # encryption
+ # require_strong = yes
+ }
+
+ # Lightweight Directory Access Protocol (LDAP)
+ #
+ # This module definition allows you to use LDAP for
+ # authorization and authentication (Auth-Type := LDAP)
+ #
+ # See doc/rlm_ldap for description of configuration options
+ # and sample authorize{} and authenticate{} blocks
+ ldap {
+ server = "ldap.your.domain"
+ # identity = "cn=admin,o=My Org,c=UA"
+ # password = mypass
+ basedn = "o=My Org,c=UA"
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ # set this to 'yes' to use TLS encrypted connections
+ # to the LDAP database by using the StartTLS extended
+ # operation.
+ # The StartTLS operation is supposed to be used with normal
+ # ldap connections instead of using ldaps (port 636) connections
+ start_tls = no
+
+ # default_profile = "cn=radprofile,ou=dialup,o=My Org,c=UA"
+ # profile_attribute = "radiusProfileDn"
+ access_attr = "dialupAccess"
+
+ # Mapping of RADIUS dictionary attributes to LDAP
+ # directory attributes.
+ dictionary_mapping = ${raddbdir}/ldap.attrmap
+
+ ldap_connections_number = 5
+ # password_header = "{clear}"
+ # password_attribute = userPassword
+ # groupname_attribute = cn
+ # groupmembership_filter = "(|(&(objectClass=GroupOfNames)(member=%{Ldap-UserDn}))(&(objectClass=GroupOfUniqueNames)(uniquemember=%{Ldap-UserDn})))"
+ # groupmembership_attribute = radiusGroupName
+ timeout = 4
+ timelimit = 3
+ net_timeout = 1
+ # compare_check_items = yes
+ # access_attr_used_for_allow = yes
+ }
+
+ # passwd module allows to do authorization via any passwd-like
+ # file and to extract any attributes from these modules
+ #
+ # parameters are:
+ # filename - path to filename
+ # format - format for filename record. This parameters
+ # correlates record in the passwd file and RADIUS
+ # attributes.
+ #
+ # Field marked as '*' is key field. That is, the parameter
+ # with this name from the request is used to search for
+ # the record from passwd file
+ # Attribute marked as '=' is added to reply_items instead
+ # of default configure_items
+ # Attribute marked as '~' is added to request_items
+ #
+ # Field marked as ',' may contain a comma separated list
+ # of attributes.
+ # authtype - if record found this Auth-Type is used to authenticate
+ # user
+ # hash_size - hashtable size. If 0 or not specified records are not
+ # stored in memory and file is red on every request.
+ # allow_multiple_keys - if few records for every key are allowed
+ # ignore_nislike - ignore NIS-related records
+ # delimiter - symbol to use as a field separator in passwd file,
+ # for format ':' symbol is always used. '\0', '\n' are
+ # not allowed
+ #
+
+ # An example configuration for using /etc/smbpasswd.
+ #
+ #passwd etc_smbpasswd {
+ # filename = /etc/smbpasswd
+ # format = "*User-Name::LM-Password:NT-Password:SMB-Account-CTRL-TEXT::"
+ # authtype = MS-CHAP
+ # hash_size = 100
+ # ignore_nislike = no
+ # allow_multiple_keys = no
+ #}
+
+ # Similar configuration, for the /etc/group file. Adds a Group-Name
+ # attribute for every group that the user is member of.
+ #
+ #passwd etc_group {
+ # filename = /etc/group
+ # format = "=Group-Name:::*,User-Name"
+ # hash_size = 50
+ # ignore_nislike = yes
+ # allow_multiple_keys = yes
+ # delimiter = ":"
+ #}
+
+ # Realm module, for proxying.
+ #
+ # You can have multiple instances of the realm module to
+ # support multiple realm syntaxs at the same time. The
+ # search order is defined the order in the authorize and
+ # preacct blocks after the module config block.
+ #
+ # Two config options:
+ # format - must be 'prefix' or 'suffix'
+ # delimiter - must be a single character
+
+ # 'realm/username'
+ #
+ # Using this entry, IPASS users have their realm set to "IPASS".
+ realm realmslash {
+ format = prefix
+ delimiter = "/"
+ }
+
+ # 'username@realm'
+ #
+ realm suffix {
+ format = suffix
+ delimiter = "@"
+ }
+
+ # 'username%realm'
+ #
+ realm realmpercent {
+ format = suffix
+ delimiter = "%"
+ }
+
+ # Preprocess the incoming RADIUS request, before handing it off
+ # to other modules.
+ #
+ # This module processes the 'huntgroups' and 'hints' files.
+ # In addition, it re-writes some weird attributes created
+ # by some NASes, and converts the attributes into a form which
+ # is a little more standard.
+ #
+ preprocess {
+ huntgroups = ${confdir}/huntgroups
+ hints = ${confdir}/hints
+
+ # This hack changes Ascend's wierd port numberings
+ # to standard 0-??? port numbers so that the "+" works
+ # for IP address assignments.
+ with_ascend_hack = no
+ ascend_channels_per_line = 23
+
+ # Windows NT machines often authenticate themselves as
+ # NT_DOMAIN\username
+ #
+ # If this is set to 'yes', then the NT_DOMAIN portion
+ # of the user-name is silently discarded.
+ with_ntdomain_hack = no
+
+ # Specialix Jetstream 8500 24 port access server.
+ #
+ # If the user name is 10 characters or longer, a "/"
+ # and the excess characters after the 10th are
+ # appended to the user name.
+ #
+ # If you're not running that NAS, you don't need
+ # this hack.
+ with_specialix_jetstream_hack = no
+
+ # Cisco sends it's VSA attributes with the attribute
+ # name *again* in the string, like:
+ #
+ # H323-Attribute = "h323-attribute=value".
+ #
+ # If this configuration item is set to 'yes', then
+ # the redundant data in the the attribute text is stripped
+ # out. The result is:
+ #
+ # H323-Attribute = "value"
+ #
+ # If you're not running a Cisco NAS, you don't need
+ # this hack.
+ with_cisco_vsa_hack = no
+ }
+
+ # Livingston-style 'users' file
+ #
+ files {
+ usersfile = ${confdir}/users
+ acctusersfile = ${confdir}/acct_users
+
+ # If you want to use the old Cistron 'users' file
+ # with FreeRADIUS, you should change the next line
+ # to 'compat = cistron'. You can the copy your 'users'
+ # file from Cistron.
+ compat = no
+ }
+
+ # Write a detailed log of all accounting records received.
+ #
+ detail {
+ # Note that we do NOT use NAS-IP-Address here, as
+ # that attribute MAY BE from the originating NAS, and
+ # NOT from the proxy which actually sent us the
+ # request. The Client-IP-Address attribute is ALWAYS
+ # the address of the client which sent us the
+ # request.
+ #
+ # The following line creates a new detail file for
+ # every radius client (by IP address or hostname).
+ # In addition, a new detail file is created every
+ # day, so that the detail file doesn't have to go
+ # through a 'log rotation'
+ #
+ # If your detail files are large, you may also want
+ # to add a ':%H' (see doc/configuration/variables.rst) to the end
+ # of it, to create a new detail file every hour, e.g.:
+ #
+ # ..../detail-%Y%m%d:%H
+ #
+ # This will create a new detail file for every hour.
+ #
+ detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
+
+ #
+ # The Unix-style permissions on the 'detail' file.
+ #
+ # The detail file often contains secret or private
+ # information about users. So by keeping the file
+ # permissions restrictive, we can prevent unwanted
+ # people from seeing that information.
+ detailperm = 0600
+ }
+
+ # Include another file that has the SQL-related configuration.
+ # This is another file only because it tends to be big.
+ #
+ # The following configuration file is for use with MySQL.
+ #
+ # For Postgresql, use: ${confdir}/postgresql.conf
+ # For MS-SQL, use: ${confdir}/mssql.conf
+ # For Oracle, use: ${confdir}/oraclesql.conf
+ #
+ $INCLUDE ${confdir}/sql.conf
+
+ # Write a 'utmp' style file, of which users are currently
+ # logged in, and where they've logged in from.
+ #
+ # This file is used mainly for Simultaneous-Use checking,
+ # and also 'radwho', to see who's currently logged in.
+ #
+ radutmp {
+ # Where the file is stored. It's not a log file,
+ # so it doesn't need rotating.
+ #
+ filename = ${logdir}/radutmp
+
+ # The field in the packet to key on for the
+ # 'user' name, If you have other fields which you want
+ # to use to key on to control Simultaneous-Use,
+ # then you can use them here.
+ #
+ # Note, however, that the size of the field in the
+ # 'utmp' data structure is small, around 32
+ # characters, so that will limit the possible choices
+ # of keys.
+ #
+ username = %{User-Name}
+
+ # Whether or not we want to treat "user" the same
+ # as "USER", or "User". Some systems have problems
+ # with case sensitivity, so this should be set to
+ # 'no' to enable the comparisons of the key attribute
+ # to be case insensitive.
+ #
+ case_sensitive = yes
+
+ # Accounting information may be lost, so the user MAY
+ # have logged off of the NAS, but we haven't noticed.
+ # If so, we can verify this information with the NAS,
+ #
+ # If we want to believe the 'utmp' file, then this
+ # configuration entry can be set to 'no'.
+ #
+ check_with_nas = yes
+
+ # Set the file permissions, as the contents of this file
+ # are usually private.
+ perm = 0600
+
+ caller_id = "yes"
+ }
+
+ # "Safe" radutmp - does not contain caller ID, so it can be
+ # world-readable, and radwho can work for normal users, without
+ # exposing any information that isn't already exposed by who(1).
+ #
+ # This is another 'instance' of the radutmp module, but it is given
+ # then name "sradutmp" to identify it later in the "accounting"
+ # section.
+ radutmp sradutmp {
+ filename = ${logdir}/sradutmp
+ perm = 0644
+ caller_id = "no"
+ }
+
+ # attr_filter - filters the attributes received in replies from
+ # proxied servers, to make sure we send back to our RADIUS client
+ # only allowed attributes.
+ attr_filter {
+ attrsfile = ${confdir}/attrs
+ }
+
+ # counter module:
+ # This module takes an attribute (count_attribute).
+ # It also takes a key, and creates a counter for each unique
+ # key. The count is incremented when accounting packets are
+ # received by the server. The value of the increment depends
+ # on the attribute type.
+ # If the attribute is Acct-Session-Time or of an integer type we add the
+ # value of the attribute. If it is anything else we increase the
+ # counter by one.
+ #
+ # The 'reset' parameter defines when the counters are all reset to
+ # zero. It can be hourly, daily, weekly, monthly or never.
+ #
+ # hourly: Reset on 00:00 of every hour
+ # daily: Reset on 00:00:00 every day
+ # weekly: Reset on 00:00:00 on sunday
+ # monthly: Reset on 00:00:00 of the first day of each month
+ #
+ # It can also be user defined. It should be of the form:
+ # num[hdwm] where:
+ # h: hours, d: days, w: weeks, m: months
+ # If the letter is ommited days will be assumed. In example:
+ # reset = 10h (reset every 10 hours)
+ # reset = 12 (reset every 12 days)
+ #
+ #
+ # The check_name attribute defines an attribute which will be
+ # registered by the counter module and can be used to set the
+ # maximum allowed value for the counter after which the user
+ # is rejected.
+ # Something like:
+ #
+ # DEFAULT Max-Daily-Session := 36000
+ # Fall-Through = 1
+ #
+ # You should add the counter module in the instantiate
+ # section so that it registers check_name before the files
+ # module reads the users file.
+ #
+ # If check_name is set and the user is to be rejected then we
+ # send back a Reply-Message and we log a Failure-Message in
+ # the radius.log
+ # If the count attribute is Acct-Session-Time then on each login
+ # we send back the remaining online time as a Session-Timeout attribute
+ #
+ # The counter-name can also be used instead of using the check_name
+ # like below:
+ #
+ # DEFAULT Daily-Session-Time > 3600, Auth-Type = Reject
+ # Reply-Message = "You've used up more than one hour today"
+ #
+ # The allowed-servicetype attribute can be used to only take
+ # into account specific sessions. For example if a user first
+ # logs in through a login menu and then selects ppp there will
+ # be two sessions. One for Login-User and one for Framed-User
+ # service type. We only need to take into account the second one.
+ #
+ # The module should be added in the instantiate, authorize and
+ # accounting sections. Make sure that in the authorize
+ # section it comes after any module which sets the
+ # 'check_name' attribute.
+ #
+ counter daily {
+ filename = ${raddbdir}/db.daily
+ key = User-Name
+ count_attribute = Acct-Session-Time
+ reset = daily
+ counter_name = Daily-Session-Time
+ check_name = Max-Daily-Session
+ allowed_service_type = Framed-User
+ cache_size = 5000
+ }
+
+ # The "always" module is here for debugging purposes. Each
+ # instance simply returns the same result, always, without
+ # doing anything.
+ always fail {
+ rcode = fail
+ }
+ always reject {
+ rcode = reject
+ }
+ always ok {
+ rcode = ok
+ simulcount = 0
+ mpp = no
+ }
+
+ #
+ # The 'expression' module currently has no configuration.
+ expr {
+ }
+
+ #
+ # The 'digest' module currently has no configuration.
+ #
+ # "Digest" authentication against a Cisco SIP server.
+ # See 'doc/rfc/draft-sterman-aaa-sip-00.txt' for details
+ # on performing digest authentication for Cisco SIP servers.
+ #
+ digest {
+ }
+
+ #
+ # Execute external programs
+ #
+ # The first example is useful only for 'xlat'. To use it,
+ # put 'exec' into the 'instantiate' section. You can then
+ # do dynamic translation of attributes like:
+ #
+ # Attribute-Name = `{%exec:/path/to/program args}`
+ #
+ # The value of the attribute will be replaced with the output
+ # of the program which is executed. Due to RADIUS protocol
+ # limitations, any output over 253 bytes will be ignored.
+ #
+ # The RADIUS attributes from the user request will be placed
+ # into environment variables of the executed program, as
+ # described in 'doc/configuration/variables.rst'
+ #
+ exec {
+ wait = yes
+ input_pairs = request
+ }
+
+ #
+ # This is a more general example of the execute module.
+ #
+ # If you wish to execute an external program in more than
+ # one section (e.g. 'authorize', 'pre_proxy', etc), then it
+ # is probably best to define a different instance of the
+ # 'exec' module for every section.
+ #
+ exec echo {
+ #
+ # Wait for the program to finish.
+ #
+ # If we do NOT wait, then the program is "fire and
+ # forget", and any output attributes from it are ignored.
+ #
+ # If we are looking for the program to output
+ # attributes, and want to add those attributes to the
+ # request, then we MUST wait for the program to
+ # finish, and therefore set 'wait=yes'
+ #
+ # allowed values: {no, yes}
+ wait = yes
+
+ #
+ # The name of the program to execute, and it's
+ # arguments. Dynamic translation is done on this
+ # field, so things like the following example will
+ # work.
+ #
+ program = "/bin/echo %{User-Name}"
+
+ #
+ # The attributes which are placed into the
+ # environment variables for the program.
+ #
+ # Allowed values are:
+ #
+ # request attributes from the request
+ # reply attributes from the reply
+ # proxy-request attributes from the proxy request
+ # proxy-reply attributes from the proxy reply
+ #
+ # Note that some attributes may not exist at some
+ # stages. e.g. There may be no proxy-reply
+ # attributes if this module is used in the
+ # 'authorize' section.
+ #
+ input_pairs = request
+
+ #
+ # Where to place the output attributes (if any) from
+ # the executed program. The values allowed, and the
+ # restrictions as to availability, are the same as
+ # for the input_pairs.
+ #
+ output_pairs = reply
+
+ #
+ # When to execute the program. If the packet
+ # type does NOT match what's listed here, then
+ # the module does NOT execute the program.
+ #
+ # For a list of allowed packet types, see
+ # the 'dictionary' file, and look for VALUEs
+ # of the Packet-Type attribute.
+ #
+ # By default, the module executes on ANY packet.
+ # Un-comment out the following line to tell the
+ # module to execute only if an Access-Accept is
+ # being sent to the NAS.
+ #
+ #packet_type = Access-Accept
+ }
+
+ # Do server side ip pool management. Should be added in post-auth and
+ # accounting sections.
+ #
+ # The module also requires the existence of the Pool-Name
+ # attribute. That way the administrator can add the Pool-Name
+ # attribute in the user profiles and use different pools
+ # for different users. The Pool-Name attribute is a *check* item not
+ # a reply item.
+ #
+ # Example:
+ # radiusd.conf: ippool students { [...] }
+ # users file : DEFAULT Group == students, Pool-Name := "students"
+ #
+ # ********* IF YOU CHANGE THE RANGE PARAMETERS YOU MUST THEN ERASE THE DB FILES *******
+ #
+ ippool main_pool {
+
+ # range-start,range-stop: The start and end ip
+ # addresses for the ip pool
+ range-start = 192.0.2.1
+ range-stop = 192.0.2.254
+
+ # netmask: The network mask used for the ip's
+ netmask = 255.255.255.0
+
+ # cache_size: The gdbm cache size for the db
+ # files. Should be equal to the number of ip's
+ # available in the ip pool
+ cache_size = 800
+
+ # session-db: The main db file used to allocate ip's to clients
+ session-db = ${raddbdir}/db.ippool
+
+ # ip-index: Helper db index file used in multilink
+ ip-index = ${raddbdir}/db.ipindex
+
+ # override: Will this ippool override a Framed-IP-Address already set
+ override = no
+ }
+
+ # ANSI X9.9 token support. Not included by default.
+ # $INCLUDE ${confdir}/x99.conf
+
+}
+
+# Instantiation
+#
+# This section orders the loading of the modules. Modules
+# listed here will get loaded BEFORE the later sections like
+# authorize, authenticate, etc. get examined.
+#
+# This section is not strictly needed. When a section like
+# authorize refers to a module, it's automatically loaded and
+# initialized. However, some modules may not be listed in any
+# of the following sections, so they can be listed here.
+#
+# Also, listing modules here ensures that you have control over
+# the order in which they are initalized. If one module needs
+# something defined by another module, you can list them in order
+# here, and ensure that the configuration will be OK.
+#
+instantiate {
+ #
+ # The expression module doesn't do authorization,
+ # authentication, or accounting. It only does dynamic
+ # translation, of the form:
+ #
+ # Session-Timeout = `%{expr:2 + 3}`
+ #
+ # So the module needs to be instantiated, but CANNOT be
+ # listed in any other section. See 'doc/rlm_expr' for
+ # more information.
+ #
+ expr
+
+ #
+ # We add the counter module here so that it registers
+ # the check_name attribute before any module which sets
+ # it
+# daily
+}
+
+# Authorization. First preprocess (hints and huntgroups files),
+# then realms, and finally look in the "users" file.
+#
+# The order of the realm modules will determine the order that
+# we try to find a matching realm.
+#
+# Make *sure* that 'preprocess' comes before any realm if you
+# need to setup hints for the remote radius server
+authorize {
+ #
+ # The preprocess module takes care of sanitizing some bizarre
+ # attributes in the request, and turning them into attributes
+ # which are more standard.
+ #
+ # It takes care of processing the 'raddb/hints' and the
+ # 'raddb/huntgroups' files.
+ #
+ # It also adds a Client-IP-Address attribute to the request.
+ preprocess
+
+ #
+ # The chap module will set 'Auth-Type := CHAP' if we are
+ # handling a CHAP request and Auth-Type has not already been set
+ chap
+
+# attr_filter
+
+ #
+ # This module takes care of EAP-MD5, EAP-TLS, and EAP-LEAP
+ # authentication.
+ eap
+
+ #
+ # If you have a Cisco SIP server authenticating against
+ # FreeRADIUS, uncomment the following line.
+ # digest
+
+ #
+ # Look for IPASS style 'realm/', and if not found, look for
+ # '@realm', and decide whether or not to proxy, based on
+ # that.
+# realmslash
+ suffix
+
+ #
+ # Read the 'users' file
+ files
+
+ #
+ # If you are using /etc/smbpasswd, and are also doing
+ # mschap authentication, the un-comment this line, and
+ # configure the 'etc_smbpasswd' module, above.
+# etc_smbpasswd
+
+ #
+ # If the users are logging in with an MS-CHAP-Challenge
+ # attribute for authentication, the mschap module will find
+ # the MS-CHAP-Challenge attribute, and add 'Auth-Type := MS-CHAP'
+ # to the request, which will cause the server to then use
+ # the mschap module for authentication.
+ mschap
+
+
+# The ldap module will set Auth-Type to LDAP if it has not already been set
+# ldap
+# daily
+}
+
+
+# Authentication.
+#
+# This section lists which modules are available for authentication.
+# Note that it does NOT mean 'try each module in order'. It means
+# that you have to have a module from the 'authorize' section add
+# a configuration attribute 'Auth-Type := FOO'. That authentication type
+# is then used to pick the appropriate module from the list below.
+#
+# The default Auth-Type is Local. That is, whatever is not included inside
+# an authtype section will be called only if Auth-Type is set to Local.
+#
+# So you should do the following:
+# - Set Auth-Type to an appropriate value in the authorize modules above.
+# For example, the chap module will set Auth-Type to CHAP, ldap to LDAP, etc.
+# - After that create corresponding authtype sections in the
+# authenticate section below and call the appropriate modules.
+authenticate {
+ #
+ # PAP authentication, when a back-end database listed
+ # in the 'authorize' section supplies a password. The
+ # password can be clear-text, or encrypted.
+ Auth-Type PAP {
+ pap
+ }
+
+ #
+ # Most people want CHAP authentication
+ # A back-end database listed in the 'authorize' section
+ # MUST supply a CLEAR TEXT password. Encrypted passwords
+ # won't work.
+ Auth-Type CHAP {
+ chap
+ }
+
+ #
+ # MSCHAP authentication.
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ #
+ # If you have a Cisco SIP server authenticating against
+ # FreeRADIUS, uncomment the following line.
+ # digest
+
+ #
+ # Pluggable Authentication Modules.
+# pam
+
+ #
+ # See 'man getpwent' for information on how the 'unix'
+ # module checks the users password. Note that packets
+ # containing CHAP-Password attributes CANNOT be authenticated
+ # against /etc/passwd! See the FAQ for details.
+ #
+ unix
+
+ # Uncomment it if you want to use ldap for authentication
+# Auth-Type LDAP {
+# ldap
+# }
+
+
+ #
+ # Allow EAP authentication.
+ eap
+}
+
+
+#
+# Pre-accounting. Decide which accounting type to use.
+#
+preacct {
+ preprocess
+
+ #
+ # Look for IPASS-style 'realm/', and if not found, look for
+ # '@realm', and decide whether or not to proxy, based on
+ # that.
+ #
+ # Accounting requests are generally proxied to the same
+ # home server as authentication requests.
+# realmslash
+ suffix
+
+ #
+ # Read the 'acct_users' file
+ files
+}
+
+#
+# Accounting. Log the accounting data.
+#
+accounting {
+ #
+ # Ensure that we have a semi-unique identifier for every
+ # request, and many NAS boxes are broken.
+ acct_unique
+
+ #
+ # Create a 'detail'ed log of the packets.
+ # Note that accounting requests which are proxied
+ # are also logged in the detail file.
+ detail
+# daily
+
+ unix # wtmp file
+
+ #
+ # For Simultaneous-Use tracking.
+ #
+ # Due to packet losses in the network, the data here
+ # may be incorrect. There's little we can do about it.
+ radutmp
+# sradutmp
+
+ # Return an address to the IP Pool when we see a stop record.
+# main_pool
+}
+
+
+# Session database, used for checking Simultaneous-Use. Either the radutmp
+# or rlm_sql module can handle this.
+# The rlm_sql module is *much* faster
+session {
+ radutmp
+# sql
+}
+
+
+# Post-Authentication
+# Once we KNOW that the user has been authenticated, there are
+# additional steps we can take.
+post-auth {
+ # Get an address from the IP Pool.
+# main_pool
+}
+
+#
+# When the server decides to proxy a request to a home server,
+# the proxied request is first passed through the pre-proxy
+# stage. This stage can re-write the request, or decide to
+# cancel the proxy.
+#
+# Only a few modules currently have this method.
+#
+pre-proxy {
+}
+
+#
+# When the server receives a reply to a request it proxied
+# to a home server, the request may be massaged here, in the
+# post-proxy stage.
+#
+post-proxy {
+ #
+ # If you are proxing LEAP, you MUST configure the EAP
+ # module, and you MUST list it here, in the post-proxy
+ # stage.
+ #
+ # You MUST also use the 'nostrip' option in the 'realm'
+ # configuration. Otherwise, the User-Name attribute
+ # in the proxied request will not match the user name
+ # hidden inside of the EAP packet, and the end server will
+ # reject the EAP request.
+ #
+ eap
+}
diff --git a/src/tests/eapsim-03/users-example.txt b/src/tests/eapsim-03/users-example.txt
new file mode 100644
index 0000000..7bcfc89
--- /dev/null
+++ b/src/tests/eapsim-03/users-example.txt
@@ -0,0 +1,34 @@
+1244070100000001@eapsim.foo Auth-Type := EAP, Autz-Type:= EAP, EAP-Type := SIM
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f,
+ EAP-Sim-SRES1 = 0xd1d2d3d4,
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f,
+ EAP-Sim-SRES2 = 0xe1e2e3e4,
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f,
+ EAP-Sim-SRES3 = 0xf1f2f3f4,
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7,
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7,
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7,
+
+1232420100000015 Auth-Type := EAP, Autz-Type:=EAP, EAP-Type := SIM
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000,
+ EAP-Sim-SRES1 = 0x30112233,
+ EAP-Sim-KC1 = 0x445566778899AABB,
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000,
+ EAP-Sim-SRES2 = 0x31112233,
+ EAP-Sim-KC2 = 0x445566778899AABB,
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000,
+ EAP-Sim-SRES3 = 0x32112233,
+ EAP-Sim-KC3 = 0x445566778899AABB,
+
+eapsim Auth-Type := EAP, Autz-Type:=EAP, EAP-Type := SIM
+ EAP-Sim-Rand1 = 0xabcd1234abcd1234abcd1234abcd1234,
+ EAP-Sim-SRES1 = 0x1234abcd,
+ EAP-Sim-KC1 = 0x0011223344556677,
+ EAP-Sim-Rand2 = 0xbcd1234abcd1234abcd1234abcd1234a,
+ EAP-Sim-SRES2 = 0x234abcd1,
+ EAP-Sim-KC2 = 0x1021324354657687,
+ EAP-Sim-Rand3 = 0xcd1234abcd1234abcd1234abcd1234ab,
+ EAP-Sim-SRES3 = 0x34abcd12,
+ EAP-Sim-KC3 = 0x30415263748596a7
+
+
diff --git a/src/tests/eapsim-04/client.sh b/src/tests/eapsim-04/client.sh
new file mode 100644
index 0000000..2ae1747
--- /dev/null
+++ b/src/tests/eapsim-04/client.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+../../main/radeapclient -x localhost auth testing123 <eapsim-in.txt
+
+
+
diff --git a/src/tests/eapsim-04/eapsim-cooked.txt b/src/tests/eapsim-04/eapsim-cooked.txt
new file mode 100644
index 0000000..7c6d97f
--- /dev/null
+++ b/src/tests/eapsim-04/eapsim-cooked.txt
@@ -0,0 +1,169 @@
+
++++> About to send encoded packet:
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "1244070100000001@eapsim.foo"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+ EAP-Sim-SRES1 = 0xd1d2d3d4
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+ EAP-Sim-SRES2 = 0xe1e2e3e4
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+ EAP-Sim-SRES3 = 0xf1f2f3f4
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+ EAP-Sim-SRES1 = 0xd1d2d3d4
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+ EAP-Sim-SRES2 = 0xe1e2e3e4
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+ EAP-Sim-SRES3 = 0xf1f2f3f4
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x001b313234343037303130303030303030314065617073696d2e666f6f
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+Input was:
+ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
+ nonce_mt: 00a3f6b4e832cf46b4d3e0d090623e22
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: d1d2d3d4
+ sres1: e1e2e3e4
+ sres2: f1f2f3f4
+ Kc0: a0a1a2a3a4a5a6a7
+ Kc1: b0b1b2b3b4b5b6b7
+ Kc2: c0c1c2c3c4c5c6c7
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: 2a56fd95_adac4bf7_645c2e60_7296a8af_9e1214a1
+K_aut: 2853a70a_4ca089cc_0cf8a24a_45ecec93
+K_encr: 77987afb_1cfd251d_749d2f16_0611338e
+msk: e8adff17_1d82d5e6_9a78d526_1e86ee56_93cbe646
+ 59332585_1f1f58f0_598c3a0c_1640339b_c3407fb4
+ 56a14ada_a4791445_e8a3cf40_49b4628f_8e9f597a
+ 7891e9d2
+emsk: b33c4a19_c1df9108_17196271_7c4b7f98_e53a64ba
+ a67d4e23_5ff142cb_6e427434_8a71358a_3c2b1313
+ 4cec6be3_a99e60c8_ae543fdd_52ecd7b3_0542e1df
+ 5d10c5f7
+MAC check succeed
+
++++> About to send encoded packet:
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+ EAP-Sim-SRES1 = 0xd1d2d3d4
+ EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+ EAP-Sim-SRES2 = 0xe1e2e3e4
+ EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+ EAP-Sim-SRES3 = 0xf1f2f3f4
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Sim-MAC = 0xd1d2d3d4e1e2e3e4f1f2f3f4
+ EAP-Sim-KEY = 0x2853a70a4ca089cc0cf8a24a45ecec93
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "1244070100000001@eapsim.foo"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=999, length=189
+ MS-MPPE-Recv-Key = 0xe8adff171d82d5e69a78d5261e86ee5693cbe646593325851f1f58f0598c3a0c
+ MS-MPPE-Send-Key = 0x1640339bc3407fb456a14adaa4791445e8a3cf4049b4628f8e9f597a7891e9d2
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "1244070100000001@eapsim.foo"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0xe8adff171d82d5e69a78d5261e86ee5693cbe646593325851f1f58f0598c3a0c
+ MS-MPPE-Send-Key = 0x1640339bc3407fb456a14adaa4791445e8a3cf4049b4628f8e9f597a7891e9d2
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "1244070100000001@eapsim.foo"
+ EAP-Id = YY
+ EAP-Code = Success
diff --git a/src/tests/eapsim-04/eapsim-in.txt b/src/tests/eapsim-04/eapsim-in.txt
new file mode 100644
index 0000000..eadd58f
--- /dev/null
+++ b/src/tests/eapsim-04/eapsim-in.txt
@@ -0,0 +1,17 @@
+User-Name = "1244070100000001@eapsim.foo"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Type-Identity = "1244070100000001@eapsim.foo"
+Message-Authenticator = 0
+NAS-Port = 0
+EAP-Sim-Rand1 = 0x101112131415161718191a1b1c1d1e1f
+EAP-Sim-SRES1 = 0xd1d2d3d4
+EAP-Sim-Rand2 = 0x202122232425262728292a2b2c2d2e2f
+EAP-Sim-SRES2 = 0xe1e2e3e4
+EAP-Sim-Rand3 = 0x303132333435363738393a3b3c3d3e3f
+EAP-Sim-SRES3 = 0xf1f2f3f4
+EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7
+EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7
+EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7
+
+
diff --git a/src/tests/eapsim-04/myvectors.txt b/src/tests/eapsim-04/myvectors.txt
new file mode 100644
index 0000000..d1cfadd
--- /dev/null
+++ b/src/tests/eapsim-04/myvectors.txt
@@ -0,0 +1,136 @@
++Input was:
++ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
++ nonce_mt: 0123456789abcdeffedcba9876543201
++ chal0: 101112131415161718191a1b1c1d1e1f
++ chal1: 202122232425262728292a2b2c2d2e2f
++ chal2: 303132333435363738393a3b3c3d3e3f
++ sres0: d1d2d3d4
++ sres1: e1e2e3e4
++ sres2: f1f2f3f4
++ Kc0: a0a1a2a3a4a5a6a7
++ Kc1: b0b1b2b3b4b5b6b7
++ Kc2: c0c1c2c3c4c5c6c7
++ versionlist[4]: 00020001
++ select 00 01
++
++
++Output
++mk: c21b4e4f_4e43619b_891e711f_f84f5e37_5e296d1a
++K_aut: cdd4e489_a7ae78da_67b593bd_8c231102
++K_encr: c322b087_a282de07_b0079dab_8e65d96f
++msk: eeea3a75_8d74d4f4_a7a77b98_5733806e_8093c8f9
++ 6a733668_70fcfb7e_4b0d7ab3_e8657531_25de1aa1
++ 318e21c4_57346f82_ba047e35_16ea4648_22f8039e
++ aa6cc9be
++emsk: fdc00fa1_d159910d_99251485_5d057d84_a4b1bd00
++ 4d34bef5_f7070000_cb380340_e8f00240_fcf9ffbf
++ c0970040_fdb20408_00000000_58e50640_003b3731
++ fcf9ffbf
+
++SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
++ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
++ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
++ dcba9876_54320100_010001
+
+VERSION is 1 byte:
+
++SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
++ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
++ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
++ dcba9876_54320100_0101
++Input was:
++ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
++ nonce_mt: 0123456789abcdeffedcba9876543201
++ rand0: 101112131415161718191a1b1c1d1e1f
++ rand1: 202122232425262728292a2b2c2d2e2f
++ rand2: 303132333435363738393a3b3c3d3e3f
++ sres0: d1d2d3d4
++ sres1: e1e2e3e4
++ sres2: f1f2f3f4
++ Kc0: a0a1a2a3a4a5a6a7
++ Kc1: b0b1b2b3b4b5b6b7
++ Kc2: c0c1c2c3c4c5c6c7
++ versionlist[2]: 0001
++ select 00 01
++
++
++Output
++mk: cfe4d5bc_fb87bcab_4d83ebea_90c179df_3cfee43c
++K_aut: 32aa4046_770c30ed_bce21212_d7d9393c
++K_encr: e3810875_f8c40f7f_cb2544ed_d0d873c3
++msk: 3a8dd0fb_411d15e1_4d485c8b_bd94ab23_a8ea3e5a
++ d888521c_d1a3fa7d_1fabd7e2_afd062f6_75c3de8b
++ 5adda978_91d78a3d_2efcb988_265ceee3_fa924279
++ 43fa0125
++emsk: 5296957b_61bc72f8_5c2acbd5_501299d1_b7e2b04f
++ 39127a69_003b0140_f8200340_003b0140_03000000
++ 98bb0240_003b0140_e8f9ffbf_a4810408_bc373731
++ fcf9ffbf
+
+1-byte:
++SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
++ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
++ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
++ dcba9876_54321000_0101
++Input was:
++ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
++ nonce_mt: 0123456789abcdeffedcba9876543210
++ rand0: 101112131415161718191a1b1c1d1e1f
++ rand1: 202122232425262728292a2b2c2d2e2f
++ rand2: 303132333435363738393a3b3c3d3e3f
++ sres0: d1d2d3d4
++ sres1: e1e2e3e4
++ sres2: f1f2f3f4
++ Kc0: a0a1a2a3a4a5a6a7
++ Kc1: b0b1b2b3b4b5b6b7
++ Kc2: c0c1c2c3c4c5c6c7
++ versionlist[2]: 0001
++ select 00 01
++
++
++Output
++mk: d328f534_d9292b67_0e73c798_591e1e09_04c0c8cc
++K_aut: aa19e454_833aa2ea_ccc116db_9312b543
++K_encr: 51fc0641_e4d9fa43_23f9516d_15b9f618
++msk: ced8e588_7d883785_ee2d2e41_f1aeb82d_1cfca277
++ 7309b411_30047c52_130807c0_bdf0e56e_205433e0
++ 58b2f48e_2337809d_e1b2681c_e30932d9_2a62cbe8
++ 40bfb568
++emsk: a273b6f5_47d12da7_c1d0dff4_746e0ded_70e74a83
++ 520b22a8_003b0140_f8200340_003b0140_03000000
++ 98bb0240_003b0140_e8f9ffbf_a4810408_bc373731
++ fcf9ffbf
+
+2-bytes:
++SHA1buffer was: 31323434_30373031_30303030_30303031_40656170_
++ 73696d2e_666f6fa0_a1a2a3a4_a5a6a7b0_b1b2b3b4_
++ b5b6b7c0_c1c2c3c4_c5c6c701_23456789_abcdeffe_
++ dcba9876_54321000_010001
++Input was:
++ identity: (len=27)313234343037303130303030303030314065617073696d2e666f6f
++ nonce_mt: 0123456789abcdeffedcba9876543210
++ rand0: 101112131415161718191a1b1c1d1e1f
++ rand1: 202122232425262728292a2b2c2d2e2f
++ rand2: 303132333435363738393a3b3c3d3e3f
++ sres0: d1d2d3d4
++ sres1: e1e2e3e4
++ sres2: f1f2f3f4
++ Kc0: a0a1a2a3a4a5a6a7
++ Kc1: b0b1b2b3b4b5b6b7
++ Kc2: c0c1c2c3c4c5c6c7
++ versionlist[2]: 0001
++ select 00 01
++
++
++Output
++mk: e576d5ca_332e9930_018bf1ba_ee2763c7_95b3c712
++K_aut: 536e5ebc_4465582a_a6a8ec99_86ebb620
++K_encr: 25af1942_efcbf4bc_72b39434_21f2a974
++msk: 39d45aea_f4e30601_983e972b_6cfd46d1_c3637733
++ 65690d09_cd44976b_525f47d3_a60a985e_955c53b0
++ 90b2e4b7_3719196a_40254296_8fd14a88_8f46b9a7
++ 886e4488
++emsk: 5949eab0_fff69d52_315c6c63_4fd14a7f_0d52023d
++ 56f79698_003b0140_f8200340_003b0140_03000000
++ 98bb0240_003b0140_e8f9ffbf_a4810408_bc373731
++ fcf9ffbf
diff --git a/src/tests/eapsim-04/users.txt b/src/tests/eapsim-04/users.txt
new file mode 100644
index 0000000..af2e006
--- /dev/null
+++ b/src/tests/eapsim-04/users.txt
@@ -0,0 +1,17 @@
+1244070100000001@eapsim.foo Auth-Type := EAP, EAP-Type := SIM
+ EAP-Sim-Chal1 = 0x101112131415161718191a1b1c1d1e1f,
+ EAP-Sim-SRES1 = 0xd1d2d3d4,
+ EAP-Sim-Chal2 = 0x202122232425262728292a2b2c2d2e2f,
+ EAP-Sim-SRES2 = 0xe1e2e3e4,
+ EAP-Sim-Chal3 = 0x303132333435363738393a3b3c3d3e3f,
+ EAP-Sim-SRES3 = 0xf1f2f3f4,
+ EAP-Sim-KC1 = 0xa0a1a2a3a4a5a6a7,
+ EAP-Sim-KC2 = 0xb0b1b2b3b4b5b6b7,
+ EAP-Sim-KC3 = 0xc0c1c2c3c4c5c6c7,
+ Service-Type = Framed-User,
+ Framed-Protocol = PPP,
+ Framed-IP-Address = 172.16.3.34,
+ Framed-IP-Netmask = 255.255.255.0,
+ Framed-Routing = Broadcast-Listen,
+ Framed-MTU = 1234
+
diff --git a/src/tests/eapsim-05/check.gdb b/src/tests/eapsim-05/check.gdb
new file mode 100644
index 0000000..8418d96
--- /dev/null
+++ b/src/tests/eapsim-05/check.gdb
@@ -0,0 +1,2 @@
+file ../../main/radeapclient
+set args -x localhost auth testing123 <eapsim-in.txt \ No newline at end of file
diff --git a/src/tests/eapsim-05/client.sh b/src/tests/eapsim-05/client.sh
new file mode 100644
index 0000000..2ae1747
--- /dev/null
+++ b/src/tests/eapsim-05/client.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+../../main/radeapclient -x localhost auth testing123 <eapsim-in.txt
+
+
+
diff --git a/src/tests/eapsim-05/description.txt b/src/tests/eapsim-05/description.txt
new file mode 100644
index 0000000..a490df4
--- /dev/null
+++ b/src/tests/eapsim-05/description.txt
@@ -0,0 +1,2 @@
+This test is identical to eapsim-03, except that the RAND is purposely
+wrong.
diff --git a/src/tests/eapsim-05/eapsim-cooked.txt b/src/tests/eapsim-05/eapsim-cooked.txt
new file mode 100644
index 0000000..8b8c4a5
--- /dev/null
+++ b/src/tests/eapsim-05/eapsim-cooked.txt
@@ -0,0 +1,148 @@
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "eapsim"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+__________________
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 0
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
diff --git a/src/tests/eapsim-05/eapsim-in.txt b/src/tests/eapsim-05/eapsim-in.txt
new file mode 100644
index 0000000..a48fdd9
--- /dev/null
+++ b/src/tests/eapsim-05/eapsim-in.txt
@@ -0,0 +1,15 @@
+User-Name = "eapsim"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Type-Identity = "eapsim"
+Message-Authenticator = 0
+NAS-Port = 0
+EAP-Sim-Rand1 = 0x89abcBEEF9abcdef89abcdef89abcdef
+EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+EAP-Sim-Sres1 = 0x1234abcd
+EAP-Sim-Sres2 = 0x234abcd1
+EAP-Sim-Sres3 = 0x34abcd12
+EAP-Sim-KC1 = 0x0011223344556677
+EAP-Sim-KC2 = 0x1021324354657687
+EAP-Sim-KC3 = 0x30415263748596a7
diff --git a/src/tests/eapsim-05/eapsim-out.txt b/src/tests/eapsim-05/eapsim-out.txt
new file mode 100644
index 0000000..8b8c4a5
--- /dev/null
+++ b/src/tests/eapsim-05/eapsim-out.txt
@@ -0,0 +1,148 @@
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "eapsim"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+__________________
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 0
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
diff --git a/src/tests/eapsim-05/eapsim-raw.txt b/src/tests/eapsim-05/eapsim-raw.txt
new file mode 100644
index 0000000..ef7d7c6
--- /dev/null
+++ b/src/tests/eapsim-05/eapsim-raw.txt
@@ -0,0 +1,148 @@
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "eapsim"
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+Sending Access-Request of id 204 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Message = 0x02cb000b0165617073696d
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=204, length=78
+ EAP-Message = 0x01a70014120a00000f0200020001000011010100
+ Message-Authenticator = 0xce4f705db940a4a61c0896712e259ecb
+ State = 0xc313c2aa36347b14bc248a365651d25f
+<+++ EAP decoded packet:
+ EAP-Message = 0x01a70014120a00000f0200020001000011010100
+ Message-Authenticator = 0xce4f705db940a4a61c0896712e259ecb
+ State = 0xc313c2aa36347b14bc248a365651d25f
+ EAP-Id = 167
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01a70014120a00000f0200020001000011010100
+ Message-Authenticator = 0xce4f705db940a4a61c0896712e259ecb
+ State = 0xc313c2aa36347b14bc248a365651d25f
+ EAP-Id = 167
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = 167
+ EAP-Message = 0x02a7002c120a0000100100010705000000a3f6b4e832cf46b4d3e0d090623e220e03000665617073696d0000
+ State = 0xc313c2aa36347b14bc248a365651d25f
+Sending Access-Request of id 205 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Message = 0x02a7002c120a0000100100010705000000a3f6b4e832cf46b4d3e0d090623e220e03000665617073696d0000
+ State = 0xc313c2aa36347b14bc248a365651d25f
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=205, length=138
+ EAP-Message = 0x01a80050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b0500004295110227f46b83717e6d2f64ecd5f5
+ Message-Authenticator = 0xe76cfc6fb346d107b4b1d313faac212e
+ State = 0xf94335155e78fbfc00ee2fab6d277167
+<+++ EAP decoded packet:
+ EAP-Message = 0x01a80050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b0500004295110227f46b83717e6d2f64ecd5f5
+ Message-Authenticator = 0xe76cfc6fb346d107b4b1d313faac212e
+ State = 0xf94335155e78fbfc00ee2fab6d277167
+ EAP-Id = 168
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b0500004295110227f46b83717e6d2f64ecd5f5
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01a80050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b0500004295110227f46b83717e6d2f64ecd5f5
+ Message-Authenticator = 0xe76cfc6fb346d107b4b1d313faac212e
+ State = 0xf94335155e78fbfc00ee2fab6d277167
+ EAP-Id = 168
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b0500004295110227f46b83717e6d2f64ecd5f5
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0x00004295110227f46b83717e6d2f64ecd5f5
+__________________
++++> About to send encoded packet:
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x89abcbeef9abcdef89abcdef89abcdef
+ EAP-Sim-Rand2 = 0x9abcdef89abcdef89abcdef89abcdef8
+ EAP-Sim-Rand3 = 0xabcdef89abcdef89abcdef89abcdef89
+ EAP-Sim-SRES1 = 0x1234abcd
+ EAP-Sim-SRES2 = 0x234abcd1
+ EAP-Sim-SRES3 = 0x34abcd12
+ EAP-Sim-KC1 = 0x0011223344556677
+ EAP-Sim-KC2 = 0x1021324354657687
+ EAP-Sim-KC3 = 0x30415263748596a7
+ EAP-Sim-State = 0
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x000000a3f6b4e832cf46b4d3e0d090623e22
+ EAP-Sim-IDENTITY = 0x000665617073696d
+ EAP-Id = 168
+ State = 0xf94335155e78fbfc00ee2fab6d277167
+ EAP-Message = 0x02a8002c120a0000100100010705000000a3f6b4e832cf46b4d3e0d090623e220e03000665617073696d0000
+Sending Access-Request of id 206 to 127.0.0.1:1812
+ User-Name = "eapsim"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ State = 0xf94335155e78fbfc00ee2fab6d277167
+ EAP-Message = 0x02a8002c120a0000100100010705000000a3f6b4e832cf46b4d3e0d090623e220e03000665617073696d0000
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=206, length=138
+ EAP-Message = 0x01a90050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000d7c75f997bf27cd7a46f3b34f8a8f5b3
+ Message-Authenticator = 0x16fc76638c72e04b8b43ab48edcf5088
+ State = 0xb9449aca40be007b0a641b9fa5b1f761
+<+++ EAP decoded packet:
+ EAP-Message = 0x01a90050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000d7c75f997bf27cd7a46f3b34f8a8f5b3
+ Message-Authenticator = 0x16fc76638c72e04b8b43ab48edcf5088
+ State = 0xb9449aca40be007b0a641b9fa5b1f761
+ EAP-Id = 169
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000d7c75f997bf27cd7a46f3b34f8a8f5b3
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01a90050120b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000d7c75f997bf27cd7a46f3b34f8a8f5b3
+ Message-Authenticator = 0x16fc76638c72e04b8b43ab48edcf5088
+ State = 0xb9449aca40be007b0a641b9fa5b1f761
+ EAP-Id = 169
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab0b050000d7c75f997bf27cd7a46f3b34f8a8f5b3
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000abcd1234abcd1234abcd1234abcd1234bcd1234abcd1234abcd1234abcd1234acd1234abcd1234abcd1234abcd1234ab
+ EAP-Sim-MAC = 0x0000d7c75f997bf27cd7a46f3b34f8a8f5b3
diff --git a/src/tests/eapsim-05/eapsim-sanitize.sed b/src/tests/eapsim-05/eapsim-sanitize.sed
new file mode 100644
index 0000000..84410ca
--- /dev/null
+++ b/src/tests/eapsim-05/eapsim-sanitize.sed
@@ -0,0 +1,10 @@
+s/\(Sending Access-Request of id\).*\(to 127.0.0.1:1812\)/\1 999 \2/
+s/\(Message-Authenticator = 0x\).*/\1ABCDABCDABCDABCDABCDABCDABCDABCD/
+s/\(State = 0x\).*/\1ABCDABCDABCDABCDABCDABCDABCDABCD/
+s/\(rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id\)=.*,\( length=.*\)/\1=999,\2/
+s/\(rad_recv: Access-Accept packet from host 127.0.0.1:1812, id\)=.*,\( length=.*\)/\1=999,\2/
+s/\(EAP-Message = 0x..\)\(.*\)/\1XX/
+s/\(EAP-Id = \).*/\1YY/
+s/\(EAP-Type-MD5 = \).*/\1MD5/
+
+
diff --git a/src/tests/eapsim-06/check.gdb b/src/tests/eapsim-06/check.gdb
new file mode 100644
index 0000000..a3bb6be
--- /dev/null
+++ b/src/tests/eapsim-06/check.gdb
@@ -0,0 +1,2 @@
+file ../../modules/rlm_eap/radeapclient
+set args -x localhost auth testing123 <eapsim-in.txt \ No newline at end of file
diff --git a/src/tests/eapsim-06/client.sh b/src/tests/eapsim-06/client.sh
new file mode 100644
index 0000000..2ae1747
--- /dev/null
+++ b/src/tests/eapsim-06/client.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+../../main/radeapclient -x localhost auth testing123 <eapsim-in.txt
+
+
+
diff --git a/src/tests/eapsim-06/description.txt b/src/tests/eapsim-06/description.txt
new file mode 100644
index 0000000..dacee1a
--- /dev/null
+++ b/src/tests/eapsim-06/description.txt
@@ -0,0 +1,24 @@
+This test is identical to eapsim-05, but uses triplets that come from
+the file simtriplets.dat.
+
+To configure this test, add the following to radiusd.conf:
+
+In modules {},
+
+ sim_files {
+ simtriplets = "/some/file"
+ }
+
+ (The default is to use ${raddbdir}/simtriplets.dat )
+
+In authorized {}, add:
+
+ sim_files
+
+before eap.
+
+Of course, you'll already have "sim" listed in the eap{} section of
+modules.
+
+
+
diff --git a/src/tests/eapsim-06/eapsim-cooked.txt b/src/tests/eapsim-06/eapsim-cooked.txt
new file mode 100644
index 0000000..6597b00
--- /dev/null
+++ b/src/tests/eapsim-06/eapsim-cooked.txt
@@ -0,0 +1,184 @@
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "232420100000015"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x00001b764ea5668faa4b0e7dd876d25753f8
+ EAP-Sim-IDENTITY = 0x000f323332343230313030303030303135
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000300000000000000000000000000000003100000000000000000000000000000032000000000000000000000000000000
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+Input was:
+ identity: (len=15)323332343230313030303030303135
+ nonce_mt: 1b764ea5668faa4b0e7dd876d25753f8
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: 30112233
+ sres1: 31112233
+ sres2: 32112233
+ Kc0: 445566778899aabb
+ Kc1: 445566778899aabb
+ Kc2: 445566778899aabb
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: a444d7cc_dd514568_da171dd4_229ed4d1_a088c470
+K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+K_encr: f544a796_43c4d95f_90aaa5b7_74267742
+msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
+emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (96) 01YY0050_120b0000_010d0000_30000000_00000000
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
+
+hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
+MAC check succeed
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (40) 02YY001c_120b0000_0b050000_00000000_00000000
+ 00000000_00000000_30112233_31112233_32112233
+
+hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Sim-MAC = 0x301122333111223332112233
+ EAP-Sim-KEY = 0xa4c96a3c1b4e1932acc3878decb5d9c6
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=999, length=177
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "232420100000015"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "232420100000015"
+ EAP-Id = YY
+ EAP-Code = Success
diff --git a/src/tests/eapsim-06/eapsim-in.txt b/src/tests/eapsim-06/eapsim-in.txt
new file mode 100644
index 0000000..5f875cc
--- /dev/null
+++ b/src/tests/eapsim-06/eapsim-in.txt
@@ -0,0 +1,15 @@
+User-Name = "232420100000015"
+NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+EAP-Code = Response
+EAP-Type-Identity = "232420100000015"
+Message-Authenticator = 0
+NAS-Port = 0
+EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+EAP-Sim-Sres1 = 0x30112233
+EAP-Sim-Sres2 = 0x31112233
+EAP-Sim-Sres3 = 0x32112233
+EAP-Sim-KC1 = 0x445566778899AABB
+EAP-Sim-KC2 = 0x445566778899AABB
+EAP-Sim-KC3 = 0x445566778899AABB
diff --git a/src/tests/eapsim-06/eapsim-out.txt b/src/tests/eapsim-06/eapsim-out.txt
new file mode 100644
index 0000000..6597b00
--- /dev/null
+++ b/src/tests/eapsim-06/eapsim-out.txt
@@ -0,0 +1,184 @@
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "232420100000015"
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=78
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x00001b764ea5668faa4b0e7dd876d25753f8
+ EAP-Sim-IDENTITY = 0x000f323332343230313030303030303135
+ EAP-Id = YY
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Message = 0x02XX
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=999, length=138
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+<+++ EAP decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Id = YY
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000300000000000000000000000000000003100000000000000000000000000000032000000000000000000000000000000
+ EAP-Sim-MAC = 0xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
+Input was:
+ identity: (len=15)323332343230313030303030303135
+ nonce_mt: 1b764ea5668faa4b0e7dd876d25753f8
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: 30112233
+ sres1: 31112233
+ sres2: 32112233
+ Kc0: 445566778899aabb
+ Kc1: 445566778899aabb
+ Kc2: 445566778899aabb
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: a444d7cc_dd514568_da171dd4_229ed4d1_a088c470
+K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+K_encr: f544a796_43c4d95f_90aaa5b7_74267742
+msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
+emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (96) 01YY0050_120b0000_010d0000_30000000_00000000
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
+
+hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
+MAC check succeed
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (40) 02YY001c_120b0000_0b050000_00000000_00000000
+ 00000000_00000000_30112233_31112233_32112233
+
+hmac-sha1 mac(20): XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = YY
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Sim-MAC = 0x301122333111223332112233
+ EAP-Sim-KEY = 0xa4c96a3c1b4e1932acc3878decb5d9c6
+ EAP-Message = 0x02XX
+Sending Access-Request of id 999 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ NAS-Port = 0
+ State = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ EAP-Message = 0x02XX
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=999, length=177
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "232420100000015"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03XX
+ Message-Authenticator = 0xABCDABCDABCDABCDABCDABCDABCDABCD
+ User-Name = "232420100000015"
+ EAP-Id = YY
+ EAP-Code = Success
diff --git a/src/tests/eapsim-06/eapsim-raw.txt b/src/tests/eapsim-06/eapsim-raw.txt
new file mode 100644
index 0000000..a2b0836
--- /dev/null
+++ b/src/tests/eapsim-06/eapsim-raw.txt
@@ -0,0 +1,184 @@
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ EAP-Type-Identity = "232420100000015"
+ Message-Authenticator = 0x30
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+Sending Access-Request of id 22 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Message = 0x0215001401323332343230313030303030303135
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=22, length=78
+ EAP-Message = 0x01270014120a00000f0200020001000011010100
+ Message-Authenticator = 0x77ea02a9c89f5e87f5ce65c10877232f
+ State = 0xf0524fef7731860cc1d28b0dc573017c
+<+++ EAP decoded packet:
+ EAP-Message = 0x01270014120a00000f0200020001000011010100
+ Message-Authenticator = 0x77ea02a9c89f5e87f5ce65c10877232f
+ State = 0xf0524fef7731860cc1d28b0dc573017c
+ EAP-Id = 39
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01270014120a00000f0200020001000011010100
+ Message-Authenticator = 0x77ea02a9c89f5e87f5ce65c10877232f
+ State = 0xf0524fef7731860cc1d28b0dc573017c
+ EAP-Id = 39
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0a00000f0200020001000011010100
+ EAP-Sim-Subtype = Start
+ EAP-Sim-VERSION_LIST = 0x000200010000
+ EAP-Sim-FULLAUTH_ID_REQ = 0x0100
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Start
+ EAP-Sim-SELECTED_VERSION = 0x0001
+ EAP-Sim-NONCE_MT = 0x00001b764ea5668faa4b0e7dd876d25753f8
+ EAP-Sim-IDENTITY = 0x000f323332343230313030303030303135
+ EAP-Id = 39
+ EAP-Message = 0x02270034120a000010010001070500001b764ea5668faa4b0e7dd876d25753f80e05000f32333234323031303030303030313500
+ State = 0xf0524fef7731860cc1d28b0dc573017c
+Sending Access-Request of id 23 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Message = 0x02270034120a000010010001070500001b764ea5668faa4b0e7dd876d25753f80e05000f32333234323031303030303030313500
+ State = 0xf0524fef7731860cc1d28b0dc573017c
+rad_recv: Access-Challenge packet from host 127.0.0.1:1812, id=23, length=138
+ EAP-Message = 0x01280050120b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000a91362adf370809ac998c123ebcb32bd
+ Message-Authenticator = 0x2a36d73274543865af44e142fcce7723
+ State = 0x73765e7615012c333beac9182696279c
+<+++ EAP decoded packet:
+ EAP-Message = 0x01280050120b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000a91362adf370809ac998c123ebcb32bd
+ Message-Authenticator = 0x2a36d73274543865af44e142fcce7723
+ State = 0x73765e7615012c333beac9182696279c
+ EAP-Id = 40
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000a91362adf370809ac998c123ebcb32bd
+<+++ EAP-sim decoded packet:
+ EAP-Message = 0x01280050120b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000a91362adf370809ac998c123ebcb32bd
+ Message-Authenticator = 0x2a36d73274543865af44e142fcce7723
+ State = 0x73765e7615012c333beac9182696279c
+ EAP-Id = 40
+ EAP-Code = Request
+ EAP-Type-SIM = 0x0b0000010d00003000000000000000000000000000000031000000000000000000000000000000320000000000000000000000000000000b050000a91362adf370809ac998c123ebcb32bd
+ EAP-Sim-Subtype = Challenge
+ EAP-Sim-RAND = 0x0000300000000000000000000000000000003100000000000000000000000000000032000000000000000000000000000000
+ EAP-Sim-MAC = 0x0000a91362adf370809ac998c123ebcb32bd
+Input was:
+ identity: (len=15)323332343230313030303030303135
+ nonce_mt: 1b764ea5668faa4b0e7dd876d25753f8
+ rand0: 00000000000000000000000000000000
+ rand1: 00000000000000000000000000000000
+ rand2: 00000000000000000000000000000000
+ sres0: 30112233
+ sres1: 31112233
+ sres2: 32112233
+ Kc0: 445566778899aabb
+ Kc1: 445566778899aabb
+ Kc2: 445566778899aabb
+ versionlist[2]: 0001
+ select 00 01
+
+
+Output
+mk: a444d7cc_dd514568_da171dd4_229ed4d1_a088c470
+K_aut: a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+K_encr: f544a796_43c4d95f_90aaa5b7_74267742
+msk: 8000f5e4_ed05a9bf_17b9ec6a_27f92d9d_f104966b
+ 03689665_de45db49_82ecdcc4_85c26910_e886de4f
+ bdfa4218_b4ef2f64_319c9b41_b77b3c90_69d616f9
+ 0781438a
+emsk: 3c87c92f_44193e35_dd18e906_3d7cff8f_cb6d6002
+ bf233300_5df66776_70086929_f0d27970_3e59c480
+ 675d6b45_0dc6a79a_51dc34b0_7091a5ff_8ca145ce
+ 98accef2
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (96) 01280050_120b0000_010d0000_30000000_00000000
+ 00000000_00000000_31000000_00000000_00000000
+ 00000000_32000000_00000000_00000000_00000000
+ 0b050000_00000000_00000000_00000000_00000000
+ 1b764ea5_668faa4b_0e7dd876_d25753f8
+
+hmac-sha1 mac(20): a91362ad_f370809a_c998c123_ebcb32bd_6a2915c2
+MAC check succeed
+
+hmac-sha1 key(16): a4c96a3c_1b4e1932_acc3878d_ecb5d9c6
+DATA: (40) 0228001c_120b0000_0b050000_00000000_00000000
+ 00000000_00000000_30112233_31112233_32112233
+
+hmac-sha1 mac(20): 7a3818ad_17959b80_99cd84eb_64e45346_d63098e9
+
++++> About to send encoded packet:
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ EAP-Code = Response
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ EAP-Sim-Rand1 = 0x30000000000000000000000000000000
+ EAP-Sim-Rand2 = 0x31000000000000000000000000000000
+ EAP-Sim-Rand3 = 0x32000000000000000000000000000000
+ EAP-Sim-SRES1 = 0x30112233
+ EAP-Sim-SRES2 = 0x31112233
+ EAP-Sim-SRES3 = 0x32112233
+ EAP-Sim-KC1 = 0x445566778899aabb
+ EAP-Sim-KC2 = 0x445566778899aabb
+ EAP-Sim-KC3 = 0x445566778899aabb
+ EAP-Sim-State = 1
+ EAP-Sim-Subtype = Challenge
+ EAP-Id = 40
+ State = 0x73765e7615012c333beac9182696279c
+ EAP-Sim-MAC = 0x301122333111223332112233
+ EAP-Sim-KEY = 0xa4c96a3c1b4e1932acc3878decb5d9c6
+ EAP-Message = 0x0228001c120b00000b0500007a3818ad17959b8099cd84eb64e45346
+Sending Access-Request of id 24 to 127.0.0.1:1812
+ User-Name = "232420100000015"
+ NAS-IP-Address = marajade.sandelman.ottawa.on.ca
+ Message-Authenticator = 0x00000000000000000000000000000000
+ NAS-Port = 0
+ State = 0x73765e7615012c333beac9182696279c
+ EAP-Message = 0x0228001c120b00000b0500007a3818ad17959b8099cd84eb64e45346
+rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=24, length=177
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03000004
+ Message-Authenticator = 0xc34c14d1a9c794cbc3f7c5c274831277
+ User-Name = "232420100000015"
+<+++ EAP decoded packet:
+ MS-MPPE-Recv-Key = 0x8000f5e4ed05a9bf17b9ec6a27f92d9df104966b03689665de45db4982ecdcc4
+ MS-MPPE-Send-Key = 0x85c26910e886de4fbdfa4218b4ef2f64319c9b41b77b3c9069d616f90781438a
+ EAP-Message = 0x03000004
+ Message-Authenticator = 0xc34c14d1a9c794cbc3f7c5c274831277
+ User-Name = "232420100000015"
+ EAP-Id = 0
+ EAP-Code = Success
diff --git a/src/tests/eapsim-06/simtriplets.dat b/src/tests/eapsim-06/simtriplets.dat
new file mode 100644
index 0000000..3a64447
--- /dev/null
+++ b/src/tests/eapsim-06/simtriplets.dat
@@ -0,0 +1,5 @@
+232420100000015,30000000000000000000000000000000,30112233,445566778899AABB
+232420100000015,31000000000000000000000000000000,31112233,445566778899AABB
+232420100000015,32000000000000000000000000000000,32112233,445566778899AABB
+232420100000015,33000000000000000000000000000000,33112233,445566778899AABB
+232420100000015,34000000000000000000000000000000,34112233,445566778899AABB
diff --git a/src/tests/example.com b/src/tests/example.com
new file mode 100644
index 0000000..6ad3296
--- /dev/null
+++ b/src/tests/example.com
@@ -0,0 +1,5 @@
+#
+# TESTS 1
+#
+User-Name = "bob@example.com"
+User-Password = "bob"
diff --git a/src/tests/fips186-02/description.txt b/src/tests/fips186-02/description.txt
new file mode 100644
index 0000000..5c6859c
--- /dev/null
+++ b/src/tests/fips186-02/description.txt
@@ -0,0 +1,5 @@
+Test vectors were from
+http://csrc.nist.gov/CryptoToolkit/dss/Examples-1024bit.pdf
+
+
+
diff --git a/src/tests/fips186-02/fips186-2.txt b/src/tests/fips186-02/fips186-2.txt
new file mode 100644
index 0000000..d93053f
--- /dev/null
+++ b/src/tests/fips186-02/fips186-2.txt
@@ -0,0 +1,9 @@
+Input was: |bd029bbe_7f51960b_cf9edb2b_61f06f0f_eb5a38b6|
+Output was: 2070b322_3dba372f_de1c0ffc_7b2e3b49_8b260614
+ 3c6c18ba_cb0f6c55_babb1378_8e20d737_a3275116
+ c9ec5c2f_3261cba3_98384ecf_9189707c_20dbe3b6
+ 8d6fc9d2_37313854_7338c3f5_7cf68f38_683aea5b
+ f9e60c0d_73b177bc_69edde1b_eb3f596a_9555fee9
+ 0d570204_a3044bb5_a67f6509_25f14c1d_0446b252
+ 78360140_28faffbf_49840408_ccb30408_00b40408
+ 38faffbf_18ef0440_48ae1340_c0970040_48faffbf
diff --git a/src/tests/hmac-md5-01/digest1.txt b/src/tests/hmac-md5-01/digest1.txt
new file mode 100644
index 0000000..d3b63ee
--- /dev/null
+++ b/src/tests/hmac-md5-01/digest1.txt
@@ -0,0 +1 @@
+750c783e6ab0b503eaa86e310a5db738
diff --git a/src/tests/hmac-sha1-01/digest1.txt b/src/tests/hmac-sha1-01/digest1.txt
new file mode 100644
index 0000000..eb8f81e
--- /dev/null
+++ b/src/tests/hmac-sha1-01/digest1.txt
@@ -0,0 +1 @@
+effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
diff --git a/src/tests/keywords/3gpp b/src/tests/keywords/3gpp
new file mode 100644
index 0000000..05e3fb2
--- /dev/null
+++ b/src/tests/keywords/3gpp
@@ -0,0 +1,19 @@
+#
+# PRE: update
+#
+update request {
+ 3GPP-IMSI := "hello"
+}
+
+#
+# "request:[0-9]" should be parsed as a list followed
+# by an attribute.
+#
+update control {
+ Tmp-String-0 := "%{3GPP-IMSI}"
+ Tmp-String-1 := "%{request:3GPP-IMSI}"
+}
+
+update reply {
+ Filter-Id := "filter"
+} \ No newline at end of file
diff --git a/src/tests/keywords/README.md b/src/tests/keywords/README.md
new file mode 100644
index 0000000..68ce136
--- /dev/null
+++ b/src/tests/keywords/README.md
@@ -0,0 +1,43 @@
+# The Keyword test Framework
+
+See `update` and `default-input.attrs` for examples.
+
+In short, the test framework assumes Access-Request with PAP
+authentication. The password is hard-coded into the configuration,
+and can't be changed.
+
+The entire test suite consists of two files:
+
+* foo
+
+ Contains a short piece of "unlang". The shorter the better. The
+ goal is to do something useful in unlang, and modify the input
+ packet and/or the reply.
+
+ If the test depends on another one, it should name the other test
+ at the top of the file. For example, the `if-else` test depends
+ on the `if` test. This dependency is given by the following lines
+ at the top of the `if-else` file:
+
+ `# PRE: if`
+
+* foo.attrs
+
+ Contains the input packet and the filter for the reply. There
+ always has to be attributes in the input, and filter attributes in the
+ reply.
+
+ If `foo` doesn't exist, then the `default-input.attrs` file is used.
+ This allows many tests to be simplified, as all they need is a
+ little bit of "unlang".
+
+
+## How it works
+
+The input packet is passed into the unit test framework, through the
+unlang snippet in `foo`, and filtered through the reply filter in
+`foo.attrs`. If everything matches, then the test case passes.
+
+To add a test, just put `foo` and (optionally) `foo.attrs` into this
+directory. The build framework will pick them up and automatically
+run them.
diff --git a/src/tests/keywords/all.mk b/src/tests/keywords/all.mk
new file mode 100644
index 0000000..739b738
--- /dev/null
+++ b/src/tests/keywords/all.mk
@@ -0,0 +1,123 @@
+#
+# Unit tests for unlang keywords
+#
+
+#
+# The test files are files without extensions.
+# The list is unordered. The order is added in the next step by looking
+# at precursors.
+#
+KEYWORD_FILES := $(filter-out %.conf %.md %.attrs %.mk %~ %.rej,$(subst $(DIR)/,,$(wildcard $(DIR)/*)))
+
+ifeq "$(OPENSSL_LIBS)" ""
+KEYWORD_FILES := $(filter-out pap-ssha2,$(KEYWORD_FILES))
+endif
+
+#
+# Create the output directory
+#
+.PHONY: $(BUILD_DIR)/tests/keywords
+$(BUILD_DIR)/tests/keywords:
+ @mkdir -p $@
+
+#
+# Find which input files are needed by the tests
+# strip out the ones which exist
+# move the filenames to the build directory.
+#
+BOOTSTRAP_EXISTS := $(addprefix $(DIR)/,$(addsuffix .attrs,$(KEYWORD_FILES)))
+BOOTSTRAP_NEEDS := $(filter-out $(wildcard $(BOOTSTRAP_EXISTS)),$(BOOTSTRAP_EXISTS))
+BOOTSTRAP := $(subst $(DIR),$(BUILD_DIR)/tests/keywords,$(BOOTSTRAP_NEEDS))
+
+#
+# For each file, look for precursor test.
+# Ensure that each test depends on its precursors.
+#
+-include $(BUILD_DIR)/tests/keywords/depends.mk
+
+export OPENSSL_LIBS
+
+$(BUILD_DIR)/tests/keywords/depends.mk: $(addprefix $(DIR)/,$(KEYWORD_FILES)) | $(BUILD_DIR)/tests/keywords
+ @rm -f $@
+ @for x in $^; do \
+ y=`grep 'PRE: ' $$x | sed 's/.*://;s/ / /g;s, , $(BUILD_DIR)/tests/keywords/,g'`; \
+ if [ "$$y" != "" ]; then \
+ z=`echo $$x | sed 's,src/,$(BUILD_DIR)/',`; \
+ echo "$$z: $$y" >> $@; \
+ echo "" >> $@; \
+ fi \
+ done
+
+#
+# These ones get copied over from the default input
+#
+$(BOOTSTRAP): $(DIR)/default-input.attrs | $(BUILD_DIR)/tests/keywords
+ @cp $< $@
+
+#
+# These ones get copied over from their original files
+#
+$(BUILD_DIR)/tests/keywords/%.attrs: $(DIR)/%.attrs | $(BUILD_DIR)/tests/keywords
+ @cp $< $@
+
+#
+# Don't auto-remove the files copied by the rule just above.
+# It's unnecessary, and it clutters the output with crap.
+#
+.PRECIOUS: $(BUILD_DIR)/tests/keywords/%.attrs
+
+KEYWORD_MODULES := $(shell grep -- mods-enabled src/tests/keywords/radiusd.conf | sed 's,.*/,,')
+KEYWORD_RADDB := $(addprefix raddb/mods-enabled/,$(KEYWORD_MODULES))
+KEYWORD_LIBS := $(addsuffix .la,$(addprefix rlm_,$(KEYWORD_MODULES))) rlm_example.la rlm_cache.la
+
+#
+# Files in the output dir depend on the unit tests
+#
+# src/tests/keywords/FOO unlang for the test
+# src/tests/keywords/FOO.attrs input RADIUS and output filter
+# build/tests/keywords/FOO updated if the test succeeds
+# build/tests/keywords/FOO.log debug output for the test
+#
+# Auto-depend on modules via $(shell grep INCLUDE $(DIR)/radiusd.conf | grep mods-enabled | sed 's/.*}/raddb/'))
+#
+# If the test fails, then look for ERROR in the input. No error
+# means it's unexpected, so we die.
+#
+# Otherwise, check the log file for a parse error which matches the
+# ERROR line in the input.
+#
+$(BUILD_DIR)/tests/keywords/%: ${DIR}/% $(BUILD_DIR)/tests/keywords/%.attrs $(TESTBINDIR)/unittest | $(BUILD_DIR)/tests/keywords $(KEYWORD_RADDB) $(KEYWORD_LIBS) build.raddb rlm_cache_rbtree.la rlm_test.la rlm_unix.la
+ @echo UNIT-TEST $(notdir $@)
+ @if ! KEYWORD=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/keywords/ -i $@.attrs -f $@.attrs -xx > $@.log 2>&1; then \
+ if ! grep ERROR $< 2>&1 > /dev/null; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo KEYWORD=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/keywords/ -i $@.attrs -f $@.attrs -xx; \
+ exit 1; \
+ fi; \
+ FOUND=$$(grep ^$< $@.log | head -1 | sed 's/:.*//;s/.*\[//;s/\].*//'); \
+ EXPECTED=$$(grep -n ERROR $< | sed 's/:.*//'); \
+ if [ "$$EXPECTED" != "$$FOUND" ]; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo KEYWORD=$(notdir $@) $(TESTBIN)/unittest -D share -d src/tests/keywords/ -i $@.attrs -f $@.attrs -xx; \
+ exit 1; \
+ fi \
+ fi
+ @touch $@
+
+#
+# Get all of the unit test output files
+#
+TESTS.KEYWORDS_FILES := $(addprefix $(BUILD_DIR)/tests/keywords/,$(KEYWORD_FILES))
+
+#
+# Depend on the output files, and create the directory first.
+#
+tests.keywords: $(TESTS.KEYWORDS_FILES)
+
+$(TESTS.KEYWORDS_FILES): $(TESTS.XLAT_FILES) $(TESTS.MAP_FILES)
+
+.PHONY: clean.tests.keywords
+clean.tests.keywords:
+ @rm -rf $(BUILD_DIR)/tests/keywords/
diff --git a/src/tests/keywords/array b/src/tests/keywords/array
new file mode 100644
index 0000000..a901a2b
--- /dev/null
+++ b/src/tests/keywords/array
@@ -0,0 +1,53 @@
+#
+# PRE: if
+#
+# Tests for dereferencing the Nth attribute
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Class := 0x01020304
+ Class += 0x05060708
+ Class += 0x090a0b0c
+}
+
+if (&Class != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 0"
+ }
+}
+
+# Must be the same as above
+if (&Class[0] != 0x01020304) {
+ update reply {
+ Filter-Id += "fail 0a"
+ }
+}
+
+if (&Class[1] != 0x05060708) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if (&Class[2] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+# must not exist
+if (&Class[3]) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+# Last element of the array
+if (&Class[n] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
diff --git a/src/tests/keywords/base64 b/src/tests/keywords/base64
new file mode 100644
index 0000000..9661252
--- /dev/null
+++ b/src/tests/keywords/base64
@@ -0,0 +1,141 @@
+#
+# PRE: hex
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-0 := "%{base64:&Tmp-String-0}"
+ Tmp-String-1 := "%{base64:&Tmp-Octets-0}"
+ Tmp-String-2 := "%{base64:&Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{base64:&Tmp-Date-0}"
+ Tmp-String-4 := "%{base64:&Tmp-Integer-0}"
+ Tmp-String-5 := "%{base64:&Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{base64:&Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{base64:&Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{base64:&Tmp-Cast-IPv6Prefix}"
+ Tmp-String-9 := "%{base64:&Tmp-Cast-Byte}"
+}
+
+# String - bin 0x39383730
+if (Tmp-String-0 != 'OTg3MA==') {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Octets - bin 0x39383731
+if (Tmp-String-1 != 'OTg3MQ==') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# IP Address - bin 0x39383732
+if (Tmp-String-2 != 'OTg3Mg==') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Date - bin 0x39383733
+if (Tmp-String-3 != 'OTg3Mw==') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Integer - bin 0x39383734
+if (Tmp-String-4 != 'OTg3NA==') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Abinary - bin 0x0101000039383735000000002000110000000714000200000000000000000000
+if (Tmp-String-5 != 'AQEAADk4NzUAAAAAIAARAAAABxQAAgAAAAAAAAAAAAA=') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# ifid - bin 0x0000000039383737
+if (Tmp-String-6 != 'AAAAADk4Nzc=') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# ipv6addr - bin 0x00000000000000000000000039383738
+if (Tmp-String-7 != 'AAAAAAAAAAAAAAAAOTg3OA==') {
+ update reply {
+ Filter-ID += 'fail 7'
+ }
+}
+
+# ipv6addrprefix - bin 0x008000000000000000000000000039383739
+if (Tmp-String-8 != 'AIAAAAAAAAAAAAAAAAA5ODc5') {
+ update reply {
+ Filter-ID += 'fail 8'
+ }
+}
+
+# byte - bin 0x3a
+if (Tmp-String-9 != 'Og==') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{base64:&Tmp-Cast-Short}"
+ Tmp-String-1 := "%{base64:&Tmp-Cast-Ethernet}"
+ Tmp-String-2 := "%{base64:&Tmp-Cast-Integer64}"
+ Tmp-String-3 := "%{base64:&Tmp-Cast-IPv4Prefix}"
+}
+
+# short - bin 0x373b
+if (Tmp-String-0 != 'Nzs=') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+# ethernet - bin 0x00003938373c
+if (Tmp-String-1 != 'AAA5ODc8') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# integer64 - bin 0x100000003938373d
+if (Tmp-String-2 != 'EAAAADk4Nz0=') {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+# ipv4prefix - bin 0x00203938373e
+if (Tmp-String-3 != 'ACA5ODc+') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
diff --git a/src/tests/keywords/break-error b/src/tests/keywords/break-error
new file mode 100644
index 0000000..fff20f0
--- /dev/null
+++ b/src/tests/keywords/break-error
@@ -0,0 +1,11 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+if (User-Name == "bob") {
+ break # ERROR
+}
diff --git a/src/tests/keywords/cache b/src/tests/keywords/cache
new file mode 100644
index 0000000..58ce207
--- /dev/null
+++ b/src/tests/keywords/cache
@@ -0,0 +1,229 @@
+#
+# PRE: update if
+#
+update {
+ &control:Cleartext-Password := 'hello'
+ &request:Tmp-String-0 := 'testkey'
+ &reply:Filter-Id := 'filter'
+}
+
+
+#
+# Basic store and retrieve
+#
+update control {
+ &control:Tmp-String-1 := 'cache me'
+}
+
+cache
+if (!updated) {
+ update reply {
+ Filter-Id := 'fail 0'
+ }
+ reject
+}
+
+# Check status-only works correctly (should return ok and consume attribute)
+update control {
+ Cache-Status-Only := 'yes'
+}
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 2a'
+ }
+ reject
+}
+
+if (&control:Cache-Status-Only) {
+ update reply {
+ Filter-Id := 'fail 2b'
+ }
+ reject
+}
+
+# Retrieve the entry (should be copied to request list)
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 3a'
+ }
+ reject
+}
+
+if (&request:Tmp-String-1 != &control:Tmp-String-1) {
+ update reply {
+ Filter-Id := 'fail 3b'
+ }
+}
+
+# Retrieving the entry should not expire it
+update request {
+ Tmp-String-1 !* ANY
+}
+
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 4a'
+ }
+ reject
+}
+
+if (&request:Tmp-String-1 != &control:Tmp-String-1) {
+ update reply {
+ Filter-Id := 'fail 4b'
+ }
+ reject
+}
+
+# Force expiry of the entry
+update control {
+ Cache-TTL := 0
+}
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 5'
+ }
+ reject
+}
+
+# Check status-only works correctly (should return notfound and consume attribute)
+update control {
+ Cache-Status-Only := 'yes'
+}
+cache
+if (!notfound) {
+ update reply {
+ Filter-Id := 'fail 6a'
+ }
+ reject
+}
+
+if (&control:Cache-Status-Only) {
+ update reply {
+ Filter-Id := 'fail 6b'
+ }
+ reject
+}
+
+# Check read-only works correctly (should return notfound and consume attribute)
+update control {
+ Cache-Read-Only := 'yes'
+}
+cache
+if (!notfound) {
+ update reply {
+ Filter-Id := 'fail 7a'
+ }
+ reject
+}
+
+if (&control:Cache-Read-Only) {
+ update reply {
+ Filter-Id := 'fail 7b'
+ }
+ reject
+}
+
+# ...and check the entry wasn't recreated
+update control {
+ Cache-Status-Only := 'yes'
+}
+cache
+if (!notfound) {
+ update reply {
+ Filter-Id := 'fail 7c'
+ }
+ reject
+}
+
+# This should still allow the creation of a new entry
+update control {
+ Cache-TTL := -1
+}
+cache
+if (!updated) {
+ update reply {
+ Filter-Id := 'fail 8a'
+ }
+ reject
+}
+
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 8b'
+ }
+ reject
+}
+
+if (&Cache-TTL) {
+ update reply {
+ Filter-Id := 'fail 8c'
+ }
+ reject
+}
+
+if (&request:Tmp-String-1 != &control:Tmp-String-1) {
+ update reply {
+ Filter-Id := 'fail 8d'
+ }
+ reject
+}
+
+update control {
+ Tmp-String-1 := 'cache me2'
+}
+
+# Updating the Cache-TTL shouldn't make things go boom (we can't really check if it works)
+update control {
+ Cache-TTL := 30
+}
+cache
+if (!ok) {
+ update reply {
+ Filter-Id := 'fail 9a'
+ }
+ reject
+}
+
+# Request Tmp-String-1 shouldn't have been updated yet
+if (&request:Tmp-String-1 == &control:Tmp-String-1) {
+ update reply {
+ Filter-Id := 'fail 9b'
+ }
+ reject
+}
+
+# Check that a new entry is created
+update control {
+ Cache-TTL := -1
+}
+cache
+if (!updated) {
+ update reply {
+ Filter-Id := 'fail 10a'
+ }
+ reject
+}
+
+# Check Cache-Entry-Hits is updated as we expect
+if (&request:Cache-Entry-Hits != 0) {
+ update reply {
+ Filter-Id := 'fail 12a'
+ }
+ reject
+}
+
+cache
+
+if (&request:Cache-Entry-Hits != 1) {
+ update reply {
+ Filter-Id := 'fail 12b'
+ }
+ reject
+}
+
+
diff --git a/src/tests/keywords/case-attr-error b/src/tests/keywords/case-attr-error
new file mode 100644
index 0000000..e9516cc
--- /dev/null
+++ b/src/tests/keywords/case-attr-error
@@ -0,0 +1,20 @@
+# PRE: case-empty
+#
+update reply {
+ Filter-Id := "fail"
+}
+
+switch &reply:Filter-Id {
+ # deliberately empty
+ case "filter" {
+ }
+
+ case &Not-Dynamically-Allocated { # ERROR
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+
+ case {
+ }
+}
diff --git a/src/tests/keywords/case-empty b/src/tests/keywords/case-empty
new file mode 100644
index 0000000..46ea054
--- /dev/null
+++ b/src/tests/keywords/case-empty
@@ -0,0 +1,23 @@
+# PRE: switch
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+switch &reply:Filter-Id {
+ # deliberately empty
+ case "filter" {
+ }
+
+ case "fail" {
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+}
diff --git a/src/tests/keywords/case-empty-string b/src/tests/keywords/case-empty-string
new file mode 100644
index 0000000..4b8e7cd
--- /dev/null
+++ b/src/tests/keywords/case-empty-string
@@ -0,0 +1,25 @@
+# PRE: switch
+#
+update request {
+ Filter-Id := ""
+}
+
+switch &Filter-Id {
+ case "" {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case "doug" {
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+}
diff --git a/src/tests/keywords/case-list b/src/tests/keywords/case-list
new file mode 100644
index 0000000..e4a0290
--- /dev/null
+++ b/src/tests/keywords/case-list
@@ -0,0 +1,19 @@
+switch &User-Name {
+ case "bob" {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case &reply: { # ERROR
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+}
diff --git a/src/tests/keywords/cast-byte b/src/tests/keywords/cast-byte
new file mode 100644
index 0000000..4663d95
--- /dev/null
+++ b/src/tests/keywords/cast-byte
@@ -0,0 +1,25 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:Class := 0xad
+}
+
+if (<byte>Class == 173) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+
+if (<byte>Class < 173) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if (<byte>Class > 173) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
diff --git a/src/tests/keywords/cast-integer b/src/tests/keywords/cast-integer
new file mode 100644
index 0000000..4972ee7
--- /dev/null
+++ b/src/tests/keywords/cast-integer
@@ -0,0 +1,25 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:Class := 0x00000101
+}
+
+if (<integer>Class == 257) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+
+if (<integer>Class < 256) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if (<integer>Class > 257) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
diff --git a/src/tests/keywords/cast-ipaddr b/src/tests/keywords/cast-ipaddr
new file mode 100644
index 0000000..f0dd356
--- /dev/null
+++ b/src/tests/keywords/cast-ipaddr
@@ -0,0 +1,442 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:NAS-IP-Address := 127.0.0.1
+ request:Tmp-Integer-0 := 2130706433
+ reply:Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := "%{request:NAS-IP-Address}"
+}
+
+if (<ipaddr>Tmp-Integer-0 != NAS-IP-Address) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+#
+# Update statements do implicit casts, so we can check
+# cast results are correct, by using the update to perform
+# the cast, and looking at the results.
+#
+update request {
+ Tmp-Cast-Ipaddr := 203.0.113.1
+ Tmp-Cast-IPv4Prefix := 203.0.113.0/24
+ Tmp-Cast-IPv4Prefix += 203.0.113.1/32
+ Tmp-Cast-IPv6Addr := 2001:DB8::1
+ Tmp-Cast-IPv6Addr += ::ffff:203.0.113.1
+ Tmp-Cast-IPv6Prefix := 2001:DB8::/32
+ Tmp-Cast-IPv6Prefix += ::ffff:203.0.113.1/128
+ Tmp-Cast-IPv6Prefix += ::ffff:203.0.113.1/64
+}
+
+#
+# IPv4 address to IPv6 address
+#
+update control {
+ Tmp-Cast-IPv6addr := &Tmp-Cast-IPaddr
+}
+
+if (&control:Tmp-Cast-IPv6addr != ::ffff:203.0.113.1) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+#
+# IPv6 address to IPv4 address
+#
+update control {
+ Tmp-Cast-IPaddr := &control:Tmp-Cast-IPv6addr
+}
+
+if (&control:Tmp-Cast-IPaddr != 203.0.113.1) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+#
+# IPv4 prefix to IPv6 prefix
+#
+update control {
+ Tmp-Cast-IPv6Prefix := &Tmp-Cast-IPv4Prefix
+}
+
+if (&control:Tmp-Cast-IPv6Prefix != ::ffff:203.0.113.0/120) {
+ update reply {
+ Filter-Id += 'Fail 31'
+ }
+}
+
+#
+# IPv6 prefix to IPv4 prefix
+#
+update control {
+ Tmp-Cast-IPv4Prefix := &control:Tmp-Cast-IPv6Prefix
+}
+
+if (&control:Tmp-Cast-IPv4Prefix != 203.0.113.1/24) {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
+
+#
+# IPv4 prefix (32) to IPv6 address
+#
+update control {
+ Tmp-Cast-IPv6Addr := &Tmp-Cast-IPv4Prefix[1]
+}
+
+if (&control:Tmp-Cast-IPv6Addr != ::ffff:203.0.113.1) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+#
+# IPv6 prefix (128) to IPv4 address
+#
+update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv6Prefix[1]
+}
+
+if (&control:Tmp-Cast-Ipaddr != 203.0.113.1/32) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+#
+# IPv4 address to IPv6 prefix (128)
+#
+update control {
+ Tmp-Cast-IPv6Prefix := &Tmp-Cast-Ipaddr
+}
+
+if (&control:Tmp-Cast-IPv6Prefix != ::ffff:203.0.113.1/128) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+#
+# IPv6 address to IPv4 prefix (32)
+#
+update control {
+ Tmp-Cast-IPv4Prefix := &Tmp-Cast-IPv6Addr[1]
+}
+
+if (&control:Tmp-Cast-IPv4Prefix != 203.0.113.1/32) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+#
+# IPv4 address to IPv4 prefix (32)
+#
+update control {
+ Tmp-Cast-IPv4Prefix := &Tmp-Cast-Ipaddr
+}
+
+if (&control:Tmp-Cast-IPv4Prefix != 203.0.113.1/32) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+#
+# IPv6 address to IPv6 prefix (128)
+#
+update control {
+ Tmp-Cast-IPv6Prefix := Tmp-Cast-Ipv6addr
+}
+
+if (&control:Tmp-Cast-IPv6Prefix != 2001:DB8::1/128) {
+ update reply {
+ Filter-Id += 'Fail 11'
+ }
+}
+
+#
+# IPv4 prefix (32) to IPv4 address
+#
+update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv4Prefix[1]
+}
+
+if (&control:Tmp-Cast-Ipaddr != 203.0.113.1) {
+ update reply {
+ Filter-Id += 'Fail 12'
+ }
+}
+
+#
+# IPv6 prefix (128) to IPv6 address
+#
+update control {
+ Tmp-Cast-IPv6Addr := &Tmp-Cast-IPv6Prefix[1]
+}
+
+if (&control:Tmp-Cast-IPv6Addr != ::ffff:203.0.113.1) {
+ update reply {
+ Filter-Id += 'Fail 13'
+ }
+}
+
+#
+# And the invalid cases...
+#
+
+#
+# IPv6 Prefix < 128 to IPv6 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-IPv6Addr := Tmp-Cast-IPv6Prefix
+ }
+ update reply {
+ Filter-Id += 'Fail 14'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipv6addr. Only /128 prefixes may be cast to IP address types') {
+ update reply {
+ Filter-Id += 'Fail 14.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Prefix < 128 to IPv4 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv6Prefix[2]
+ }
+ update reply {
+ Filter-Id += 'Fail 15'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr. Only /128 prefixes may be cast to IP address types') {
+ update reply {
+ Filter-Id += 'Fail 15.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Prefix < 96 to IPv4 prefix (causes part of the IPv4/v6 mapping prefix to be masked off)
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-Ipv4Prefix := &Tmp-Cast-IPv6Prefix[2]
+ }
+ update reply {
+ Filter-Id += 'Fail 16'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipv4prefix. No IPv4-IPv6 mapping prefix') {
+ update reply {
+ Filter-Id += 'Fail 16.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv4 Prefix < 32 to IPv6 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-IPv6Addr := &Tmp-Cast-IPv4Prefix
+ }
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipv6addr. Only /32 prefixes may be cast to IP address types') {
+ update reply {
+ Filter-Id += 'Fail 17.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv4 Prefix < 32 to IPv4 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv4Prefix
+ }
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv4prefix to ipaddr. Only /32 prefixes may be cast to IP address types') {
+ update reply {
+ Filter-Id += 'Fail 17.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Prefix outside mapping range to IPv4 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv6Prefix
+ }
+ update reply {
+ Filter-Id += 'Fail 18'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipaddr. Only /128 prefixes may be cast to IP address types') {
+ update reply {
+ Filter-Id += 'Fail 18.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Prefix outside mapping range to IPv4 prefix
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-IPv4Prefix := &Tmp-Cast-IPv6Prefix
+ }
+ update reply {
+ Filter-Id += 'Fail 19'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6prefix to ipv4prefix. No IPv4-IPv6 mapping prefix') {
+ update reply {
+ Filter-Id += 'Fail 19.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Address outside mapping range to IPv4 address
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-Ipaddr := &Tmp-Cast-IPv6Addr
+ }
+ update reply {
+ Filter-Id += 'Fail 20'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6addr to ipaddr. No IPv4-IPv6 mapping prefix') {
+ update reply {
+ Filter-Id += 'Fail 20'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv6 Address outside mapping range to IPv4 prefix
+#
+redundant {
+ group {
+ update control {
+ Tmp-Cast-IPv4Prefix := &Tmp-Cast-IPv6Addr
+ }
+ update reply {
+ Filter-Id += 'Fail 21'
+ }
+ }
+ group {
+ if ("%{Module-Failure-Message}" != 'Attribute conversion failed: Invalid cast from ipv6addr to ipv4prefix. No IPv4-IPv6 mapping prefix') {
+ update reply {
+ Filter-Id += 'Fail 21.5'
+ }
+ }
+ update request {
+ Module-Failure-Message !* ANY
+ }
+ ok
+ }
+}
+
+#
+# IPv4 address to integer
+#
+update request {
+ Tmp-Integer-0 := &NAS-IP-Address
+}
+
+if (Tmp-Integer-0 != 0x7f000001) {
+ update reply {
+ Filter-Id += 'Fail 22'
+ }
+}
+
+#
+# Check the decimal value just for the heck of it
+#
+if (Tmp-Integer-0 != 2130706433) {
+ update reply {
+ Filter-Id += 'Fail 23'
+ }
+}
diff --git a/src/tests/keywords/cast-short b/src/tests/keywords/cast-short
new file mode 100644
index 0000000..a17b379
--- /dev/null
+++ b/src/tests/keywords/cast-short
@@ -0,0 +1,25 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:Class := 0x0101
+}
+
+if (<short>Class == 257) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+
+if (<short>Class < 256) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
+
+if (<short>Class > 257) {
+ update reply {
+ Filter-Id += "wrong"
+ }
+}
diff --git a/src/tests/keywords/cmp b/src/tests/keywords/cmp
new file mode 100644
index 0000000..4cd59b8
--- /dev/null
+++ b/src/tests/keywords/cmp
@@ -0,0 +1,20 @@
+#
+# PRE: update
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ Called-Station-Id := "This is a test"
+ Calling-Station-Id := "This is a test"
+}
+
+#
+# Check attribute references
+#
+if (Called-Station-Id == &Calling-Station-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/cmp-ipaddr b/src/tests/keywords/cmp-ipaddr
new file mode 100644
index 0000000..bf197af
--- /dev/null
+++ b/src/tests/keywords/cmp-ipaddr
@@ -0,0 +1,20 @@
+#
+# PRE: update
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ NAS-IP-Address := 127.0.0.1
+ Framed-IP-Address := 127.0.0.1
+}
+
+#
+# Check attribute references
+#
+if (NAS-IP-Address == &Framed-IP-Address) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/comments b/src/tests/keywords/comments
new file mode 100644
index 0000000..483bd05
--- /dev/null
+++ b/src/tests/keywords/comments
@@ -0,0 +1,48 @@
+#
+# PRE: update if
+#
+
+# One comment
+#{ Two comment
+#} Three comment
+#'Four'
+#"Five comment"
+##Six Comment#
+ #Seven comment (yes i'm meant to be tabbed in)
+ #Eight comment (yes i'm meant to have spaces before me)
+ #Nine comment (tabs and spaces, are you crazy?!)
+
+update { #}'{ Opening block with extra special chars {} '"
+ control:Cleartext-Password := 'hello' # This should update the password so the test passes
+ reply:Filter-Id := 'filter'# Eek! Too close
+} #{'} Closing block with extra special chars {} '"
+
+update { request:Tmp-String-0 := 'candy' } # Comment after unicorn block
+
+update request {
+ request:Reply-Message += 'I am #literally a comment #'
+ request:Reply-Message += "I am #literally a comment #"
+}
+
+if (&request:Tmp-String-0 != 'candy') {
+ update reply {
+ reply:Filter-Id += 'fail 0'
+ }
+}
+
+if (&request:Reply-Message[0] != 'I am #literally a comment #') {
+ update reply {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if (&request:Reply-Message[1] != "I am #literally a comment #") {
+ update reply {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+ok # I'm a comment after a module call
+ok # I'm a comment # after a module {} call
+
+ok, ok, ok, ok, ok
diff --git a/src/tests/keywords/count-error b/src/tests/keywords/count-error
new file mode 100644
index 0000000..f0723cb
--- /dev/null
+++ b/src/tests/keywords/count-error
@@ -0,0 +1,11 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := &reply:Filter-Id[#] # ERROR
+}
diff --git a/src/tests/keywords/crypt b/src/tests/keywords/crypt
new file mode 100644
index 0000000..e6d63aa
--- /dev/null
+++ b/src/tests/keywords/crypt
@@ -0,0 +1,151 @@
+#
+# PRE: update if
+#
+
+# Skip all these tests if crypt_r was not available
+#
+if ("%{crypt:&User-Password}") {
+ noop
+}
+if ("%{request:Module-Failure-Message[0]}" !~ /^Crypt not available at compile time/) {
+
+
+# Set required attributes
+#
+update reply {
+ &Filter-Id := "filter"
+}
+
+update request {
+ &Tmp-String-0 := 'foo'
+ &Tmp-String-1 := 'foo:bar'
+ &Tmp-String-2 := 'f:'
+ &Tmp-String-3 := &User-Password
+ &Tmp-String-4 := &control:Cleartext-Password
+ &Tmp-String-5 := 'fwtLWDtMiSbH8lmXCMIVfrSMJjF'
+ &Tmp-String-8 := 'aa'
+ &Tmp-String-9 := '$1$abcdefgh'
+}
+
+
+# Check for error on no salt
+#
+if ("%{crypt:&User-Password}") {
+ update reply {
+ &Filter-Id += 'fail 1a'
+ }
+}
+
+if ("%{request:Module-Failure-Message[0]}" != 'No salt specified in crypt xlat') {
+ update reply {
+ &Filter-Id += 'fail 1b'
+ }
+}
+
+
+# Check DES - all crypt_r() implementations should do this.
+#
+if ("%{crypt:aa:foo}" != "aaKNIEDOaueR6") {
+ update reply {
+ &Filter-Id += 'fail 2a'
+ }
+}
+
+if ("%{crypt:&Tmp-String-8:foo}" != "aaKNIEDOaueR6") {
+ update reply {
+ &Filter-Id += 'fail 2b'
+ }
+}
+
+if ("%{crypt:aa:&User-Password}" != "aaPwJ9XL9Y99E") {
+ update reply {
+ &Filter-Id += 'fail 2c'
+ }
+}
+
+
+# Test we can encrypt and then authenticate
+#
+update {
+ &request:User-Password := &request:Tmp-String-5
+ &control:Crypt-Password := "%{crypt:AZ:&Tmp-String-5}"
+ &control:Cleartext-Password !* ""
+}
+
+group {
+ pap.authenticate {
+ fail = 1
+ reject = 1
+ }
+
+ if (!ok) {
+ update reply {
+ &Filter-Id += 'fail 3'
+ }
+ }
+}
+
+update {
+ &request:User-Password := &Tmp-String-3
+ &control:Cleartext-Password := &Tmp-String-4
+}
+
+
+# Clear Module-Failure-Message so below tests work no matter what
+# happened above
+#
+update request {
+ &Module-Failure-Message !* ""
+}
+
+
+# Check colons in password
+#
+if ("%{crypt:aa:foo:bar}" != "aadzEnaZwH90k") {
+ update reply {
+ &Filter-Id += 'fail 4a'
+ }
+}
+
+if ("%{crypt:aa:&Tmp-String-1}" != "aadzEnaZwH90k") {
+ update reply {
+ &Filter-Id += 'fail 4b'
+ }
+}
+
+
+# Check invalid chars in salt
+#
+# In this case, depending on the library implementation, crypt
+# seems to either return an empty string (null) and set an error,
+# or it will return an invalid hash beginning with '*'.
+#
+update request {
+ &Tmp-String-7 := "%{crypt:&Tmp-String-2:foo}"
+}
+
+if (&Tmp-String-7 !~ /^\*/ && \
+ "%{request:Module-Failure-Message[0]}" !~ /Crypt salt has the wrong format/) {
+ update reply {
+ &Filter-Id += 'fail 5a'
+ }
+}
+
+
+# Convert the Cleartext-Password to Password-With-Header and auth with that
+#
+update control {
+ &Password-With-Header := "{crypt}%{crypt:$1$abcdefgh:&Tmp-String-4}"
+ &Crypt-Password !* ""
+ &Cleartext-Password !* ""
+}
+
+
+# Crypt not available at compile time? Force the test to pass.
+#
+}
+else {
+ update reply {
+ &Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/default-input.attrs b/src/tests/keywords/default-input.attrs
new file mode 100644
index 0000000..93566a6
--- /dev/null
+++ b/src/tests/keywords/default-input.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Filter-Id == 'filter'
diff --git a/src/tests/keywords/else-error b/src/tests/keywords/else-error
new file mode 100644
index 0000000..3816270
--- /dev/null
+++ b/src/tests/keywords/else-error
@@ -0,0 +1,14 @@
+#
+# PRE: update if
+#
+# "else" has to be preceded by an "if" or "elsif"
+#
+if (1) {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ else { # ERROR
+ ok
+ }
+}
diff --git a/src/tests/keywords/escape b/src/tests/keywords/escape
new file mode 100644
index 0000000..5d0b3bc
--- /dev/null
+++ b/src/tests/keywords/escape
@@ -0,0 +1,67 @@
+#
+# PRE: update if xlat-attr-index
+#
+update request {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+
+ Tmp-String-0 := '@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /'
+ Tmp-String-1 := '±§#$%^&+={[}];<,>?`|"'
+ Tmp-String-2 := '™¥¤'
+ Tmp-String-3 := '=C2=B1=C2=A7=23=24=25=5E=26=2B=3D=7B=5B=7D=5D=3B=3C=2C=3E=3F=60=7C=22'
+ Tmp-String-4 := '=E2=84=A2=C2=A5=C2=A4'
+ Tmp-String-5 := '=40=61=62=63=64=65=66=67'
+
+ # Mixture of safe and unsafe chars
+ Tmp-String-6 := 'ŒČÿ'
+ Tmp-String-7 := 'Œ=C4=8Cÿ'
+}
+
+if (<string>"%{escape:%{request:Tmp-String-0}}" != &Tmp-String-0) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+if (<string>"%{escape:%{request:Tmp-String-1}}" != &Tmp-String-3) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+if (<string>"%{escape:%{request:Tmp-String-2}}" != &Tmp-String-4) {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if (<string>"%{unescape:%{request:Tmp-String-0}}" != &Tmp-String-0) {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
+
+if (<string>"%{unescape:%{request:Tmp-String-3}}" != "%{Tmp-String-1}") {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+if (<string>"%{unescape:%{request:Tmp-String-4}}" != &Tmp-String-2) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+if (<string>"%{escape:%{request:Tmp-String-6}}" != &Tmp-String-7) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+if (<string>"%{unescape:%{request:Tmp-String-7}}" != &Tmp-String-6) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
diff --git a/src/tests/keywords/escape-sequences b/src/tests/keywords/escape-sequences
new file mode 100644
index 0000000..967656d
--- /dev/null
+++ b/src/tests/keywords/escape-sequences
@@ -0,0 +1,95 @@
+#
+# PRE: update if xlat-attr-index
+#
+update request {
+ control:Cleartext-Password := 'hello'
+ Tmp-Octets-0 := 0x69206861766520736361727920656d626564646564207468696e67730020696e73696465206d65
+ Tmp-Octets-1 := 0x30783031013078303707307830410A307830440D222230786230b0C2b0
+ Tmp-String-0 := "i have scary embedded things\000 inside me"
+ Tmp-String-0 += "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°"
+
+ # and again with single quoted strings.
+ # unlike other languages, \r, \t, and \n have meaning inside of 'string'
+ Tmp-String-1 := 'i have scary embedded things\000 inside me'
+ Tmp-String-1 += '0x01\0010x07\0070x0A\n0x0D\r""0xb0\260°'
+
+ Tmp-String-2 := 'i have scary embedded things\000 inside me'
+ Tmp-String-2 += "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°"
+
+ reply:Filter-Id := "filter"
+}
+
+
+if ("%{length:&Tmp-String-0}" != 39) {
+ update reply {
+ Filter-Id += 'fail l-0'
+ }
+}
+
+if ("%{length:&Tmp-String-1}" != 42) {
+ update reply {
+ Filter-Id += 'fail l-1'
+ }
+}
+
+if ("%{string:Tmp-Octets-0}" != "i have scary embedded things\000 inside me") {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if (&Tmp-String-0 != "i have scary embedded things\000 inside me") {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{string:Tmp-Octets-1}" != "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{Tmp-String-0[0]}" != "i have scary embedded things\000 inside me") {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+if ("%{Tmp-String-0[1]}" != "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# And another slightly different codepath...
+if ("%{Tmp-String-0[*]}" != "i have scary embedded things\000 inside me,0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+if (&Tmp-String-0[0] != &Tmp-String-0[0]) {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+#
+# This seems weird... double escapes for most things, but single escapes
+# for the quotation marks.
+#
+if ("%{Tmp-String-2[1]}" != "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°") {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+#
+# And again as an attribute reference
+#
+if (&Tmp-String-2[1] != "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°") {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
diff --git a/src/tests/keywords/expand b/src/tests/keywords/expand
new file mode 100644
index 0000000..ada0ee9
--- /dev/null
+++ b/src/tests/keywords/expand
@@ -0,0 +1,39 @@
+#
+# PRE: update switch
+#
+
+#
+# This is a virtual attribute.
+# It is NOT optimized to
+#
+# switch &Request-Processing-Stage
+#
+# because it doesn't really exist.
+# The xlat expansion code will take care of
+# returning the string value of the "attribute"
+#
+switch "%{Request-Processing-Stage}" {
+ case authorize {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case authenticate {
+ update reply {
+ Filter-Id := "authenticate"
+ }
+ }
+
+ case bob {
+ update reply {
+ Filter-Id := "bob"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+}
diff --git a/src/tests/keywords/expr b/src/tests/keywords/expr
new file mode 100644
index 0000000..7645931
--- /dev/null
+++ b/src/tests/keywords/expr
@@ -0,0 +1,108 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+#
+# Simple
+#
+if ("%{expr: 1 + 2 + 3 + 4}" != 10) {
+ update reply {
+ Filter-Id := "fail-1"
+ }
+}
+
+#
+# Precedence
+#
+if ("%{expr: 1 + 2 * 3 + 4}" != 11) {
+ update reply {
+ Filter-Id := "fail-2"
+ }
+}
+
+#
+# attribute references
+#
+update request {
+ Tmp-Integer-0 = 1
+ Tmp-Integer-1 = 3
+ Tmp-Integer-2 = 4
+ Tmp-Date-0 = "%l"
+}
+
+if ("%{expr: 1 + 2 * &Tmp-Integer-1 + 4}" != 11) {
+ update reply {
+ Filter-Id := "fail-3"
+ }
+}
+
+if ("%{expr: 1 + 2 * (&Tmp-Integer-1 + 4)}" != 15) {
+ update reply {
+ Filter-Id := "fail-4"
+ }
+}
+
+if ("%{expr: 1 + 2 * (&Tmp-Integer-1 + &Tmp-Integer-2)}" != 15) {
+ update reply {
+ Filter-Id := "fail-5"
+ }
+}
+
+if ("%{expr: 1 & ~1}" != 0) {
+ update reply {
+ Filter-Id := "fail-6"
+ }
+}
+
+if ("%{expr: 1 & ~2}" != 1) {
+ update reply {
+ Filter-Id := "fail-7"
+ }
+}
+
+if ("%{expr: -1 * 2}" != -2) {
+ update reply {
+ Filter-Id := "fail-8"
+ }
+}
+
+if ("%{expr: 2 - -1}" != 3) {
+ update reply {
+ Filter-Id := "fail-9"
+ }
+}
+
+if ("%{expr: 1 << 2 | 1}" != 5) {
+ update reply {
+ Filter-Id := "fail-10"
+ }
+}
+
+if ("%{expr: &Tmp-Date-0}" <= 0) {
+ update reply {
+ Filter-Id := "fail-11"
+ }
+}
+
+#
+# Unary negation
+#
+if ("%{expr: 6 + -(1 + 3)}" != 2) {
+ update reply {
+ Filter-Id := "fail-12"
+ }
+}
+
+if ("%{expr: 6 * -&Tmp-Integer-2}" != -24) {
+ update reply {
+ Filter-Id := "fail-13"
+ }
+}
+
diff --git a/src/tests/keywords/foreach b/src/tests/keywords/foreach
new file mode 100644
index 0000000..9a4c266
--- /dev/null
+++ b/src/tests/keywords/foreach
@@ -0,0 +1,5 @@
+foreach Filter-Id {
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0}"
+ }
+}
diff --git a/src/tests/keywords/foreach-break b/src/tests/keywords/foreach-break
new file mode 100644
index 0000000..67812fe
--- /dev/null
+++ b/src/tests/keywords/foreach-break
@@ -0,0 +1,73 @@
+# PRE: foreach
+#
+
+#
+# We DON'T want to see this one.
+#
+update request {
+ Filter-Id += "broken"
+}
+
+foreach Filter-Id {
+ #
+ # If we see this one, "break" out of the
+ # foreach loop.
+ #
+ if ("%{Foreach-Variable-0}" == "broken") {
+ break
+ }
+
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0}"
+ }
+}
+
+
+#
+# Adding attribute during request and immediately breaking
+#
+update {
+ request:Filter-Id += "1"
+ request:Filter-Id += "2"
+}
+
+foreach &request:Reply-Message {
+ if("%{Foreach-Variable-0}" == "1") {
+ update {
+ request:Filter-Id += "3"
+ }
+ break
+
+ update reply {
+ Filter-Id := "fail-break-1"
+ }
+ }
+}
+
+update {
+ request:Filter-Id !* ANY
+}
+
+#
+# Adding attribute during request and continuing
+#
+update {
+ request:Filter-Id += "1"
+ request:Filter-Id += "2"
+}
+
+foreach &request:Reply-Message {
+ if("%{Foreach-Variable-0}" == "1") {
+ update {
+ request:Filter-Id += "3"
+ }
+ }
+
+ if ("%{Foreach-Variable-0}" == "3") {
+ break
+
+ update reply {
+ Filter-Id := "fail-break-2"
+ }
+ }
+}
diff --git a/src/tests/keywords/foreach-break-2 b/src/tests/keywords/foreach-break-2
new file mode 100644
index 0000000..b1f6040
--- /dev/null
+++ b/src/tests/keywords/foreach-break-2
@@ -0,0 +1,46 @@
+#
+# PRE: foreach foreach-break
+#
+
+update request {
+ Calling-Station-Id := "ABCDEF_8"
+}
+
+update control {
+ &Tmp-String-0 := "0"
+ &Tmp-String-0 += "1"
+ &Tmp-String-0 += "2"
+ &Tmp-String-0 += "3"
+ &Tmp-String-0 += "4"
+ &Tmp-String-0 += "5"
+ &Tmp-String-0 += "6"
+ &Tmp-String-0 += "7"
+ &Tmp-String-0 += "8"
+ &Tmp-String-0 += "9"
+ &Tmp-String-0 += "a"
+ &Tmp-String-0 += "b"
+ &Tmp-String-0 += "c"
+ &Tmp-String-0 += "d"
+ &Tmp-String-0 += "e"
+ &Tmp-String-0 += "f"
+ &Tmp-String-0 += "g"
+}
+
+foreach control:Tmp-String-0 {
+ if ("%{Calling-Station-Id[*]}" =~ /([A-Z0-9\-]*)_%{Foreach-Variable-0}/) {
+ update request {
+ Called-Station-Id := "%{1}"
+ }
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ break
+ }
+ elsif ("%{Foreach-Variable-0}" == '9') {
+ update reply {
+ Filter-Id := "fail-9"
+ }
+ reject
+ }
+}
diff --git a/src/tests/keywords/foreach-break-3 b/src/tests/keywords/foreach-break-3
new file mode 100644
index 0000000..af03da6
--- /dev/null
+++ b/src/tests/keywords/foreach-break-3
@@ -0,0 +1,44 @@
+#
+# PRE: foreach foreach-break
+#
+
+update request {
+ Calling-Station-Id := "8"
+}
+
+update control {
+ &Calling-Station-Id := "0"
+ &Calling-Station-Id += "1"
+ &Calling-Station-Id += "2"
+ &Calling-Station-Id += "3"
+ &Calling-Station-Id += "4"
+ &Calling-Station-Id += "5"
+ &Calling-Station-Id += "6"
+ &Calling-Station-Id += "7"
+ &Calling-Station-Id += "8"
+ &Calling-Station-Id += "9"
+ &Calling-Station-Id += "a"
+ &Calling-Station-Id += "b"
+ &Calling-Station-Id += "c"
+ &Calling-Station-Id += "d"
+ &Calling-Station-Id += "e"
+ &Calling-Station-Id += "f"
+ &Calling-Station-Id += "g"
+}
+
+foreach &control:Calling-Station-Id {
+ if (&request:Calling-Station-Id == "%{Foreach-Variable-0}") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ break
+ }
+ elsif ("%{Foreach-Variable-0}" == '9') {
+ update reply {
+ Filter-Id := "fail-9"
+ }
+
+ reject
+ }
+}
diff --git a/src/tests/keywords/foreach-break-4 b/src/tests/keywords/foreach-break-4
new file mode 100644
index 0000000..037af8e
--- /dev/null
+++ b/src/tests/keywords/foreach-break-4
@@ -0,0 +1,44 @@
+#
+# PRE: foreach foreach-break-3
+#
+
+update request {
+ Calling-Station-Id := "8"
+}
+
+update control {
+ &Calling-Station-Id := "0"
+ &Calling-Station-Id += "1"
+ &Calling-Station-Id += "2"
+ &Calling-Station-Id += "3"
+ &Calling-Station-Id += "4"
+ &Calling-Station-Id += "5"
+ &Calling-Station-Id += "6"
+ &Calling-Station-Id += "7"
+ &Calling-Station-Id += "8"
+ &Calling-Station-Id += "9"
+ &Calling-Station-Id += "a"
+ &Calling-Station-Id += "b"
+ &Calling-Station-Id += "c"
+ &Calling-Station-Id += "d"
+ &Calling-Station-Id += "e"
+ &Calling-Station-Id += "f"
+ &Calling-Station-Id += "g"
+}
+
+foreach &control:Calling-Station-Id {
+ if (&request:Calling-Station-Id == "%{Foreach-Variable-0}") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ break
+ }
+ elsif ("%{Foreach-Variable-0}" == '9') {
+ update reply {
+ Filter-Id := "fail-9"
+ }
+
+ reject
+ }
+}
diff --git a/src/tests/keywords/foreach-break.attrs b/src/tests/keywords/foreach-break.attrs
new file mode 100644
index 0000000..26c2876
--- /dev/null
+++ b/src/tests/keywords/foreach-break.attrs
@@ -0,0 +1,18 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Filter-Id = "1"
+Filter-Id += "2"
+Filter-Id += "3"
+Filter-Id += "4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == "1"
+Called-Station-Id == "2"
+Called-Station-Id == "3"
+Called-Station-Id == "4"
diff --git a/src/tests/keywords/foreach-error b/src/tests/keywords/foreach-error
new file mode 100644
index 0000000..fb4a236
--- /dev/null
+++ b/src/tests/keywords/foreach-error
@@ -0,0 +1,5 @@
+foreach "%{expr:1 + 2}" { # ERROR
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0}"
+ }
+}
diff --git a/src/tests/keywords/foreach-isolation b/src/tests/keywords/foreach-isolation
new file mode 100644
index 0000000..b77806d
--- /dev/null
+++ b/src/tests/keywords/foreach-isolation
@@ -0,0 +1,38 @@
+#
+# PRE: foreach if-multivalue
+#
+
+update {
+ &reply:Filter-Id := 'filter'
+ &control:Tmp-String-0 := '0'
+ &control:Tmp-String-0 += '1'
+ &control:Tmp-String-0 += '2'
+ &control:Tmp-String-0 += '3'
+}
+
+foreach control:Tmp-String-0 {
+ update control {
+ Tmp-String-0 -= "%{expr:%{Foreach-Variable-0} + 1}"
+ }
+ update request {
+ Tmp-String-0 += "%{Foreach-Variable-0}"
+ }
+}
+
+if (!&Tmp-String-0[0] || !&Tmp-String-0[1] || !&Tmp-String-0[2] || !&Tmp-String-0[3]) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if ((&Tmp-String-0[0] != '0') || (&Tmp-String-0[1] != '1') || (&Tmp-String-0[2] != '2') || (&Tmp-String-0[3] != '3')) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+if (!&control:Tmp-String-0[0] || &control:Tmp-String-0[1] || &control:Tmp-String-0[2] || &control:Tmp-String-0[3]) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
diff --git a/src/tests/keywords/foreach-list b/src/tests/keywords/foreach-list
new file mode 100644
index 0000000..4780e4f
--- /dev/null
+++ b/src/tests/keywords/foreach-list
@@ -0,0 +1,5 @@
+foreach &request: {
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0}"
+ }
+}
diff --git a/src/tests/keywords/foreach-list.attrs b/src/tests/keywords/foreach-list.attrs
new file mode 100644
index 0000000..aedd599
--- /dev/null
+++ b/src/tests/keywords/foreach-list.attrs
@@ -0,0 +1,21 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Filter-Id = "1"
+Filter-Id += "2"
+Filter-Id += "3"
+Filter-Id += "4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == 'bob'
+Called-Station-Id == 'hello'
+Called-Station-Id == '1'
+Called-Station-Id == '2'
+Called-Station-Id == '3'
+Called-Station-Id == '4'
+
diff --git a/src/tests/keywords/foreach-nested b/src/tests/keywords/foreach-nested
new file mode 100644
index 0000000..b6109a3
--- /dev/null
+++ b/src/tests/keywords/foreach-nested
@@ -0,0 +1,9 @@
+# PRE: foreach
+#
+foreach Filter-Id {
+ foreach Calling-Station-Id {
+ update reply {
+ Called-Station-Id += "%{Foreach-Variable-0} %{Foreach-Variable-1}"
+ }
+ }
+}
diff --git a/src/tests/keywords/foreach-nested.attrs b/src/tests/keywords/foreach-nested.attrs
new file mode 100644
index 0000000..52d1f81
--- /dev/null
+++ b/src/tests/keywords/foreach-nested.attrs
@@ -0,0 +1,25 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Filter-Id = "1"
+Filter-Id += "2"
+Filter-Id += "3"
+Filter-Id += "4"
+Calling-Station-Id = "foo\n"
+Calling-Station-Id += "bar"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == '1 foo\n'
+Called-Station-Id == '1 bar'
+Called-Station-Id == '2 foo\n'
+Called-Station-Id == '2 bar'
+Called-Station-Id == '3 foo\n'
+Called-Station-Id == '3 bar'
+Called-Station-Id == '4 foo\n'
+Called-Station-Id == '4 bar'
+
diff --git a/src/tests/keywords/foreach-regex b/src/tests/keywords/foreach-regex
new file mode 100644
index 0000000..dab57a3
--- /dev/null
+++ b/src/tests/keywords/foreach-regex
@@ -0,0 +1,26 @@
+# PRE: foreach if-regex-match
+
+# This is what most people end up using foreach for,
+# so we should probably test it works.
+update request {
+ Tmp-String-0 := "cisco"
+}
+
+# Expanded regex
+foreach Cisco-AVPair {
+ if ("%{Foreach-Variable-0}" =~ /^%{Tmp-String-0}=(.*)$/i) {
+ update reply {
+ Called-Station-Id += "%{1}"
+ }
+ }
+}
+
+# Compiled regex
+foreach Cisco-AVPair {
+ if ("%{Foreach-Variable-0}" =~ /^stupid=(.*)$/i) {
+ update reply {
+ Called-Station-Id += "%{1}"
+ }
+ }
+}
+
diff --git a/src/tests/keywords/foreach-regex.attrs b/src/tests/keywords/foreach-regex.attrs
new file mode 100644
index 0000000..79996c7
--- /dev/null
+++ b/src/tests/keywords/foreach-regex.attrs
@@ -0,0 +1,16 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Cisco-AVPair = "stupid=1"
+Cisco-AVPair += "retarded=2"
+Cisco-AVPair += "cisco=3"
+Cisco-AVPair += "shit=4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == "3"
+Called-Station-Id == "1"
diff --git a/src/tests/keywords/foreach-return b/src/tests/keywords/foreach-return
new file mode 100644
index 0000000..05409c9
--- /dev/null
+++ b/src/tests/keywords/foreach-return
@@ -0,0 +1,52 @@
+# PRE: foreach foreach-break
+#
+
+update control {
+ Cleartext-Password := 'hello'
+}
+
+#
+# Adding attribute during request and immediately returning should still work
+#
+update request {
+ Filter-Id := "1"
+ Filter-Id += "2"
+ Filter-Id += "3"
+ Filter-Id += "4"
+ Filter-Id += "5"
+}
+
+foreach &Filter-Id {
+ if ("%{Foreach-Variable-0}" == "3") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ #
+ # We need this because the "return" below
+ # will prevent the "pap" module from being run
+ # in the "authorize" section.
+ #
+ update control {
+ Auth-Type := PAP
+ }
+
+ #
+ # Stop processing "authorize", and go to the next section.
+ #
+ return
+
+ #
+ # Shouldn't reach this
+ #
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+
+ if ("%{Foreach-Variable-0}" == "4") {
+ update reply {
+ Filter-Id := "fail-4"
+ }
+ }
+}
diff --git a/src/tests/keywords/foreach-varied-depth b/src/tests/keywords/foreach-varied-depth
new file mode 100644
index 0000000..3c3918d
--- /dev/null
+++ b/src/tests/keywords/foreach-varied-depth
@@ -0,0 +1,43 @@
+update {
+ control:Tmp-String-0 := "ssid=ABCDEF"
+ control:Tmp-String-0 += "ssid=GHIJKL"
+ reply:Filter-Id := "filter"
+}
+
+if (User-Name) {
+ foreach &control:Tmp-String-0 {
+ if ("%{Foreach-Variable-0}" =~ /(.*)/) {
+ update control {
+ Tmp-String-1 := "%{1}"
+ }
+ }
+ }
+}
+
+if (&control:Tmp-String-1 != 'ssid=GHIJKL') {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+update control {
+ Tmp-String-1 !* ANY
+}
+
+foreach &control:Tmp-String-0 {
+ if ("%{Foreach-Variable-0}" =~ /(.*)/) {
+ update control {
+ Tmp-String-1 := "%{1}"
+ }
+ }
+}
+
+if (&control:Tmp-String-1 != 'ssid=GHIJKL') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+update control {
+ Tmp-String-1 !* ANY
+}
diff --git a/src/tests/keywords/foreach.attrs b/src/tests/keywords/foreach.attrs
new file mode 100644
index 0000000..26c2876
--- /dev/null
+++ b/src/tests/keywords/foreach.attrs
@@ -0,0 +1,18 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+Filter-Id = "1"
+Filter-Id += "2"
+Filter-Id += "3"
+Filter-Id += "4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Called-Station-Id == "1"
+Called-Station-Id == "2"
+Called-Station-Id == "3"
+Called-Station-Id == "4"
diff --git a/src/tests/keywords/hex b/src/tests/keywords/hex
new file mode 100644
index 0000000..b55bab2
--- /dev/null
+++ b/src/tests/keywords/hex
@@ -0,0 +1,141 @@
+#
+# PRE: update
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-0 := "%{hex:Tmp-String-0}"
+ Tmp-String-1 := "%{hex:Tmp-Octets-0}"
+ Tmp-String-2 := "%{hex:Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{hex:Tmp-Date-0}"
+ Tmp-String-4 := "%{hex:Tmp-Integer-0}"
+ Tmp-String-5 := "%{hex:Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{hex:Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{hex:Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{hex:Tmp-Cast-IPv6Prefix}"
+ Tmp-String-9 := "%{hex:Tmp-Cast-Byte}"
+}
+
+# String
+if (Tmp-String-0 != '39383730') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Octets
+if (Tmp-String-1 != '39383731') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# IP Address
+if (Tmp-String-2 != '39383732') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Date
+if (Tmp-String-3 != '39383733') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Integer
+if (Tmp-String-4 != '39383734') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Abinary
+if (Tmp-String-5 != '0101000039383735000000002000110000000714000200000000000000000000') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# ifid
+if (Tmp-String-6 != '0000000039383737') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+# ipv6addr
+if (Tmp-String-7 != '00000000000000000000000039383738') {
+ update reply {
+ Filter-ID += 'fail 8'
+ }
+}
+
+# ipv6addrprefix
+if (Tmp-String-8 != '008000000000000000000000000039383739') {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+# byte
+if (Tmp-String-9 != '3a') {
+ update reply {
+ Filter-ID += "fail 10 - expected 3a got %{Tmp-String-9}"
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{hex:Tmp-Cast-Short}"
+ Tmp-String-1 := "%{hex:Tmp-Cast-Ethernet}"
+ Tmp-String-2 := "%{hex:Tmp-Cast-Integer64}"
+ Tmp-String-3 := "%{hex:Tmp-Cast-IPv4Prefix}"
+}
+
+# short
+if (Tmp-String-0 != '373b') {
+ update reply {
+ Filter-ID += 'fail 11'
+ }
+}
+
+# ethernet
+if (Tmp-String-1 != '00003938373c') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# integer64
+if (Tmp-String-2 != '100000003938373d') {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+# ipv4prefix
+if (Tmp-String-3 != '00203938373e') {
+ update reply {
+ Filter-Id += 'fail 14 expected 00203938373e got %{Tmp-String-3}'
+ }
+}
diff --git a/src/tests/keywords/if b/src/tests/keywords/if
new file mode 100644
index 0000000..a146029
--- /dev/null
+++ b/src/tests/keywords/if
@@ -0,0 +1,10 @@
+#
+# PRE: update
+#
+# Static if condition
+#
+if (1) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/if-bob b/src/tests/keywords/if-bob
new file mode 100644
index 0000000..4e8ae3c
--- /dev/null
+++ b/src/tests/keywords/if-bob
@@ -0,0 +1,15 @@
+# PRE: if
+#
+# Matching "if" conditions
+#
+if (User-Name == "bob") {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+
+if (User-Name != "bob") {
+ update reply {
+ Filter-Id := "not bob"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/if-else b/src/tests/keywords/if-else
new file mode 100644
index 0000000..788d606
--- /dev/null
+++ b/src/tests/keywords/if-else
@@ -0,0 +1,15 @@
+#
+# PRE: if
+#
+# Matching "if" conditions
+#
+if (User-Name != "bob") {
+ update reply {
+ Filter-Id := "not bob"
+ }
+}
+else {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/if-elsif b/src/tests/keywords/if-elsif
new file mode 100644
index 0000000..c0a41ed
--- /dev/null
+++ b/src/tests/keywords/if-elsif
@@ -0,0 +1,19 @@
+# PRE: if if-else
+#
+# Matching "if" conditions
+#
+if (User-Name != "bob") {
+ update reply {
+ Filter-Id := "not bob"
+ }
+}
+elsif (User-Name == "bob") {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+else {
+ update reply {
+ Filter-Id := "last else"
+ }
+}
diff --git a/src/tests/keywords/if-multivalue b/src/tests/keywords/if-multivalue
new file mode 100644
index 0000000..f12d6fe
--- /dev/null
+++ b/src/tests/keywords/if-multivalue
@@ -0,0 +1,173 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-String-0 := 'foo'
+ Tmp-String-0 += 'bar'
+ Tmp-String-0 += 'baz'
+
+ Tmp-String-1 := 'GROUP ADMINISTRATORS'
+ Tmp-String-1 += 'GROUP STUDENTS'
+ Tmp-String-1 += 'GROUP PEONS'
+
+ Tmp-String-2 := 'PEONS'
+ Tmp-String-2 += 'STUDENTS'
+ Tmp-String-2 += 'ADMINISTRATORS'
+
+ Tmp-String-3 := 'no'
+ Tmp-String-3 += 'no'
+ Tmp-String-3 += 'yes'
+
+ Tmp-Integer-0 := 1
+ Tmp-Integer-0 += 2
+ Tmp-Integer-0 += 5
+}
+
+update control {
+ Tmp-String-0 := 'foo'
+ Tmp-String-0 += 'bar'
+ Tmp-String-0 += 'baz'
+
+ Tmp-String-1 := 'boink'
+ Tmp-String-1 += 'tard'
+ Tmp-String-1 += 'dink'
+ Tmp-String-1 += 'slink'
+
+ Tmp-Integer-0 := 01
+ Tmp-Integer-0 += 02
+ Tmp-Integer-0 += 05
+ Tmp-Integer-0 += 04
+
+ Tmp-Integer-1 := 10
+ Tmp-Integer-1 += 20
+ Tmp-Integer-1 += 30
+}
+
+#
+# Mmmm O(N^2)
+#
+if (&request:Tmp-String-0[*] != &control:Tmp-String-0[*]) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+if (&request:Tmp-String-0[*] == &control:Tmp-String-1[*]) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if (&request:Tmp-String-1[*] == &control:Tmp-String-0[*]) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+#
+# Integer comparison and normalisation
+#
+if (&request:Tmp-Integer-0 != &control:Tmp-Integer-0) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+#
+# if any value of request:Tmp-Integer-0 > any value of
+# request:Tmp-Integer-1 then evaluate to true
+#
+if (&request:Tmp-Integer-0[*] > &control:Tmp-Integer-1[*]) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+#
+# Compiled regex comparisons
+#
+if (&request:Tmp-String-1[*] !~ /PEONS$/) {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+if (&control:Tmp-String-1 =~ /PEONS$/) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+if (&control:Tmp-String-1 =~ /DINKS$/) {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+#
+# Dynamic regex comparisons
+#
+if (&request:Tmp-String-1[*] !~ /%{Tmp-String-2[0]}$/) {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+if (&request:Tmp-String-1 =~ /%{Tmp-String-2[1]}$/) {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
+
+if (&request:Tmp-String-1 !~ /%{Tmp-String-2[2]}$/) {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+if (&request:Tmp-String-1 =~ /%{Tmp-String-2[#]}$/) {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+#
+# XLAT virtual comparisons
+#
+if (&control:Tmp-Integer-0[*] != "%{control:Tmp-Integer-0[#]}") {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+#
+# Literal comparisons
+#
+if (&control:Tmp-String-1[*] != 'boink') {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+if (&control:Tmp-String-1[*] == 'foo') {
+ update reply {
+ Filter-Id += 'fail 14'
+ }
+}
+
+if (&request:Tmp-Integer-0[*] > 10) {
+ update reply {
+ Filter-Id += 'fail 15'
+ }
+}
+
+if (!(&request:Tmp-Integer-0[*] < 10)) {
+ update reply {
+ Filter-Id += 'fail 16'
+ }
+}
diff --git a/src/tests/keywords/if-paircmp b/src/tests/keywords/if-paircmp
new file mode 100644
index 0000000..6ed06e3
--- /dev/null
+++ b/src/tests/keywords/if-paircmp
@@ -0,0 +1,27 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+#
+# Paircmp
+#
+
+#
+# Passing 'yes' causes the test paircmp to return match
+# Passing 'no' causes the test paircmp to return a non-match
+#
+if (&Test-Paircmp != 'yes') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if (&Test-Paircmp == 'no') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
diff --git a/src/tests/keywords/if-rcode-error b/src/tests/keywords/if-rcode-error
new file mode 100644
index 0000000..fed8a49
--- /dev/null
+++ b/src/tests/keywords/if-rcode-error
@@ -0,0 +1,11 @@
+# PRE: if
+#
+# return code in an "if" section.
+#
+if (User-Name == "bob") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ ok = reject # ERROR
+}
diff --git a/src/tests/keywords/if-regex-bad-attribute b/src/tests/keywords/if-regex-bad-attribute
new file mode 100644
index 0000000..f330fde
--- /dev/null
+++ b/src/tests/keywords/if-regex-bad-attribute
@@ -0,0 +1,21 @@
+#
+# PRE: if-regex-match if-regex-error
+#
+
+#
+# This should parse
+#
+if (&User-Name =~ /%{User-Name}/) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
+
+#
+# Check regexes which refer to unknown attributes
+#
+if (&User-Name =~ /%{What-The-Heck-Is-This-Thing}/) { # ERROR
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/if-regex-error b/src/tests/keywords/if-regex-error
new file mode 100644
index 0000000..f618e82
--- /dev/null
+++ b/src/tests/keywords/if-regex-error
@@ -0,0 +1,12 @@
+#
+# PRE: if-regex-match
+#
+
+#
+# Check that bad regular expressions will fail
+#
+if (&User-Name =~ /[a-3]/) { # ERROR
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/if-regex-match b/src/tests/keywords/if-regex-match
new file mode 100644
index 0000000..458e455
--- /dev/null
+++ b/src/tests/keywords/if-regex-match
@@ -0,0 +1,183 @@
+# PRE: if
+#
+update request {
+ Tmp-Integer-0 := '123456789'
+}
+
+# Non matching on attribute ref
+if (User-Name !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+# Matching on xlat expanded value
+if ("%{User-Name}" !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+# Matching on attribute ref with capture groups
+if (User-Name =~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])%{Tmp-String-0}/) {
+ # Test all the capture groups
+ update {
+ reply:User-Name := "%{7}_%{6}_%{5}_%{4}_%{3}_%{2}_%{1}_%{0}"
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+# Checking capture groups are cleared out correctly
+if (User-Name =~ /^([0-9])_%{Tmp-String-0}/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1_1') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 3.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly when there are no matches
+if (User-Name =~ /^.%{Tmp-String-0}/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+
+# Checking full capture group range
+if ('a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_A_B_C_D_E_F' =~ /^(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)$/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}%{8}%{9}%{10}%{11}%{12}%{13}%{14}%{15}%{16}%{17}%{18}%{19}%{20}%{21}%{22}%{23}%{24}%{25}%{26}%{27}%{28}%{29}%{30}%{31}%{32}" != 'a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_A_B_C_D_E_FabcdefghijklmnopqrstuvwxyzABCDEF') {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 6.5'
+ }
+}
+
+# Checking full capture group overun
+if ('a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_A_B_C_D_E_F_G' =~ /^(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)_(.)$/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}%{8}%{9}%{10}%{11}%{12}%{13}%{14}%{15}%{16}%{17}%{18}%{19}%{20}%{21}%{22}%{23}%{24}%{25}%{26}%{27}%{28}%{29}%{30}%{31}%{32}" != 'a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_A_B_C_D_E_F_GabcdefghijklmnopqrstuvwxyzABCDEF') {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 7.5'
+ }
+}
+
+# uncompiled - ref - insensitive
+if (Calling-Station-Id !~ /:roamyroam%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+# uncompiled - expansion - insensitive
+if ("%{Calling-Station-Id}" !~ /:roamyroam%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+# uncompiled - enum - ref - insensitive
+if (Service-Type !~ /^framed-user%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 10'
+ }
+}
+
+# uncompiled - enum - expansion - insensitive
+if ("%{Service-Type}" !~ /^framed-user%{Tmp-String-0}$/i) {
+ update reply {
+ Filter-Id += 'Fail 11'
+ }
+}
+
+# uncompiled - enum - ref
+if (Service-Type =~ /^framed-user%{Tmp-String-0}$/) {
+ update reply {
+ Filter-Id += 'Fail 12'
+ }
+}
+
+# uncompiled - integer - ref
+if (Tmp-Integer-0 !~ /%{Tmp-Integer-0}/) {
+ update reply {
+ Filter-Id += 'Fail 13'
+ }
+}
+
+update request {
+ Tmp-String-0 := "foo\nbar"
+}
+
+# uncompiled - ref - multiline
+if (&Tmp-String-0 !~ /^foo$%{Tmp-String-8}/m) {
+ update reply {
+ Filter-Id += 'Fail 14'
+ }
+}
+
+# uncompiled - ref - non-multiline
+if (&Tmp-String-0 =~ /^foo$%{Tmp-String-8}/) {
+ update reply {
+ Filter-Id += 'Fail 15'
+ }
+}
+
+# uncompiled - ref - non-multiline
+if (&Tmp-String-0 !~ /^foo\nbar%{Tmp-String-8}$/) {
+ update reply {
+ Filter-Id += 'Fail 16'
+ }
+}
+
+# uncompiled - ref - multiline
+if (&Tmp-String-0 !~ /^bar%{Tmp-String-8}$/m) {
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+}
+
+# uncompiled - ref - multiline - sensitive
+if (&Tmp-String-0 =~ /^BAR%{Tmp-String-8}$/m) {
+ update reply {
+ Filter-Id += 'Fail 18'
+ }
+}
+
+# uncompiled - ref - multiline - insensitive
+if (&Tmp-String-0 !~ /^BAR%{Tmp-String-8}$/mi) {
+ update reply {
+ Filter-Id += 'Fail 19'
+ }
+}
+
+# uncompiled - ref - multiline - insensitive (flag order reversed)
+if (&Tmp-String-0 !~ /^BAR%{Tmp-String-8}$/im) {
+ update reply {
+ Filter-Id += 'Fail 20'
+ }
+}
diff --git a/src/tests/keywords/if-regex-match-comp b/src/tests/keywords/if-regex-match-comp
new file mode 100644
index 0000000..c9c2d15
--- /dev/null
+++ b/src/tests/keywords/if-regex-match-comp
@@ -0,0 +1,149 @@
+# PRE: if
+#
+
+# Non matching on attribute ref
+if (User-Name !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+# Matching on xlat expanded value
+if ("%{User-Name}" !~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+# Matching on attribute ref with capture groups
+if (User-Name =~ /^([0-9])_([0-9])?_([0-9]*)_([0-9]+)_([^_])_(6)_([7-8])/) {
+ # Test all the capture groups
+ update {
+ reply:User-Name := "%{7}_%{6}_%{5}_%{4}_%{3}_%{2}_%{1}_%{0}"
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+# Checking capture groups are cleared out correctly
+if (User-Name =~ /^([0-9])_/) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1_1') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 3.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly when there are no matches
+if (User-Name =~ /^./) {
+ if ("%{0}%{1}%{2}%{3}%{4}%{5}%{6}%{7}" != '1') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+
+# compiled - ref - insensitive
+if (Calling-Station-Id !~ /:roamyroam$/i) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+# compiled - expansion - insensitive
+if ("%{Calling-Station-Id}" !~ /:roamyroam$/i) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+# compiled - enum - ref - insensitive
+if (Service-Type !~ /^framed-user$/i) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+# compiled - enum - expansion - insensitive
+if ("%{Service-Type}" !~ /^framed-user$/i) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+# compiled - enum - ref
+if (Service-Type =~ /^framed-user$/) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+update request {
+ Tmp-String-0 := "foo\nbar"
+}
+
+# compiled - ref - multiline
+if (&Tmp-String-0 !~ /^foo$/m) {
+ update reply {
+ Filter-Id += 'Fail 14'
+ }
+}
+
+# compiled - ref - non-multiline
+if (&Tmp-String-0 =~ /^foo$/) {
+ update reply {
+ Filter-Id += 'Fail 15'
+ }
+}
+
+# compiled - ref - non-multiline
+
+# Not all POSIX implementations support the \n character classes
+# so only run this test if the server was built with libpcre.
+if (("${feature.regex-pcre}" == 'yes') && (&Tmp-String-0 !~ /^foo\nbar$/)) {
+ update reply {
+ Filter-Id += 'Fail 16'
+ }
+}
+
+# compiled - ref - multiline
+if (&Tmp-String-0 !~ /^bar$/m) {
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+}
+
+# compiled - ref - multiline - sensitive
+if (&Tmp-String-0 =~ /^BAR$/m) {
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+}
+
+# compiled - ref - multiline - insensitive
+if (&Tmp-String-0 !~ /^BAR$/mi) {
+ update reply {
+ Filter-Id += 'Fail 17'
+ }
+}
+
+# compiled - ref - multiline - insensitive (flag order reversed)
+if (&Tmp-String-0 !~ /^BAR$/im) {
+ update reply {
+ Filter-Id += 'Fail 18'
+ }
+}
+
diff --git a/src/tests/keywords/if-regex-match-comp.attrs b/src/tests/keywords/if-regex-match-comp.attrs
new file mode 100644
index 0000000..ba7188d
--- /dev/null
+++ b/src/tests/keywords/if-regex-match-comp.attrs
@@ -0,0 +1,7 @@
+User-Name = '1_2_3_4_5_6_7'
+User-Password = 'hello'
+Service-Type := 'Framed-User'
+Calling-Station-ID := '00:11:22:33:44:55:66:ROAMYROAM'
+
+Response-Packet-Type == Access-Accept
+User-Name == '7_6_5_4_3_2_1_1_2_3_4_5_6_7'
diff --git a/src/tests/keywords/if-regex-match-named b/src/tests/keywords/if-regex-match-named
new file mode 100644
index 0000000..2aa665f
--- /dev/null
+++ b/src/tests/keywords/if-regex-match-named
@@ -0,0 +1,117 @@
+# PRE: if
+#
+if ('${feature.regex-pcre}' == 'yes') {
+update request {
+ Tmp-Integer-0 := '123456789'
+ Tmp-Integer-1 := 1
+}
+
+# Check failures when no previous capture
+if ("%{regex:}" != "") {
+ update reply {
+ Filter-Id += 'Fail 0.1'
+ }
+}
+
+if ("%{regex:foo}" != "") {
+ update reply {
+ Filter-Id += 'Fail 0.2'
+ }
+}
+
+if ("%{regex:%{Tmp-Integer-1}}" != "") {
+ update reply {
+ Filter-Id += 'Fail 0.3'
+ }
+}
+
+if ("%{regex:1}" != "") {
+ update reply {
+ Filter-Id += 'Fail 0.4'
+ }
+}
+
+# uncompiled - ref - named capture groups
+if (User-Name =~ /^(?<one>[0-9])_(?<two>[0-9])?_(?<three>[0-9]*)_(?<four>[0-9]+)_(?<five>[^_])_(?<six>6)_(?<seven>[7-8])%{Tmp-String-0}/) {
+ if ("%{regex:seven}_%{regex:six}_%{regex:five}_%{regex:four}_%{regex:three}_%{regex:two}_%{regex:one}_%{0}" != '7_6_5_4_3_2_1_1_2_3_4_5_6_7') {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 1.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly
+if (User-Name =~ /^(?<one>[0-9])_%{Tmp-String-0}/) {
+ if ("%{0}%{regex:one}%{regex:two}%{regex:three}%{regex:four}%{regex:five}%{regex:six}%{regex:seven}" != '1_1') {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 2.5'
+ }
+}
+
+# Checking capture groups are cleared out correctly when there are no matches
+if (User-Name =~ /^.%{Tmp-String-0}/) {
+ if ("%{0}%{regex:one}%{regex:two}%{regex:three}%{regex:four}%{regex:five}%{regex:six}%{regex:seven}" != '1') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 3.5'
+ }
+}
+
+# compiled - ref - named capture groups
+if (User-Name =~ /^(?<one>[0-9])_(?<two>[0-9])?_(?<three>[0-9]*)_(?<four>[0-9]+)_(?<five>[^_])_(?<six>6)_(?<seven>[7-8])/) {
+ if ("%{regex:seven}_%{regex:six}_%{regex:five}_%{regex:four}_%{regex:three}_%{regex:two}_%{regex:one}_%{0}" != '7_6_5_4_3_2_1_1_2_3_4_5_6_7') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+
+# compiled - xlat - named capture groups
+if ('1_2_3_4_5_6_7' =~ /^(?<one>[0-9])_(?<two>[0-9])?_(?<three>[0-9]*)_(?<four>[0-9]+)_(?<five>[^_])_(?<six>6)_(?<seven>[7-8])/) {
+ if ("%{regex:seven}_%{regex:six}_%{regex:five}_%{regex:four}_%{regex:three}_%{regex:two}_%{regex:one}_%{0}" != '7_6_5_4_3_2_1_1_2_3_4_5_6_7') {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 5.5'
+ }
+}
+
+# compiled - ref - named capture groups (numeric indexes)
+if (User-Name =~ /^(?<one>[0-9])_(?<two>[0-9])?_(?<three>[0-9]*)_(?<four>[0-9]+)_(?<five>[^_])_(?<six>6)_(?<seven>[7-8])/) {
+ if ("%{7}_%{6}_%{5}_%{4}_%{3}_%{2}_%{1}_%{0}" != '7_6_5_4_3_2_1_1_2_3_4_5_6_7') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 4.5'
+ }
+}
+}
diff --git a/src/tests/keywords/if-regex-match-named.attrs b/src/tests/keywords/if-regex-match-named.attrs
new file mode 100644
index 0000000..867ed23
--- /dev/null
+++ b/src/tests/keywords/if-regex-match-named.attrs
@@ -0,0 +1,6 @@
+User-Name = '1_2_3_4_5_6_7'
+User-Password = 'hello'
+Service-Type := 'Framed-User'
+Calling-Station-ID := '00:11:22:33:44:55:66:ROAMYROAM'
+
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/keywords/if-regex-match.attrs b/src/tests/keywords/if-regex-match.attrs
new file mode 100644
index 0000000..ba7188d
--- /dev/null
+++ b/src/tests/keywords/if-regex-match.attrs
@@ -0,0 +1,7 @@
+User-Name = '1_2_3_4_5_6_7'
+User-Password = 'hello'
+Service-Type := 'Framed-User'
+Calling-Station-ID := '00:11:22:33:44:55:66:ROAMYROAM'
+
+Response-Packet-Type == Access-Accept
+User-Name == '7_6_5_4_3_2_1_1_2_3_4_5_6_7'
diff --git a/src/tests/keywords/if-regex-multivalue b/src/tests/keywords/if-regex-multivalue
new file mode 100644
index 0000000..7358c93
--- /dev/null
+++ b/src/tests/keywords/if-regex-multivalue
@@ -0,0 +1,26 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Cisco-AVPair := 'foo=bar'
+ Cisco-AVPair += 'bar=baz'
+ Cisco-AVPair += 'baz=foo'
+}
+
+if (&Cisco-AVPair[*] =~ /bar=(.*)/) {
+ if ("%{1}" != 'baz') {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+ }
+}
+else {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
diff --git a/src/tests/keywords/if-skip b/src/tests/keywords/if-skip
new file mode 100644
index 0000000..0e74f22
--- /dev/null
+++ b/src/tests/keywords/if-skip
@@ -0,0 +1,42 @@
+# PRE: if
+#
+# Conditions which statically evaluate to "false"
+# have their entire contents skipped on load.
+#
+# Conditions which statically evaluate to "true"
+# have the following "else" sections skipped, too.
+#
+# i.e. we can reference things which don't exist,
+# and they'll get ignored.
+#
+if (0) {
+ no-such-module
+}
+
+if (0) {
+ no-such-module
+}
+else {
+ ok
+}
+
+if (1) {
+ ok
+}
+else {
+ no-such-module
+}
+
+if (1) {
+ ok
+}
+elsif ("%{foo:bar}") { # no pass2
+ no-such-module
+}
+else {
+ no-such-module
+}
+
+update reply {
+ Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/integer b/src/tests/keywords/integer
new file mode 100644
index 0000000..7e43270
--- /dev/null
+++ b/src/tests/keywords/integer
@@ -0,0 +1,209 @@
+#
+# PRE: update
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '9870'
+ Tmp-String-1 := '98709870'
+ Tmp-String-2 := '987098709870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-Octets-1 := 0x3938373139383731
+ Tmp-Octets-2 := 0x393837313938373139383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-String-2 := "%{integer:Tmp-IP-Address-0}"
+ Tmp-String-3 := "%{integer:Tmp-Date-0}"
+ Tmp-String-4 := "%{integer:Tmp-Integer-0}"
+ Tmp-String-5 := "%{integer:Tmp-Cast-Abinary}"
+ Tmp-String-6 := "%{integer:Tmp-Cast-Ifid}"
+ Tmp-String-7 := "%{integer:Tmp-Cast-IPv6Addr}"
+ Tmp-String-8 := "%{integer:Tmp-Cast-IPv6Prefix}"
+}
+
+# String - network order representation of a 4 char string
+update request {
+ Tmp-Integer-0 := "%{integer:Tmp-String-0}"
+}
+if ((Tmp-String-0 != "%{string:Tmp-Integer-0}") || (Tmp-Integer-0 != 959985456)) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# String - network order representation of a 8 char string
+update request {
+ Tmp-Integer64-0 := "%{integer:Tmp-String-1}"
+}
+if ((Tmp-String-1 != "%{string:Tmp-Integer64-0}") || (Tmp-Integer64-0 != 4123106139115632432)) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# String - Can't convert 12 byte string to integer (our biggest native size is a 64bit unsigned int)
+if ("%{integer:Tmp-String-2}" != '') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Octets - network order representation of a 4 byte octet string
+update request {
+ Tmp-Integer-0 := "%{integer:Tmp-Octets-0}"
+}
+if (Tmp-Octets-0 != "0x%{hex:Tmp-Integer-0}") {
+ update reply {
+ Filter-Id += 'fail 4a'
+ }
+}
+
+if (Tmp-Integer-0 != 959985457) {
+ update reply {
+ Filter-Id += 'fail 4b'
+ }
+}
+
+# Octets - network order representation of a 8 byte octet string
+update request {
+ Tmp-Integer64-0 := "%{integer:Tmp-Octets-1}"
+}
+if (Tmp-Octets-1 != "0x%{hex:Tmp-Integer64-0}") {
+ update reply {
+ Filter-Id += 'fail 5a'
+ }
+}
+
+if (Tmp-Integer64-0 != 4123106143410599729) {
+ update reply {
+ Filter-Id += 'fail 5b'
+ }
+}
+
+# String - Can't convert 12 byte octet string to integer (our biggest native size is a 64bit unsigned int)
+if ("%{integer:Tmp-Octets-2}" != '') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# IP Address
+if (Tmp-String-2 != '959985458') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+if (<ipaddr>Tmp-String-2 != &Tmp-IP-Address-0) {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+# Date
+if (Tmp-String-3 != '959985459') {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
+
+# Integer
+if (Tmp-String-4 != '959985460') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# Abinary - Can't convert ascend binary to an integer
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+# ifid - Can't convert interface ID to an integer
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# ipv6addr - Can't convert IPv6 to integer
+if (Tmp-String-7 != '959985464') {
+ update reply {
+ Filter-ID += 'fail 13'
+ }
+}
+
+# ipv6addrprefix
+if (Tmp-String-8 != '959985465') {
+ update reply {
+ Filter-ID += 'fail 14'
+ }
+}
+update request {
+ Tmp-String-0 := "%{integer:Tmp-Cast-Byte}"
+ Tmp-String-1 := "%{integer:Tmp-Cast-Short}"
+ Tmp-String-2 := "%{integer:Tmp-Cast-Ethernet}"
+ Tmp-String-3 := "%{integer:Tmp-Cast-Integer64}"
+ Tmp-String-4 := "%{integer:Tmp-Cast-IPv4Prefix}"
+}
+
+# byte
+if (Tmp-String-0 != '58') {
+ update reply {
+ Filter-ID += 'fail 15'
+ }
+}
+
+# short
+if (Tmp-String-1 != '14139') {
+ update reply {
+ Filter-ID += 'fail 16'
+ }
+}
+
+# ethernet
+if (Tmp-String-2 != '62913607630848') {
+ update reply {
+ Filter-Id += 'fail 17'
+ }
+}
+if (<ether>Tmp-String-2 != &Tmp-Cast-Ethernet) {
+ update reply {
+ Filter-Id += 'fail 18'
+ }
+}
+
+# integer64
+if (Tmp-String-3 != '1152921505566832445') {
+ update reply {
+ Filter-Id += 'fail 19'
+ }
+}
+
+# ipv4prefix
+if (Tmp-String-4 != '959985470') {
+ update reply {
+ Filter-Id += 'fail 20'
+ }
+}
+
+
+
+
diff --git a/src/tests/keywords/ipaddr b/src/tests/keywords/ipaddr
new file mode 100644
index 0000000..3010a23
--- /dev/null
+++ b/src/tests/keywords/ipaddr
@@ -0,0 +1,51 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+}
+
+update request {
+ # Dotted Quad
+ Tmp-IP-Address-0 := 127.0.0.1
+
+ # Dotted Quad with prefix
+ Tmp-IP-Address-1 := 127.0.0.2/32
+
+ # Hex (0x)
+ Tmp-IP-Address-2 := 0x7f000003
+
+ # Decimal
+ Tmp-IP-Address-3 := 2130706436
+}
+
+if (NAS-IP-Address != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if (Tmp-IP-Address-0 != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+if (Tmp-IP-Address-1 != 127.0.0.2) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+if (Tmp-IP-Address-2 != 127.0.0.3) {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+if (Tmp-IP-Address-3 != 127.0.0.4) {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
diff --git a/src/tests/keywords/ipaddr-error b/src/tests/keywords/ipaddr-error
new file mode 100644
index 0000000..5483a4f
--- /dev/null
+++ b/src/tests/keywords/ipaddr-error
@@ -0,0 +1,10 @@
+#
+# PRE: update ipaddr
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Framed-IP-Address := 256.1 # ERROR
+}
diff --git a/src/tests/keywords/ipaddr.attrs b/src/tests/keywords/ipaddr.attrs
new file mode 100644
index 0000000..ab9c27e
--- /dev/null
+++ b/src/tests/keywords/ipaddr.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+NAS-IP-Address = 127.0.0.1
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Filter-Id == 'filter'
diff --git a/src/tests/keywords/ipprefix b/src/tests/keywords/ipprefix
new file mode 100644
index 0000000..0ab8dce
--- /dev/null
+++ b/src/tests/keywords/ipprefix
@@ -0,0 +1,52 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+update control {
+ Tmp-Cast-IPv4Prefix := 198.51.100.255/16
+ Tmp-Cast-IPv6Prefix := ::198.51.100.255/112
+ Framed-IP-Address := 198.51.0.1
+}
+
+if ("%{control:Tmp-Cast-IPv6Prefix}" != '::198.51.0.0/112') {
+ update reply {
+ Filter-Id += "Fail 0"
+ }
+}
+
+if ("%{control:Tmp-Cast-IPv4Prefix}" != '198.51.0.0/16') {
+ update reply {
+ Filter-Id += "Fail 1"
+ }
+}
+
+if (control:Tmp-Cast-IPv6Prefix != ::198.51.0.0/112) {
+ update reply {
+ Filter-Id += "Fail 2"
+ }
+}
+
+if (control:Tmp-Cast-IPv4Prefix != 198.51.0.0/16) {
+ update reply {
+ Filter-Id += "Fail 3"
+ }
+}
+
+if (!(&control:Tmp-Cast-IPv4Prefix < 198.0.0.0/8)) {
+ update reply {
+ Filter-Id += "Fail 4"
+ }
+}
+
+if (!(&control:Framed-IP-Address < 198.51.0.0/16)) {
+ update reply {
+ Filter-Id += "Fail 5"
+ }
+}
diff --git a/src/tests/keywords/length b/src/tests/keywords/length
new file mode 100644
index 0000000..ad37fc8
--- /dev/null
+++ b/src/tests/keywords/length
@@ -0,0 +1,155 @@
+#
+# PRE: hex
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ Tmp-String-0 := '\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\
+abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
+ Tmp-String-2 := '9870'
+ Tmp-Octets-0 := 0x39383731
+ Tmp-IP-Address-0 := 57.56.55.50
+ Tmp-Date-0 := 959985459
+ Tmp-Integer-0 := 959985460
+ Tmp-Cast-Abinary := 'ip out forward srcip 57.56.55.53/32 udp dstport = 1812'
+ Tmp-Cast-IfId := '0000:0000:3938:3737'
+ Tmp-Cast-IPv6Addr := '::3938:3738'
+ Tmp-Cast-IPv6Prefix := '::3938:3739/128'
+ Tmp-Cast-Byte := 58
+ Tmp-Cast-Short := 14139
+ Tmp-Cast-Ethernet := 00:00:39:38:37:3c
+ Tmp-Cast-Integer64 := 1152921505566832445
+ Tmp-Cast-IPv4Prefix := 57.56.55.62/32
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-String-0}"
+}
+
+if (Tmp-Integer-0 != 260) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-String-2}"
+ Tmp-Integer-1 := "%{length:Tmp-Octets-0}"
+ Tmp-Integer-2 := "%{length:Tmp-IP-Address-0}"
+ Tmp-Integer-3 := "%{length:Tmp-Date-0}"
+ Tmp-Integer-4 := "%{length:Tmp-Integer-0}"
+ Tmp-Integer-5 := "%{length:Tmp-Cast-Abinary}"
+ Tmp-Integer-6 := "%{length:Tmp-Cast-Ifid}"
+ Tmp-Integer-7 := "%{length:Tmp-Cast-IPv6Addr}"
+ Tmp-Integer-8 := "%{length:Tmp-Cast-IPv6Prefix}"
+ Tmp-Integer-9 := "%{length:Tmp-Cast-Byte}"
+}
+
+# String - bin 0x39383730
+if (Tmp-Integer-0 != 4) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Octets - bin 0x39383731
+if (Tmp-Integer-1 != 4) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# IP Address - bin 0x39383732
+if (Tmp-Integer-2 != 4) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Date - bin 0x39383733
+if (Tmp-Integer-3 != 4) {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Integer - bin 0x39383734
+if (Tmp-Integer-4 != 4) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# Abinary - bin 0x0101000039383735000000002000110000000714000200000000000000000000
+if (Tmp-Integer-5 != 32) {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+# ifid - bin 0x0000000039383737
+if (Tmp-Integer-6 != 8) {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+# ipv6addr - bin 0x00000000000000000000000039383738
+if (Tmp-Integer-7 != 16) {
+ update reply {
+ Filter-ID += 'fail 9'
+ }
+}
+
+# ipv6addrprefix - bin 0x008000000000000000000000000039383739
+if (Tmp-Integer-8 != 18) {
+ update reply {
+ Filter-ID += 'fail 10'
+ }
+}
+
+# byte - bin 0x3a
+if (Tmp-Integer-9 != 1) {
+ update reply {
+ Filter-ID += 'fail 11'
+ }
+}
+
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-Cast-Short}"
+ Tmp-Integer-1 := "%{length:Tmp-Cast-Ethernet}"
+ Tmp-Integer-2 := "%{length:Tmp-Cast-Integer64}"
+ Tmp-Integer-3 := "%{length:Tmp-Cast-IPv4Prefix}"
+}
+
+# short - bin 0x373b
+if (Tmp-Integer-0 != 2) {
+ update reply {
+ Filter-ID += 'fail 12'
+ }
+}
+
+# ethernet - bin 0x00003938373c
+if (Tmp-Integer-1 != 6) {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+# integer64 - bin 0x100000003938373d
+if (Tmp-Integer-2 != 8) {
+ update reply {
+ Filter-Id += 'fail 14'
+ }
+}
+
+# ipv4prefix - bin 0x00203938373e
+if (Tmp-Integer-3 != 6) {
+ update reply {
+ Filter-Id += 'fail 15'
+ }
+}
diff --git a/src/tests/keywords/load-balance b/src/tests/keywords/load-balance
new file mode 100644
index 0000000..d07939a
--- /dev/null
+++ b/src/tests/keywords/load-balance
@@ -0,0 +1,97 @@
+# PRE: update if foreach
+#
+# Load-Balance blocks.
+#
+# Should distribute load between the modules.
+#
+update request {
+ Tmp-Integer-0 := 0
+ Tmp-Integer-1 := 0
+
+ Tmp-Integer-2 += 0 # 0
+ Tmp-Integer-2 += 1
+ Tmp-Integer-2 += 2
+ Tmp-Integer-2 += 3
+ Tmp-Integer-2 += 4
+ Tmp-Integer-2 += 5
+ Tmp-Integer-2 += 6
+ Tmp-Integer-2 += 7
+ Tmp-Integer-2 += 8
+ Tmp-Integer-2 += 9 # 10
+ Tmp-Integer-2 += 0
+ Tmp-Integer-2 += 1
+ Tmp-Integer-2 += 2
+ Tmp-Integer-2 += 3
+ Tmp-Integer-2 += 4
+ Tmp-Integer-2 += 5
+ Tmp-Integer-2 += 6
+ Tmp-Integer-2 += 7
+ Tmp-Integer-2 += 8
+ Tmp-Integer-2 += 9 # 20
+ Tmp-Integer-2 += 0
+ Tmp-Integer-2 += 1
+ Tmp-Integer-2 += 2
+ Tmp-Integer-2 += 3
+ Tmp-Integer-2 += 4
+ Tmp-Integer-2 += 5
+ Tmp-Integer-2 += 6
+ Tmp-Integer-2 += 7
+ Tmp-Integer-2 += 8
+ Tmp-Integer-2 += 9 # 30
+ Tmp-Integer-2 += 0
+ Tmp-Integer-2 += 1
+ Tmp-Integer-2 += 2
+ Tmp-Integer-2 += 3
+ Tmp-Integer-2 += 4
+ Tmp-Integer-2 += 5
+ Tmp-Integer-2 += 6
+ Tmp-Integer-2 += 7
+ Tmp-Integer-2 += 8
+ Tmp-Integer-2 += 9 # 40
+ Tmp-Integer-2 += 0
+ Tmp-Integer-2 += 1
+ Tmp-Integer-2 += 2
+ Tmp-Integer-2 += 3
+ Tmp-Integer-2 += 4
+ Tmp-Integer-2 += 5
+ Tmp-Integer-2 += 6
+ Tmp-Integer-2 += 7
+ Tmp-Integer-2 += 8
+ Tmp-Integer-2 += 9 # 49
+}
+
+#
+# Loop 0..9
+#
+foreach &Tmp-Integer-2 {
+ load-balance {
+ group {
+ update request {
+ Tmp-Integer-0 := "%{expr:%{Tmp-Integer-0} + 1}"
+ Filter-Id += "PICKED GROUP 1 %{Tmp-Integer-0} TIME(S)"
+ }
+ ok
+ }
+ group {
+ update request {
+ Tmp-Integer-1 := "%{expr:%{Tmp-Integer-1} + 1}"
+ Filter-Id += "PICKED GROUP 2 %{Tmp-Integer-1} TIME(S)"
+ }
+ ok
+ }
+ }
+}
+
+# The chances of one group being used over another 50 times by random occurrence
+# is quite small, and if this happens repeatedly, it's likely there's a bug in
+# the load-balance code or random number generator.
+if ((&Tmp-Integer-0 == 0) || (&Tmp-Integer-1 == 0)) {
+ update reply {
+ Filter-Id += "fail 1 %{Tmp-Integer-0}/%{Tmp-Integer-1})"
+ }
+}
+else {
+ update reply {
+ Filter-Id := 'filter'
+ }
+}
diff --git a/src/tests/keywords/log b/src/tests/keywords/log
new file mode 100644
index 0000000..97a2557
--- /dev/null
+++ b/src/tests/keywords/log
@@ -0,0 +1,7 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/map-xlat b/src/tests/keywords/map-xlat
new file mode 100644
index 0000000..24446a5
--- /dev/null
+++ b/src/tests/keywords/map-xlat
@@ -0,0 +1,25 @@
+#
+# PRE: update
+#
+# Test the map xlat
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+}
+
+update {
+ Tmp-String-0 := '&control:Tmp-String-0 := \'testing123\''
+}
+
+if ("%{map:%{Tmp-String-0}}" != 1) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if (&control:Tmp-String-0 != 'testing123') {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
diff --git a/src/tests/keywords/md4 b/src/tests/keywords/md4
new file mode 100644
index 0000000..7e9b1ff
--- /dev/null
+++ b/src/tests/keywords/md4
@@ -0,0 +1,58 @@
+#
+# PRE: update if
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+ request:Tmp-String-1 := "what do ya want for nothing?"
+ request:Tmp-String-2 := "Jefe"
+}
+
+#
+# Put "This is a string" into a file and call "md5sum" on it.
+# You should get this string.
+#
+if ("%{md4:This is a string\n}" != '1f60d5cd85e17bfbdda7c923822f060c') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{md4:&Tmp-String-0}" != '1f60d5cd85e17bfbdda7c923822f060c') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{md4:&request:Tmp-String-0}" != '1f60d5cd85e17bfbdda7c923822f060c') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{md4:%{request:Tmp-String-0}}" != '1f60d5cd85e17bfbdda7c923822f060c') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+#
+# MD4 should also be able to cope with references to octet attributes
+#
+if ("%{md4:&request:Tmp-Octets-0}" != 'ac3ed17b3cf19ec38352ec534a932fc6') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+if ("%{md4:&Tmp-String-1}" != 'f7b44afb9cfdc877aa99d44654fe808b') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
diff --git a/src/tests/keywords/md5 b/src/tests/keywords/md5
new file mode 100644
index 0000000..a973660
--- /dev/null
+++ b/src/tests/keywords/md5
@@ -0,0 +1,60 @@
+#
+# PRE: update if
+#
+update reply {
+ Filter-Id := "filter"
+}
+
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+ request:Tmp-String-1 := "what do ya want for nothing?"
+ request:Tmp-String-2 := "Jefe"
+}
+
+#
+# Put "This is a string" into a file and call "md5sum" on it.
+# You should get this string.
+#
+if ("%{md5:This is a string\n}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{md5:&Tmp-String-0}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{md5:&request:Tmp-String-0}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{md5:%{request:Tmp-String-0}}" != '9ac4dbbc3c0ad2429e61d0df5dc28add') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+#
+# MD5 should also be able to cope with references to octet attributes
+#
+if ("%{md5:&request:Tmp-Octets-0}" != 'c1e7fa505b2fc1fd0da6cac3db6f6f44') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+#
+# MD5 HMAC with attribute references
+#
+if ("%{hmacmd5:&Tmp-String-1 &Tmp-String-2}" != '750c783e6ab0b503eaa86e310a5db738') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
diff --git a/src/tests/keywords/module-failure-message b/src/tests/keywords/module-failure-message
new file mode 100644
index 0000000..51b1ef4
--- /dev/null
+++ b/src/tests/keywords/module-failure-message
@@ -0,0 +1,40 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+test
+if ("%{request:Module-Failure-Message[0]}" != 'test: RERROR error message') {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if ("%{request:Module-Failure-Message[1]}" != 'test: RDEBUG error message') {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+if ("%{request:Module-Failure-Message[2]}" != 'test: RDEBUG2 error message') {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+if ("%{request:Module-Failure-Message[3]}" != 'test: RDEBUG3 error message') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if ("%{request:Module-Failure-Message[4]}" != 'test: RDEBUG4 error message') {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
diff --git a/src/tests/keywords/ok-return b/src/tests/keywords/ok-return
new file mode 100644
index 0000000..f79ef02
--- /dev/null
+++ b/src/tests/keywords/ok-return
@@ -0,0 +1,13 @@
+update {
+ control:Auth-Type = 'Accept'
+ reply:Reply-Message = 'pass'
+}
+
+# Section should exit after this statement
+ok {
+ ok = return
+}
+
+update {
+ reply:Reply-Message := 'fail'
+}
diff --git a/src/tests/keywords/ok-return.attrs b/src/tests/keywords/ok-return.attrs
new file mode 100644
index 0000000..ad30f4d
--- /dev/null
+++ b/src/tests/keywords/ok-return.attrs
@@ -0,0 +1,4 @@
+User-Name = 'test'
+
+Response-Packet-Type == Access-Accept
+Reply-Message == 'pass'
diff --git a/src/tests/keywords/pad b/src/tests/keywords/pad
new file mode 100644
index 0000000..0a1f9ce
--- /dev/null
+++ b/src/tests/keywords/pad
@@ -0,0 +1,62 @@
+#
+# PRE: if update return
+#
+
+update request {
+ Tmp-String-0 = "test"
+}
+
+#
+# rpad tests
+#
+
+if ("%{rpad:&Tmp-String-0 7}" != "test ") {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+ return
+}
+
+if ("%{rpad:&Tmp-String-0 2}" != "te") {
+ update reply {
+ Filter-Id := "fail 2"
+ }
+ return
+}
+
+if ("%{rpad:&Tmp-String-0 7 x}" != "testxxx") {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+ return
+}
+
+#
+# lpad tests
+#
+
+if ("%{lpad:&Tmp-String-0 7}" != " test") {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+ return
+}
+
+if ("%{lpad:&Tmp-String-0 2}" != "te") {
+ update reply {
+ Filter-Id := "fail 2"
+ }
+ return
+}
+
+if ("%{lpad:&Tmp-String-0 7 x}" != "xxxtest") {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+ return
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
diff --git a/src/tests/keywords/pairs b/src/tests/keywords/pairs
new file mode 100644
index 0000000..4230c57
--- /dev/null
+++ b/src/tests/keywords/pairs
@@ -0,0 +1,42 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string"
+ request:Tmp-String-0 += "This is another one"
+ request:Tmp-Octets-0 := 0x000504030201
+ request:Tmp-Integer-0 := 7331
+ request:Tunnel-Private-Group-Id:5 = 127.0.0.1
+ reply:Filter-Id = 'filter'
+}
+
+if ("%{pairs:request:}" != "User-Name = \"bob\", User-Password = \"hello\", Tmp-String-0 = \"This is a string\", Tmp-String-0 = \"This is another one\", Tmp-Octets-0 = 0x000504030201, Tmp-Integer-0 = 7331, Tunnel-Private-Group-Id:5 = \"127.0.0.1\"") {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{pairs:Tmp-String-0}" != "Tmp-String-0 = \"This is a string\"") {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{pairs:Tmp-String-0[*]}" != "Tmp-String-0 = \"This is a string\", Tmp-String-0 = \"This is another one\"") {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{pairs:control:}" != "Cleartext-Password = \"hello\"") {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+if ("%{pairs:control:User-Name}" != '') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
diff --git a/src/tests/keywords/pap b/src/tests/keywords/pap
new file mode 100644
index 0000000..a347b7c
--- /dev/null
+++ b/src/tests/keywords/pap
@@ -0,0 +1,146 @@
+#
+# PRE: update if
+#
+update {
+ reply:Filter-Id := 'filter'
+ control: !* ANY
+ request:Tmp-String-0 := "5RNqNl8iYLbkCc7JhR8as4TtDDCX6otuuWtcja8rITUyx9zrnHSe9tTHGmKK" # 60 byte salt
+}
+
+#
+# Unencoded Cleartext-Password in password with header
+#
+update {
+ control:Password-With-Header := "%{request:User-Password}"
+}
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Base64 encoded Cleartext-Password in password with header
+#
+update {
+ Tmp-String-1 := "{clear}%{User-Password}"
+}
+update {
+ control:Password-With-Header := "%{base64:&request:Tmp-String-1}"
+}
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Hex encoded SSHA password
+#
+update {
+ control:Password-With-Header += "{ssha}%{sha1:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Base64 encoded SSHA password
+#
+update {
+ control:Tmp-String-1 := "%{sha1:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+# To Binary
+update {
+ control:Tmp-Octets-0 := "0x%{control:Tmp-String-1}"
+}
+
+# To Base64
+update {
+ control:Tmp-String-1 := "%{base64:&control:Tmp-Octets-0}"
+}
+
+update {
+ control:Password-With-Header += "{ssha}%{control:Tmp-String-1}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Base64 of Base64 encoded SSHA password
+#
+update {
+ control:Tmp-String-1 := "%{sha1:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+# To Binary
+update {
+ control:Tmp-Octets-0 := "0x%{control:Tmp-String-1}"
+}
+
+# To Base64
+update {
+ control:Tmp-String-1 := "{ssha}%{base64:&control:Tmp-Octets-0}"
+}
+
+update {
+ control:Password-With-Header += "%{base64:&control:Tmp-String-1}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+update control {
+ Auth-Type := Accept
+}
diff --git a/src/tests/keywords/pap-ssha2 b/src/tests/keywords/pap-ssha2
new file mode 100644
index 0000000..a8c9c9b
--- /dev/null
+++ b/src/tests/keywords/pap-ssha2
@@ -0,0 +1,114 @@
+#
+# PRE: update if pap
+#
+
+#
+# Skip if the server wasn't built with openssl
+#
+if ('${feature.tls}' != 'yes') {
+ update control {
+ Response-Packet-Type := Access-Accept
+ }
+ handled
+}
+
+update {
+ reply:Filter-Id := 'filter'
+ control: !* ANY
+ request:Tmp-String-0 := "5RNqNl8iYLbkCc7JhR8as4TtDDCX6otuuWtcja8rITUyx9zrnHSe9tTHGmKK" # 60 byte salt
+}
+
+#
+# Hex encoded SSHA2-512 password
+#
+update {
+ control:Password-With-Header += "{ssha512}%{sha512:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Base64 encoded SSHA2-512 password
+#
+update {
+ control:Tmp-String-1 := "%{sha512:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+# To Binary
+update {
+ control:Tmp-Octets-0 := "0x%{control:Tmp-String-1}"
+}
+
+# To Base64
+update {
+ control:Tmp-String-1 := "%{base64:&control:Tmp-Octets-0}"
+}
+
+update {
+ control:Password-With-Header += "{ssha512}%{control:Tmp-String-1}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+#
+# Base64 of Base64 encoded SSHA2-512 password
+#
+update {
+ control:Tmp-String-1 := "%{sha512:%{request:User-Password}%{&request:Tmp-String-0}}%{hex:&request:Tmp-String-0}"
+}
+
+# To Binary
+update {
+ control:Tmp-Octets-0 := "0x%{control:Tmp-String-1}"
+}
+
+# To Base64
+update {
+ control:Tmp-String-1 := "{ssha512}%{base64:&control:Tmp-Octets-0}"
+}
+
+update {
+ control:Password-With-Header += "%{base64:&control:Tmp-String-1}"
+}
+
+pap.authorize
+pap.authenticate {
+ reject = 1
+}
+if (reject) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+update {
+ control: !* ANY
+}
+
+update control {
+ Auth-Type := Accept
+}
diff --git a/src/tests/keywords/radiusd.conf b/src/tests/keywords/radiusd.conf
new file mode 100644
index 0000000..58cb356
--- /dev/null
+++ b/src/tests/keywords/radiusd.conf
@@ -0,0 +1,127 @@
+#
+# Minimal radiusd.conf for testing keywords
+#
+
+raddb = raddb
+keyword = src/tests/keywords
+
+modconfdir = ${raddb}/mods-config
+
+correct_escapes = true
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+modules {
+ $INCLUDE ${raddb}/mods-enabled/always
+
+ $INCLUDE ${raddb}/mods-enabled/pap
+
+ $INCLUDE ${raddb}/mods-enabled/expr
+
+ $INCLUDE ${raddb}/mods-enabled/unpack
+
+ test {
+
+ }
+
+ unix {
+ }
+
+ cache {
+ driver = "rlm_cache_rbtree"
+
+ key = "%{Tmp-String-0}"
+ ttl = 2
+
+ update {
+ &request:Tmp-String-1 := &control:Tmp-String-1
+ &request:Tmp-Integer-0 := &control:Tmp-Integer-0
+ &control: += &reply:
+ }
+
+ add_stats = yes
+ }
+}
+
+policy {
+ #
+ # Outputs the contents of the control list in debugging (-X) mode
+ #
+ debug_control {
+ if("%{debug_attr:control:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the request list in debugging (-X) mode
+ #
+ debug_request {
+ if("%{debug_attr:request:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the reply list in debugging (-X) mode
+ #
+ debug_reply {
+ if("%{debug_attr:reply:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the main lists in debugging (-X) mode
+ #
+ debug_all {
+ debug_control
+ debug_request
+ debug_reply
+ }
+
+ #
+ # Just check that this can be referred to as "virtual_policy.post-auth"
+ #
+ virtual_policy {
+ ok
+ }
+
+ with.dots {
+ ok
+ }
+}
+
+instantiate {
+ #
+ # Just check that this can be referred to as "virtual_instantiate.post-auth"
+ #
+ load-balance virtual_instantiate {
+ ok
+ ok
+ }
+}
+
+server default {
+ authorize {
+ update control {
+ Cleartext-Password := 'hello'
+ }
+
+ #
+ # Include the test file specified by the
+ # KEYWORD environment variable.
+ #
+ $INCLUDE ${keyword}/$ENV{KEYWORD}
+
+ pap
+ }
+
+ authenticate {
+ pap
+ }
+}
diff --git a/src/tests/keywords/redundant b/src/tests/keywords/redundant
new file mode 100644
index 0000000..cebe7be
--- /dev/null
+++ b/src/tests/keywords/redundant
@@ -0,0 +1,17 @@
+# PRE: update if foreach
+#
+# Redundant blocks.
+#
+# The first one fails, so the second one is used
+#
+redundant {
+ group {
+ fail
+ }
+
+ group {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+}
diff --git a/src/tests/keywords/redundant-error b/src/tests/keywords/redundant-error
new file mode 100644
index 0000000..bec4335
--- /dev/null
+++ b/src/tests/keywords/redundant-error
@@ -0,0 +1,6 @@
+#
+# Check that redundant blocks can't be empty
+#
+redundant { # ERROR
+
+}
diff --git a/src/tests/keywords/redundant-load-balance b/src/tests/keywords/redundant-load-balance
new file mode 100644
index 0000000..27721f1
--- /dev/null
+++ b/src/tests/keywords/redundant-load-balance
@@ -0,0 +1,65 @@
+# PRE: update if foreach
+#
+# Redundant blocks.
+#
+# The first one fails, so the second one is used
+#
+update request {
+ Tmp-Integer-0 := 0
+ Tmp-Integer-1 += 0
+ Tmp-Integer-1 += 1
+ Tmp-Integer-1 += 2
+ Tmp-Integer-1 += 3
+ Tmp-Integer-1 += 4
+ Tmp-Integer-1 += 5
+ Tmp-Integer-1 += 6
+ Tmp-Integer-1 += 7
+ Tmp-Integer-1 += 8
+ Tmp-Integer-1 += 9
+
+}
+
+#
+# Loop 0..9
+#
+foreach &Tmp-Integer-1 {
+ redundant-load-balance {
+ group {
+ # fail on even numbered values, succeed on odd numbered ones
+ if ("%{expr:%{Foreach-Variable-0} %% 2}" == 0) {
+ fail
+ }
+ else {
+ update request {
+ Tmp-Integer-0 := "%{expr:%{Tmp-Integer-0} + 1}"
+ Filter-Id += "SUCCEED ODD %{Foreach-Variable-0} %{Tmp-Integer-0}"
+ }
+ ok
+ }
+ }
+ group {
+ # succeed on even-numbered values, fail on off-numbered ones.
+ if ("%{expr:%{Foreach-Variable-0} %% 2}" == 1) {
+ fail
+ }
+ else {
+ update request {
+ Tmp-Integer-0 := "%{expr:%{Tmp-Integer-0} + 1}"
+ Filter-Id += "SUCCEED EVEN %{Foreach-Variable-0} %{Tmp-Integer-0}"
+ }
+ ok
+ }
+ }
+ }
+}
+
+if (&Tmp-Integer-0 != "%{Tmp-Integer-1[#]}") {
+ update reply {
+ Filter-Id += "fail 2 (passed %{Tmp-Integer-0}/%{Tmp-Integer-1[#]})"
+ }
+}
+else {
+ update reply {
+ Filter-Id := 'filter'
+ }
+}
diff --git a/src/tests/keywords/redundant-redundant b/src/tests/keywords/redundant-redundant
new file mode 100644
index 0000000..294f53e
--- /dev/null
+++ b/src/tests/keywords/redundant-redundant
@@ -0,0 +1,73 @@
+# PRE: update if foreach redundant redundant-load-balance
+#
+# Nested redundant blocks.
+#
+#
+update request {
+ Tmp-Integer-2 := 0
+ Tmp-Integer-3 := 0
+ Tmp-Integer-4 := 0
+ Tmp-Integer-5 := 0
+}
+
+redundant {
+ redundant-load-balance {
+ group {
+ update request {
+ Tmp-Integer-2 := "%{expr:&Tmp-Integer-2 + 1}"
+ }
+ fail
+ }
+ group {
+ update request {
+ Tmp-Integer-3 := "%{expr:&Tmp-Integer-3 + 1}"
+ }
+ fail
+ }
+ group {
+ update request {
+ Tmp-Integer-4 := "%{expr:&Tmp-Integer-4 + 1}"
+ }
+ fail
+ }
+ group {
+ update request {
+ Tmp-Integer-5 := "%{expr:&Tmp-Integer-5 + 1}"
+ }
+ fail
+ }
+ }
+ ok
+}
+
+if (&Tmp-Integer-2 != 1) {
+ update reply {
+ Filter-Id += 'Fail 3a'
+ }
+ return
+}
+
+if (&Tmp-Integer-3 != 1) {
+ update reply {
+ Filter-Id += 'Fail 3b'
+ }
+ return
+}
+
+if (&Tmp-Integer-4 != 1) {
+ update reply {
+ Filter-Id += 'Fail 3c'
+ }
+ return
+}
+
+if (&Tmp-Integer-5 != 1) {
+ update reply {
+ Filter-Id += 'Fail 3d'
+ }
+ return
+}
+
+update reply {
+ Filter-Id := "filter"
+} \ No newline at end of file
diff --git a/src/tests/keywords/regex-escape b/src/tests/keywords/regex-escape
new file mode 100644
index 0000000..4ab1e5b
--- /dev/null
+++ b/src/tests/keywords/regex-escape
@@ -0,0 +1,29 @@
+#
+# PRE: update if
+#
+
+#
+# Strings which are expanded in a regex have regex special
+# characters escaped. Because the input strings are unsafe.
+#
+update request {
+ Tmp-String-0 := "example.com"
+ Tmp-String-1 := "exampleXcom"
+}
+
+if ("exampleXcom" =~ /%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+}
+
+elsif (&Tmp-String-1 =~ /%{Tmp-String-0}/) {
+ update reply {
+ Filter-Id := "fail 2"
+ }
+}
+else {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/regex-lhs b/src/tests/keywords/regex-lhs
new file mode 100644
index 0000000..91b0b20
--- /dev/null
+++ b/src/tests/keywords/regex-lhs
@@ -0,0 +1,27 @@
+#
+# PRE: update if regex-escape
+#
+
+#
+# Strings which are expanded in a regex have regex special
+# characters escaped. Because the input strings are unsafe.
+#
+update request {
+ Tmp-String-0 := "example.com"
+ Tmp-String-1 := "^foo$bar"
+}
+
+if (&Tmp-String-0 !~ /example\.com$/) {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+}
+elsif (&Tmp-String-1 !~ /\^foo\$bar/) {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+} else {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/return b/src/tests/keywords/return
new file mode 100644
index 0000000..49779a5
--- /dev/null
+++ b/src/tests/keywords/return
@@ -0,0 +1,33 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+if (User-Name == "bob") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ #
+ # We need this because the "return" below
+ # will prevent the "pap" module from being run
+ # in the "authorize" section.
+ #
+ update control {
+ Auth-Type := PAP
+ }
+
+ #
+ # Stop processing "authorize", and go to the next section.
+ #
+ return
+
+ #
+ # Shouldn't reach this
+ #
+ update reply {
+ Filter-Id := "fail"
+ }
+}
diff --git a/src/tests/keywords/return-group b/src/tests/keywords/return-group
new file mode 100644
index 0000000..92978e4
--- /dev/null
+++ b/src/tests/keywords/return-group
@@ -0,0 +1,22 @@
+# PRE: return
+#
+update {
+ control:Auth-Type = 'Accept'
+}
+
+group {
+ # Section should exit after this statement
+ ok {
+ ok = return
+ }
+
+ # This entry should never be reached
+ update {
+ reply:Reply-Message := 'fail'
+ }
+}
+
+# We should continue processing after the previous group.
+update {
+ reply:Reply-Message += 'pass'
+}
diff --git a/src/tests/keywords/return-group.attrs b/src/tests/keywords/return-group.attrs
new file mode 100644
index 0000000..ad30f4d
--- /dev/null
+++ b/src/tests/keywords/return-group.attrs
@@ -0,0 +1,4 @@
+User-Name = 'test'
+
+Response-Packet-Type == Access-Accept
+Reply-Message == 'pass'
diff --git a/src/tests/keywords/return-section b/src/tests/keywords/return-section
new file mode 100644
index 0000000..21ecea1
--- /dev/null
+++ b/src/tests/keywords/return-section
@@ -0,0 +1,35 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+if (User-Name == "bob") {
+ update reply {
+ Filter-Id := "filter"
+ }
+
+ #
+ # We need this because the "return" below
+ # will prevent the "pap" module from being run
+ # in the "authorize" section.
+ #
+ update control {
+ Auth-Type := PAP
+ }
+
+ #
+ # Stop processing "authorize", and go to the next section.
+ #
+ return { # ERROR
+ ok = 1
+ }
+
+ #
+ # Shouldn't reach this
+ #
+ update reply {
+ Filter-Id := "fail"
+ }
+}
diff --git a/src/tests/keywords/sha1 b/src/tests/keywords/sha1
new file mode 100644
index 0000000..0d577a9
--- /dev/null
+++ b/src/tests/keywords/sha1
@@ -0,0 +1,60 @@
+#
+# PRE: update if
+#
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+ request:Tmp-String-1 := "what do ya want for nothing?"
+ request:Tmp-String-2 := "Jefe"
+}
+
+update reply {
+ Filter-Id := 'filter'
+}
+
+#
+# Put "This is a string" into a file and call "sha1sum" on it.
+# You should get this string.
+#
+if ("%{sha1:This is a string\n}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{sha1:&Tmp-String-0}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{sha1:&request:Tmp-String-0}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{sha1:%{Tmp-String-0}}" != 'cc7edf1ccc4bdf1e0ec8f72b95388b65218ecf0c') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+#
+# SHA1 should also be able to cope with references to octet attributes
+#
+if ("%{sha1:&request:Tmp-Octets-0}" != '365b244645fe7294dff062174996572319d5a82c') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+#
+# SHA1 HMAC with attribute references
+#
+if ("%{hmacsha1:&Tmp-String-1 &Tmp-String-2}" != 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
diff --git a/src/tests/keywords/sha2 b/src/tests/keywords/sha2
new file mode 100644
index 0000000..89c54f4
--- /dev/null
+++ b/src/tests/keywords/sha2
@@ -0,0 +1,81 @@
+#
+# PRE: update if
+#
+if ("$ENV{OPENSSL_LIBS}" != "") {
+
+update {
+ control:Cleartext-Password := 'hello'
+ request:Tmp-String-0 := "This is a string\n"
+ request:Tmp-Octets-0 := 0x000504030201
+}
+
+update reply {
+ Filter-Id := 'filter'
+}
+
+#
+# Put "This is a string" into a file and call "sha256sum" on it.
+# You should get this string.
+#
+if ("%{sha256:This is a string\n}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{sha256:&Tmp-String-0}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{sha256:&request:Tmp-String-0}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+if ("%{sha256:%{Tmp-String-0}}" != 'b3716a1ab53042bb392034f29071e13b0c38aa19b4edd75d9a76022f91189124') {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+#
+# SHA256 should also be able to cope with references to octet attributes
+#
+if ("%{sha256:&request:Tmp-Octets-0}" != 'f307e202b881fded70e58017aa0c4d7b29c76ab25d02bf078301a5f6635187eb') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+#
+# SHA512 and SHA256 share common code paths, so the tests don't need to be
+# as exhaustive.
+#
+if ("%{sha512:This is a string\n}" != '56b57df5cce42d4e35c644649798ea23ec16f4f4626e78faf4d2d8f430ea349bcc28cd5532457c82f0aa66bf68988346039fe75b900a92ff94fd53993d45990f') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+if ("%{sha512:&Tmp-String-0}" != '56b57df5cce42d4e35c644649798ea23ec16f4f4626e78faf4d2d8f430ea349bcc28cd5532457c82f0aa66bf68988346039fe75b900a92ff94fd53993d45990f') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+if ("%{sha512:&request:Tmp-Octets-0}" != 'de80271eb5e03a1c24dd0cd823a22305a743ee3a54f1de5bf97adbf56984561154bfb6928b1da4ccc3f5dde9f4032ad461937b60b9ace4ad3898cf45c90596d7') {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+}
+
+else { # no OPENSSL. Force the test to pass
+ update reply {
+ Filter-Id := 'filter'
+ }
+}
diff --git a/src/tests/keywords/smash b/src/tests/keywords/smash
new file mode 100644
index 0000000..fd19d3f
--- /dev/null
+++ b/src/tests/keywords/smash
@@ -0,0 +1,6 @@
+#
+# PRE: update
+#
+# This gives the game away.
+#
+update { control:Cleartext-Password := 'hello', reply:Filter-Id := "filter" }
diff --git a/src/tests/keywords/string b/src/tests/keywords/string
new file mode 100644
index 0000000..bcf0fcf
--- /dev/null
+++ b/src/tests/keywords/string
@@ -0,0 +1,19 @@
+#
+# PRE: cmp
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ Tmp-String-0 := "this\000is\000a\000string"
+}
+
+#
+# %{string:...} is explicitly not binary safe
+#
+if ("%{string:Tmp-String-0}" == "this") {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/substring b/src/tests/keywords/substring
new file mode 100644
index 0000000..0ce4e9d
--- /dev/null
+++ b/src/tests/keywords/substring
@@ -0,0 +1,418 @@
+#
+# PRE: update
+#
+# Check substring xlat works correctly
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-String-0 := 'foo bar'
+ Tmp-Integer-0 := 54786512
+ Tmp-IP-Address-0 := 192.168.56.34
+ Tmp-Cast-Ethernet := 01:23:45:67:89:ab
+}
+
+update request {
+ Tmp-String-1 := "%{substring:&Tmp-String-0 2 3}"
+ Tmp-String-2 := "%{substring:&Tmp-String-0 -3 2}"
+ Tmp-String-3 := "%{substring:&Tmp-String-0 1 -3}"
+ Tmp-String-4 := "%{substring:&Tmp-String-0 -4 -1}"
+ Tmp-String-5 := "%{substring:&Tmp-String-0 8 5}"
+ Tmp-String-6 := "%{substring:&Tmp-String-0 4 -10}"
+ Tmp-String-7 := "%{substring:&Tmp-String-0 0 7}"
+ Tmp-String-8 := "%{substring:&Tmp-String-0 3 0}"
+ Tmp-String-9 := "%{substring:&Tmp-String-0 4 8}"
+}
+
+if (Tmp-String-1 != 'o b') {
+ update reply {
+ Filter-Id += 'fail 0.1'
+ }
+}
+
+if (Tmp-String-2 != 'ba') {
+ update reply {
+ Filter-Id += 'fail 0.2'
+ }
+}
+
+if (Tmp-String-3 != 'oo ') {
+ update reply {
+ Filter-Id += 'fail 0.3'
+ }
+}
+
+if (Tmp-String-4 != ' ba') {
+ update reply {
+ Filter-Id += 'fail 0.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 0.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 0.6'
+ }
+}
+
+if (Tmp-String-7 != 'foo bar') {
+ update reply {
+ Filter-Id += 'fail 0.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 0.8'
+ }
+}
+
+if (Tmp-String-9 != 'bar') {
+ update reply {
+ Filter-Id += 'fail 0.9'
+ }
+}
+
+update request {
+ Tmp-String-0 := ' foo bar '
+}
+
+update request {
+ Tmp-String-1 := "%{substring: &Tmp-String-0 2 3}"
+ Tmp-String-2 := "%{substring:&Tmp-String-0 -3 2}"
+ Tmp-String-3 := "%{substring:&Tmp-String-0 1 -3}"
+ Tmp-String-4 := "%{substring:&Tmp-String-0 -4 -1}"
+ Tmp-String-5 := "%{substring:&Tmp-String-0 10 5}"
+ Tmp-String-6 := "%{substring:&Tmp-String-0 4 -10}"
+ Tmp-String-7 := "%{substring:&Tmp-String-0 0 9}"
+ Tmp-String-8 := "%{substring:&Tmp-String-0 3 0}"
+ Tmp-String-9 := "%{substring:&Tmp-String-0 4 10}"
+}
+
+if (Tmp-String-1 != 'oo ') {
+ update reply {
+ Filter-Id += 'fail 1.1'
+ }
+}
+
+if (Tmp-String-2 != 'ar') {
+ update reply {
+ Filter-Id += 'fail 1.2'
+ }
+}
+
+if (Tmp-String-3 != 'foo b') {
+ update reply {
+ Filter-Id += 'fail 1.3'
+ }
+}
+
+if (Tmp-String-4 != 'bar') {
+ update reply {
+ Filter-Id += 'fail 1.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 1.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 1.6'
+ }
+}
+
+if (Tmp-String-7 != ' foo bar ') {
+ update reply {
+ Filter-Id += 'fail 1.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 1.8'
+ }
+}
+
+if (Tmp-String-9 != ' bar ') {
+ update reply {
+ Filter-Id += 'fail 1.9'
+ }
+}
+
+update request {
+ Tmp-String-1 := "%{substring:&Tmp-Integer-0 2 3}"
+ Tmp-String-2 := "%{substring:&Tmp-Integer-0 -3 2}"
+ Tmp-String-3 := "%{substring:&Tmp-Integer-0 1 -3}"
+ Tmp-String-4 := "%{substring:&Tmp-Integer-0 -4 -1}"
+ Tmp-String-5 := "%{substring:&Tmp-Integer-0 8 5}"
+ Tmp-String-6 := "%{substring:&Tmp-Integer-0 4 -10}"
+ Tmp-String-7 := "%{substring:&Tmp-Integer-0 0 8}"
+ Tmp-String-8 := "%{substring:&Tmp-Integer-0 5 0}"
+ Tmp-String-9 := "%{substring:&Tmp-Integer-0 4 10}"
+}
+
+if (Tmp-String-1 != '786') {
+ update reply {
+ Filter-Id += 'fail 2.1'
+ }
+}
+
+if (Tmp-String-2 != '51') {
+ update reply {
+ Filter-Id += 'fail 2.2'
+ }
+}
+
+if (Tmp-String-3 != '4786') {
+ update reply {
+ Filter-Id += 'fail 2.3'
+ }
+}
+
+if (Tmp-String-4 != '651') {
+ update reply {
+ Filter-Id += 'fail 2.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 2.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 2.6'
+ }
+}
+
+if (Tmp-String-7 != '54786512') {
+ update reply {
+ Filter-Id += 'fail 2.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 2.8'
+ }
+}
+
+if (Tmp-String-9 != '6512') {
+ update reply {
+ Filter-Id += 'fail 2.9'
+ }
+}
+
+update request {
+ Tmp-String-1 := "%{substring:&Tmp-IP-Address-0 2 3}"
+ Tmp-String-2 := "%{substring:&Tmp-IP-Address-0 -3 2}"
+ Tmp-String-3 := "%{substring:&Tmp-IP-Address-0 1 -3}"
+ Tmp-String-4 := "%{substring:&Tmp-IP-Address-0 -4 -1}"
+ Tmp-String-5 := "%{substring:&Tmp-IP-Address-0 15 5}"
+ Tmp-String-6 := "%{substring:&Tmp-IP-Address-0 4 -20}"
+ Tmp-String-7 := "%{substring:&Tmp-IP-Address-0 0 13}"
+ Tmp-String-8 := "%{substring:&Tmp-IP-Address-0 6 0}"
+ Tmp-String-9 := "%{substring:&Tmp-IP-Address-0 8 12}"
+}
+
+if (Tmp-String-1 != '2.1') {
+ update reply {
+ Filter-Id += 'fail 3.1'
+ }
+}
+
+if (Tmp-String-2 != '.3') {
+ update reply {
+ Filter-Id += 'fail 3.2'
+ }
+}
+
+if (Tmp-String-3 != '92.168.56') {
+ update reply {
+ Filter-Id += 'fail 3.3'
+ }
+}
+
+if (Tmp-String-4 != '6.3') {
+ update reply {
+ Filter-Id += 'fail 3.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 3.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 3.6'
+ }
+}
+
+if (Tmp-String-7 != '192.168.56.34') {
+ update reply {
+ Filter-Id += 'fail 3.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 3.8'
+ }
+}
+
+if (Tmp-String-9 != '56.34') {
+ update reply {
+ Filter-Id += 'fail 3.9'
+ }
+}
+
+update request {
+ Tmp-String-1 := "%{substring:&Tmp-Cast-Ethernet 2 3}"
+ Tmp-String-2 := "%{substring:&Tmp-Cast-Ethernet -3 2}"
+ Tmp-String-3 := "%{substring:&Tmp-Cast-Ethernet 1 -3}"
+ Tmp-String-4 := "%{substring:&Tmp-Cast-Ethernet -4 -1}"
+ Tmp-String-5 := "%{substring:&Tmp-Cast-Ethernet 20 5}"
+ Tmp-String-6 := "%{substring:&Tmp-Cast-Ethernet 4 -20}"
+ Tmp-String-7 := "%{substring:&Tmp-Cast-Ethernet 0 17}"
+ Tmp-String-8 := "%{substring:&Tmp-Cast-Ethernet 8 0}"
+ Tmp-String-9 := "%{substring:&Tmp-Cast-Ethernet 9 12}"
+}
+
+if (Tmp-String-1 != ':23') {
+ update reply {
+ Filter-Id += 'fail 4.1'
+ }
+}
+
+if (Tmp-String-2 != ':a') {
+ update reply {
+ Filter-Id += 'fail 4.2'
+ }
+}
+
+if (Tmp-String-3 != '1:23:45:67:89') {
+ update reply {
+ Filter-Id += 'fail 4.3'
+ }
+}
+
+if (Tmp-String-4 != '9:a') {
+ update reply {
+ Filter-Id += 'fail 4.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 4.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 4.6'
+ }
+}
+
+if (Tmp-String-7 != '01:23:45:67:89:ab') {
+ update reply {
+ Filter-Id += 'fail 4.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 4.8'
+ }
+}
+
+if (Tmp-String-9 != '67:89:ab') {
+ update reply {
+ Filter-Id += 'fail 4.9'
+ }
+}
+
+update request {
+ Tmp-String-1 := "%{substring:foo bar 2 3}"
+ Tmp-String-2 := "%{substring:foo bar -3 2}"
+ Tmp-String-3 := "%{substring:foo bar 1 -3}"
+ Tmp-String-4 := "%{substring:foo bar -4 -1}"
+ Tmp-String-5 := "%{substring:foo bar 8 5}"
+ Tmp-String-6 := "%{substring:foo bar 4 -10}"
+ Tmp-String-7 := "%{substring: foo bar 0 9}"
+ Tmp-String-8 := "%{substring: foo bar 5 0}"
+ Tmp-String-9 := "%{substring: foo bar 4 10}"
+}
+
+debug_request
+
+if (Tmp-String-1 != 'o b') {
+ update reply {
+ Filter-Id += 'fail 5.1'
+ }
+}
+
+if (Tmp-String-2 != 'ba') {
+ update reply {
+ Filter-Id += 'fail 5.2'
+ }
+}
+
+if (Tmp-String-3 != 'oo ') {
+ update reply {
+ Filter-Id += 'fail 5.3'
+ }
+}
+
+if (Tmp-String-4 != ' ba') {
+ update reply {
+ Filter-Id += 'fail 5.4'
+ }
+}
+
+if (Tmp-String-5 != '') {
+ update reply {
+ Filter-Id += 'fail 5.5'
+ }
+}
+
+if (Tmp-String-6 != '') {
+ update reply {
+ Filter-Id += 'fail 5.6'
+ }
+}
+
+if (Tmp-String-7 != ' foo bar ') {
+ update reply {
+ Filter-Id += 'fail 5.7'
+ }
+}
+
+if (Tmp-String-8 != '') {
+ update reply {
+ Filter-Id += 'fail 5.8'
+ }
+}
+
+if (Tmp-String-9 != ' bar ') {
+ update reply {
+ Filter-Id += 'fail 5.9'
+ }
+}
diff --git a/src/tests/keywords/switch b/src/tests/keywords/switch
new file mode 100644
index 0000000..f64aeaf
--- /dev/null
+++ b/src/tests/keywords/switch
@@ -0,0 +1,19 @@
+switch &User-Name {
+ case "bob" {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case "doug" {
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+}
diff --git a/src/tests/keywords/switch-attr-cast b/src/tests/keywords/switch-attr-cast
new file mode 100644
index 0000000..e271a18
--- /dev/null
+++ b/src/tests/keywords/switch-attr-cast
@@ -0,0 +1,34 @@
+#
+# PRE: switch switch-attr-cmp
+#
+
+update request {
+ Service-Type := Login-User
+ Filter-Id := "Login-User"
+}
+
+switch &Service-Type {
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ #
+ # The Filter-Id will get printed to a string,
+ # have the string parsed as a Service-Type attr,
+ # and then that compared to the input Service-Type
+ #
+ case &Filter-Id {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
diff --git a/src/tests/keywords/switch-attr-cmp b/src/tests/keywords/switch-attr-cmp
new file mode 100644
index 0000000..e28ded8
--- /dev/null
+++ b/src/tests/keywords/switch-attr-cmp
@@ -0,0 +1,36 @@
+#
+# PRE: switch
+#
+update request {
+ Tmp-String-0 := &User-Name
+}
+
+#
+# A switch statement where we compare two attributes
+#
+switch &User-Name {
+ case &Tmp-String-0 {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case "bob" {
+ update reply {
+ Filter-Id := "failed 0"
+ }
+ }
+
+ case "doug" {
+ update reply {
+ Filter-Id := "failed 1"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "failed 2"
+ }
+ }
+
+}
diff --git a/src/tests/keywords/switch-default b/src/tests/keywords/switch-default
new file mode 100644
index 0000000..6115ed9
--- /dev/null
+++ b/src/tests/keywords/switch-default
@@ -0,0 +1,22 @@
+# PRE: switch
+#
+switch User-Name {
+ case "harry" {
+ update reply {
+ Filter-Id := "harry"
+ }
+ }
+
+ case "doug" {
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/tests/keywords/switch-escape b/src/tests/keywords/switch-escape
new file mode 100644
index 0000000..50d9fdf
--- /dev/null
+++ b/src/tests/keywords/switch-escape
@@ -0,0 +1,43 @@
+update request {
+ &Tmp-String-0 := 'foo'
+}
+
+switch "%{tolower:%{request:Tmp-String-0}}" {
+ case 'foo' {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case '' {
+ update reply {
+ Filter-Id += "fail-empty-1"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id += "fail-default-1"
+ }
+ }
+}
+
+switch "%{request:Tmp-String-0}" {
+ case 'foo' {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case '' {
+ update reply {
+ Filter-Id += "fail-empty-2"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id += "fail-default-2"
+ }
+ }
+}
diff --git a/src/tests/keywords/switch-nodefault b/src/tests/keywords/switch-nodefault
new file mode 100644
index 0000000..5fb9469
--- /dev/null
+++ b/src/tests/keywords/switch-nodefault
@@ -0,0 +1,22 @@
+#
+# User-Name is "bob", and a switch statement
+# with no "default" should not crash the server.
+#
+switch &User-Name {
+ case "doug" {
+ update reply {
+ Filter-Id := "doug"
+ }
+ }
+}
+
+if (&reply:Filter-Id) {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+}
+else {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/switch-value-error b/src/tests/keywords/switch-value-error
new file mode 100644
index 0000000..18db9e1
--- /dev/null
+++ b/src/tests/keywords/switch-value-error
@@ -0,0 +1,29 @@
+#
+# PRE: switch
+#
+switch &Service-Type {
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ case Login-User {
+ update reply {
+ Filter-Id := "Login-User"
+ }
+ }
+
+ case No-Such-Value { # ERROR
+ update reply {
+ Filter-Id := "FAILED"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
diff --git a/src/tests/keywords/switch-value-error2 b/src/tests/keywords/switch-value-error2
new file mode 100644
index 0000000..a291e7b
--- /dev/null
+++ b/src/tests/keywords/switch-value-error2
@@ -0,0 +1,27 @@
+#
+# PRE: switch-value-error
+#
+# The same as "switch-value-error", but the attribute
+# is hidden inside of an xlat expansion. We now turn
+# simple attribute xlats into templates.
+#
+switch "%{Service-Type}" { # ERROR
+ case "%{expr: 1 + 2}" {
+ update reply {
+ Filter-Id := "3"
+ }
+ }
+
+ case Login-User {
+ update reply {
+ Filter-Id := "Login-User"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
diff --git a/src/tests/keywords/switch-virtual b/src/tests/keywords/switch-virtual
new file mode 100644
index 0000000..659604d
--- /dev/null
+++ b/src/tests/keywords/switch-virtual
@@ -0,0 +1,23 @@
+#
+# PRE: update switch
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+#
+# Virtual attribute references get mashed to xlats
+#
+switch &Packet-Type {
+ case Access-Request {
+ update reply {
+ Filter-Id := "filter"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/switch-xlat-error b/src/tests/keywords/switch-xlat-error
new file mode 100644
index 0000000..d03f6d3
--- /dev/null
+++ b/src/tests/keywords/switch-xlat-error
@@ -0,0 +1,17 @@
+#
+# PRE: switch
+#
+switch &User-Name {
+ case "%{no-such-module:bob}" { # ERROR
+ update reply {
+ Filter-Id := "fail"
+ }
+ }
+
+ case {
+ update reply {
+ Filter-Id := "default"
+ }
+ }
+
+}
diff --git a/src/tests/keywords/truncation b/src/tests/keywords/truncation
new file mode 100644
index 0000000..8217e36
--- /dev/null
+++ b/src/tests/keywords/truncation
@@ -0,0 +1,109 @@
+# cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c <n>
+
+update reply {
+ Filter-Id := "filter"
+}
+
+# 8192 - 0x (2) - '' (2) there are unlikely to be any static buffers this big outside of the conffile parser
+update request {
+ Tmp-Octets-0 := '0x\
+d8abccb7834711af1de1812be2579febe946f5d7beef6fa5c7074c0cb917e9b91e23e14b016f27610097c16c0e0fad88176e077b24198c770746159\
+05b8810d1c8b774d98889fa5c6027cde5e9c56dd4f7c48298c7713aeca5ba5dcfd506032ad05b1396f50e825b633d5a6af0dce6181b640287e03a65\
+8734df46a86341556f28455b3f377313a5a2ac8c8267b8a5de559b95f9b493a68b9e0278485f9e3914d702b2b7b90ee85ff393461f197386d09b836\
+5a8ae85ea025aea095f5d834c2ddf21e9a16b945da03c97f8a52687f19c605af9a245878b4bc5ed15b7937371ad629081159cf7de613d02c43f5cab\
+3529abbe61a6da1e55c685c2310c8eccb452f9758bf63fddfa58cdffb5cbf912f90e628310978dd1b3b7c2d3a08dd7ca6ca51081a114b013cc9d4c1\
+9f5ce0b1af81166c9402c105019a0fa9d15996c4f3d5fa35226bf88166598ff4f619322866df276d8b92fad06d120470c29217d29abb96ff861751e\
+acebbe839e28287c8cd485769d9a09e5bab524bde5776e15037d19503a2d032658e21aec7090032707ba0d662fcfa99e5e5ec183f8c63c6022bf281\
+22cf090fb80263f70c523aa0e00dd9f610c5b669754092253edd6f83b57bdd7a251514cdd99ab86cfa98b11469d1d1118aba0a149db6f0ccceb2f17\
+06bf33f657c7b8547dc284dfc10fdc1678c184901aa17f756d18df43409e1c4ead239cb78c46a9c412ccb097bba2244bb680bb249c15004d796731f\
+3890c1f94d8e0eda81487da9a65f817b5dbac4e639fce063f61a7db87d8b9d4b855120f56c3a0d57cb61ced57092506da881337280a18b2729717f5\
+133978362ca7941f9dbe9462ae5a46886c4d3c51b633278d6ad58a331c95e481cbbae866f046cb1a59ae2545fa32b12d4772244fd24bb91f7611d0c\
+beffbc5dee309c671fb5a171eacf45b20641e1cb4db306965eb43e98cb900ee805065c7adf4db3cdb97bbf8116dbb29f5ac07c7041a5f02d1a4fd1f\
+a7be6da388146d6b80ae8e152ac873cbf1f88c98cdd2e1de02df76461a1c50139f558f43ac1a91824fc48ea35976fab29d412f1ad990e528893ad4c\
+b6045b63d2a7af0657f1c348302e674ef0b39bd689b3b33dd3664c3e2386d0ea3241e70d2a2990b6243638d68033cc6040758e11f82ef783db2ae94\
+d2a8dbccd25fe2dce554837a2ca424199e4bd5442215623a77bffd603b575c847f88763fff1d6d0ff314851b1af06f99fb44d0a3115ad4389462452\
+c2331be24d486f6b5f2224cdfe44909e0a3bec47cdf6fe49fa60518e37950f986677e7f45617adcb20bc02990d3fe60de54ad2d1950bdd423e752c4\
+60f4eeaf2eeece07f3dea26db63cc0bc222a6f3228131cdb3360b9ec7e8f861c3e0bc822f9da00fef17f44ab4de7c166e5cb07d5c671f0364d4bccb\
+dc7f24868e066998bc8b3ab9052171b967162d536082b0a11c24f263c0e5f656b8349f970124af712cf098e8b08910aefcf7d42dd8a74e84ae6f9c4\
+006aa09483715b514833291c9d2e2bcdda567a16a493ac4fa17d5dff7a04b9f7f967febe7a8bdf911b1b668716be73fbf6f2416609224494dca1a18\
+1c1c7bb298671d39bdc1f664c833c9d2d4c08a65866db885929611fcd0c33139bc2959a865cbb686694896b539daa1db265ba78298cb3a09a331ef0\
+1423a7fd04b38ccdfbf1182a493c7a53c720a2dcf486249ff2b674341e77c2c0d5eb78efc07f295d562a77667457df58ea419c488680b9ce51aac01\
+4cd78984f70f29aec2a9b77fd45d38e0b07257b71f2146ccb11cd07681cbfff787b39b7ce9c42ce60513eccec2b490c68378e86bd441735b30410be\
+8710e71b2a326bd8b929abde80f25a0adb312f8ed5bb748866ddd8fb5fa81855d194afbdb1d511be453e21ab3f6481e47fa86b0697342706f85b8e8\
+84c6bf427390ef4c62532797de25004bb9d293e196ed29950e14682c68a8b6ab7c03256bc493b61eb3e44dc16726fcedb6c6776e2e9e0b3450fe6c6\
+24eef42e4806ef7c8abc367b7f1c83b7955ff6579d03362b428ca7711d228cf88402b60fd162ef4819216b9db66b4a1b0a5e0651a7901290eafa3d5\
+c698e40f73b3d66345d9e328d50ef2c767d370879890980d0d989de122ab22d7ef9979832b022e676eba4630d49434ec70025b44cb7146f9688d102\
+ceb55e6ca8ee9b9a66327da80f46367f452de7e2a84bf702b155539c7fa488d86c83faf3f150fda6d75eb476e2c31d73cea88148d9f02d178b0c098\
+5b4061830231ca405fbf41547ed9c036f53fc706b0fd1bb084e84a9e6dec81b4b4eea46c5ea26e99993ee930ccfeff4a185ffbce8a937243fa4734b\
+c24abbf465b0cd1f87686d44762140b5dfe57ae904cd8ed121f055d8a1bbf9c8a977133215f135e563b935451a7f797e72ef8f96390bc2477ad7aac\
+d2679557bac3b9a030926ff0801cc692dd641cf4f8a7bd9bdee21cdab3f7fbcf7d1d0de51101c5d816b19db49109958a8e75662ac700653112cd86c\
+10cbf45d3ea16f861de2d46714dfba8a34c1ad7ed4d5484802270187c3c7f70f7a51858479d8504e3b6267194404011b416329401ec55940f890f33\
+97d4bb3eab46990a4a03cdae9951ccd0bd42584ec88262f7d80193f09843c1fca7627b9cf708c646e84883b19fe3a8987912d04f1c0d1c779b740a7\
+fea0270374416a3987dd91d706e22e8c9698ef870d7f80d1c3042914a34736c185e542976d0145531c8eb20c3a6c5a5f747e97228ff55425fd93222\
+2d802ca36ac61555f69be4d645532579ddadb24a821f0bab1fb1f3b724ed4759b5303fe0015626ad00879e1a363d5e8b3aa0b7f3e572df3dc5f7352\
+7eb30b78e70dbe6ca81052315925d3892485168dd6f900289d1a0f9285e52988480bfda6a2c8b28cbd175b4dec735240c8f79afd5c93ed058da5551\
+8f20fb09edf4b4112c352604876f4083b68e534874d0b9ce2f977be2bcea0f9c123e119a70d269bc26ece608c39c98dbb069118148b01e403c16076\
+330b5d7929a7a7d724a7030d514ff0e38bee78e0044ffa508fc9793d7fc59075fd825e68d34e58568bffd8b20791862a8d0686763e49f1e3ed8a728\
+e33bb32a57c6374d153f93ba3cd283ce0af9a0a3b0ced4f83e3d604ff66f6584a35b51938ff4a0282c51f6f8561bd77b842ed0fd39fc43be825652f\
+f2c021f2b4d2b8c8ed2cf8eeb16f86863e59b374eda5a17e1bfc0b5a54169dd3e62b84a81bc1afd5cc3a1b193484428bcc3afb5344da990697f6787\
+5f72bc1ab04f52f75bc671b8d1239fc811d44032822abc95f8ea3465cdabdce5f83d5895d50fcbd97ad88e6b193172a4cf5f51814d9348498b1736e\
+de25f8b5afc8556d3b9573cb2ae8f51e8f0bca2f048d883592c9ab317e87864d48ca901e2aa2774360c77ba3f0a76c21f10155e32e91a2239d00e6b\
+0279bbc8977fadbea04b7b67575437fd5f6611a8889ecbde5fe45fcab8db9b62e831aadcd0ade54a94d30b6963d727979c116ef9f4a9a16a0e7a76e\
+d4f1177ad0ac7022beb12581629a7fd36c8ca5eeaa40d1a0d88cb0f701b288baae6c00a74c0b0dc3ffa6e9710bf3264684c1b9ff220710b2348cc93\
+d658d9eddae36232a0d0e06439d5dafdc7271eafbb3d16a17e36de7470c7a5ed034d735e2c216073ba6b4be7b319718d5afbd634684f5468d26afd0\
+63edfbc7fe6c8e98914eff397fcfdf44a10b84ba90b30d1a5da6823aab1792d666b32bdd0516ce3590c5dc2b49a6eabdb28cdc72dbc24e60ba0883f\
+953f0a99d29c1089b06063588b8bd965ba42e27f618d2b046fb3db93161981bbcd67fc965b0084ac25993445732b52d18cd2868e6b545214a2d501a\
+0002d2043d9a9790905dde296f16517e295dd295a97991c205d50dba331e86f06b0195e52fdd21f8e65e6b00fe7165e1a951805e5947aaee125f180\
+a2127375d8898aba1af3a3db34470e78bed99917a6bb87725788c1e2c8f35d6022d51bafdc3e69673cbdd80dc9cfde7dc1bd06e3a6437c720cb7b6c\
+2b3bc808111593d5f2a88c6e5b499c51155f4ff0267606abcbfa03dc5e4c108e7f3d33989952df2f4f1476df8fe53eaa39d2338a87b6ccc91587a67\
+bc0da2f5667248ce969b91f1521c5bfda97c8f062b62d768a9d302f4a4bd0e67646c6666a9fea93749a65d06fdcd0168fe81edac542fc287503a592\
+61591a686b418ac2602e2464f6679ef7ecf5387af45e5fdd72224695e454d6676687b03a5858afe71dda7180a59ef2e1d8c81c4a9c8375e62c43711\
+cbd0e7d437a5913bc4d7e8fbb71f68e4805ad41bd624c06e84761dbda3014c1576a866c073ca32b37007884730ac9f831b95db8ce10f0db45e009d0\
+6e1ad8c96c340c98debee0dd0ca9e6694fe7a69306c15e6a7054cfd612e070f538c6ff0c1a34b257df10087b650da852a5b663a5795a335193dfe64\
+1950ea614ae05b0c202cedabd1ebe6da561e167fe81dd9fc190740a20db38f5356e61f8bed7b3db783a6b53e48f408a8b08f9f79738438a3ed0c4bc\
+f444d5922c76ff03c943a3c72c513047aa75caf51381b5c306fdbaedcd4001a2df456c3afef7559241f553dffac2dfd9ac94570e50c571329203bf0\
+38cbdac9bc76f896635356c402f2f5c105eb4e334f7792716e8e8883352870e949623f29bb8fac428bc858ec3297166afe358e1947b0c2337309315\
+062a040129f978b036657e9323550765cc4c14aaa4c24572eb17a0aa940ba336fd8fd385fb46b5b0c067c59ee42922d2702feb7b43d2ffef11cbdf0\
+1f11c92ac18197a387f0633fd19509b19c0b8a2f63983f6c0a6286593c84d5866ae8d91139b141e8bdf3b7ae7df7d92754186e545f4b600fbe69494\
+3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49fa69c9a5feac5376e07f52e64be9c873afca3ebf776fe9\
+fc813bd2e58c6d0dfd951570dbff4b5e73ce547cd100ab320b6944e887d611b3425bfcdf3bfa852ff5804119a1f69e33d624eda6f9e5d1fb2811f9f\
+9f5b3224d009e09621a8fcb524f89c6fcf38f7c933aa027de2b48aa9ddbfa55f56b383f06b8feef09e4709bc4fdcbab659bab4a277a2fbebb98970e\
+44bd68a61b264c695d8ae27a676e123b5fb60c7c4cbc88f24b6554dcfebfde607500f50ec85f589eaa4213ccaa237598660a66009bc56d55455487a\
+28fa24d62e50df57feab0d1c8ec77b1085002d922c52d4a3092f8693c3b9ba9725a4d225637350812b534e93209b414b4516642eca67490199a9217\
+614322972fa2fcc5c7fc2695e9b5762d442e2c7dd8403d14228aa90df58e2ffe1a3c9922f6c5d62649664b63c017fbf3859723e7e97ea6710097683\
+6408a97de3ad7d902c7be0296fb3d476de2460602f65eb7edacc2e4f49b1652fe8948f7afb1cc9f83f3283e6013304160cd2ac7c311c492133252a6\
+5ccf45c5af9c05a47905ac8bfe55f9b912c3fca856abe7863f87392b6f6b0069e3d8412a056b1034aaac506bf2ca51760aa180c5f43a751beb06e88\
+fc6afab4c5dd4aae4a2e6f0293c15278d557c2925acba90c73eeea09ebb95f0d469aa77ae983a0e69dacd55bd8a7e78a41df5227de35af05127fa3b\
+a02f4a3ab98d75992d68a15d393387fe9ef01041569570ad6fe884764e55567311bcacfcffae76554dcfebfde607500f50ec85f589eaade607500f5\
+3ae4bcef324b9a3f47ba5c835b54a010ca42f3b9cc5368278c148c9b02ea8c4c9f244fd49fab'
+}
+
+# Actual length of octet string is 4084 bytes
+update request {
+ Tmp-Integer-0 := "%{length:Tmp-Octets-0}"
+}
+
+if (Tmp-Integer-0 != 4084) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+# Octets are expanded to 8168 hexits
+if ("%{Tmp-Octets-0}" !~ /^0x([0-9a-f]+)$/) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{1}"
+}
+
+if ("%{length:Tmp-String-0}" != 8168) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+# We can't do any more until all the xlat code uses dynamically allocated buffers
diff --git a/src/tests/keywords/unknown b/src/tests/keywords/unknown
new file mode 100644
index 0000000..eb96591
--- /dev/null
+++ b/src/tests/keywords/unknown
@@ -0,0 +1,84 @@
+#
+# PRE: wimax
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+update request {
+ FreeRADIUS-Proxied-To := 127.0.0.2
+}
+
+#
+# Check that a known but malformed attr is malformed
+#
+update request {
+ Attr-26.24757.84.9.5.7 = 0xab
+}
+
+if (&Attr-26.24757.84.9.5.7 != 0xab) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+#
+# Check that an unknown attr is OK
+#
+update request {
+ Attr-26.24757.84.9.5.15 = 0xabcdef
+}
+
+if (&Attr-26.24757.84.9.5.15 != 0xabcdef) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+#
+# Check that unknown attributes which are defined
+# get automatically resolved to the real attribute.
+#
+if (&Vendor-11344-Attr-1 == 127.0.0.1) {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if (&Vendor-11344-Attr-1 != 127.0.0.2) {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
+
+update request {
+ &Vendor-11344-Attr-1 := 127.0.0.1
+}
+
+if (&FreeRADIUS-Proxied-To == 127.0.0.2) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+if (&FreeRADIUS-Proxied-To != 127.0.0.1) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+if (&Vendor-11344-Attr-1 == 127.0.0.2) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+if (&Vendor-11344-Attr-1 != 127.0.0.1) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
diff --git a/src/tests/keywords/unknown-if b/src/tests/keywords/unknown-if
new file mode 100644
index 0000000..3dccbff
--- /dev/null
+++ b/src/tests/keywords/unknown-if
@@ -0,0 +1,8 @@
+#
+# PRE: unknown-update
+#
+if (&This-Does-Not-Exist == 1) { # ERROR
+ update reply {
+ Filter-Id := "fail"
+ }
+}
diff --git a/src/tests/keywords/unknown-name b/src/tests/keywords/unknown-name
new file mode 100644
index 0000000..5a99ac9
--- /dev/null
+++ b/src/tests/keywords/unknown-name
@@ -0,0 +1,15 @@
+#
+# PRE: update unknown
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+#
+# This delayed binding should result in a parse error
+#
+if (&User-Name == &Foo-Bar-Baz) { # ERROR
+ update reply {
+ Filter-Id += "fail-2"
+ }
+}
diff --git a/src/tests/keywords/unknown-update b/src/tests/keywords/unknown-update
new file mode 100644
index 0000000..1403879
--- /dev/null
+++ b/src/tests/keywords/unknown-update
@@ -0,0 +1,6 @@
+#
+# PRE: update unknown
+#
+update control {
+ This-Does-Not-Exist = 1 # ERROR
+}
diff --git a/src/tests/keywords/update b/src/tests/keywords/update
new file mode 100644
index 0000000..97a2557
--- /dev/null
+++ b/src/tests/keywords/update
@@ -0,0 +1,7 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/update-add-ref-index b/src/tests/keywords/update-add-ref-index
new file mode 100644
index 0000000..7f5e74a
--- /dev/null
+++ b/src/tests/keywords/update-add-ref-index
@@ -0,0 +1,118 @@
+#
+# PRE: update array
+#
+
+update request {
+ reply:Filter-Id := "filter"
+ Class := 0x01020304
+ Class += 0x05060708
+ Class += 0x090a0b0c
+}
+
+#
+# Copy all the class attributes to Proxy-State
+#
+update request {
+ Proxy-State += &Class[*]
+}
+
+if (&Proxy-State[0] != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 0a"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[1] != 0x05060708) {
+ update reply {
+ Filter-Id += "fail 0b"
+ }
+}
+
+if (&Proxy-State[2] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 0c"
+ }
+}
+
+# must not exist
+if (&Proxy-State[3]) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+# Remove all the Proxy-State attributes
+update request {
+ Proxy-State !* ANY
+}
+
+#
+# Copy the first instance (implicitly) of class
+#
+update request {
+ Proxy-State += &Class
+}
+
+if (&Proxy-State[0] != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 2a"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[1]) {
+ update reply {
+ Filter-Id += "fail 2b"
+ }
+}
+
+# Remove all the Proxy-State attributes
+update request {
+ Proxy-State !* ANY
+}
+
+#
+# Copy the first instance (explicitly) of class
+#
+update request {
+ Proxy-State += &Class[0]
+}
+
+if (&Proxy-State[0] != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 3a"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[1]) {
+ update reply {
+ Filter-Id += "fail 3b"
+ }
+}
+
+# Remove all the Proxy-State attributes
+update request {
+ Proxy-State !* ANY
+}
+
+#
+# Copy the second instance of class
+#
+update request {
+ Proxy-State += &Class[1]
+}
+
+if (&Proxy-State[0] != 0x05060708) {
+ update reply {
+ Filter-Id := "fail 4a"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[1]) {
+ update reply {
+ Filter-Id += "fail 4b"
+ }
+}
diff --git a/src/tests/keywords/update-add-ref-tag b/src/tests/keywords/update-add-ref-tag
new file mode 100644
index 0000000..39800b8
--- /dev/null
+++ b/src/tests/keywords/update-add-ref-tag
@@ -0,0 +1,118 @@
+#
+# PRE: update array
+#
+
+update request {
+ reply:Filter-Id := "filter"
+ request:Tunnel-Server-Endpoint += '192.0.1.1'
+ request:Tunnel-Server-Endpoint += '192.0.1.2'
+ request:Tunnel-Server-Endpoint:1 += '192.0.1.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.2'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.1'
+}
+
+#
+# Copy all Tunnel-Server-Endpoint attributes
+#
+update request {
+ control:Tunnel-Server-Endpoint += &Tunnel-Server-Endpoint[*]
+}
+
+if ((&control:Tunnel-Server-Endpoint[0] != '192.0.1.1') || \
+ (&control:Tunnel-Server-Endpoint[1] != '192.0.1.2') || \
+ (&control:Tunnel-Server-Endpoint[2] != '192.0.1.1') || \
+ (&control:Tunnel-Server-Endpoint[3] != '192.0.2.1') || \
+ (&control:Tunnel-Server-Endpoint[4] != '192.0.2.2') || \
+ (&control:Tunnel-Server-Endpoint[5] != '192.0.3.1') || \
+ &control:Tunnel-Server-Endpoint[6]) {
+ update reply {
+ Filter-Id := "fail 0"
+ }
+}
+
+#
+# Clear out control attributes...
+#
+update control {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+#
+# Copy all Tunnel-Server-Endpoint attributes with tag 2
+#
+update request {
+ control:Tunnel-Server-Endpoint += &Tunnel-Server-Endpoint:2[*]
+}
+
+if ((&control:Tunnel-Server-Endpoint[0] != '192.0.2.1') || \
+ (&control:Tunnel-Server-Endpoint[1] != '192.0.2.2') || \
+ &control:Tunnel-Server-Endpoint[2]) {
+ update reply {
+ Filter-Id := "fail 1"
+ }
+}
+
+#
+# Clear out control attributes...
+#
+update control {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+#
+# Copy all Tunnel-Server-Endpoint attributes with no tag
+#
+update request {
+ control:Tunnel-Server-Endpoint += &Tunnel-Server-Endpoint:0[*]
+}
+
+if ((&control:Tunnel-Server-Endpoint[0] != '192.0.1.1') || \
+ (&control:Tunnel-Server-Endpoint[1] != '192.0.1.2') || \
+ &control:Tunnel-Server-Endpoint[2]) {
+ update reply {
+ Filter-Id := "fail 2"
+ }
+}
+
+#
+# Clear out control attributes...
+#
+update control {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+#
+# Copy the first attribute with tag 2 (implicit)
+#
+update request {
+ control:Tunnel-Server-Endpoint += &Tunnel-Server-Endpoint:2
+}
+
+if ((&control:Tunnel-Server-Endpoint[0] != '192.0.2.1') || \
+ &control:Tunnel-Server-Endpoint[1]) {
+ update reply {
+ Filter-Id := "fail 3"
+ }
+}
+
+#
+# Clear out control attributes...
+#
+update control {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+#
+# Copy the first attribute with tag 2 (explicit)
+#
+update request {
+ control:Tunnel-Server-Endpoint += &Tunnel-Server-Endpoint:2[0]
+}
+
+if ((&control:Tunnel-Server-Endpoint[0] != '192.0.2.1') || \
+ &control:Tunnel-Server-Endpoint[1]) {
+ update reply {
+ Filter-Id := "fail 4"
+ }
+}
diff --git a/src/tests/keywords/update-all b/src/tests/keywords/update-all
new file mode 100644
index 0000000..549a122
--- /dev/null
+++ b/src/tests/keywords/update-all
@@ -0,0 +1,9 @@
+#
+# PRE: update
+#
+# A more generic "update" mechanism
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/update-array b/src/tests/keywords/update-array
new file mode 100644
index 0000000..c872f4e
--- /dev/null
+++ b/src/tests/keywords/update-array
@@ -0,0 +1,63 @@
+#
+# PRE: update array
+#
+
+update request {
+ Class := 0x01020304
+ Class += 0x05060708
+ Class += 0x090a0b0c
+}
+
+
+#
+# Use array references in the RHS
+# of the update section
+#
+
+update request {
+ Proxy-State += &Class[0]
+ Proxy-State += &Class[1]
+ Proxy-State += &Class[2]
+}
+
+if (&Proxy-State != 0x01020304) {
+ update reply {
+ Filter-Id := "fail 0"
+ }
+}
+
+# Must be the same as above
+if (&Proxy-State[0] != 0x01020304) {
+ update reply {
+ Filter-Id += "fail 0a"
+ }
+}
+
+if (&Proxy-State[1] != 0x05060708) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if (&Proxy-State[2] != 0x090a0b0c) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+# must not exist
+if (&Proxy-State[3]) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+#
+# The test passes only if no test above
+# added a Filter-Id
+#
+if (!reply:Filter-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/update-delete b/src/tests/keywords/update-delete
new file mode 100644
index 0000000..a5c2d5a
--- /dev/null
+++ b/src/tests/keywords/update-delete
@@ -0,0 +1,40 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-String-0 := 'foobarbaz'
+ Tmp-Integer-0 := 123456789
+ Tmp-IP-Address-0 := 192.0.2.1
+}
+
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789) || (Tmp-IP-Address-0 != 192.0.2.1)) {
+ update {
+ reply:Filter-Id := 'fail'
+ }
+}
+
+# Remove all attributes in the control list
+update {
+ request: !* ANY
+}
+
+# All attributes should now of been removed
+if ((Tmp-String-0 && (Tmp-String-0 == 'foobarbaz')) || \
+ (Tmp-Integer-0 && (Tmp-Integer-0 == 123456789)) || \
+ (Tmp-IP-Address-0 && (Tmp-IP-Address-0 == 192.0.2.1))) {
+ update {
+ reply:Filter-Id := 'fail'
+ }
+}
+
+# This will of been removed too
+update request {
+ User-Password := 'hello'
+}
diff --git a/src/tests/keywords/update-error b/src/tests/keywords/update-error
new file mode 100644
index 0000000..92e0ed2
--- /dev/null
+++ b/src/tests/keywords/update-error
@@ -0,0 +1,9 @@
+#
+# PRE: update
+#
+# It's an error to update lists that don't exist.
+#
+update no-such-list { # ERROR
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/update-error-2 b/src/tests/keywords/update-error-2
new file mode 100644
index 0000000..1fe98f0
--- /dev/null
+++ b/src/tests/keywords/update-error-2
@@ -0,0 +1,9 @@
+#
+# PRE: update-error
+#
+# It's an error to update lists that don't exist.
+#
+update {
+ no-such-list:Cleartext-Password := 'hello' # ERROR
+ reply:Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/update-error-3 b/src/tests/keywords/update-error-3
new file mode 100644
index 0000000..ffab73a
--- /dev/null
+++ b/src/tests/keywords/update-error-3
@@ -0,0 +1,10 @@
+#
+# PRE: update-error
+#
+# It's an error to assign literal values which are not
+# part of the set of enumerated values for an attribute
+#
+update {
+ Service-Type := 'hello' # ERROR
+ reply:Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/update-exec b/src/tests/keywords/update-exec
new file mode 100644
index 0000000..b9a0f73
--- /dev/null
+++ b/src/tests/keywords/update-exec
@@ -0,0 +1,94 @@
+#
+# PRE: update if redundant
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
+
+#
+# Exec with script output to attribute
+#
+update request {
+ Tmp-String-0 = `/bin/sh -c "echo 'foo bar baz'"`
+}
+
+if (Tmp-String-0 != "foo bar baz") {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+#
+# Exec with output to list (single attribute)
+#
+update {
+ request: = `/bin/sh -c "echo Tmp-String-0 := foo"`
+}
+
+if (Tmp-String-0 != 'foo') {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+#
+# Exec with output to list (multiple attributes)
+#
+update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo, Tmp-String-1 := bar'`
+}
+
+if ((Tmp-String-0 != 'foo') || (Tmp-String-1 != 'bar')) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+#
+# Failed exec (malformed attributes) - check no attributes are added
+#
+update request {
+ Tmp-String-0 !* ANY
+ Tmp-String-1 !* ANY
+}
+
+redundant {
+ group {
+ update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo, Tmp-String-1 ?= bar'`
+ }
+ }
+ ok
+}
+if (Tmp-String-0 || Tmp-String-1) {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+#
+# Exec with output to list - error code
+#
+update request {
+ Tmp-String-0 !* ANY
+ Tmp-String-1 !* ANY
+}
+
+redundant {
+ group {
+ update {
+ request: = `/bin/sh -c 'echo Tmp-String-0 := foo; exit 64'`
+ }
+ }
+ ok
+}
+if (Tmp-String-0) {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
+
diff --git a/src/tests/keywords/update-filter b/src/tests/keywords/update-filter
new file mode 100644
index 0000000..30f96be
--- /dev/null
+++ b/src/tests/keywords/update-filter
@@ -0,0 +1,75 @@
+#
+# PRE: update
+#
+update control {
+ Tmp-Integer-0 := 5
+ Tmp-Integer-0 += 10
+ Tmp-Integer-0 += 15
+ Tmp-Integer-0 += 20
+ Tmp-String-0 := 'foo'
+ Tmp-String-0 += 'baz'
+ Tmp-String-0 += 'boink'
+}
+
+#
+# Reset the request list
+#
+update {
+ &request: !* ANY
+ &request: += &control:[*]
+}
+
+debug_request
+
+#
+# Only matching attributes of the specified type should remain
+#
+update request {
+ &Tmp-Integer-0 == 10
+}
+
+if (&Tmp-Integer-0[0] != 10) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if ("%{Tmp-Integer-0[#]}" != 1) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+if ("%{Tmp-String-0[#]}" != 3) {
+ update reply {
+ Filter-Id += "fail 3"
+ }
+}
+
+debug_request
+
+#
+# Only matching attributes of the specified type should remain
+#
+update request {
+ &Tmp-String-0 == 'baz'
+}
+
+if (&Tmp-String-0[0] != 'baz') {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+if ("%{Tmp-String-0[#]}" != 1) {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
+
+update {
+ control:Auth-Type := Accept
+ reply:Filter-Id := "filter"
+}
+
+debug_request
diff --git a/src/tests/keywords/update-index b/src/tests/keywords/update-index
new file mode 100644
index 0000000..390aca7
--- /dev/null
+++ b/src/tests/keywords/update-index
@@ -0,0 +1,52 @@
+#
+# PRE: update update-remove-index
+#
+# A more generic "update" mechanism
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := "filter"
+}
+
+update {
+ control:Reply-Message += 'a'
+ control:Reply-Message += 'b'
+ control:Reply-Message += 'c'
+}
+
+if ((&control:Reply-Message[0] != 'a') || (&control:Reply-Message[1] != 'b') || (&control:Reply-Message[2] != 'c')) {
+ update {
+ reply:Filter-Id := 'Fail 0'
+ }
+}
+
+# Overwrite a specific index, and check the value here is replaced
+update {
+ &control:Reply-Message[1] := 'd'
+}
+
+if ((&control:Reply-Message[0] != 'a') || (&control:Reply-Message[1] != 'd') || (&control:Reply-Message[2] != 'c')) {
+ update {
+ reply:Filter-Id := 'Fail 1'
+ }
+}
+
+# Check isolation...
+update {
+ &control:Reply-Message[0] := &control:Reply-Message[0]
+}
+
+if ((&control:Reply-Message[0] != 'a') || (&control:Reply-Message[1] != 'd') || (&control:Reply-Message[2] != 'c')) {
+ update {
+ reply:Filter-Id := 'Fail 2'
+ }
+}
+
+# Verify we haven't acquired any extra..
+
+if ("%{control:Reply-Message[#]}" != 3) {
+ update {
+ reply:Filter-Id := 'Fail 3'
+ }
+}
+
diff --git a/src/tests/keywords/update-list-error b/src/tests/keywords/update-list-error
new file mode 100644
index 0000000..2613055
--- /dev/null
+++ b/src/tests/keywords/update-list-error
@@ -0,0 +1,19 @@
+#
+# PRE: update
+#
+# It's an error to update lists that don't exist.
+#
+update {
+ request := reply
+ config += request
+ reply !* ANY
+}
+
+update {
+ reply += `/path/to/foo bar baz`
+}
+
+
+update {
+ request := nope # ERROR
+}
diff --git a/src/tests/keywords/update-operator b/src/tests/keywords/update-operator
new file mode 100644
index 0000000..ccbcb16
--- /dev/null
+++ b/src/tests/keywords/update-operator
@@ -0,0 +1,85 @@
+#
+# PRE: update
+#
+
+#
+# Set it.
+#
+update request {
+ NAS-Port := 1000
+}
+
+#
+# Enforce it.
+#
+update request {
+ NAS-Port == 1000
+}
+
+if (NAS-Port != 1000) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+#
+# Enforce to new lower value.
+#
+update request {
+ NAS-Port <= 500
+}
+
+if (NAS-Port != 500) {
+ update reply {
+ Filter-Id += "fail 2 - expected 500, got %{NAS-Port}"
+ }
+}
+
+#
+# Enforce to new higher value
+#
+update request {
+ NAS-Port >= 2000
+}
+
+if (NAS-Port != 2000) {
+ update reply {
+ Filter-Id += "fail 3 - expected 2000, got %{NAS-Port}"
+ }
+}
+
+#
+# Enforce value which previously didn't exist.
+#
+update request {
+ Idle-Timeout >= 14400
+}
+
+if (&request:Idle-Timeout != 14400) {
+ update reply {
+ Filter-Id += "fail Idle-Timeout >= 14400"
+ }
+}
+
+# non-existent attribute
+update request {
+ Class -= 0xabcdef
+}
+
+update request {
+ Class -= &Class
+}
+
+update request {
+ NAS-Port -= &NAS-Port
+}
+
+if (!reply:Filter-Id) {
+ update control {
+ Cleartext-Password := 'hello'
+ }
+
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/update-prepend b/src/tests/keywords/update-prepend
new file mode 100644
index 0000000..4ba9335
--- /dev/null
+++ b/src/tests/keywords/update-prepend
@@ -0,0 +1,65 @@
+#
+# PRE: update
+#
+update control {
+ &Tmp-String-0 := 'foo'
+ &Tmp-String-0 += 'baz'
+}
+
+# Reset the request list
+update {
+ &request !* ANY
+ &request += &control
+}
+
+debug_request
+
+# Prepend a single value
+update request {
+ &Tmp-String-0 ^= 'boink'
+}
+
+# The prepended value should be first followd by the other two
+if (("%{Tmp-String-0[0]}" != 'boink') || ("%{Tmp-String-0[1]}" != 'foo') || ("%{Tmp-String-0[2]}" != 'baz')) {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if ("%{Tmp-String-0[#]}" != 3) {
+ update reply {
+ Filter-Id += "fail 1a"
+ }
+}
+
+# Add an extra element to the start of control
+update control {
+ &Tmp-String-0 ^= 'wibble'
+}
+
+# Prepend control to request
+update {
+ &request ^= &control
+}
+
+debug_request
+
+# The attributes should now be "wibble", "foo", "baz", "boink", "foo", "baz"
+if (("%{Tmp-String-0[0]}" != 'wibble') || ("%{Tmp-String-0[1]}" != 'foo') || ("%{Tmp-String-0[2]}" != 'baz') || ("%{Tmp-String-0[3]}" != 'boink') || ("%{Tmp-String-0[4]}" != 'foo') || ("%{Tmp-String-0[5]}" != 'baz')) {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+if ("%{Tmp-String-0[#]}" != 6) {
+ update reply {
+ Filter-Id += "fail 2a"
+ }
+}
+
+if (!reply:Filter-Id) {
+ update {
+ &request:User-Password := 'hello'
+ &reply:Filter-Id := 'filter'
+ }
+}
diff --git a/src/tests/keywords/update-remove-any b/src/tests/keywords/update-remove-any
new file mode 100644
index 0000000..e0ef600
--- /dev/null
+++ b/src/tests/keywords/update-remove-any
@@ -0,0 +1,50 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ control:Tmp-IP-Address-0 := 192.0.2.1
+ control:Tmp-IP-Address-0 += 192.0.2.3
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id := 'fail 1'
+ }
+}
+
+# Remove all attributes in the control list
+update {
+ request:Tmp-IP-Address-0 !* ANY
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+# There should be no Tmp-IP-Address attributes in the request list
+if (Tmp-IP-Address-0 || ("%{Tmp-IP-Address-0[1]}" != '')) {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+# But there should still be some in the control list
+if ((control:Tmp-IP-Address-0 != 192.0.2.1) || ("%{control:Tmp-IP-Address-0[1]}" != 192.0.2.3)) {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
diff --git a/src/tests/keywords/update-remove-index b/src/tests/keywords/update-remove-index
new file mode 100644
index 0000000..58df9a5
--- /dev/null
+++ b/src/tests/keywords/update-remove-index
@@ -0,0 +1,100 @@
+#
+# PRE: update update-remove-value
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.3
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.4
+}
+
+
+update request {
+ Tmp-IP-Address-0[3] -= 192.0.2.2
+}
+
+# Only the 1st, 2nd, 3rd and 5th Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.1') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[3]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[4]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# There's still a 192.0.2.2 but it's not at index 3
+update request {
+ Tmp-IP-Address-0[3] -= 192.0.2.2
+}
+
+# Should be the same as the previous result
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.1') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[3]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[4]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Remove whatever's at index 0
+update request {
+ Tmp-IP-Address-0[0] !* ANY
+}
+
+# IP address at index 0 should be removed
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Remove whatever's at index 3 (should be nothing)
+update request {
+ Tmp-IP-Address-0[3] !* ANY
+}
+
+# Should be the same as the previous result
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Remove all instances of Tmp-IP-Address
+update request {
+ Tmp-IP-Address-0 !* ANY
+}
+
+# No more IP address attributes!
+if ("%{Tmp-IP-Address-0[0]}" != '') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
diff --git a/src/tests/keywords/update-remove-list b/src/tests/keywords/update-remove-list
new file mode 100644
index 0000000..22ae577
--- /dev/null
+++ b/src/tests/keywords/update-remove-list
@@ -0,0 +1,40 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-String-0 := 'foobarbaz'
+ Tmp-Integer-0 := 123456789
+ Tmp-IP-Address-0 := 192.0.2.1
+}
+
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789) || (Tmp-IP-Address-0 != 192.0.2.1)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Remove all attributes in the control list
+update {
+ request: !* ANY
+}
+
+# All attributes should now of been removed
+if ((Tmp-String-0 && (Tmp-String-0 == 'foobarbaz')) || \
+ (Tmp-Integer-0 && (Tmp-Integer-0 == 123456789)) || \
+ (Tmp-IP-Address-0 && (Tmp-IP-Address-0 == 192.0.2.1))) {
+ update reply {
+ Filter-Id := 'fail 1'
+ }
+}
+
+# This will of been removed too
+update request {
+ User-Password := 'hello'
+}
diff --git a/src/tests/keywords/update-remove-tag b/src/tests/keywords/update-remove-tag
new file mode 100644
index 0000000..3328789
--- /dev/null
+++ b/src/tests/keywords/update-remove-tag
@@ -0,0 +1,275 @@
+#
+# PRE: update update-remove-value update-remove-index update-tag
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tunnel-Server-Endpoint += '192.0.1.1'
+ request:Tunnel-Server-Endpoint += '192.0.1.2'
+ request:Tunnel-Server-Endpoint:1 += '192.0.1.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.1'
+ request:Tunnel-Server-Endpoint:2 += '192.0.2.2'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.1'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.2'
+ request:Tunnel-Server-Endpoint:3 += '192.0.3.3'
+ control: += request:
+}
+
+# Check [#] is working correctly (should probably be another set of tests)
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 8) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+update {
+ Tunnel-Server-Endpoint !* ANY
+}
+
+# List should now be empty
+if ("%{request:Tunnel-Server-Endpoint[#]}" != 0) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Reset the list
+update {
+ request: += control:
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :2
+update {
+ Tunnel-Server-Endpoint:2 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 6) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 2) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :0 (no tags)
+update {
+ Tunnel-Server-Endpoint:0 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 4) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 3)) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :3
+update {
+ Tunnel-Server-Endpoint:3 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 1) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 0)) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Now remove all Tunnel-Server-Endpoint attributes with :1
+update {
+ Tunnel-Server-Endpoint:1 !* ANY
+}
+
+if (("%{request:Tunnel-Server-Endpoint[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:0[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:1[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:2[#]}" != 0) || \
+ ("%{request:Tunnel-Server-Endpoint:3[#]}" != 0)) {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Reset the list
+update {
+ request: += control:
+}
+
+# Remove all Tunnel-Server-Endpoint attributes at :3[0] (none)
+update {
+ Tunnel-Server-Endpoint:1[3] !* ANY
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.2') {
+ update reply {
+ Filter-Id += 'fail 7'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[2] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 8'
+ }
+}
+
+# Remove all Tunnel-Server-Endpoint attributes at :3[1]
+update {
+ Tunnel-Server-Endpoint:3[1] !* ANY
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 9'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 10'
+ }
+}
+
+# Remove any Tunnel-Server-Endpoint with a value of '192.0.1.1' (should remove both tagged and untagged versions)
+update {
+ Tunnel-Server-Endpoint -= '192.0.1.1'
+}
+
+# Also checks whether presence checks for tagged attributes work correctly
+if (request:Tunnel-Server-Endpoint:1) {
+ update reply {
+ Filter-Id += 'fail 11'
+ }
+}
+
+if (request:Tunnel-Server-Endpoint:0[0] != '192.0.1.2') {
+ update reply {
+ Filter-Id += 'fail 12'
+ }
+}
+
+# Remove any Tunnel-Server-Endpoint with a value of '192.0.3.1'
+update {
+ Tunnel-Server-Endpoint:3 -= '192.0.3.2'
+}
+
+if (request:Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 13'
+ }
+}
+
+if (request:Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 14'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove only the tagged version of '192.0.1.1'
+update {
+ request:Tunnel-Server-Endpoint:1 -= '192.0.1.1'
+}
+
+if (request:Tunnel-Server-Endpoint:0[0] != '192.0.1.1') {
+ update reply {
+ Filter-Id += 'fail 15'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove only the untagged version of '192.0.1.1'
+update {
+ request:Tunnel-Server-Endpoint:0 -= '192.0.1.1'
+}
+
+if (request:Tunnel-Server-Endpoint:1[0] != '192.0.1.1') {
+ update reply {
+ Filter-Id += 'fail 16'
+ }
+}
+
+# Remove the value of Tunnel-Server-Endpoint:3 at index 1 only if it matches '192.0.3.3' (which it does)
+update {
+ Tunnel-Server-Endpoint:3[1] -= '192.0.3.2'
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 17'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 18'
+ }
+}
+
+# Reset the list
+update {
+ request: !* ANY
+}
+update {
+ request: += control:
+}
+
+# Remove the value of Tunnel-Server-Endpoint:3 at index 1 only if it matches '192.0.3.4' (which it doesn't)
+update {
+ Tunnel-Server-Endpoint:3[1] -= '192.0.3.4'
+}
+
+if (Tunnel-Server-Endpoint:3[0] != '192.0.3.1') {
+ update reply {
+ Filter-Id += 'fail 19'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[1] != '192.0.3.2') {
+ update reply {
+ Filter-Id += 'fail 20'
+ }
+}
+
+if (Tunnel-Server-Endpoint:3[2] != '192.0.3.3') {
+ update reply {
+ Filter-Id += 'fail 21'
+ }
+}
+
diff --git a/src/tests/keywords/update-remove-value b/src/tests/keywords/update-remove-value
new file mode 100644
index 0000000..3fd1f94
--- /dev/null
+++ b/src/tests/keywords/update-remove-value
@@ -0,0 +1,116 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update {
+ request:Tmp-String-0 := 'foobarbaz'
+ request:Tmp-Integer-0 := 123456789
+ request:Tmp-IP-Address-0 := 192.0.2.1
+ request:Tmp-IP-Address-0 += 192.0.2.2
+ request:Tmp-IP-Address-0 += 192.0.2.3
+ request:Tmp-IP-Address-0 += 192.0.2.4
+ control:Tmp-IP-Address-0 := 192.0.2.1
+ control:Tmp-IP-Address-0 += 192.0.2.3
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || \
+ ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2) || \
+ ("%{Tmp-IP-Address-0[2]}" != 192.0.2.3) || \
+ ("%{Tmp-IP-Address-0[3]}" != 192.0.2.4)) {
+ update reply {
+ Filter-Id += 'fail 0'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.1
+}
+
+# Only the 2nd, 3rd and 4th Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.3') || \
+ ("%{Tmp-IP-Address-0[2]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[3]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 1'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value (somewhere in the middle)
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.3
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[2]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 2'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value (which doesn't exist)
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.3
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '192.0.2.4') || \
+ ("%{Tmp-IP-Address-0[2]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 3'
+ }
+}
+
+# Remove Tmp-IP-Address-4 (which doesn't exist - more to check for SEGV/assert)
+update {
+ request:Tmp-IP-Address-4 -= 192.0.2.3
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.4
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if (("%{Tmp-IP-Address-0[0]}" != '192.0.2.2') || \
+ ("%{Tmp-IP-Address-0[1]}" != '')) {
+ update reply {
+ Filter-Id += 'fail 4'
+ }
+}
+
+# Remove Tmp-IP-Address-0 with a specific value
+update {
+ request:Tmp-IP-Address-0 -= 192.0.2.2
+}
+
+# Only the 1st, and 3rd Tmp-IP-Address attributes should still be in the list
+if ("%{Tmp-IP-Address-0[0]}" != '') {
+ update reply {
+ Filter-Id += 'fail 5'
+ }
+}
+
+# Non Tmp-IP-Address-0 address attributes should still be in the request list
+if ((Tmp-String-0 != 'foobarbaz') || (Tmp-Integer-0 != 123456789)) {
+ update reply {
+ Filter-Id += 'fail 6'
+ }
+}
+
+# But there should still be some in the control list
+if (("%{control:Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{control:Tmp-IP-Address-0[1]}" != 192.0.2.3)) {
+ update {
+ Filter-Id += 'fail 7'
+ }
+}
diff --git a/src/tests/keywords/update-tag b/src/tests/keywords/update-tag
new file mode 100644
index 0000000..15afd59
--- /dev/null
+++ b/src/tests/keywords/update-tag
@@ -0,0 +1,176 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tunnel-Server-Endpoint:0 := '192.0.1.1' # Should not be tagged
+ Tunnel-Server-Endpoint:0 += '192.0.1.2' # Should not be tagged
+ Tunnel-Server-Endpoint:1 := '192.0.2.1'
+ Tunnel-Server-Endpoint:1 += '192.0.2.2'
+ Tunnel-Server-Endpoint:2 := '192.0.3.1'
+ Tunnel-Server-Endpoint:2 += '192.0.3.2'
+}
+
+update request {
+ Tmp-Integer-0 := "%{debug_attr:request:}"
+}
+
+
+#
+# Selecting on attributes which have no tag (0)
+#
+if (Tunnel-Server-Endpoint:0[0] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if (Tunnel-Server-Endpoint:0[1] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+#
+# Selecting on attributes with no tag specified (should match all of that type)
+#
+if (Tunnel-Server-Endpoint[0] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+if (Tunnel-Server-Endpoint[1] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+if (Tunnel-Server-Endpoint[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 5'
+ }
+}
+
+#
+# Now the none xlat version
+#
+# Check that access attributes by tag works first
+if (Tunnel-Server-Endpoint:2 != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 6'
+ }
+}
+
+if (Tunnel-Server-Endpoint:2 == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 7'
+ }
+}
+
+if (Tunnel-Server-Endpoint:1 != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 8'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tunnel-Server-Endpoint:2[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 9'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tunnel-Server-Endpoint:2[1] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 10'
+ }
+}
+
+#
+# Assignment (bare)
+#
+update request {
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2 # 0
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2 # 1
+ Tmp-String-1 += &Tunnel-Server-Endpoint:1 # 2
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2[0] # 3
+ Tmp-String-1 += &Tunnel-Server-Endpoint:2[1] # 4
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[0] # 5
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[1] # 6
+ Tmp-String-1 += &Tunnel-Server-Endpoint:0[2] # 7 (No attribute should be added here)
+ Tmp-String-1 += &Tunnel-Server-Endpoint[0] # 8
+ Tmp-String-1 += &Tunnel-Server-Endpoint[1] # 9
+ Tmp-String-1 += &Tunnel-Server-Endpoint[2] # 10
+}
+
+# Check that access attributes by tag works first
+if (Tmp-String-1[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 11'
+ }
+}
+
+if (Tmp-String-1[1] == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 12'
+ }
+}
+
+if (Tmp-String-1[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 13'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-1[3] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 14'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-1[4] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 15'
+ }
+}
+
+# Now check the assignment
+if (Tmp-String-1[5] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 16'
+ }
+}
+
+if (Tmp-String-1[6] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 17'
+ }
+}
+
+if (Tmp-String-1[7] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 19'
+ }
+}
+
+if (Tmp-String-1[8] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 20'
+ }
+}
+
+if (Tmp-String-1[9] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 21'
+ }
+}
diff --git a/src/tests/keywords/update-xlat b/src/tests/keywords/update-xlat
new file mode 100644
index 0000000..59230dc
--- /dev/null
+++ b/src/tests/keywords/update-xlat
@@ -0,0 +1,61 @@
+#
+# PRE: update
+#
+# Form attribute references with xlats
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+
+update request {
+ Tmp-String-0 := 'Tmp-String-1'
+}
+
+#
+# Shouldn't update Tmp-String-0, should instead update Tmp-String-1
+# ... maybe this is what Alan meant when he was talking about people
+# doing stupid things with this feature.
+#
+update request {
+ "%{Tmp-String-0}" := 'hello'
+}
+
+if (&Tmp-String-1 != 'hello') {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if (&Tmp-String-0 == 'hello') {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+#
+# Try updating an attribute specified by an OID string
+#
+update {
+ Tmp-Integer-0 := 11344
+}
+update {
+ "Vendor-%{Tmp-Integer-0}-Attr-1" := 127.0.0.1
+}
+
+if (&FreeRADIUS-Proxied-To != 127.0.0.1) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+update {
+ "Attr-%{attr_num:Tmp-String-1}" := 'hello2'
+}
+
+if (&Tmp-String-1 != 'hello2') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
diff --git a/src/tests/keywords/urlquote b/src/tests/keywords/urlquote
new file mode 100644
index 0000000..35057d8
--- /dev/null
+++ b/src/tests/keywords/urlquote
@@ -0,0 +1,50 @@
+#
+# PRE: update if
+#
+update {
+ # Some encoders replace ~ with %7E RFC3986 Section 2.4 says this should not be done.
+ request:Tmp-String-0 := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~'
+ request:Tmp-String-1 := '±§!@#$%^&*()+={[}]:;"\'|\<,>?/`'
+ request:Tmp-String-2 := '™œ¥¤'
+ request:Tmp-String-3 := '%C2%B1%C2%A7%21%40%23%24%25%5E%26%2A%28%29%2B%3D%7B%5B%7D%5D%3A%3B%22%27%7C%5C%3C%2C%3E%3F%2F%60'
+
+ request:Tmp-String-4 := '%E2%84%A2%C5%93%C2%A5%C2%A4'
+ reply:Filter-ID := 'filter'
+}
+
+
+if (<string>"%{urlquote:%{request:Tmp-String-0}}" != &Tmp-String-0) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+if (<string>"%{urlquote:%{request:Tmp-String-1}}" != &Tmp-String-3) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+if (<string>"%{urlquote:%{request:Tmp-String-2}}" != &Tmp-String-4) {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if (<string>"%{urlunquote:%{request:Tmp-String-0}}" != &Tmp-String-0) {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
+
+if (<string>"%{urlunquote:%{request:Tmp-String-3}}" != &Tmp-String-1) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+if (<string>"%{urlunquote:%{request:Tmp-String-4}}" != &Tmp-String-2) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
diff --git a/src/tests/keywords/virtual b/src/tests/keywords/virtual
new file mode 100644
index 0000000..d6dbe32
--- /dev/null
+++ b/src/tests/keywords/virtual
@@ -0,0 +1,12 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+if (request:Packet-Type == Access-Request) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/virtual-exists b/src/tests/keywords/virtual-exists
new file mode 100644
index 0000000..7a8e8f3
--- /dev/null
+++ b/src/tests/keywords/virtual-exists
@@ -0,0 +1,12 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+if (&Client-Shortname) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/virtual-load-balance b/src/tests/keywords/virtual-load-balance
new file mode 100644
index 0000000..256c2ff
--- /dev/null
+++ b/src/tests/keywords/virtual-load-balance
@@ -0,0 +1,14 @@
+# PRE: update if foreach
+#
+# Virtual Load-Balance blocks.
+#
+
+#
+# Both of these should parse.
+#
+virtual_instantiate
+virtual_instantiate.post-auth
+
+update reply {
+ Filter-Id := 'filter'
+}
diff --git a/src/tests/keywords/virtual-rhs b/src/tests/keywords/virtual-rhs
new file mode 100644
index 0000000..0d21e7f
--- /dev/null
+++ b/src/tests/keywords/virtual-rhs
@@ -0,0 +1,16 @@
+#
+# PRE: update if
+#
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ Tmp-String-0 := "<UNKNOWN-CLIENT>"
+}
+
+if (&Tmp-String-0 == &Client-Shortname) {
+ update reply {
+ Filter-Id := "filter"
+ }
+}
diff --git a/src/tests/keywords/virtual_policy b/src/tests/keywords/virtual_policy
new file mode 100644
index 0000000..4ab00e2
--- /dev/null
+++ b/src/tests/keywords/virtual_policy
@@ -0,0 +1,15 @@
+# PRE: update if foreach
+#
+# Virtual policies
+#
+
+
+#
+# Both of these should parse.
+#
+virtual_policy
+virtual_policy.post-auth
+
+update reply {
+ Filter-Id := 'filter'
+}
diff --git a/src/tests/keywords/wimax b/src/tests/keywords/wimax
new file mode 100644
index 0000000..f149da4
--- /dev/null
+++ b/src/tests/keywords/wimax
@@ -0,0 +1,31 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ WiMAX-PFDv2-Src-Port = 6809
+}
+
+if (WiMAX-PFDv2-Src-Port != 6809) {
+ update reply {
+ Filter-Id := "fail-1"
+ }
+}
+
+#
+# This is known, and should be renamed
+update request {
+ Attr-26.24757.84.9.5.7 = 0x01
+}
+
+if (WiMAX-PFDv2-Src-Assigned != 1) {
+ update reply {
+ Filter-Id := "fail-2"
+ }
+}
+
+if (!reply:Filter-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/wimax-comboip b/src/tests/keywords/wimax-comboip
new file mode 100644
index 0000000..c4c8a3f
--- /dev/null
+++ b/src/tests/keywords/wimax-comboip
@@ -0,0 +1,19 @@
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update request {
+ WiMAX-DHCPv4-Server := 192.0.2.23
+}
+
+if (WiMAX-DHCPv4-Server != 192.0.2.23) {
+ update reply {
+ Filter-Id := "fail-1"
+ }
+}
+
+if (!reply:Filter-Id) {
+ update reply {
+ Filter-Id := "filter"
+ }
+} \ No newline at end of file
diff --git a/src/tests/keywords/with_dots b/src/tests/keywords/with_dots
new file mode 100644
index 0000000..4fc6b06
--- /dev/null
+++ b/src/tests/keywords/with_dots
@@ -0,0 +1,19 @@
+#
+# PRE: update
+#
+
+#
+# Ensure that policies can have dots.
+#
+# The main problem is that conf section references
+# also have dots in them...
+#
+with.dots
+
+update control {
+ Cleartext-Password := 'hello'
+}
+
+update reply {
+ Filter-Id := "filter"
+}
diff --git a/src/tests/keywords/xlat-attr b/src/tests/keywords/xlat-attr
new file mode 100644
index 0000000..d19495a
--- /dev/null
+++ b/src/tests/keywords/xlat-attr
@@ -0,0 +1,62 @@
+#
+# PRE: update
+#
+# Check attribute info xlats work correctly
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Reply-Message := 'foo'
+ FreeRADIUS-Proxied-To := 127.0.0.1
+}
+
+if ("%{attr:&FreeRADIUS-Proxied-To}" != 'FreeRADIUS-Proxied-To') {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if ("%{attr_num:&FreeRADIUS-Proxied-To}" != 1) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+if ("%{vendor:&FreeRADIUS-Proxied-To}" != 'FreeRADIUS') {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if ("%{vendor_num:&FreeRADIUS-Proxied-To}" != 11344) {
+ update reply {
+ Filter-Id += 'Fail 4'
+ }
+}
+
+if ("%{attr:&Reply-Message}" != 'Reply-Message') {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+if ("%{attr_num:&Reply-Message}" != 18) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+if ("%{vendor:&Reply-Message}" != '') {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+if ("%{vendor_num:&Reply-Message}" != 0) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
diff --git a/src/tests/keywords/xlat-attr-index b/src/tests/keywords/xlat-attr-index
new file mode 100644
index 0000000..c967dd6
--- /dev/null
+++ b/src/tests/keywords/xlat-attr-index
@@ -0,0 +1,53 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tmp-IP-Address-0 := 192.0.2.1
+ Tmp-IP-Address-0 += 192.0.2.2
+}
+
+if ("%{Tmp-IP-Address-0[#]}" != 2) {
+ update {
+ reply:Filter-Id += 'fail 0'
+ }
+}
+
+if (("%{Tmp-IP-Address-0[0]}" != 192.0.2.1) || ("%{Tmp-IP-Address-0[1]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{Tmp-IP-Address-0[*]}" != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+# Try calling these xlats in mapping too, they may get optimised to VPTs which is a
+# different code path.
+update request {
+ Tmp-IP-Address-1 += "%{Tmp-IP-Address-0[1]}"
+ Tmp-IP-Address-1 += "%{Tmp-IP-Address-0[0]}"
+ Tmp-String-0 = "%{Tmp-IP-Address-0[*]}"
+ Tmp-Integer-0 = "%{Tmp-IP-Address-0[#]}"
+}
+
+if (Tmp-String-0 != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+if (Tmp-Integer-0 != 2) {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
diff --git a/src/tests/keywords/xlat-attr-tag b/src/tests/keywords/xlat-attr-tag
new file mode 100644
index 0000000..c0bd8b6
--- /dev/null
+++ b/src/tests/keywords/xlat-attr-tag
@@ -0,0 +1,225 @@
+#
+# PRE: update
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+update request {
+ Tunnel-Server-Endpoint := '192.0.1.1' # Should not be tagged
+ Tunnel-Server-Endpoint:0 += '192.0.1.2' # Should not be tagged
+ Tunnel-Server-Endpoint:1 := '192.0.2.1'
+ Tunnel-Server-Endpoint:1 += '192.0.2.2'
+ Tunnel-Server-Endpoint:2 := '192.0.3.1'
+ Tunnel-Server-Endpoint:2 += '192.0.3.2'
+}
+
+update request {
+ Tmp-Integer-0 := "%{debug_attr:request:}"
+}
+
+# Check the tag printing xlat works correctly
+if ("%{tag:Tunnel-Server-Endpoint[0]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0a'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[1]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0b'
+ }
+}
+
+
+if ("%{tag:Tunnel-Server-Endpoint[2]}" != '1') {
+ update {
+ reply:Filter-Id += 'fail 0c'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[5]}" != '2') {
+ update {
+ reply:Filter-Id += 'fail 0d'
+ }
+}
+
+if ("%{tag:Tunnel-Server-Endpoint[6]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0e'
+ }
+}
+
+if ("%{tag:control:Cleartext-Password}" != '') {
+ update {
+ reply:Filter-Id += 'fail 0f'
+ }
+}
+
+# Check that access attributes by tag works first
+if ("%{Tunnel-Server-Endpoint:2}" != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:2}" == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:1}" != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if ("%{Tunnel-Server-Endpoint:2[0]}" != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if ("%{Tunnel-Server-Endpoint:2[1]}" != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 5'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[2]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 6'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[0]}" != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 7'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[1]}" != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 8'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint:0[2]}" != '') {
+ update {
+ reply:Filter-Id += 'fail 9'
+ }
+}
+
+#
+# Selecting on attributes with no tag specified (should match all of that type)
+#
+if ("%{Tunnel-Server-Endpoint[0]}" != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 10'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint[1]}" != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 11'
+ }
+}
+
+if ("%{Tunnel-Server-Endpoint[2]}" != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 12'
+ }
+}
+
+#
+# Assignment (xlat)
+#
+update request {
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2}" #0
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2}" #1
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:1}" #2
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2[0]}" #3
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:2[1]}" #4
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[0]}" #5
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[1]}" #6
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint:0[2]}" #7
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[0]}" #8
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[1]}" #9
+ Tmp-String-0 += "%{Tunnel-Server-Endpoint[2]}" #10
+}
+
+# Check that access attributes by tag works first
+if (Tmp-String-0[0] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 13'
+ }
+}
+
+if (Tmp-String-0[1] == '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 14'
+ }
+}
+
+if (Tmp-String-0[2] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 15'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-0[3] != '192.0.3.1') {
+ update {
+ reply:Filter-Id += 'fail 16'
+ }
+}
+
+# Get the first instance of Tunnel-Server-Endpoint:2
+if (Tmp-String-0[4] != '192.0.3.2') {
+ update {
+ reply:Filter-Id += 'fail 17'
+ }
+}
+
+# Now check the assignment
+if (Tmp-String-0[5] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 18'
+ }
+}
+
+if (Tmp-String-0[6] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 19'
+ }
+}
+
+if (Tmp-String-0[7] != '') {
+ update {
+ reply:Filter-Id += 'fail 20'
+ }
+}
+
+if (Tmp-String-0[8] != '192.0.1.1') {
+ update {
+ reply:Filter-Id += 'fail 21'
+ }
+}
+
+if (Tmp-String-0[9] != '192.0.1.2') {
+ update {
+ reply:Filter-Id += 'fail 22'
+ }
+}
+
+if (Tmp-String-0[10] != '192.0.2.1') {
+ update {
+ reply:Filter-Id += 'fail 23'
+ }
+}
diff --git a/src/tests/keywords/xlat-concat b/src/tests/keywords/xlat-concat
new file mode 100644
index 0000000..e0c55a9
--- /dev/null
+++ b/src/tests/keywords/xlat-concat
@@ -0,0 +1,40 @@
+#
+# PRE: xlat-list
+#
+# concat xlat
+#
+
+update control {
+ control !* ANY
+}
+
+update control {
+ Tmp-IP-Address-0 := 192.0.2.1
+ Tmp-IP-Address-0 += 192.0.2.2
+}
+
+update request {
+ Tmp-String-0 := "%{concat:control:[*] ;}"
+}
+
+if (Tmp-String-0 != '192.0.2.1;192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+update request {
+ Tmp-String-0 := "%{concat:control:[*] X}"
+}
+
+if (Tmp-String-0 != '192.0.2.1X192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+# Boilerplate junk
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
diff --git a/src/tests/keywords/xlat-error b/src/tests/keywords/xlat-error
new file mode 100644
index 0000000..b6a2587
--- /dev/null
+++ b/src/tests/keywords/xlat-error
@@ -0,0 +1,12 @@
+#
+# PRE: if xlat-attr-tag
+#
+
+#
+# missing a closing } for the expansion in the string.
+#
+if ("%{expr:1 + 2" == 3) { # ERROR
+ update reply {
+ Filter-Id := "fail"
+ }
+}
diff --git a/src/tests/keywords/xlat-explode b/src/tests/keywords/xlat-explode
new file mode 100644
index 0000000..ea727d9
--- /dev/null
+++ b/src/tests/keywords/xlat-explode
@@ -0,0 +1,91 @@
+#
+# PRE: update
+#
+# Check explode works correctly
+#
+update {
+ request:Class := '1=1|my_attr=2|my_attr=hello|'
+ request:Calling-Station-ID += '|'
+ control:User-Name += '|hello|goodbye'
+ control:User-Name += '|morning|night|1|'
+ control:Reply-Message := 'Can\'t touch this'
+ reply:Filter-Id = 'filter'
+}
+
+if ("%{explode:&Class |}" != 3) {
+ update reply {
+ Filter-Id += 'Fail 0'
+ }
+}
+
+if ("%{Class[#]}" != 3) {
+ update reply {
+ Filter-Id += 'Fail 1'
+ }
+}
+
+if ((&Class[0] != '1=1') || (&Class[1] != 'my_attr=2') || (&Class[2] != 'my_attr=hello')) {
+ update reply {
+ Filter-Id += 'Fail 2'
+ }
+}
+
+if (&Class[3]) {
+ update reply {
+ Filter-Id += 'Fail 3'
+ }
+}
+
+if ("%{explode:&control:Calling-Station-Id |}" != 0) {
+ update reply {
+ filter-Id += 'Fail 4'
+ }
+}
+
+if ("%{explode:&control:User-Name[*] |}" != 5) {
+ update reply {
+ Filter-Id += 'Fail 5'
+ }
+}
+
+if ("%{control:User-Name[#]}" != 5) {
+ update reply {
+ Filter-Id += 'Fail 6'
+ }
+}
+
+if ((&control:User-Name[0] != 'hello') || \
+ (&control:User-Name[1] != 'goodbye') || \
+ (&control:User-Name[2] != 'morning') || \
+ (&control:User-Name[3] != 'night') || \
+ (&control:User-Name[4] != '1')) {
+ update reply {
+ Filter-Id += 'Fail 7'
+ }
+}
+
+if (&control:User-Name[5]) {
+ update reply {
+ Filter-Id += 'Fail 8'
+ }
+}
+
+if ("%{explode:&control:Reply-Message |}" != 0) {
+ update reply {
+ Filter-Id += 'Fail 9'
+ }
+}
+
+if ("%{control:Reply-Message[#]}" != 1) {
+ update reply {
+ Filter-Id += 'Fail 10'
+ }
+}
+
+if (&control:Reply-Message != 'Can\'t touch this') {
+ update reply {
+ Filter-Id += 'Fail 11'
+ }
+}
+
+debug_all
diff --git a/src/tests/keywords/xlat-list b/src/tests/keywords/xlat-list
new file mode 100644
index 0000000..fcd9e84
--- /dev/null
+++ b/src/tests/keywords/xlat-list
@@ -0,0 +1,64 @@
+#
+# PRE: update
+#
+update control {
+ control !* ANY
+}
+
+update control {
+ Tmp-IP-Address-0 := 192.0.2.1
+ Tmp-IP-Address-0 += 192.0.2.2
+}
+
+if ("%{control:[#]}" != 2) {
+ update {
+ reply:Filter-Id += 'fail 0'
+ }
+}
+
+debug_control
+
+if (("%{control:[0]}" != 192.0.2.1) || ("%{control:[1]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id += 'fail 1'
+ }
+}
+
+if (("%{control:[n]}" != 192.0.2.2)) {
+ update {
+ reply:Filter-Id += 'fail 1a'
+ }
+}
+
+if ("%{control:[*]}" != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+# Try calling these xlats in mapping too, they may get optimised to VPTs which is a
+# different code path.
+update request {
+ Tmp-IP-Address-1 += "%{control:[1]}"
+ Tmp-IP-Address-1 += "%{control:[0]}"
+ Tmp-String-0 = "%{control:[*]}"
+ Tmp-Integer-0 = "%{control:[#]}"
+}
+
+if (Tmp-String-0 != '192.0.2.1,192.0.2.2') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
+
+if (Tmp-Integer-0 != 2) {
+ update {
+ reply:Filter-Id += 'fail 4'
+ }
+}
+
+# Boilerplate junk
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
diff --git a/src/tests/keywords/xlat-octets b/src/tests/keywords/xlat-octets
new file mode 100644
index 0000000..ea9543c
--- /dev/null
+++ b/src/tests/keywords/xlat-octets
@@ -0,0 +1,36 @@
+#
+# PRE: update if
+#
+# Remove all attributes in a list
+#
+update {
+ control:Cleartext-Password := 'hello'
+ reply:Filter-Id := 'filter'
+}
+
+#
+# Regression test for 0x prefix. xlat expanded
+# octet strings must NOT have a 0x prefix added
+#
+update request {
+ Tmp-Octets-0 := 0x0001020304050607
+ Tmp-Octets-0 += 0x0706050403020100
+}
+
+if ("%{Tmp-Octets-0}" != '0x0001020304050607') {
+ update {
+ reply:Filter-Id := 'fail 1'
+ }
+}
+
+if ("%{Tmp-Octets-0[0]}" != '0x0001020304050607') {
+ update {
+ reply:Filter-Id += 'fail 2'
+ }
+}
+
+if ("%{Tmp-Octets-0[*]}" != '0x0001020304050607,0x0706050403020100') {
+ update {
+ reply:Filter-Id += 'fail 3'
+ }
+}
diff --git a/src/tests/keywords/xlat-virtual-attr b/src/tests/keywords/xlat-virtual-attr
new file mode 100644
index 0000000..e476993
--- /dev/null
+++ b/src/tests/keywords/xlat-virtual-attr
@@ -0,0 +1,131 @@
+#
+# PRE: if
+#
+
+update reply {
+ Filter-Id := "filter"
+}
+
+if ("%{Client-Shortname}" != '<UNKNOWN-CLIENT>') {
+ update reply {
+ Filter-Id += "fail 0"
+ }
+}
+
+if ("%{Request-Processing-Stage}" != 'authorize') {
+ update reply {
+ Filter-Id += "fail 1"
+ }
+}
+
+if ("%{Virtual-Server}" != 'default') {
+ update reply {
+ Filter-Id += "fail 2"
+ }
+}
+
+if ("%{Module-Return-Code}" != '') {
+ update reply {
+ Filter-Id += "fail 3a"
+ }
+}
+
+ok
+if ("%{Module-Return-Code}" != 'ok') {
+ update reply {
+ Filter-Id += "fail 3b"
+ }
+}
+
+if ("%{Packet-Type}" != 'Access-Request') {
+ update reply {
+ Filter-Id += "fail 4"
+ }
+}
+
+# Response hasn't been set yet
+if ("%{Response-Packet-Type}" != '') {
+ update reply {
+ Filter-Id += "fail 5"
+ }
+}
+
+if ("%{Packet-Authentication-Vector}" != '0x00000000000000000000000000000000') {
+ update reply {
+ Filter-Id += "fail 6"
+ }
+}
+
+if ("%{Client-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 7a"
+ }
+}
+
+if ("%{Packet-Src-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 7b"
+ }
+}
+
+if ("%{Packet-Dst-IP-Address}" != 127.0.0.1) {
+ update reply {
+ Filter-Id += "fail 8"
+ }
+}
+
+# Can't have both...
+if ("%{Packet-Src-IPv6-Address}" != '') {
+ update reply {
+ Filter-Id += "fail 9"
+ }
+}
+
+if ("%{Packet-Dst-IPv6-Address}" != '') {
+ update reply {
+ Filter-Id += "fail 10"
+ }
+}
+
+if ("%{Packet-Src-Port}" != '18120') {
+ update reply {
+ Filter-Id += "fail 11"
+ }
+}
+
+if ("%{Packet-Dst-Port}" != '1812') {
+ update reply {
+ Filter-Id += "fail 12"
+ }
+}
+
+
+# We should allow the user to overload virtual attributes
+update request {
+ Client-Shortname := 'my_test_client'
+}
+
+if ("%{Client-Shortname}" != 'my_test_client') {
+ update reply {
+ Filter-Id += "fail 13"
+ }
+}
+
+# Operations on virtual attributes should be the same as on real ones
+if ("%{Virtual-Server[0]}" != 'default') {
+ update reply {
+ Filter-Id += "fail 14"
+ }
+}
+
+if ("%{Virtual-Server[*]}" != 'default') {
+ update reply {
+ Filter-Id += "fail 15"
+ }
+}
+
+if ("%{Virtual-Server[#]}" != 1) {
+ update reply {
+ Filter-Id += "fail 16"
+ }
+}
diff --git a/src/tests/map/all.mk b/src/tests/map/all.mk
new file mode 100644
index 0000000..fedd29d
--- /dev/null
+++ b/src/tests/map/all.mk
@@ -0,0 +1 @@
+SUBMAKEFILES := map_unit.mk map_tests.mk
diff --git a/src/tests/map/base b/src/tests/map/base
new file mode 100644
index 0000000..633c32a
--- /dev/null
+++ b/src/tests/map/base
@@ -0,0 +1,6 @@
+update request {
+ Filter-Id := "filter"
+ User-Name := "blah"
+
+ &reply:Filter-Id += &request:Filter-Id[*]
+}
diff --git a/src/tests/map/base.out b/src/tests/map/base.out
new file mode 100644
index 0000000..34c519b
--- /dev/null
+++ b/src/tests/map/base.out
@@ -0,0 +1,5 @@
+update request {
+ &Filter-Id := "filter"
+ &User-Name := "blah"
+ &reply:Filter-Id += &Filter-Id[*]
+}
diff --git a/src/tests/map/count-error b/src/tests/map/count-error
new file mode 100644
index 0000000..925360d
--- /dev/null
+++ b/src/tests/map/count-error
@@ -0,0 +1,6 @@
+#
+# This should be an xlat, not a direct assignment
+#
+update request {
+ Tmp-Integer-0 := &Filter-Id[#] # ERROR
+} \ No newline at end of file
diff --git a/src/tests/map/count-list-error b/src/tests/map/count-list-error
new file mode 100644
index 0000000..a7beae1
--- /dev/null
+++ b/src/tests/map/count-list-error
@@ -0,0 +1,6 @@
+#
+# Updating lists isn't allowed
+#
+update {
+ &request:Filter-Id := &Filter-Id[#] # ERROR
+}
diff --git a/src/tests/map/map_tests.mk b/src/tests/map/map_tests.mk
new file mode 100644
index 0000000..7474489
--- /dev/null
+++ b/src/tests/map/map_tests.mk
@@ -0,0 +1,50 @@
+MAP_TESTS := $(patsubst $(top_srcdir)/src/tests/map/%,%,$(filter-out %.conf %.md %.attrs %.c %.mk %~ %.rej %.out,$(wildcard $(top_srcdir)/src/tests/map/*)))
+MAP_OUTPUT := $(addsuffix .out,$(addprefix $(BUILD_DIR)/tests/map/,$(MAP_TESTS)))
+MAP_UNIT_BIN := $(BUILD_DIR)/bin/local/map_unit
+MAP_UNIT := ./build/make/jlibtool --silent --mode=execute $(MAP_UNIT_BIN)
+
+.PHONY: $(BUILD_DIR)/tests/map/
+$(BUILD_DIR)/tests/map/:
+ @mkdir -p $@
+
+#
+# Re-run the tests if the test program changes
+#
+# Create the output directory before the files
+#
+$(MAP_OUTPUT): $(MAP_UNIT_BIN) | $(BUILD_DIR)/tests/map/
+
+#
+# Re-run the tests if the input file changes
+#
+$(BUILD_DIR)/tests/map/%.out: $(top_srcdir)/src/tests/map/%
+ @echo MAP_TEST $(notdir $<)
+ @if ! $(MAP_UNIT) -d $(top_srcdir)/raddb -D $(top_srcdir)/share $< > $@ 2>&1; then \
+ if ! grep ERROR $< 2>&1 > /dev/null; then \
+ cat $@; \
+ echo "# $@"; \
+ echo FAILED: "$(MAP_UNIT) -d $(top_srcdir)/raddb -D $(top_srcdir)/share $<"; \
+ exit 1; \
+ fi; \
+ FOUND=$$(grep $< $@ | head -1 | sed 's,^.*$(top_srcdir),,;s/:.*//;s/.*\[//;s/\].*//'); \
+ EXPECTED=$$(grep -n ERROR $< | sed 's/:.*//'); \
+ if [ "$$EXPECTED" != "$$FOUND" ]; then \
+ cat $@; \
+ echo "# $@"; \
+ echo "E $$EXPECTED F $$FOUND"; \
+ echo UNEXPECTED ERROR: "$(MAP_UNIT) -d $(top_srcdir)/raddb -D $(top_srcdir)/share $<"; \
+ exit 1; \
+ fi; \
+ else \
+ if ! diff $<.out $@; then \
+ echo FAILED: " diff $<.out $@"; \
+ echo FAILED: "$(MAP_UNIT) -d $(top_srcdir)/raddb -D $(top_srcdir)/share $<"; \
+ exit 1; \
+ fi; \
+ fi
+
+TESTS.MAP_FILES := $(MAP_OUTPUT)
+
+$(TESTS.MAP_FILES): $(TESTS.UNIT_FILES)
+
+tests.map: $(MAP_OUTPUT)
diff --git a/src/tests/map/map_unit.c b/src/tests/map/map_unit.c
new file mode 100644
index 0000000..af6d016
--- /dev/null
+++ b/src/tests/map/map_unit.c
@@ -0,0 +1,219 @@
+/*
+ * radattr.c Map debugging tool.
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Copyright 2015 Alan DeKok <aland@freeradius.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/libradius.h>
+
+#include <freeradius-devel/conf.h>
+#include <freeradius-devel/modpriv.h>
+#include <freeradius-devel/modcall.h>
+
+#include <ctype.h>
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#include <assert.h>
+
+#include <freeradius-devel/log.h>
+
+#include <sys/wait.h>
+
+/* Linker hacks */
+
+#ifdef HAVE_PTHREAD_H
+pid_t rad_fork(void)
+{
+ return fork();
+}
+
+pid_t rad_waitpid(pid_t pid, int *status)
+{
+ return waitpid(pid, status, 0);
+}
+#endif
+
+rlm_rcode_t indexed_modcall(UNUSED rlm_components_t comp, UNUSED int idx, UNUSED REQUEST *request)
+{
+ return RLM_MODULE_OK;
+}
+
+char const *get_radius_dir(void)
+{
+ return NULL;
+}
+
+module_instance_t *module_instantiate(UNUSED CONF_SECTION *modules, UNUSED char const *askedname)
+{
+ return NULL;
+}
+
+module_instance_t *module_instantiate_method(UNUSED CONF_SECTION *modules, UNUSED char const *name, UNUSED rlm_components_t *method)
+{
+ return NULL;
+}
+
+/* Linker hacks */
+
+static void NEVER_RETURNS usage(void)
+{
+ fprintf(stderr, "usage: map_unit [OPTS] filename ...\n");
+ fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
+ fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
+ fprintf(stderr, " -O <output_dir> Set output directory\n");
+ fprintf(stderr, " -x Debugging mode.\n");
+ fprintf(stderr, " -M Show program version information.\n");
+
+ exit(1);
+}
+
+static int process_file(char const *filename)
+{
+ int rcode;
+ char const *name1, *name2;
+ CONF_SECTION *cs, *main_cs;
+ vp_map_t *head, *map;
+ char buffer[8192];
+
+ main_cs = cf_section_alloc(NULL, "main", NULL);
+ if (cf_file_read(main_cs, filename) < 0) {
+ fprintf(stderr, "map_unit: Failed parsing %s\n",
+ filename);
+ exit(1);
+ }
+
+ /*
+ * Always has to be an "update" section.
+ */
+ cs = cf_section_sub_find(main_cs, "update");
+ if (!cs) {
+ talloc_free(main_cs);
+ return -1;
+ }
+
+ /*
+ * Convert the update section to a list of maps.
+ */
+ rcode = map_afrom_cs(&head, cs, PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, modcall_fixup_update, NULL, 128);
+ if (rcode < 0) return -1; /* message already printed */
+ if (!head) {
+ cf_log_err_cs(cs, "'update' sections cannot be empty");
+ return -1;
+ }
+
+ buffer[0] = '\t';
+
+ name1 = cf_section_name1(cs);
+ name2 = cf_section_name2(cs);
+
+ /*
+ * And print it all out.
+ */
+ if (!name2) {
+ printf("%s {\n", name1);
+ } else {
+ printf("%s %s {\n", name1, name2);
+ }
+
+ for (map = head; map != NULL; map = map->next) {
+ map_prints(buffer + 1, sizeof(buffer) - 1, map);
+ puts(buffer);
+ }
+ printf("}\n");
+
+ talloc_free(main_cs);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, rcode = 0;
+ bool report = false;
+ char const *radius_dir = RADDBDIR;
+ char const *dict_dir = DICTDIR;
+
+ cf_new_escape = true; /* fix the tests */
+
+#ifndef NDEBUG
+ if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
+ fr_perror("radattr");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ while ((c = getopt(argc, argv, "d:D:xMh")) != EOF) switch (c) {
+ case 'd':
+ radius_dir = optarg;
+ break;
+ case 'D':
+ dict_dir = optarg;
+ break;
+ case 'x':
+ fr_debug_lvl++;
+ rad_debug_lvl = fr_debug_lvl;
+ break;
+ case 'M':
+ report = true;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * Mismatch between the binary and the libraries it depends on
+ */
+ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
+ fr_perror("radattr");
+ return 1;
+ }
+
+ if (argc < 2) {
+ rcode = process_file("-");
+
+ } else {
+ rcode = process_file(argv[1]);
+ }
+
+ if (report) {
+ dict_free();
+ fr_log_talloc_report(NULL);
+ }
+
+ if (rcode < 0) rcode = 1; /* internal to Unix process return code */
+
+ return rcode;
+}
diff --git a/src/tests/map/map_unit.mk b/src/tests/map/map_unit.mk
new file mode 100644
index 0000000..88d319b
--- /dev/null
+++ b/src/tests/map/map_unit.mk
@@ -0,0 +1,5 @@
+TARGET := map_unit
+SOURCES := map_unit.c ${top_srcdir}/src/main/modcall.c
+
+TGT_PREREQS := libfreeradius-server.a libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS)
diff --git a/src/tests/modules/README.rst b/src/tests/modules/README.rst
new file mode 100644
index 0000000..164509d
--- /dev/null
+++ b/src/tests/modules/README.rst
@@ -0,0 +1,18 @@
+Module Tests
+------------
+
+To test module `foo`, create a directory `foo`, and put a file `all.mk` into it, e.g.
+
+ foo/all.mk
+
+All of the tests for the module should go here. The tests will be run
+*only* if the module is available, and has been built correctly on the system.
+
+The file should contain a target "MODULE.test". This is the main
+target used to test the module. The framework automatically makes the
+tests depend on the module (i.e. library). So if the module source
+changes, you can just do `make MODULE.test`. The module will be
+re-built, and the tests will be run.
+
+Note: all SQL tests share the same tests definitions (see sql directory).
+The modules themselves simply link to the actual tests files.
diff --git a/src/tests/modules/all.mk b/src/tests/modules/all.mk
new file mode 100644
index 0000000..9960df7
--- /dev/null
+++ b/src/tests/modules/all.mk
@@ -0,0 +1,40 @@
+#
+# Find the subdirs which have "all.mk"
+#
+TEST_SUBDIRS := $(patsubst src/tests/modules/%/all.mk,%,$(wildcard src/tests/modules/*/all.mk))
+
+#
+# Find out which of those have a similar target. i.e. modules/foo -> rlm_foo.la
+#
+TEST_TARGETS := $(foreach x,$(TEST_SUBDIRS),$(findstring rlm_$x.la,$(ALL_TGTS)))
+
+TEST_BUILT := $(patsubst rlm_%.la,%,$(TEST_TARGETS))
+
+#
+# Ensure that the tests depend on the module, so that changes to the
+# module will re-run the test
+#
+$(foreach x,$(TEST_BUILT),$(eval $x.test: rlm_$x.la))
+
+######################################################################
+
+#
+# And do the same thing for sub-directories
+#
+TEST_SUBSUBDIRS := $(patsubst src/tests/modules/%/all.mk,%,$(wildcard src/tests/modules/*/*/all.mk))
+
+TEST_SUBTARGETS := $(foreach x,$(TEST_SUBSUBDIRS),$(findstring rlm_$(subst /,_,$x).la,$(ALL_TGTS)))
+
+TEST_SUBBUILT := $(patsubst rlm_%.la,%,$(TEST_SUBTARGETS))
+
+$(foreach x,$(TEST_SUBBUILT),$(eval $x.test: rlm_$(subst /,_,$x).la))
+
+######################################################################
+#
+# For the remaining subdirs, add on the directory to include.
+# test.mk will run the tests for all modules
+# It is included last so that the module specific makefiles can be processed first
+# (modules that require a test server can set the corresponding require_test_server variable)
+#
+SUBMAKEFILES := $(addsuffix /all.mk,$(TEST_BUILT) $(subst _,/,$(TEST_SUBBUILT))) test.mk
+
diff --git a/src/tests/modules/always/all.mk b/src/tests/modules/always/all.mk
new file mode 100644
index 0000000..8f1127f
--- /dev/null
+++ b/src/tests/modules/always/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "always" module
+#
diff --git a/src/tests/modules/always/module.conf b/src/tests/modules/always/module.conf
new file mode 100644
index 0000000..39995e5
--- /dev/null
+++ b/src/tests/modules/always/module.conf
@@ -0,0 +1,7 @@
+always my_reject {
+ rcode = reject
+}
+
+always db_status {
+ rcode = ok
+}
diff --git a/src/tests/modules/always/replace.unlang b/src/tests/modules/always/replace.unlang
new file mode 100644
index 0000000..1d502f7
--- /dev/null
+++ b/src/tests/modules/always/replace.unlang
@@ -0,0 +1,11 @@
+%{poke:my_reject.rcode=ok}
+
+my_reject # should be "ok"
+
+update control {
+ Cleartext-Password := "hello"
+}
+
+update reply {
+ Filter-Id := "success"
+}
diff --git a/src/tests/modules/always/set_rcode.unlang b/src/tests/modules/always/set_rcode.unlang
new file mode 100644
index 0000000..faaed28
--- /dev/null
+++ b/src/tests/modules/always/set_rcode.unlang
@@ -0,0 +1,44 @@
+#
+# Set status to "notfound". xlat should expand to previous status, "alive"
+#
+if ("%{db_status:notfound}" != "alive") {
+ update reply {
+ Filter-Id += "failed"
+ }
+}
+
+
+#
+# Verify that the status was changed
+#
+db_status
+if (!notfound) {
+ update reply {
+ Filter-Id += "failed"
+ }
+}
+
+
+#
+# Fetch status using xlat without setting the status
+#
+if ("%{db_status:}" != "notfound") {
+ update reply {
+ Filter-Id += "failed"
+ }
+}
+
+
+#
+# Verify that the status did not change
+#
+db_status
+if (notfound) {
+ update reply {
+ Filter-Id += "success"
+ }
+}
+
+update control {
+ Cleartext-Password := "hello"
+}
diff --git a/src/tests/modules/always/set_status_dead.unlang b/src/tests/modules/always/set_status_dead.unlang
new file mode 100644
index 0000000..6b29ede
--- /dev/null
+++ b/src/tests/modules/always/set_status_dead.unlang
@@ -0,0 +1,18 @@
+#
+# Set the module status to dead, call it and check that it fails
+#
+%{db_status:dead}
+
+db_status {
+ fail = 1
+}
+
+if (fail) {
+ update reply {
+ Filter-Id := "success"
+ }
+}
+
+update control {
+ Cleartext-Password := "hello"
+}
diff --git a/src/tests/modules/always/set_status_revive.unlang b/src/tests/modules/always/set_status_revive.unlang
new file mode 100644
index 0000000..3e71d39
--- /dev/null
+++ b/src/tests/modules/always/set_status_revive.unlang
@@ -0,0 +1,28 @@
+#
+# Fail a module...
+#
+%{db_status:dead}
+db_status {
+ fail = 1
+}
+if (!fail) {
+ update reply {
+ Filter-Id += "failed"
+ }
+}
+
+
+#
+# ... Now revive it
+#
+%{db_status:alive}
+db_status
+if (ok) {
+ update reply {
+ Filter-Id += "success"
+ }
+}
+
+update control {
+ Cleartext-Password := "hello"
+}
diff --git a/src/tests/modules/cache/rbtree/all.mk b/src/tests/modules/cache/rbtree/all.mk
new file mode 100644
index 0000000..8f89aa6
--- /dev/null
+++ b/src/tests/modules/cache/rbtree/all.mk
@@ -0,0 +1,2 @@
+cache_rbtree.test:
+
diff --git a/src/tests/modules/default-input.attrs b/src/tests/modules/default-input.attrs
new file mode 100644
index 0000000..d24ac4b
--- /dev/null
+++ b/src/tests/modules/default-input.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "hello"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Filter-Id == 'success'
diff --git a/src/tests/modules/files/addcontrol.attrs b/src/tests/modules/files/addcontrol.attrs
new file mode 100644
index 0000000..7588b9c
--- /dev/null
+++ b/src/tests/modules/files/addcontrol.attrs
@@ -0,0 +1,13 @@
+#
+# Input packet
+#
+User-Name = "addcontrol"
+User-Password = "testing123"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Cleartext-Password == 'testing123'
+Reply-Message == "success1"
+Reply-Message == "success2"
diff --git a/src/tests/modules/files/addcontrol.unlang b/src/tests/modules/files/addcontrol.unlang
new file mode 100644
index 0000000..5b431f1
--- /dev/null
+++ b/src/tests/modules/files/addcontrol.unlang
@@ -0,0 +1,8 @@
+#
+# Run the "files" module
+#
+files
+
+update {
+ &reply: += &control:[*]
+}
diff --git a/src/tests/modules/files/addreply.attrs b/src/tests/modules/files/addreply.attrs
new file mode 100644
index 0000000..69e1a19
--- /dev/null
+++ b/src/tests/modules/files/addreply.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "addreply"
+User-Password = "testing123"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Reply-Message == 'success1'
+Reply-Message == 'success2'
diff --git a/src/tests/modules/files/addreply.unlang b/src/tests/modules/files/addreply.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/addreply.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/files/all.mk b/src/tests/modules/files/all.mk
new file mode 100644
index 0000000..07449db
--- /dev/null
+++ b/src/tests/modules/files/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "files" module
+#
diff --git a/src/tests/modules/files/authorize b/src/tests/modules/files/authorize
new file mode 100644
index 0000000..b85f6a2
--- /dev/null
+++ b/src/tests/modules/files/authorize
@@ -0,0 +1,92 @@
+#
+# Test if the "users" file works
+#
+
+
+#
+# Basic syntax tests with comments. Parsing only.
+#
+
+user Cleartext-Password := "hello" # comment!
+
+
+user2 # comment!
+ Reply-Message := "24"
+
+
+#
+# Setting ":=" of reply and control items
+#
+
+bob Cleartext-Password := "hello"
+ Reply-Message := "success"
+
+
+#
+# Detect erroneous Fall-Through
+#
+
+doug Cleartext-Password := "goodbye"
+ Reply-Message := "success"
+
+doug
+ Reply-Message := "unreachable"
+
+
+#
+# Fall-Through across a non-matching entry
+#
+
+famous Cleartext-Password := "bradpitt"
+ Fall-Through = yes
+
+unused Cleartext-Password := "jabberwocky"
+ Reply-Message := "fail"
+
+famous
+ Reply-Message := "success"
+
+
+#
+# Modification of the reply list
+#
+
+addreply Cleartext-Password := "testing123"
+ Reply-Message := "success1",
+ Fall-Through = yes
+
+addreply
+ Reply-Message += "success2"
+
+
+subreply Cleartext-Password := "testing123"
+ Reply-Message := "success1",
+ Reply-Message += "success2",
+ Reply-Message += "success3",
+ Fall-Through = yes
+
+subreply Cleartext-Password := "testing123"
+ Reply-Message -= "success2"
+
+
+filterreply Cleartext-Password := "testing123"
+ Reply-Message := "success1",
+ Reply-Message += "success2",
+ Fall-Through = yes
+
+filterreply Cleartext-Password := "testing123"
+ Reply-Message !* ANY
+
+
+#
+# Addition "+=" to the control list
+#
+# Note: Set ":=" of control items is already tested with Cleartext-Password
+# Note: Filtering "!*" does not apply to control items as this would overload
+# the operator syntax since "!*" checks that no such attribute in the
+# request.
+
+addcontrol Cleartext-Password := "testing123", Reply-Message := "success1"
+ Fall-Through = yes
+
+addcontrol Reply-Message += "success2"
diff --git a/src/tests/modules/files/bob.attrs b/src/tests/modules/files/bob.attrs
new file mode 100644
index 0000000..a4acfab
--- /dev/null
+++ b/src/tests/modules/files/bob.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = "doug"
+User-Password = "goodbye"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Reply-Message == 'success'
diff --git a/src/tests/modules/files/bob.unlang b/src/tests/modules/files/bob.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/bob.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/files/doug.attrs b/src/tests/modules/files/doug.attrs
new file mode 100644
index 0000000..a4acfab
--- /dev/null
+++ b/src/tests/modules/files/doug.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = "doug"
+User-Password = "goodbye"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Reply-Message == 'success'
diff --git a/src/tests/modules/files/doug.unlang b/src/tests/modules/files/doug.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/doug.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/files/fall-through.attrs b/src/tests/modules/files/fall-through.attrs
new file mode 100644
index 0000000..899d3d9
--- /dev/null
+++ b/src/tests/modules/files/fall-through.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = "famous"
+User-Password = "bradpitt"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Reply-Message == 'success'
diff --git a/src/tests/modules/files/fall-through.unlang b/src/tests/modules/files/fall-through.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/fall-through.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/files/filterreply.attrs b/src/tests/modules/files/filterreply.attrs
new file mode 100644
index 0000000..c1add29
--- /dev/null
+++ b/src/tests/modules/files/filterreply.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = "filterreply"
+User-Password = "testing123"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/files/filterreply.unlang b/src/tests/modules/files/filterreply.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/filterreply.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/files/module.conf b/src/tests/modules/files/module.conf
new file mode 100644
index 0000000..12b46ac
--- /dev/null
+++ b/src/tests/modules/files/module.conf
@@ -0,0 +1,9 @@
+files {
+ # The default key attribute to use for matches. The content
+ # of this attribute is used to match the "name" of the
+ # entry.
+ #key = "%{%{Stripped-User-Name}:-%{User-Name}}"
+
+ # The old "users" style file is now located here.
+ filename = $ENV{MODULE_TEST_DIR}/authorize
+}
diff --git a/src/tests/modules/files/subreply.attrs b/src/tests/modules/files/subreply.attrs
new file mode 100644
index 0000000..6fe6237
--- /dev/null
+++ b/src/tests/modules/files/subreply.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "subreply"
+User-Password = "testing123"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Reply-Message == 'success1'
+Reply-Message == 'success3'
diff --git a/src/tests/modules/files/subreply.unlang b/src/tests/modules/files/subreply.unlang
new file mode 100644
index 0000000..456c666
--- /dev/null
+++ b/src/tests/modules/files/subreply.unlang
@@ -0,0 +1,4 @@
+#
+# Run the "files" module
+#
+files
diff --git a/src/tests/modules/json/all.mk b/src/tests/modules/json/all.mk
new file mode 100644
index 0000000..4d3197d
--- /dev/null
+++ b/src/tests/modules/json/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "json" module
+#
diff --git a/src/tests/modules/json/encode.attrs b/src/tests/modules/json/encode.attrs
new file mode 100644
index 0000000..ea8d653
--- /dev/null
+++ b/src/tests/modules/json/encode.attrs
@@ -0,0 +1,13 @@
+#
+# Input packet
+#
+User-Name = 'john'
+Filter-Id = "f1"
+Filter-Id += "f2"
+NAS-Port = 999
+Service-Type = Login-User
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/json/encode.unlang b/src/tests/modules/json/encode.unlang
new file mode 100644
index 0000000..6c7a1fe
--- /dev/null
+++ b/src/tests/modules/json/encode.unlang
@@ -0,0 +1,233 @@
+#
+# json_encode tests
+#
+
+
+# 0. Check basic xlat parsing
+
+update control {
+ &Tmp-String-1 := "%{json_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_encode:&request:[*] }"
+ &Tmp-String-3 := "%{json_encode: &request:[*]}"
+ &Tmp-String-4 := "%{json_encode: &request:[*] }"
+ &Tmp-String-5 := "%{json_encode: &request:[*] !&Filter-Id }"
+ &Tmp-String-6 := "%{json_encode:&request:[*] ! }"
+## Check defaults are the same as output_mode "object":
+ &Tmp-String-7 := "%{json_object_encode:&request:[*]}"
+ &Tmp-String-8 := "%{json_object_no_encode:&request:[*]}"
+}
+
+
+if (&control:Tmp-String-1 != '{"User-Name":{"type":"string","value":"john"},"Filter-Id":{"type":"string","value":["f1","f2"]},"NAS-Port":{"type":"integer","value":999},"Service-Type":{"type":"integer","value":"Login-User"}}') {
+ test_fail
+}
+
+# Check xlat input formats
+if (&control:Tmp-String-1 != &control:Tmp-String-2 || \
+ &control:Tmp-String-1 != &control:Tmp-String-3 || \
+ &control:Tmp-String-1 != &control:Tmp-String-4) {
+ test_fail
+}
+
+# Check defaults
+if (&control:Tmp-String-1 != &control:Tmp-String-7 || \
+ &control:Tmp-String-1 != &control:Tmp-String-8) {
+ test_fail
+}
+
+if (&control:Tmp-String-5 != '{"User-Name":{"type":"string","value":"john"},"NAS-Port":{"type":"integer","value":999},"Service-Type":{"type":"integer","value":"Login-User"}}') {
+ test_fail
+}
+
+if (&control:Tmp-String-6 != '') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Tmp-String-3 !* ANY
+ &Tmp-String-4 !* ANY
+ &Tmp-String-5 !* ANY
+ &Tmp-String-6 !* ANY
+ &Tmp-String-7 !* ANY
+ &Tmp-String-8 !* ANY
+}
+
+
+# 1a. Output mode "object" tests
+
+# These are unsorted dictionaries. Hopefully json-c doesn't suddenly
+# decide that it's going to use a different ordering of the keys...
+
+update control {
+ &Tmp-String-1 := "%{json_object_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_object_ex_encode:&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '{"User-Name":{"type":"string","value":"john"},"Filter-Id":{"type":"string","value":["f1","f2"]},"NAS-Port":{"type":"integer","value":999},"Service-Type":{"type":"integer","value":"Login-User"}}') {
+ test_fail
+}
+
+if (&control:Tmp-String-2 != '{"pf:User-Name":{"type":"string","value":["john"]},"pf:Filter-Id":{"type":"string","value":["f1","f2"]},"pf:NAS-Port":{"type":"integer","value":["999"]},"pf:Service-Type":{"type":"integer","value":["1"]}}') {
+ test_fail
+}
+
+# 1b. "object" empty inputs
+
+update control {
+ &Tmp-String-1 := "%{json_object_encode:!&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '{}') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Module-Failure-Message !* ANY
+}
+
+
+# 2a. Output mode "object_simple" tests
+
+update control {
+ &Tmp-String-1 := "%{json_object_simple_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_object_simple_ex_encode:&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '{"User-Name":"john","Filter-Id":["f1","f2"],"NAS-Port":999,"Service-Type":"Login-User"}') {
+ test_fail
+}
+
+if (&control:Tmp-String-2 != '{"pf:User-Name":["john"],"pf:Filter-Id":["f1","f2"],"pf:NAS-Port":["999"],"pf:Service-Type":["1"]}') {
+ test_fail
+}
+
+# 2b. "object_simple" empty inputs
+
+update control {
+ &Tmp-String-1 := "%{json_object_simple_encode:!&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '{}') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Module-Failure-Message !* ANY
+}
+
+
+# 3a. Output mode "array" tests
+
+update control {
+ &Tmp-String-1 := "%{json_array_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_array_ex_encode:&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '[{"name":"User-Name","type":"string","value":"john"},{"name":"Filter-Id","type":"string","value":"f1"},{"name":"Filter-Id","type":"string","value":"f2"},{"name":"NAS-Port","type":"integer","value":999},{"name":"Service-Type","type":"integer","value":"Login-User"}]') {
+ test_fail
+}
+
+if (&control:Tmp-String-2 != '[{"name":"pf:User-Name","type":"string","value":["john"]},{"name":"pf:Filter-Id","type":"string","value":["f1","f2"]},{"name":"pf:NAS-Port","type":"integer","value":["999"]},{"name":"pf:Service-Type","type":"integer","value":["1"]}]') {
+ test_fail
+}
+
+# 3b. "array" empty inputs
+
+update control {
+ &Tmp-String-1 := "%{json_array_encode:!&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '[]') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Module-Failure-Message !* ANY
+}
+
+
+# 4a. Output mode "array_of_names" tests
+
+update control {
+ &Tmp-String-1 := "%{json_array_names_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_array_names_ex_encode:&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '["User-Name","Filter-Id","Filter-Id","NAS-Port","Service-Type"]') {
+ test_fail
+}
+
+if (&control:Tmp-String-2 != '["pf:User-Name","pf:Filter-Id","pf:Filter-Id","pf:NAS-Port","pf:Service-Type"]') {
+ test_fail
+}
+
+# 4b. "array_of_names" empty inputs
+
+update control {
+ &Tmp-String-1 := "%{json_array_names_encode:!&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '[]') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Module-Failure-Message !* ANY
+}
+
+
+# 5a. Output mode "array_of_values" tests
+
+update control {
+ &Tmp-String-1 := "%{json_array_values_encode:&request:[*]}"
+ &Tmp-String-2 := "%{json_array_values_ex_encode:&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '["john","f1","f2",999,"Login-User"]') {
+ test_fail
+}
+
+if (&control:Tmp-String-2 != '["john","f1","f2","999","1"]') {
+ test_fail
+}
+
+# 5b. "array_of_values" empty inputs
+
+update control {
+ &Tmp-String-1 := "%{json_array_values_encode:!&request:[*]}"
+}
+
+if (&control:Tmp-String-1 != '[]') {
+ test_fail
+}
+
+update control {
+ &Tmp-String-1 !* ANY
+ &Tmp-String-2 !* ANY
+ &Module-Failure-Message !* ANY
+}
+
+
+# Convert `make json.test` unlang update output to tests, for when
+# things need updating.
+#
+# cat \
+# | cut -c44- \
+# | sed -e 's/\\"/"/g' \
+# -e 's/\s*$//' \
+# -e "s/:= \"/== '/" \
+# -e 's/^/if (/' \
+# -e "s/\"$/') {/" \
+# -e "s/$/\n test_pass\n} else {\n test_fail\n}\n/"
+
+test_pass
diff --git a/src/tests/modules/json/module.conf b/src/tests/modules/json/module.conf
new file mode 100644
index 0000000..04d1b1d
--- /dev/null
+++ b/src/tests/modules/json/module.conf
@@ -0,0 +1,150 @@
+json {
+}
+
+
+#
+# Output mode "object"
+#
+
+json json_object {
+ encode {
+ output_mode = object
+ }
+}
+
+json json_object_no {
+ encode {
+ output_mode = object
+
+ value {
+ single_value_as_array = no
+ enum_as_integer = no
+ always_string = no
+ }
+ }
+}
+
+
+json json_object_ex {
+ encode {
+ output_mode = object
+
+ attribute {
+ prefix = "pf"
+ }
+
+ value {
+ single_value_as_array = yes
+ enum_as_integer = yes
+ always_string = yes
+ }
+ }
+}
+
+
+#
+# Output mode "object_simple"
+#
+
+json json_object_simple {
+ encode {
+ output_mode = object_simple
+ }
+}
+
+json json_object_simple_ex {
+ encode {
+ output_mode = object_simple
+
+ attribute {
+ prefix = "pf"
+ }
+
+ value {
+ single_value_as_array = yes
+ enum_as_integer = yes
+ always_string = yes
+ }
+ }
+}
+
+
+#
+# Output mode "array"
+#
+
+json json_array {
+ encode {
+ output_mode = array
+ }
+}
+
+json json_array_ex {
+ encode {
+ output_mode = array
+
+ attribute {
+ prefix = "pf"
+ }
+
+ value {
+ single_value_as_array = yes
+ enum_as_integer = yes
+ always_string = yes
+ }
+ }
+}
+
+
+#
+# Output mode "array_of_names"
+#
+
+json json_array_names {
+ encode {
+ output_mode = array_of_names
+ }
+}
+
+json json_array_names_ex {
+ encode {
+ output_mode = array_of_names
+
+ attribute {
+ prefix = "pf"
+ }
+
+ value {
+ single_value_as_array = yes # not valid
+ enum_as_integer = yes # not valid
+ always_string = yes # not valid
+ }
+ }
+}
+
+
+#
+# Output mode "array_of_values"
+#
+
+json json_array_values {
+ encode {
+ output_mode = array_of_values
+ }
+}
+
+json json_array_values_ex {
+ encode {
+ output_mode = array_of_values
+
+ attribute {
+ prefix = "pf" # not valid
+ }
+
+ value {
+ single_value_as_array = yes # not valid
+ enum_as_integer = yes
+ always_string = yes
+ }
+ }
+}
diff --git a/src/tests/modules/ldap/acct.attrs b/src/tests/modules/ldap/acct.attrs
new file mode 100644
index 0000000..1d57034
--- /dev/null
+++ b/src/tests/modules/ldap/acct.attrs
@@ -0,0 +1,35 @@
+#
+# Input packet
+#
+User-Name = 'john'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Start
+Acct-Delay-Time = 1
+Acct-Input-Octets = 0
+Acct-Output-Octets = 0
+Acct-Session-Id = '00000000'
+Acct-Unique-Session-Id = '00000000'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 0
+Acct-Input-Packets = 0
+Acct-Output-Packets = 0
+Acct-Input-Gigawords = 0
+Acct-Output-Gigawords = 0
+Event-Timestamp = 'Feb 1 2015 08:28:58 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/ldap/acct.unlang b/src/tests/modules/ldap/acct.unlang
new file mode 100644
index 0000000..2297ea7
--- /dev/null
+++ b/src/tests/modules/ldap/acct.unlang
@@ -0,0 +1,23 @@
+#
+# Run the "ldap" module
+# PRE: auth
+#
+ldap.accounting {
+}
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{ldap:ldap://$ENV{TEST_SERVER}/uid=john,ou=people,dc=example,dc=com?description}"
+}
+
+if (&Tmp-String-0 != "User john is online") {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/ldap/all.mk b/src/tests/modules/ldap/all.mk
new file mode 100644
index 0000000..1fc53d1
--- /dev/null
+++ b/src/tests/modules/ldap/all.mk
@@ -0,0 +1,8 @@
+#
+# Test the "ldap" module
+#
+
+# MODULE.test is the main target for this module.
+
+# Don't test ldap if TEST_SERVER ENV is not set
+ldap_require_test_server := 1
diff --git a/src/tests/modules/ldap/auth.attrs b/src/tests/modules/ldap/auth.attrs
new file mode 100644
index 0000000..be988ee
--- /dev/null
+++ b/src/tests/modules/ldap/auth.attrs
@@ -0,0 +1,15 @@
+#
+# Input packet
+#
+User-Name = "john"
+User-Password = "password"
+NAS-IP-Address = 1.2.3.5
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Idle-Timeout == 3600
+Session-Timeout == 7200
+Acct-Interim-Interval == 1800
+Framed-IP-Netmask == "255.255.0.0"
diff --git a/src/tests/modules/ldap/auth.unlang b/src/tests/modules/ldap/auth.unlang
new file mode 100644
index 0000000..edf14bf
--- /dev/null
+++ b/src/tests/modules/ldap/auth.unlang
@@ -0,0 +1,72 @@
+#
+# Run the "ldap" module
+#
+ldap
+
+if (&control:NAS-IP-Address != 1.2.3.4) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+if (&control:Reply-Message != "Hello world") {
+ test_fail
+}
+else {
+ test_pass
+}
+
+# Cmp operator means Framed-IP-Address is ignored
+if (&control:Framed-IP-Address) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+# IP netmask defined in profile1 should overwrite radprofile value.
+if (&reply:Framed-IP-Netmask != 255.255.0.0) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+if (&reply:Acct-Interim-Interval != 1800) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+if (&reply:Idle-Timeout != 3600) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+if (&reply:Session-Timeout != 7200) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+if ("%{pairs:reply:}" == "") {
+ test_fail
+}
+
+ldap.post-auth
+
+update {
+ Tmp-String-0 := "%{ldap:ldap://$ENV{TEST_SERVER}/uid=john,ou=people,dc=example,dc=com?description}"
+}
+
+if (&Tmp-String-0 != "User %{User-Name} authenticated") {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/ldap/example.com.ldif b/src/tests/modules/ldap/example.com.ldif
new file mode 120000
index 0000000..055d379
--- /dev/null
+++ b/src/tests/modules/ldap/example.com.ldif
@@ -0,0 +1 @@
+../../salt-test-server/salt/ldap/base.ldif \ No newline at end of file
diff --git a/src/tests/modules/ldap/groups_rfc2307bis.attrs b/src/tests/modules/ldap/groups_rfc2307bis.attrs
new file mode 100644
index 0000000..be988ee
--- /dev/null
+++ b/src/tests/modules/ldap/groups_rfc2307bis.attrs
@@ -0,0 +1,15 @@
+#
+# Input packet
+#
+User-Name = "john"
+User-Password = "password"
+NAS-IP-Address = 1.2.3.5
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Idle-Timeout == 3600
+Session-Timeout == 7200
+Acct-Interim-Interval == 1800
+Framed-IP-Netmask == "255.255.0.0"
diff --git a/src/tests/modules/ldap/groups_rfc2307bis.unlang b/src/tests/modules/ldap/groups_rfc2307bis.unlang
new file mode 100644
index 0000000..b8f48b5
--- /dev/null
+++ b/src/tests/modules/ldap/groups_rfc2307bis.unlang
@@ -0,0 +1,41 @@
+#
+# Run the "ldap" module
+#
+ldap
+
+#
+# Resolve using group name attribute
+#
+if (LDAP-Group == 'foo') {
+ test_pass
+}
+else {
+ test_fail
+}
+
+#
+# Resolve using group DN
+#
+if (LDAP-Group == 'cn=foo,ou=groups,dc=example,dc=com') {
+ test_pass
+}
+else {
+ test_fail
+}
+
+#
+# Check we have these values cached
+#
+if (&control:LDAP-Cached-Membership[*] == 'foo') {
+ test_pass
+}
+else {
+ test_fail
+}
+
+if (&control:LDAP-Cached-Membership[*] == 'cn=foo,ou=groups,dc=example,dc=com') {
+ test_pass
+}
+else {
+ test_fail
+}
diff --git a/src/tests/modules/ldap/module.conf b/src/tests/modules/ldap/module.conf
new file mode 100644
index 0000000..dcf3126
--- /dev/null
+++ b/src/tests/modules/ldap/module.conf
@@ -0,0 +1,537 @@
+# -*- text -*-
+#
+# $Id$
+
+#
+# Lightweight Directory Access Protocol (LDAP)
+#
+ldap {
+ # Note that this needs to match the name(s) in the LDAP server
+ # certificate, if you're using ldaps. See OpenLDAP documentation
+ # for the behavioral semantics of specifying more than one host.
+ #
+ # Depending on the libldap in use, server may be an LDAP URI.
+ # In the case of OpenLDAP this allows additional the following
+ # additional schemes:
+ # - ldaps:// (LDAP over SSL)
+ # - ldapi:// (LDAP over Unix socket)
+ # - ldapc:// (Connectionless LDAP)
+ server = $ENV{LDAP_TEST_SERVER}
+# server = 'ldap.rrdns.example.org'
+
+ # Port to connect on, defaults to 389, will be ignored for LDAP URIs.
+ port = $ENV{LDAP_TEST_SERVER_PORT}
+
+ # Administrator account for searching and possibly modifying.
+ identity = 'cn=admin,dc=example,dc=com'
+ password = secret
+
+ # Unless overridden in another section, the dn from which all
+ # searches will start from.
+ base_dn = 'dc=example,dc=com'
+
+ # SASL parameters to use for admin binds
+ #
+ # When we're prompted by the SASL library, these control
+ # the responses given.
+ #
+ sasl {
+ # SASL mechanism
+# mech = 'PLAIN'
+
+ # SASL authorisation identity to proxy.
+# proxy = 'autz_id'
+
+ # SASL realm. Used for kerberos.
+# realm = 'example.org'
+ }
+
+ #
+ # Generic valuepair attribute
+ #
+
+ # If set, this will attribute will be retrieved in addition to any
+ # mapped attributes.
+ #
+ # Values should be in the format:
+ # <radius attr> <op> <value>
+ #
+ # Where:
+ # <radius attr>: Is the attribute you wish to create
+ # with any valid list and request qualifiers.
+ # <op>: Is any assignment operator (=, :=, +=, -=).
+ # <value>: Is the value to parse into the new valuepair.
+ # If the value is wrapped in double quotes it
+ # will be xlat expanded.
+ valuepair_attribute = 'radiusAttribute'
+
+ #
+ # Mapping of LDAP directory attributes to RADIUS dictionary attributes.
+ #
+
+ # WARNING: Although this format is almost identical to the unlang
+ # update section format, it does *NOT* mean that you can use other
+ # unlang constructs in module configuration files.
+ #
+ # Configuration items are in the format:
+ # <radius attr> <op> <ldap attr>
+ #
+ # Where:
+ # <radius attr>: Is the destination RADIUS attribute
+ # with any valid list and request qualifiers.
+ # <op>: Is any assignment attribute (=, :=, +=, -=).
+ # <ldap attr>: Is the attribute associated with user or
+ # profile objects in the LDAP directory.
+ # If the attribute name is wrapped in double
+ # quotes it will be xlat expanded.
+ #
+ # Request and list qualifiers may also be placed after the 'update'
+ # section name to set defaults destination requests/lists
+ # for unqualified RADIUS attributes.
+ #
+ # Note: LDAP attribute names should be single quoted unless you want
+ # the name value to be derived from an xlat expansion, or an
+ # attribute ref.
+ update {
+ control:Password-With-Header += 'userPassword'
+ reply:Idle-Timeout := 'radiusIdleTimeout'
+ reply:Framed-IP-Netmask := 'radiusFramedIPNetmask'
+# control:NT-Password := 'ntPassword'
+# reply:Reply-Message := 'radiusReplyMessage'
+# reply:Tunnel-Type := 'radiusTunnelType'
+# reply:Tunnel-Medium-Type := 'radiusTunnelMediumType'
+# reply:Tunnel-Private-Group-ID := 'radiusTunnelPrivategroupId'
+
+ # Where only a list is specified as the RADIUS attribute,
+ # the value of the LDAP attribute is parsed as a valuepair
+ # in the same format as the 'valuepair_attribute' (above).
+ control: += 'radiusControlAttribute'
+ request: += 'radiusRequestAttribute'
+ reply: += 'radiusReplyAttribute'
+ }
+
+ # Set to yes if you have eDirectory and want to use the universal
+ # password mechanism.
+# edir = no
+
+ # Set to yes if you want to bind as the user after retrieving the
+ # Cleartext-Password. This will consume the login grace, and
+ # verify user authorization.
+# edir_autz = no
+
+ # Note: set_auth_type was removed in v3.x.x
+ # Equivalent functionality can be achieved by adding the following
+ # stanza to the authorize {} section of your virtual server.
+ #
+ # ldap
+ # if ((ok || updated) && User-Password) {
+ # update {
+ # control:Auth-Type := ldap
+ # }
+ # }
+
+ #
+ # User object identification.
+ #
+ user {
+ # Where to start searching in the tree for users
+ base_dn = "ou=people,${..base_dn}"
+
+ # Filter for user objects, should be specific enough
+ # to identify a single user object.
+ filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
+
+ # SASL parameters to use for user binds
+ #
+ # When we're prompted by the SASL library, these control
+ # the responses given.
+ #
+ # Any of the config items below may be an attribute ref
+ # or and expansion, so different SASL mechs, proxy IDs
+ # and realms may be used for different users.
+ sasl {
+ # SASL mechanism
+# mech = 'PLAIN'
+
+ # SASL authorisation identity to proxy.
+# proxy = &User-Name
+
+ # SASL realm. Used for kerberos.
+# realm = 'example.org'
+ }
+
+ # Search scope, may be 'base', 'one', sub' or 'children'
+# scope = 'sub'
+
+ # If this is undefined, anyone is authorised.
+ # If it is defined, the contents of this attribute
+ # determine whether or not the user is authorised
+# access_attribute = 'dialupAccess'
+
+ # Control whether the presence of 'access_attribute'
+ # allows access, or denys access.
+ #
+ # If 'yes', and the access_attribute is present, or
+ # 'no' and the access_attribute is absent then access
+ # will be allowed.
+ #
+ # If 'yes', and the access_attribute is absent, or
+ # 'no' and the access_attribute is present, then
+ # access will not be allowed.
+ #
+ # If the value of the access_attribute is 'false', it
+ # will negate the result.
+ #
+ # e.g.
+ # access_positive = yes
+ # access_attribute = userAccessAllowed
+ #
+ # With an LDAP object containing:
+ # userAccessAllowed: false
+ #
+ # Will result in the user being locked out.
+# access_positive = yes
+ }
+
+ #
+ # User membership checking.
+ #
+ group {
+ # Where to start searching in the tree for groups
+ base_dn = "ou=groups,${..base_dn}"
+
+ # Filter for group objects, should match all available
+ # group objects a user might be a member of.
+ filter = '(objectClass=groupOfNames)'
+
+ # Search scope, may be 'base', 'one', sub' or 'children'
+ scope = 'sub'
+
+ # Attribute that uniquely identifies a group.
+ # Is used when converting group DNs to group
+ # names.
+ name_attribute = cn
+
+ # Filter to find group objects a user is a member of.
+ # That is, group objects with attributes that
+ # identify members (the inverse of membership_attribute).
+ membership_filter = "(|(member=%{control:Ldap-UserDn})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"
+
+ # The attribute in user objects which contain the names
+ # or DNs of groups a user is a member of.
+ #
+ # Unless a conversion between group name and group DN is
+ # needed, there's no requirement for the group objects
+ # referenced to actually exist.
+ membership_attribute = 'memberOf'
+
+ # If cacheable_name or cacheable_dn are enabled,
+ # all group information for the user will be
+ # retrieved from the directory and written to LDAP-Group
+ # attributes appropriate for the instance of rlm_ldap.
+ #
+ # For group comparisons these attributes will be checked
+ # instead of querying the LDAP directory directly.
+ #
+ # This feature is intended to be used with rlm_cache.
+ #
+ # If you wish to use this feature, you should enable
+ # the type that matches the format of your check items
+ # i.e. if your groups are specified as DNs then enable
+ # cacheable_dn else enable cacheable_name.
+ cacheable_name = yes
+ cacheable_dn = yes
+
+ # Override the normal cache attribute (<inst>-LDAP-Group)
+ # and create a custom attribute. This can help if multiple
+ # module instances are used in fail-over.
+ cache_attribute = 'LDAP-Cached-Membership'
+ }
+
+ #
+ # User profiles. RADIUS profile objects contain sets of attributes
+ # to insert into the request. These attributes are mapped using
+ # the same mapping scheme applied to user objects.
+ #
+ profile {
+ # Filter for RADIUS profile objects
+ filter = '(objectclass=radiusprofile)'
+
+ # The default profile applied to all users.
+ default = 'cn=radprofile,ou=profiles,dc=example,dc=com'
+
+ # The list of profiles which are applied (after the default)
+ # to all users.
+ # The 'User-Profile' attribute in the control list
+ # will override this setting at run-time.
+ attribute = 'radiusProfileDn'
+ }
+
+ #
+ # Bulk load clients from the directory
+ #
+ client {
+ # Where to start searching in the tree for clients
+ base_dn = "ou=clients,${..base_dn}"
+
+ #
+ # Filter to match client objects
+ #
+ filter = '(objectClass=radiusClient)'
+
+ # Search scope, may be 'base', 'one', 'sub' or 'children'
+# scope = 'sub'
+
+ #
+ # Sets default values (not obtained from LDAP) for new client entries
+ #
+ template {
+# login = 'test'
+# password = 'test'
+# proto = tcp
+# require_message_authenticator = yes
+
+ # Uncomment to add a home_server with the same
+ # attributes as the client.
+# coa_server {
+# response_window = 2.0
+# }
+ }
+
+ #
+ # Client attribute mappings are in the format:
+ # <client attribute> = <ldap attribute>
+ #
+ # The following attributes are required:
+ # * ipaddr | ipv4addr | ipv6addr - Client IP Address.
+ # * secret - RADIUS shared secret.
+ #
+ # All other attributes usually supported in a client
+ # definition are also supported here.
+ #
+ # Schemas are available in doc/schemas/ldap for openldap and eDirectory
+ #
+ attribute {
+ ipaddr = 'radiusClientIdentifier'
+ secret = 'radiusClientSecret'
+# shortname = 'radiusClientShortname'
+# nas_type = 'radiusClientType'
+# virtual_server = 'radiusClientVirtualServer'
+# require_message_authenticator = 'radiusClientRequireMa'
+ }
+ }
+
+ # Load clients on startup
+# read_clients = no
+
+ #
+ # Modify user object on receiving Accounting-Request
+ #
+
+ # Useful for recording things like the last time the user logged
+ # in, or the Acct-Session-ID for CoA/DM.
+ #
+ # LDAP modification items are in the format:
+ # <ldap attr> <op> <value>
+ #
+ # Where:
+ # <ldap attr>: The LDAP attribute to add modify or delete.
+ # <op>: One of the assignment operators:
+ # (:=, +=, -=, ++).
+ # Note: '=' is *not* supported.
+ # <value>: The value to add modify or delete.
+ #
+ # WARNING: If using the ':=' operator with a multi-valued LDAP
+ # attribute, all instances of the attribute will be removed and
+ # replaced with a single attribute.
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}}"
+
+ type {
+ start {
+ update {
+ description := "User %{User-Name} is online"
+ }
+ }
+
+ interim-update {
+ update {
+ description := "Last seen at %S"
+ }
+ }
+
+ stop {
+ update {
+ description := "Offline at %S"
+ }
+ }
+ }
+ }
+
+ #
+ # Post-Auth can modify LDAP objects too
+ #
+ post-auth {
+ update {
+ description := "User %{User-Name} authenticated"
+ }
+ }
+
+ #
+ # LDAP connection-specific options.
+ #
+ # These options set timeouts, keep-alives, etc. for the connections.
+ #
+ options {
+ # Control under which situations aliases are followed.
+ # May be one of 'never', 'searching', 'finding' or 'always'
+ # default: libldap's default which is usually 'never'.
+ #
+ # LDAP_OPT_DEREF is set to this value.
+# dereference = 'always'
+
+ #
+ # The following two configuration items control whether the
+ # server follows references returned by LDAP directory.
+ # They are mostly for Active Directory compatibility.
+ # If you set these to 'no', then searches will likely return
+ # 'operations error', instead of a useful result.
+ #
+ chase_referrals = yes
+ rebind = yes
+
+ # Seconds to wait for LDAP query to finish. default: 20
+ timeout = 10
+
+ # Seconds LDAP server has to process the query (server-side
+ # time limit). default: 20
+ #
+ # LDAP_OPT_TIMELIMIT is set to this value.
+ timelimit = 3
+
+ # Seconds to wait for response of the server. (network
+ # failures) default: 10
+ #
+ # LDAP_OPT_NETWORK_TIMEOUT is set to this value.
+ net_timeout = 1
+
+ # LDAP_OPT_X_KEEPALIVE_IDLE
+ idle = 60
+
+ # LDAP_OPT_X_KEEPALIVE_PROBES
+ probes = 3
+
+ # LDAP_OPT_X_KEEPALIVE_INTERVAL
+ interval = 3
+
+ # ldap_debug: debug flag for LDAP SDK
+ # (see OpenLDAP documentation). Set this to enable
+ # huge amounts of LDAP debugging on the screen.
+ # You should only use this if you are an LDAP expert.
+ #
+ # default: 0x0000 (no debugging messages)
+ # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS)
+ ldap_debug = 0x0801
+ }
+
+ #
+ # This subsection configures the tls related items
+ # that control how FreeRADIUS connects to an LDAP
+ # server. It contains all of the 'tls_*' configuration
+ # entries used in older versions of FreeRADIUS. Those
+ # configuration entries can still be used, but we recommend
+ # using these.
+ #
+ tls {
+ # Set this to 'yes' to use TLS encrypted connections
+ # to the LDAP database by using the StartTLS extended
+ # operation.
+ #
+ # The StartTLS operation is supposed to be
+ # used with normal ldap connections instead of
+ # using ldaps (port 636) connections
+# start_tls = yes
+
+# ca_file = ${certdir}/cacert.pem
+
+# ca_path = ${certdir}
+# certificate_file = /path/to/radius.crt
+# private_key_file = /path/to/radius.key
+# random_file = ${certdir}/random
+
+ # Certificate Verification requirements. Can be:
+ # 'never' (don't even bother trying)
+ # 'allow' (try, but don't fail if the certificate
+ # can't be verified)
+ # 'demand' (fail if the certificate doesn't verify.)
+ #
+ # The default is 'allow'
+# require_cert = 'demand'
+ }
+
+
+ # As of version 3.0, the 'pool' section has replaced the
+ # following configuration items:
+ #
+ # ldap_connections_number
+
+ # The connection pool is new for 3.0, and will be used in many
+ # modules, for all kinds of connection-related activity.
+ #
+ # When the server is not threaded, the connection pool
+ # limits are ignored, and only one connection is used.
+ pool {
+ # Number of connections to start
+ start = 5
+
+ # Minimum number of connections to keep open
+ min = 4
+
+ # Maximum number of connections
+ #
+ # If these connections are all in use and a new one
+ # is requested, the request will NOT get a connection.
+ #
+ # Setting 'max' to LESS than the number of threads means
+ # that some threads may starve, and you will see errors
+ # like 'No connections available and at max connection limit'
+ #
+ # Setting 'max' to MORE than the number of threads means
+ # that there are more connections than necessary.
+ max = 4
+
+ # Spare connections to be left idle
+ #
+ # NOTE: Idle connections WILL be closed if 'idle_timeout'
+ # is set.
+ spare = 3
+
+ # Number of uses before the connection is closed
+ #
+ # 0 means 'infinite'
+ uses = 0
+
+ # The lifetime (in seconds) of the connection
+ lifetime = 0
+
+ # Idle timeout (in seconds). A connection which is
+ # unused for this length of time will be closed.
+ idle_timeout = 60
+
+ # The number of seconds to wait after the server tries
+ # to open a connection, and fails. During this time,
+ # no new connections will be opened.
+ #
+ retry_delay = 1
+
+ # NOTE: All configuration settings are enforced. If a
+ # connection is closed because of 'idle_timeout',
+ # 'uses', or 'lifetime', then the total number of
+ # connections MAY fall below 'min'. When that
+ # happens, it will open a new connection. It will
+ # also log a WARNING message.
+ #
+ # The solution is to either lower the 'min' connections,
+ # or increase lifetime/idle_timeout.
+ }
+}
diff --git a/src/tests/modules/pap/all.mk b/src/tests/modules/pap/all.mk
new file mode 100644
index 0000000..5c1de6f
--- /dev/null
+++ b/src/tests/modules/pap/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "pap" module
+#
diff --git a/src/tests/modules/pap/module.conf b/src/tests/modules/pap/module.conf
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/tests/modules/pap/module.conf
@@ -0,0 +1 @@
+
diff --git a/src/tests/modules/pap/pbkfd2_dig_big.attrs b/src/tests/modules/pap/pbkfd2_dig_big.attrs
new file mode 100644
index 0000000..90fc451
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_dig_big.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_dig_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_dig_big.unlang b/src/tests/modules/pap/pbkfd2_dig_big.unlang
new file mode 100644
index 0000000..449967f
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_dig_big.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_dig_big') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_dig_small.attrs b/src/tests/modules/pap/pbkfd2_dig_small.attrs
new file mode 100644
index 0000000..dbc5bdd
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_dig_small.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_dig_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_dig_small.unlang b/src/tests/modules/pap/pbkfd2_dig_small.unlang
new file mode 100644
index 0000000..37f08ee
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_dig_small.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_dig_small') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI'
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter0.attrs b/src/tests/modules/pap/pbkfd2_iter0.attrs
new file mode 100644
index 0000000..871017e
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter0.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter0'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter0.unlang b/src/tests/modules/pap/pbkfd2_iter0.unlang
new file mode 100644
index 0000000..ca362c9
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter0.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter0') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAP:CuNDJ9NimZoP5ljnPNCBUA==:f09zV7dReGg5SIv/EXY9tCL4XQRr5guhL0Q6UXSKI3c='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter1.attrs b/src/tests/modules/pap/pbkfd2_iter1.attrs
new file mode 100644
index 0000000..e3d62cb
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter1.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter1.unlang b/src/tests/modules/pap/pbkfd2_iter1.unlang
new file mode 100644
index 0000000..6758c9b
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter1.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter1') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:OErtptMl2hOxhQqvNw7sNw==:4KkrgL+3Q9j8KlHPivtApBKRZAjyWjtDWmZEz2UjNko='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter1000.attrs b/src/tests/modules/pap/pbkfd2_iter1000.attrs
new file mode 100644
index 0000000..10a19c3
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter1000.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter1000'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter1000.unlang b/src/tests/modules/pap/pbkfd2_iter1000.unlang
new file mode 100644
index 0000000..18fe680
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter1000.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter1000') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAD6A:yhmqoKrtPLY2KYK6cNjnfw==:Y6gkSZEo4TRtlsryHqnGYZhoe2qn5tJ4IUyyVHb/3WU='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter100000.attrs b/src/tests/modules/pap/pbkfd2_iter100000.attrs
new file mode 100644
index 0000000..8da916c
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter100000.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter100000'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_iter100000.unlang b/src/tests/modules/pap/pbkfd2_iter100000.unlang
new file mode 100644
index 0000000..a1253e6
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter100000.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter100000') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AA9CQA:fCfnJGMVC1QLtTOPiaSICA==:KCmjMpQ+lokMvyFTl4f4pPJNc0xJq4iHZPdtHa0OEXM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter_big.attrs b/src/tests/modules/pap/pbkfd2_iter_big.attrs
new file mode 100644
index 0000000..9f8dddb
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_big.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter_big.unlang b/src/tests/modules/pap/pbkfd2_iter_big.unlang
new file mode 100644
index 0000000..464d944
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_big.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter_big') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ==:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter_miss.attrs b/src/tests/modules/pap/pbkfd2_iter_miss.attrs
new file mode 100644
index 0000000..983db26
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_miss.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_miss'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter_miss.unlang b/src/tests/modules/pap/pbkfd2_iter_miss.unlang
new file mode 100644
index 0000000..44d961a
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_miss.unlang
@@ -0,0 +1,19 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter_miss') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256::E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_iter_small.attrs b/src/tests/modules/pap/pbkfd2_iter_small.attrs
new file mode 100644
index 0000000..af8351b
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_small.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_iter_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/pap/pbkfd2_iter_small.unlang b/src/tests/modules/pap/pbkfd2_iter_small.unlang
new file mode 100644
index 0000000..7edee80
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_iter_small.unlang
@@ -0,0 +1,19 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_iter_small') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAA:E+VXOSsE8RwyYGdygQoW9Q==:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_passlib.attrs b/src/tests/modules/pap/pbkfd2_passlib.attrs
new file mode 100644
index 0000000..29738bb
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_passlib.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_passlib'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_passlib.unlang b/src/tests/modules/pap/pbkfd2_passlib.unlang
new file mode 100644
index 0000000..6d0f27d
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_passlib.unlang
@@ -0,0 +1,20 @@
+# Fixme - Base64 decode seems off for alt base64
+test_pass
+
+#if ("${feature.tls}" == no) {
+# test_pass
+# return
+#}
+
+#if (&User-Name == 'pbkdf2_passlib') {
+# update control {
+# &PBKDF2-Password := '$pbkdf2-sha256$29000$9t7be09prfXee2/NOUeotQ$Y.RDnnq8vsezSZSKy1QNy6xhKPdoBIwc.0XDdRm9sJ8'
+# }
+# pap.authorize
+# pap.authenticate
+# if (!ok) {
+# test_fail
+# } else {
+# test_pass
+# }
+#}
diff --git a/src/tests/modules/pap/pbkfd2_salt0.attrs b/src/tests/modules/pap/pbkfd2_salt0.attrs
new file mode 100644
index 0000000..7e6d209
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt0.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt0'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_salt0.unlang b/src/tests/modules/pap/pbkfd2_salt0.unlang
new file mode 100644
index 0000000..173f768
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt0.unlang
@@ -0,0 +1,19 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt0') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAnEA::4RJEKVFQ5nE8126aURI0cJO9tqy/DIAhq64piBEwshA='
+ }
+ pap.authorize
+ pap.authenticate {
+ invalid = 1
+ }
+ if (invalid) {
+ test_pass
+ } else {
+ test_fail
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_salt1.attrs b/src/tests/modules/pap/pbkfd2_salt1.attrs
new file mode 100644
index 0000000..20ff1fe
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt1.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_salt1.unlang b/src/tests/modules/pap/pbkfd2_salt1.unlang
new file mode 100644
index 0000000..4aa0fce
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt1.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt1') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAnEA:qg==:KQzCdedgOZYFwx+mQp1TKA8VM4fwf02pqSdJEh2ekwM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_salt1024.attrs b/src/tests/modules/pap/pbkfd2_salt1024.attrs
new file mode 100644
index 0000000..30f2706
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt1024.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt1024'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_salt1024.unlang b/src/tests/modules/pap/pbkfd2_salt1024.unlang
new file mode 100644
index 0000000..a4aab5e
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt1024.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt1024') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAnEA:/IUrkJKe+1kzJNBw7aAMbnQuSFZpjbCqPeKso3cbuSUzWinxngxjK8yyZLiWwF+WE/0Gplfx25zZEQNTdRTvjZZNefoxQBR8Hht0FpdU9YiEBaeErwVo63EDEu83+ycvB18uH0IXpJKGSSkIPRfGpHT3BkwJDGo5SqjRJadDsyQzkc/WJCMrrfJ0igaWMxb5eR5J8qfXIjBFepRrOOU6acZGtANW8qvDYLJwN+TMd9Jb1wDDY14eoAlKglTF21S3kewNMkDDyeP+oDYv29t1S/soFUnnB+Pb5IdR6pDy2VDGx4jFZMQGshSHWTYQFqgulavS/tGEF8TvzcorrJZKuksAjKdTSmfZ6j4aBY3U+oMSQ+2lO131pkNfNQuMsDfr72r9wUA2xRgUiL/J7CgKn7mamL2OCaksl0Rw2PGqqIaHvAYS6Q1EoIzsmLNrWBYYqTRLyCGZw6+hUOahYRon2lglGmnuWHPfowU+LgcaR5gF1QjvTXhXQ8I39mB3ePgdi+7TUn644Z1FB+JTqGJbue92x4V40Zyyy+Qdt52QsR49iYokbKAwQRiqfVJ7J8NzCY/kIQnqT9RE0NCxZoMBRzboZxVPchxdpmWGQ9dXP06PqIuDCFFiJlVQUfyPMgOAxIlVJ/9NAmj5MWFdWMrmlBNDx9ihEV1FdTv23iFZH5Ejg+x4D3qN5oOyCDL2i9lobzFXh5z4EDpbbogQaFkUzqKEaxRGPBrfYVOi6XXYujVUnxHJaRxbs2UqjpJNsXMg8f7P78aRvOKCIbW70CHWlt7nF0pA5+kFUQRLXKuq7bW+ivoXKeDW5o4FVP3+Pcr67+DOsUXuehALLj9Mu2ICWlMIV/AWcM2szaqk1bwSo7bAeG4RtDKmNjGA7gpnT+w2x+/qS1eWbc832Sumqc1IA8aY6HNVDPsJZf99To4BR+N0rCoQQ/KIZybI31mQagR3+FR9yNzqWzKIl+qf69RTc1CbUCkKVF8pxWZ0ocP+CAdoKadgpdF8evQIiGcUD73HiJ0RsDWo21y0tN0P5jfzWo3WMhCk9e2wl6o1JAfKw54uHzWJnNlGLBK1LXF+R2m+WvNGBgvUhh4PtYV9gPSudumFdk614oak/Aqcn6xi+YZqOMPkW4WYaiczhHyS7qAyefqKaQkRVYS0Af+79CSjlxZJq57HrD7/1E+d/i0gKmSAbPe80uGHs2a13V3VxztFMBi4xD7zj9Mq7+0goVPD4MNXcR651MZ7vxDRGbvPPmclddZe/nkTEn1YB/909b9mC5P/XzximZYW8gEhBReZouukADRTAjuH8zgSIv6/uyTURnmSVoOumVLBpL7veJIzDm4dZ38BWiasiBnzgMuG9A==:RUoCF5O11OgwLFMTqnKY/yRJy6DYh+yNq4xHZC7COGM='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_salt64.attrs b/src/tests/modules/pap/pbkfd2_salt64.attrs
new file mode 100644
index 0000000..da036f3
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt64.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt64'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept \ No newline at end of file
diff --git a/src/tests/modules/pap/pbkfd2_salt64.unlang b/src/tests/modules/pap/pbkfd2_salt64.unlang
new file mode 100644
index 0000000..754cdba
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt64.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt64') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAnEA:msGxE1XuC+wlgRr+H4+ioyxZuiN3KYLUSky2FINDTq7KJylKt4XnqloV+FuHGXUbOu1EWcsFp51u2z8wdXVnQQ==:rAV9BeEJH5kt9uZ6pJt0o5pYpN5LQRe4MAYyk2jvjpU='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_salt_big.attrs b/src/tests/modules/pap/pbkfd2_salt_big.attrs
new file mode 100644
index 0000000..ccb593e
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt_big.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt_big'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_salt_big.unlang b/src/tests/modules/pap/pbkfd2_salt_big.unlang
new file mode 100644
index 0000000..cfc96c5
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt_big.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt_big') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9QA==:pF23EcxNBhJLQ+9JRtd9wQ1Gz+k4i6YjeNZq+7DRBX8='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_salt_small.attrs b/src/tests/modules/pap/pbkfd2_salt_small.attrs
new file mode 100644
index 0000000..1c2fa20
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt_small.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_salt_small'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_salt_small.unlang b/src/tests/modules/pap/pbkfd2_salt_small.unlang
new file mode 100644
index 0000000..e46982f
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_salt_small.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_salt_small') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAAAQ:E+VXOSsE8RwyYGdygQoW9Q=:UivlvrwHML4VtZHMJLiT/xlH7oyoyvbXQceivptq9TI='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_sha1.attrs b/src/tests/modules/pap/pbkfd2_sha1.attrs
new file mode 100644
index 0000000..ef7538f
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha1.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha1'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_sha1.unlang b/src/tests/modules/pap/pbkfd2_sha1.unlang
new file mode 100644
index 0000000..5b79691
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha1.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_sha1') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA1:AAAD6A:Xw1P133xrwk=:dtQBXQRiR/No5A8Ip3JFGF/qUC0='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_sha2_224.attrs b/src/tests/modules/pap/pbkfd2_sha2_224.attrs
new file mode 100644
index 0000000..413f893
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_224.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_224'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_sha2_224.unlang b/src/tests/modules/pap/pbkfd2_sha2_224.unlang
new file mode 100644
index 0000000..00fa626
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_224.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_sha2_224') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+224:AAAnEA:UHScBrg/ZWOyBKqQdAh7bw==:tcFp6CDrkIYdhwa60g24U4ko+mBxzAiFxlpPnA=='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_sha2_256.attrs b/src/tests/modules/pap/pbkfd2_sha2_256.attrs
new file mode 100644
index 0000000..3066682
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_256.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_256'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_sha2_256.unlang b/src/tests/modules/pap/pbkfd2_sha2_256.unlang
new file mode 100644
index 0000000..5c4efce
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_256.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_sha2_256') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+256:AAAnEA:a/8HbYW2HWsMthN27JI+Ew==:3nPlXYOlOuDCFOfethUomHxTXkG9JCivOdvh6FDNdGw='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_sha2_384.attrs b/src/tests/modules/pap/pbkfd2_sha2_384.attrs
new file mode 100644
index 0000000..9e43450
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_384.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_384'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_sha2_384.unlang b/src/tests/modules/pap/pbkfd2_sha2_384.unlang
new file mode 100644
index 0000000..034bb83
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_384.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_sha2_384') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+384:AAAnEA:pyHRsYLfNZdjszRcu6eHrA==:ktGfNmZ6PyD8FNEgPzFK1fypKERZ13pgvFl+PQdyKouaMXsXIiWPuTMXHqDUCWsx'
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/pap/pbkfd2_sha2_512.attrs b/src/tests/modules/pap/pbkfd2_sha2_512.attrs
new file mode 100644
index 0000000..b908615
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_512.attrs
@@ -0,0 +1,10 @@
+#
+# Input packet
+#
+User-Name = 'pbkdf2_sha2_512'
+User-Password = 'password'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/pap/pbkfd2_sha2_512.unlang b/src/tests/modules/pap/pbkfd2_sha2_512.unlang
new file mode 100644
index 0000000..95c1f3e
--- /dev/null
+++ b/src/tests/modules/pap/pbkfd2_sha2_512.unlang
@@ -0,0 +1,17 @@
+if ("${feature.tls}" == no) {
+ test_pass
+ return
+}
+
+if (&User-Name == 'pbkdf2_sha2_512') {
+ update control {
+ &PBKDF2-Password := 'HMACSHA2+512:AAAnEA:TG8Mb94NEmfPLaePwi5CFA==:SYSFeRf9jr4Uo5DB4NvNUEuc1gmEiLjTac5J4WgyKa7mO58KHKWop9xWmcFeuLtUN/iexLTNSgcubOugAyZcog=='
+ }
+ pap.authorize
+ pap.authenticate
+ if (!ok) {
+ test_fail
+ } else {
+ test_pass
+ }
+}
diff --git a/src/tests/modules/preprocess/all.mk b/src/tests/modules/preprocess/all.mk
new file mode 100644
index 0000000..5cfad60
--- /dev/null
+++ b/src/tests/modules/preprocess/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "preprocess" module
+#
diff --git a/src/tests/modules/preprocess/hints b/src/tests/modules/preprocess/hints
new file mode 100644
index 0000000..14ceafc
--- /dev/null
+++ b/src/tests/modules/preprocess/hints
@@ -0,0 +1,2 @@
+DEFAULT
+ Calling-Station-Id := "%{User-Name}@%{NAS-IP-Address}"
diff --git a/src/tests/modules/preprocess/huntgroups b/src/tests/modules/preprocess/huntgroups
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tests/modules/preprocess/huntgroups
diff --git a/src/tests/modules/preprocess/module.conf b/src/tests/modules/preprocess/module.conf
new file mode 100644
index 0000000..7c51fa6
--- /dev/null
+++ b/src/tests/modules/preprocess/module.conf
@@ -0,0 +1,4 @@
+preprocess {
+ hints = $ENV{MODULE_TEST_DIR}/hints
+ huntgroups = $ENV{MODULE_TEST_DIR}/huntgroups
+}
diff --git a/src/tests/modules/preprocess/xlat.attrs b/src/tests/modules/preprocess/xlat.attrs
new file mode 100644
index 0000000..e7170d1
--- /dev/null
+++ b/src/tests/modules/preprocess/xlat.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "bob"
+User-Password = "bob"
+NAS-IP-Address = 127.0.0.1
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Filter-Id == 'success'
diff --git a/src/tests/modules/preprocess/xlat.unlang b/src/tests/modules/preprocess/xlat.unlang
new file mode 100644
index 0000000..da53982
--- /dev/null
+++ b/src/tests/modules/preprocess/xlat.unlang
@@ -0,0 +1,14 @@
+#
+# Run the preprocess module
+#
+preprocess
+
+if (Calling-Station-Id == "bob@127.0.0.1") {
+ update reply {
+ Filter-Id := "success"
+ }
+}
+
+update control {
+ Cleartext-Password := "%{User-Name}"
+}
diff --git a/src/tests/modules/radiusd.conf b/src/tests/modules/radiusd.conf
new file mode 100644
index 0000000..f2dce8a
--- /dev/null
+++ b/src/tests/modules/radiusd.conf
@@ -0,0 +1,103 @@
+#
+# Minimal radiusd.conf for testing modules
+#
+
+raddb = raddb
+
+modconfdir = ${raddb}/mods-config
+
+correct_escapes = true
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+modules {
+ $INCLUDE ${raddb}/mods-enabled/always
+
+ $INCLUDE ${raddb}/mods-enabled/pap
+
+ $INCLUDE ${raddb}/mods-enabled/expr
+
+ $INCLUDE $ENV{MODULE_TEST_DIR}/module.conf
+}
+
+server default {
+ authorize {
+ #
+ # Include the test file specified by the
+ # KEYWORD environment variable.
+ #
+ $INCLUDE $ENV{MODULE_TEST_UNLANG}
+
+ pap
+ }
+
+ authenticate {
+ pap
+ }
+}
+
+policy {
+ test_pass {
+ update control {
+ &Tmp-String-8 := "%{expr:%{%{control:Tmp-String-8}:-0} + 1}"
+ &Auth-Type := Accept
+ }
+ }
+
+ test_fail {
+ update reply {
+ &Reply-Message := "fail %{%{control:Tmp-String-8}:-0}"
+ }
+ reject
+ }
+
+ #
+ # Outputs the contents of the control list in debugging (-X) mode
+ #
+ debug_control {
+ if("%{debug_attr:control:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the request list in debugging (-X) mode
+ #
+ debug_request {
+ if("%{debug_attr:request:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the reply list in debugging (-X) mode
+ #
+ debug_reply {
+ if("%{debug_attr:reply:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the session state list in debugging (-X) mode
+ #
+ debug_session_state {
+ if("%{debug_attr:session-state:}" == '') {
+ noop
+ }
+ }
+
+ #
+ # Outputs the contents of the main lists in debugging (-X) mode
+ #
+ debug_all {
+ debug_control
+ debug_request
+ debug_reply
+ debug_session_state
+ }
+}
diff --git a/src/tests/modules/rest/all.mk b/src/tests/modules/rest/all.mk
new file mode 100644
index 0000000..e2a6133
--- /dev/null
+++ b/src/tests/modules/rest/all.mk
@@ -0,0 +1,6 @@
+#
+# Test the "rest" module
+#
+
+# Don't test smtp if REST_TEST_SERVER ENV is not set
+rest_require_test_server := 1
diff --git a/src/tests/modules/rest/module.conf b/src/tests/modules/rest/module.conf
new file mode 100644
index 0000000..ecfaa53
--- /dev/null
+++ b/src/tests/modules/rest/module.conf
@@ -0,0 +1,46 @@
+#rest unit test config
+json {
+}
+
+rest {
+ tls {
+ ca_info_file = "$ENV{top_srcdir}raddb/restcerts/ca.pem"
+
+ private_key_password = "whatever"
+
+ random_file = /dev/urandom
+
+ check_cert_cn = no
+ }
+
+ connect_uri = "http://$ENV{REST_TEST_SERVER}:$ENV{REST_TEST_SERVER_PORT}/"
+
+ xlat {
+ body_uri_encode = no
+ timeout = 0.5
+ tls = ${..tls}
+ }
+
+ authorize {
+ uri = "${..connect_uri}/user/%{User-Name}/mac/%{Called-Station-ID}?section=authorize"
+ method = "GET"
+ tls = ${..tls}
+ }
+
+ authenticate {
+ uri = "https://$ENV{REST_TEST_SERVER}:$ENV{REST_TEST_SERVER_SSL_PORT}/auth?section=authenticate"
+ method = "POST"
+ tls = ${..tls}
+ body = 'post'
+ data = 'user=%{User-Name}'
+ auth = 'basic'
+ }
+
+ accounting {
+ uri = "https://$ENV{REST_TEST_SERVER}:$ENV{REST_TEST_SERVER_SSL_PORT}/user/%{User-Name}/mac/%{Called-Station-ID}?action=post-auth&section=accounting"
+ method = 'POST'
+ body = 'json'
+ data = '{"NAS": "%{NAS-IP-Address}", "Password": "%{User-Password}", "Verify": true}'
+ tls = ${..tls}
+ }
+}
diff --git a/src/tests/modules/rest/rest_module.attrs b/src/tests/modules/rest/rest_module.attrs
new file mode 100644
index 0000000..3ecf895
--- /dev/null
+++ b/src/tests/modules/rest/rest_module.attrs
@@ -0,0 +1,14 @@
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = 'Bob'
+User-Password = 'Saget'
+Called-Station-Id = 'aa:bb:cc:dd:ee:ff'
+NAS-IP-Address = '192.168.1.1'
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/rest/rest_module.unlang b/src/tests/modules/rest/rest_module.unlang
new file mode 100644
index 0000000..c78c380
--- /dev/null
+++ b/src/tests/modules/rest/rest_module.unlang
@@ -0,0 +1,111 @@
+# Pre-set Tmp-String-2 to check correct operator behaviour
+update {
+ &control:Tmp-String-2 := "foo"
+}
+
+# Test "authorize" rest call. Uses http to a GET end point
+rest
+
+debug_control
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-0 == "authorize")) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-1 == "GET")) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-1[*] == "/user/<username>/mac/<client>")) {
+ test_fail
+}
+
+if (!(&control:User-Name == "Bob")) {
+ test_fail
+}
+
+# The "op" for setting Tmp-String-2 is ^=
+if (!(&control:Tmp-String-2[0] == "Bob") || !(&control:Tmp-String-2[1] == "foo")) {
+ test_fail
+}
+
+# Reset control attributes
+update control {
+ &Tmp-String-0[*] !* ANY
+ &Tmp-String-1[*] !* ANY
+ &User-Name[*] !* ANY
+}
+
+# Pre-fill NAS-IP-Address to check operator behaviour
+update {
+ &control:NAS-IP-Address := "10.0.0.10"
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# Test "accounting" rest call. Uses https to a POST end point
+rest.accounting
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-0 == "accounting")) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-1 == "POST")) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-1[*] == "/user/<username>/mac/<client>")) {
+ test_fail
+}
+
+if (!(&control:User-Name == "Bob")) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-2[0] == "Bob") || !(&control:Tmp-String-2[1] == "Bob") || !(&control:Tmp-String-2[2] == "foo")) {
+ test_fail
+}
+
+# NAS IP Address is passed in body data
+if (!(&control:NAS-IP-Address[0] == "10.0.0.10") || !(&control:NAS-IP-Address[1] == "192.168.1.1")) {
+ test_fail
+}
+
+debug_control
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# Test "authenticate" rest call. Uses http basic authentication
+rest.authenticate
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&reply:REST-HTTP-Body == "Section: authenticate, User: Bob, Authenticated: true\n")) {
+ test_fail
+}
+
+# Clear up reply
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+test_pass
diff --git a/src/tests/modules/rest/rest_xlat.attrs b/src/tests/modules/rest/rest_xlat.attrs
new file mode 100644
index 0000000..6370197
--- /dev/null
+++ b/src/tests/modules/rest/rest_xlat.attrs
@@ -0,0 +1,18 @@
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = 'Bob'
+User-Password = 'Saget'
+Called-Station-Id = 'aa:bb:cc:dd:ee:ff'
+NAS-IP-Address = '192.168.1.1'
+Login-IP-Host = 127.0.0.1
+NAS-Port = 8080
+Calling-Station-Id = 'dummy&unsafe=escaped'
+Tmp-String-9 = ''
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+
diff --git a/src/tests/modules/rest/rest_xlat.unlang b/src/tests/modules/rest/rest_xlat.unlang
new file mode 100644
index 0000000..52eb597
--- /dev/null
+++ b/src/tests/modules/rest/rest_xlat.unlang
@@ -0,0 +1,208 @@
+#
+# PRE rest_module eval
+#
+# Largely a back port of the rlm_rest tests from v4, with v4 specific functionality removed.
+#
+
+update {
+ &Tmp-String-0 := "$ENV{REST_TEST_SERVER}"
+ &Tmp-Integer-0 := "$ENV{REST_TEST_SERVER_PORT}"
+ &Tmp-Integer-1 := "$ENV{REST_TEST_SERVER_SSL_PORT}"
+ &Tmp-String-1 := "notfound"
+}
+
+# Retrieve a plain text file
+update {
+ &control:Tmp-String-1 := "%{rest:GET http://%{Tmp-String-0}:%{Tmp-Integer-0}/test.txt}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&control:Tmp-String-1 == "Sample text response\n")) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# Take host from incomming packet
+update {
+ &control:Tmp-String-1 := "%{rest:http://%{Login-IP-Host}:%{Tmp-Integer-0}/test.txt}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 200) || !(&control:Tmp-String-1 == "Sample text response\n")) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# Check a "not found" gives a 404 status code
+update {
+ &control:Tmp-String-1 := "%{rest:GET http://%{Tmp-String-0}:%{Tmp-Integer-0}/%{Tmp-String-1}}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 404)) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# GET with URL parameters
+update {
+ &Tmp-String-2 := "%{rest:GET http://%{Tmp-String-0}:%{Tmp-Integer-0}/user/%{User-Name}/mac/%{Called-Station-Id}}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&Tmp-String-2 =~ /"control:Tmp-String-1":\["GET","\\\/user\\\/<username>\\\/mac\\\/<client>"\]/)) {
+ test_fail
+}
+
+if (&Tmp-String-2 =~ /"control:User-Name":\{([^}]+)\}/) {
+ if (!("%{1}" =~ /"value":"Bob"/)) {
+ test_fail
+ }
+} else {
+ test_fail
+}
+
+update {
+ &control:Tmp-String-3 := 'dummy'
+}
+
+update {
+ &control:Tmp-String-2 = "%{json_encode:&NAS-IP-Address}"
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# POST to https with JSON body data
+update {
+ &Tmp-String-2 := "%{rest:POST https://%{Tmp-String-0}:%{Tmp-Integer-1}/user/%{User-Name}/mac/%{Called-Station-Id}?section=accounting %{control:Tmp-String-2}}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&Tmp-String-2 =~ /"control:Tmp-String-1":\["POST","\\\/user\\\/<username>\\\/mac\\\/<client>"\]/)) {
+ test_fail
+}
+
+if (&Tmp-String-2 =~ /"control:User-Name":\{([^}]+)\}/) {
+ if (!("%{1}" =~ /"value":"Bob"/)) {
+ test_fail
+ }
+} else {
+ test_fail
+}
+
+update {
+ &control:Tmp-String-2 := "NAS=%{NAS-IP-Address}&user=%{User-Name}"
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# POST to https with POST body data
+update {
+ &Tmp-String-2 := "%{rest:POST https://%{Tmp-String-0}:%{Tmp-Integer-1}/post/test?section=dummy %{control:Tmp-String-2}}"
+}
+
+if (!(&reply:REST-HTTP-Status-Code == 200)) {
+ test_fail
+}
+
+if (!(&Tmp-String-2 == "Section: dummy, User: Bob\n")) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# URI with tainted values in the arguments - input argument includes URI argument
+# separator - make sure this doesn't end up generating extra arguments, but gets escaped.
+update {
+ &Tmp-String-2 := "%{rest:GET http://%{Tmp-String-0}:%{Tmp-Integer-0}/user/%{User-Name}/reflect/?station=%{Calling-Station-Id}}"
+}
+
+if (!(&Tmp-String-2 == "{\"station\":\"dummy&unsafe=escaped\"}\n" )) {
+ test_fail
+}
+
+# Zero length untainted value - check parsing doesn't break on zero length string
+update {
+ &Tmp-String-8 := ""
+}
+update {
+ &Tmp-String-2 := "%{rest:http://%{Tmp-String-0}:%{Tmp-Integer-0}/user/%{User-Name}/reflect/%{Tmp-String-8}?station=%{User-Name}}"
+}
+
+if (!(&Tmp-String-2 == "{\"station\":\"Bob\"}\n" )) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ &REST-HTTP-Status-Code !* ANY
+ &REST-HTTP-Body !* ANY
+}
+
+# Zero length tainted value - check escaping doesn't break on zero length string
+update {
+ &Tmp-String-2 := "%{rest:http://%{Tmp-String-0}:%{Tmp-Integer-0}/user/%{User-Name}/reflect/%{Tmp-String-9}?station=%{Called-Station-Id}}"
+}
+
+if (!(&Tmp-String-2 == "{\"station\":\"aa:bb:cc:dd:ee:ff\"}\n" )) {
+ test_fail
+}
+
+# Clear previous status code and body
+update reply {
+ REST-HTTP-Status-Code !* ANY
+ REST-HTTP-Body !* ANY
+}
+
+# A request which will take longer than the timeout set for xlats
+update {
+ &Tmp-String-2 := "%{rest:http://%{Tmp-String-0}:%{Tmp-Integer-0}/delay}"
+}
+
+if (&reply:REST-HTTP-Status-Code) {
+ test_fail
+}
+
+if (!(&Tmp-String-2 == "")) {
+ test_fail
+}
+
+if (!(&Module-Failure-Message[*] == 'Request failed: 28 - Timeout was reached')) {
+ test_fail
+}
+
+test_pass
diff --git a/src/tests/modules/sql/.gitignore b/src/tests/modules/sql/.gitignore
new file mode 100644
index 0000000..405551a
--- /dev/null
+++ b/src/tests/modules/sql/.gitignore
@@ -0,0 +1 @@
+rlm_sql_sqlite.db
diff --git a/src/tests/modules/sql/acct_0_start.attrs b/src/tests/modules/sql/acct_0_start.attrs
new file mode 100644
index 0000000..01257ce
--- /dev/null
+++ b/src/tests/modules/sql/acct_0_start.attrs
@@ -0,0 +1,37 @@
+#
+# Input packet
+#
+User-Name = 'user0@example.org'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Start
+Acct-Delay-Time = 1
+Acct-Input-Octets = 0
+Acct-Output-Octets = 0
+Acct-Session-Id = '00000000'
+Acct-Unique-Session-Id = '00000000'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 0
+Acct-Input-Packets = 0
+Acct-Output-Packets = 0
+Acct-Input-Gigawords = 0
+Acct-Output-Gigawords = 0
+Event-Timestamp = 'Feb 1 2015 08:28:58 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+# There's not an Accounting-Failed packet type in RADIUS...
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/sql/acct_0_start.unlang b/src/tests/modules/sql/acct_0_start.unlang
new file mode 100644
index 0000000..64921b1
--- /dev/null
+++ b/src/tests/modules/sql/acct_0_start.unlang
@@ -0,0 +1,40 @@
+#
+# Clear out old data
+#
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radacct WHERE AcctSessionId = '00000000'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT count(*) FROM radacct WHERE AcctSessionId = '00000000'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 1)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT acctsessiontime FROM radacct WHERE AcctSessionId = '00000000'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 0)) {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/sql/acct_1_update.attrs b/src/tests/modules/sql/acct_1_update.attrs
new file mode 100644
index 0000000..28db958
--- /dev/null
+++ b/src/tests/modules/sql/acct_1_update.attrs
@@ -0,0 +1,37 @@
+#
+# Input packet
+#
+User-Name = 'user1@example.org'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Interim-Update
+Acct-Delay-Time = 1
+Acct-Input-Octets = 10
+Acct-Output-Octets = 10
+Acct-Session-Id = '00000001'
+Acct-Unique-Session-Id = '00000001'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 30
+Acct-Input-Packets = 10
+Acct-Output-Packets = 10
+Acct-Input-Gigawords = 1
+Acct-Output-Gigawords = 1
+Event-Timestamp = 'Feb 1 2015 08:28:28 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+# There's not an Accounting-Failed packet type in RADIUS...
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/sql/acct_1_update.unlang b/src/tests/modules/sql/acct_1_update.unlang
new file mode 100644
index 0000000..e566a4a
--- /dev/null
+++ b/src/tests/modules/sql/acct_1_update.unlang
@@ -0,0 +1,30 @@
+#
+# PRE: acct_0_start
+#
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT count(*) FROM radacct WHERE AcctSessionId = '00000001'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 1)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT acctsessiontime FROM radacct WHERE AcctSessionId = '00000001'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 30)) {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/sql/acct_2_stop.attrs b/src/tests/modules/sql/acct_2_stop.attrs
new file mode 100644
index 0000000..e932f84
--- /dev/null
+++ b/src/tests/modules/sql/acct_2_stop.attrs
@@ -0,0 +1,38 @@
+#
+# Input packet
+#
+User-Name = 'user2@example.org'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Stop
+Acct-Terminate-Cause = User-Request
+Acct-Delay-Time = 1
+Acct-Input-Octets = 15
+Acct-Output-Octets = 15
+Acct-Session-Id = '00000002'
+Acct-Unique-Session-Id = '00000002'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 120
+Acct-Input-Packets = 15
+Acct-Output-Packets = 15
+Acct-Input-Gigawords = 1
+Acct-Output-Gigawords = 1
+Event-Timestamp = 'Feb 1 2015 08:28:58 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+# There's not an Accounting-Failed packet type in RADIUS...
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/sql/acct_2_stop.unlang b/src/tests/modules/sql/acct_2_stop.unlang
new file mode 100644
index 0000000..3386c71
--- /dev/null
+++ b/src/tests/modules/sql/acct_2_stop.unlang
@@ -0,0 +1,40 @@
+#
+# PRE: acct_1_update
+#
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT count(*) FROM radacct WHERE AcctSessionId = '00000002'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 1)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT acctsessiontime FROM radacct WHERE AcctSessionId = '00000002'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 120)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+update {
+ Tmp-String-0 := "%{sql:SELECT AcctTerminateCause FROM radacct WHERE AcctSessionId = '00000002'}"
+}
+if (!&Tmp-String-0 || (&Tmp-String-0 != 'User-Request')) {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/sql/acct_start_conflict.attrs b/src/tests/modules/sql/acct_start_conflict.attrs
new file mode 100644
index 0000000..2bcade3
--- /dev/null
+++ b/src/tests/modules/sql/acct_start_conflict.attrs
@@ -0,0 +1,37 @@
+#
+# Input packet
+#
+User-Name = 'user3@example.org'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Start
+Acct-Delay-Time = 1
+Acct-Input-Octets = 0
+Acct-Output-Octets = 0
+Acct-Session-Id = '00000003'
+Acct-Unique-Session-Id = '00000003'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 0
+Acct-Input-Packets = 0
+Acct-Output-Packets = 0
+Acct-Input-Gigawords = 0
+Acct-Output-Gigawords = 0
+Event-Timestamp = 'Feb 1 2015 08:28:58 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+# There's not an Accounting-Failed packet type in RADIUS...
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/sql/acct_start_conflict.unlang b/src/tests/modules/sql/acct_start_conflict.unlang
new file mode 100644
index 0000000..65e69e0
--- /dev/null
+++ b/src/tests/modules/sql/acct_start_conflict.unlang
@@ -0,0 +1,76 @@
+#
+# Check that conflicting unique IDs triggers failover to alternative query
+#
+
+#
+# Clear out old data
+#
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radacct WHERE AcctSessionId = '00000003'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+#
+# Insert the Accounting-Request start
+#
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+#
+# Check the database has at least one row
+#
+update {
+ Tmp-Integer-0 := "%{sql:SELECT count(*) FROM radacct WHERE AcctSessionId = '00000003'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 1)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+#
+# Check acctsessiontime matches the value in the request
+#
+update {
+ Tmp-Integer-0 := "%{sql:SELECT acctsessiontime FROM radacct WHERE AcctSessionId = '00000003'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 0)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+#
+# Change acctsessiontime and verify it's updated
+#
+update request {
+ Connect-Info = 'updated'
+}
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+update {
+ Tmp-String-0 := "%{sql:SELECT connectinfo_start FROM radacct WHERE AcctSessionId = '00000003'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-String-0 != 'updated')) {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/sql/acct_update_no_start.attrs b/src/tests/modules/sql/acct_update_no_start.attrs
new file mode 100644
index 0000000..6f3049e
--- /dev/null
+++ b/src/tests/modules/sql/acct_update_no_start.attrs
@@ -0,0 +1,37 @@
+#
+# Input packet
+#
+User-Name = 'user4@example.org'
+NAS-Port = 17826193
+NAS-IP-Address = 192.0.2.10
+Framed-IP-Address = 198.51.100.59
+NAS-Identifier = 'nas.example.org'
+Acct-Status-Type = Interim-Update
+Acct-Delay-Time = 1
+Acct-Input-Octets = 10
+Acct-Output-Octets = 10
+Acct-Session-Id = '00000004'
+Acct-Unique-Session-Id = '00000004'
+Acct-Authentic = RADIUS
+Acct-Session-Time = 30
+Acct-Input-Packets = 10
+Acct-Output-Packets = 10
+Acct-Input-Gigawords = 1
+Acct-Output-Gigawords = 1
+Event-Timestamp = 'Feb 1 2015 08:28:28 WIB'
+NAS-Port-Type = Ethernet
+NAS-Port-Id = 'port 001'
+Service-Type = Framed-User
+Framed-Protocol = PPP
+Acct-Link-Count = 0
+Idle-Timeout = 0
+Session-Timeout = 604800
+Access-Loop-Encapsulation = 0x000000
+Proxy-State = 0x323531
+
+#
+# Expected answer
+#
+# There's not an Accounting-Failed packet type in RADIUS...
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/sql/acct_update_no_start.unlang b/src/tests/modules/sql/acct_update_no_start.unlang
new file mode 100644
index 0000000..3875b2d
--- /dev/null
+++ b/src/tests/modules/sql/acct_update_no_start.unlang
@@ -0,0 +1,40 @@
+#
+# Clear out old data
+#
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radacct WHERE AcctSessionId = '00000004'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+sql.accounting
+if (ok) {
+ test_pass
+}
+else {
+ test_fail
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT count(*) FROM radacct WHERE AcctSessionId = '00000004'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 1)) {
+ test_fail
+}
+else {
+ test_pass
+}
+
+update {
+ Tmp-Integer-0 := "%{sql:SELECT acctsessiontime FROM radacct WHERE AcctSessionId = '00000004'}"
+}
+if (!&Tmp-Integer-0 || (&Tmp-Integer-0 != 30)) {
+ test_fail
+}
+else {
+ test_pass
+}
diff --git a/src/tests/modules/sql/auth.attrs b/src/tests/modules/sql/auth.attrs
new file mode 100644
index 0000000..e7d1498
--- /dev/null
+++ b/src/tests/modules/sql/auth.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "user_auth"
+User-Password = "password"
+NAS-IP-Address = "1.2.3.4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
+Idle-Timeout == 3600
diff --git a/src/tests/modules/sql/auth.unlang b/src/tests/modules/sql/auth.unlang
new file mode 100644
index 0000000..0d76538
--- /dev/null
+++ b/src/tests/modules/sql/auth.unlang
@@ -0,0 +1,39 @@
+#
+# Clear out old data
+#
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radcheck WHERE username = 'user_auth'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radcheck (username, attribute, op, value) VALUES ('user_auth', 'NAS-IP-Address', '==', '1.2.3.4')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radcheck (username, attribute, op, value) VALUES ('user_auth', 'Cleartext-Password', ':=', 'password')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radreply WHERE username = 'user_auth'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radreply (username, attribute, op, value) VALUES ('user_auth', 'Idle-Timeout', ':=', '3600')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+sql
diff --git a/src/tests/modules/sql/reject.attrs b/src/tests/modules/sql/reject.attrs
new file mode 100644
index 0000000..cb0b9a2
--- /dev/null
+++ b/src/tests/modules/sql/reject.attrs
@@ -0,0 +1,12 @@
+#
+# Input packet
+#
+User-Name = "user_reject"
+User-Password = "password"
+NAS-IP-Address = "1.2.3.4"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Reject
+Reply-Message == "Authentication failed"
diff --git a/src/tests/modules/sql/reject.unlang b/src/tests/modules/sql/reject.unlang
new file mode 100644
index 0000000..b4afb09
--- /dev/null
+++ b/src/tests/modules/sql/reject.unlang
@@ -0,0 +1,39 @@
+#
+# Clear out old data
+#
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radcheck WHERE username = 'user_reject'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radcheck (username, attribute, op, value) VALUES ('user_reject', 'NAS-IP-Address', '==', '1.2.3.4')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radcheck (username, attribute, op, value) VALUES ('user_reject', 'Cleartext-Password', ':=', 'wrong-password')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:DELETE FROM radreply WHERE username = 'user_reject'}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+update {
+ Tmp-String-0 := "%{sql:INSERT INTO radreply (username, attribute, op, value) VALUES ('user_reject', 'Reply-Message', ':=', 'Authentication failed')}"
+}
+if (!&Tmp-String-0) {
+ test_fail
+}
+
+sql
diff --git a/src/tests/modules/sql_mysql/.gitignore b/src/tests/modules/sql_mysql/.gitignore
new file mode 100644
index 0000000..405551a
--- /dev/null
+++ b/src/tests/modules/sql_mysql/.gitignore
@@ -0,0 +1 @@
+rlm_sql_sqlite.db
diff --git a/src/tests/modules/sql_mysql/acct_0_start.attrs b/src/tests/modules/sql_mysql/acct_0_start.attrs
new file mode 120000
index 0000000..24e17ae
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_0_start.attrs
@@ -0,0 +1 @@
+../sql/acct_0_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_0_start.unlang b/src/tests/modules/sql_mysql/acct_0_start.unlang
new file mode 120000
index 0000000..3fe3e99
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_0_start.unlang
@@ -0,0 +1 @@
+../sql/acct_0_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_1_update.attrs b/src/tests/modules/sql_mysql/acct_1_update.attrs
new file mode 120000
index 0000000..1ab772d
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_1_update.attrs
@@ -0,0 +1 @@
+../sql/acct_1_update.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_1_update.unlang b/src/tests/modules/sql_mysql/acct_1_update.unlang
new file mode 120000
index 0000000..b69ff9b
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_1_update.unlang
@@ -0,0 +1 @@
+../sql/acct_1_update.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_2_stop.attrs b/src/tests/modules/sql_mysql/acct_2_stop.attrs
new file mode 120000
index 0000000..ea73931
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_2_stop.attrs
@@ -0,0 +1 @@
+../sql/acct_2_stop.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_2_stop.unlang b/src/tests/modules/sql_mysql/acct_2_stop.unlang
new file mode 120000
index 0000000..ea0be56
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_2_stop.unlang
@@ -0,0 +1 @@
+../sql/acct_2_stop.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_start_conflict.attrs b/src/tests/modules/sql_mysql/acct_start_conflict.attrs
new file mode 120000
index 0000000..117a505
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_start_conflict.attrs
@@ -0,0 +1 @@
+../sql/acct_start_conflict.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_start_conflict.unlang b/src/tests/modules/sql_mysql/acct_start_conflict.unlang
new file mode 120000
index 0000000..da35798
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_start_conflict.unlang
@@ -0,0 +1 @@
+../sql/acct_start_conflict.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_update_no_start.attrs b/src/tests/modules/sql_mysql/acct_update_no_start.attrs
new file mode 120000
index 0000000..328867f
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_update_no_start.attrs
@@ -0,0 +1 @@
+../sql/acct_update_no_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/acct_update_no_start.unlang b/src/tests/modules/sql_mysql/acct_update_no_start.unlang
new file mode 120000
index 0000000..6837977
--- /dev/null
+++ b/src/tests/modules/sql_mysql/acct_update_no_start.unlang
@@ -0,0 +1 @@
+../sql/acct_update_no_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/all.mk b/src/tests/modules/sql_mysql/all.mk
new file mode 100644
index 0000000..337528b
--- /dev/null
+++ b/src/tests/modules/sql_mysql/all.mk
@@ -0,0 +1,6 @@
+#
+# Test the mysql module
+#
+
+# Don't test sql_mysql if TEST_SERVER ENV is not set
+sql_mysql_require_test_server := 1
diff --git a/src/tests/modules/sql_mysql/auth.attrs b/src/tests/modules/sql_mysql/auth.attrs
new file mode 120000
index 0000000..6b30b6b
--- /dev/null
+++ b/src/tests/modules/sql_mysql/auth.attrs
@@ -0,0 +1 @@
+../sql/auth.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/auth.unlang b/src/tests/modules/sql_mysql/auth.unlang
new file mode 120000
index 0000000..3ccd80e
--- /dev/null
+++ b/src/tests/modules/sql_mysql/auth.unlang
@@ -0,0 +1 @@
+../sql/auth.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/module.conf b/src/tests/modules/sql_mysql/module.conf
new file mode 100644
index 0000000..e3aa02d
--- /dev/null
+++ b/src/tests/modules/sql_mysql/module.conf
@@ -0,0 +1,53 @@
+sql {
+ driver = "rlm_sql_mysql"
+ dialect = "mysql"
+
+ # Connection info:
+ #
+ server = $ENV{SQL_MYSQL_TEST_SERVER}
+ port = 3306
+ login = "radius"
+ password = "radpass"
+
+ # Database table configuration for everything except Oracle
+ radius_db = "radius"
+ radius_db = "radius"
+
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+ postauth_table = "radpostauth"
+ authcheck_table = "radcheck"
+ groupcheck_table = "radgroupcheck"
+ authreply_table = "radreply"
+ groupreply_table = "radgroupreply"
+ usergroup_table = "radusergroup"
+ read_groups = yes
+ read_profiles = yes
+
+ # Remove stale session if checkrad does not see a double login
+ delete_stale_sessions = yes
+
+ pool {
+ start = 1
+ min = 0
+ max = 1
+ spare = 3
+ uses = 2
+ lifetime = 1
+ idle_timeout = 60
+ retry_delay = 1
+ }
+
+ # Set to 'yes' to read radius clients from the database ('nas' table)
+ # Clients will ONLY be read on server startup.
+# read_clients = yes
+
+ # Table to keep radius client info
+ client_table = "nas"
+
+ # The group attribute specific to this instance of rlm_sql
+ group_attribute = "SQL-Group"
+
+ # Read database-specific queries
+ $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+}
diff --git a/src/tests/modules/sql_mysql/reject.attrs b/src/tests/modules/sql_mysql/reject.attrs
new file mode 120000
index 0000000..71a187f
--- /dev/null
+++ b/src/tests/modules/sql_mysql/reject.attrs
@@ -0,0 +1 @@
+../sql/reject.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_mysql/reject.unlang b/src/tests/modules/sql_mysql/reject.unlang
new file mode 120000
index 0000000..379839f
--- /dev/null
+++ b/src/tests/modules/sql_mysql/reject.unlang
@@ -0,0 +1 @@
+../sql/reject.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/.gitignore b/src/tests/modules/sql_postgresql/.gitignore
new file mode 100644
index 0000000..405551a
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/.gitignore
@@ -0,0 +1 @@
+rlm_sql_sqlite.db
diff --git a/src/tests/modules/sql_postgresql/acct_0_start.attrs b/src/tests/modules/sql_postgresql/acct_0_start.attrs
new file mode 120000
index 0000000..24e17ae
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_0_start.attrs
@@ -0,0 +1 @@
+../sql/acct_0_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_0_start.unlang b/src/tests/modules/sql_postgresql/acct_0_start.unlang
new file mode 120000
index 0000000..3fe3e99
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_0_start.unlang
@@ -0,0 +1 @@
+../sql/acct_0_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_1_update.attrs b/src/tests/modules/sql_postgresql/acct_1_update.attrs
new file mode 120000
index 0000000..1ab772d
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_1_update.attrs
@@ -0,0 +1 @@
+../sql/acct_1_update.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_1_update.unlang b/src/tests/modules/sql_postgresql/acct_1_update.unlang
new file mode 120000
index 0000000..b69ff9b
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_1_update.unlang
@@ -0,0 +1 @@
+../sql/acct_1_update.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_2_stop.attrs b/src/tests/modules/sql_postgresql/acct_2_stop.attrs
new file mode 120000
index 0000000..ea73931
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_2_stop.attrs
@@ -0,0 +1 @@
+../sql/acct_2_stop.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_2_stop.unlang b/src/tests/modules/sql_postgresql/acct_2_stop.unlang
new file mode 120000
index 0000000..ea0be56
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_2_stop.unlang
@@ -0,0 +1 @@
+../sql/acct_2_stop.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_start_conflict.attrs b/src/tests/modules/sql_postgresql/acct_start_conflict.attrs
new file mode 120000
index 0000000..117a505
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_start_conflict.attrs
@@ -0,0 +1 @@
+../sql/acct_start_conflict.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_start_conflict.unlang b/src/tests/modules/sql_postgresql/acct_start_conflict.unlang
new file mode 120000
index 0000000..da35798
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_start_conflict.unlang
@@ -0,0 +1 @@
+../sql/acct_start_conflict.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_update_no_start.attrs b/src/tests/modules/sql_postgresql/acct_update_no_start.attrs
new file mode 120000
index 0000000..328867f
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_update_no_start.attrs
@@ -0,0 +1 @@
+../sql/acct_update_no_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/acct_update_no_start.unlang b/src/tests/modules/sql_postgresql/acct_update_no_start.unlang
new file mode 120000
index 0000000..6837977
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/acct_update_no_start.unlang
@@ -0,0 +1 @@
+../sql/acct_update_no_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/all.mk b/src/tests/modules/sql_postgresql/all.mk
new file mode 100644
index 0000000..efd20d9
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/all.mk
@@ -0,0 +1,6 @@
+#
+# Test the postgresql module
+#
+
+# Don't test sql_postgresql if TEST_SERVER ENV is not set
+sql_postgresql_require_test_server := 1
diff --git a/src/tests/modules/sql_postgresql/auth.attrs b/src/tests/modules/sql_postgresql/auth.attrs
new file mode 120000
index 0000000..6b30b6b
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/auth.attrs
@@ -0,0 +1 @@
+../sql/auth.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/auth.unlang b/src/tests/modules/sql_postgresql/auth.unlang
new file mode 120000
index 0000000..3ccd80e
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/auth.unlang
@@ -0,0 +1 @@
+../sql/auth.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/module.conf b/src/tests/modules/sql_postgresql/module.conf
new file mode 100644
index 0000000..ee9a8a9
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/module.conf
@@ -0,0 +1,52 @@
+sql {
+ driver = "rlm_sql_postgresql"
+ dialect = "postgresql"
+
+ # Connection info:
+ #
+ server = $ENV{SQL_POSTGRESQL_TEST_SERVER}
+ port = 5432
+ login = "radius"
+ password = "radpass"
+
+ # Database table configuration for everything except Oracle
+ radius_db = "radius"
+
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+ postauth_table = "radpostauth"
+ authcheck_table = "radcheck"
+ groupcheck_table = "radgroupcheck"
+ authreply_table = "radreply"
+ groupreply_table = "radgroupreply"
+ usergroup_table = "radusergroup"
+ read_groups = yes
+ read_profiles = yes
+
+ # Remove stale session if checkrad does not see a double login
+ delete_stale_sessions = yes
+
+ pool {
+ start = 1
+ min = 0
+ max = 1
+ spare = 3
+ uses = 2
+ lifetime = 1
+ idle_timeout = 60
+ retry_delay = 1
+ }
+
+ # Set to 'yes' to read radius clients from the database ('nas' table)
+ # Clients will ONLY be read on server startup.
+# read_clients = yes
+
+ # Table to keep radius client info
+ client_table = "nas"
+
+ # The group attribute specific to this instance of rlm_sql
+ group_attribute = "SQL-Group"
+
+ # Read database-specific queries
+ $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+}
diff --git a/src/tests/modules/sql_postgresql/reject.attrs b/src/tests/modules/sql_postgresql/reject.attrs
new file mode 120000
index 0000000..71a187f
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/reject.attrs
@@ -0,0 +1 @@
+../sql/reject.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_postgresql/reject.unlang b/src/tests/modules/sql_postgresql/reject.unlang
new file mode 120000
index 0000000..379839f
--- /dev/null
+++ b/src/tests/modules/sql_postgresql/reject.unlang
@@ -0,0 +1 @@
+../sql/reject.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/.gitignore b/src/tests/modules/sql_sqlite/.gitignore
new file mode 100644
index 0000000..405551a
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/.gitignore
@@ -0,0 +1 @@
+rlm_sql_sqlite.db
diff --git a/src/tests/modules/sql_sqlite/acct_0_start.attrs b/src/tests/modules/sql_sqlite/acct_0_start.attrs
new file mode 120000
index 0000000..24e17ae
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_0_start.attrs
@@ -0,0 +1 @@
+../sql/acct_0_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_0_start.unlang b/src/tests/modules/sql_sqlite/acct_0_start.unlang
new file mode 120000
index 0000000..3fe3e99
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_0_start.unlang
@@ -0,0 +1 @@
+../sql/acct_0_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_1_update.attrs b/src/tests/modules/sql_sqlite/acct_1_update.attrs
new file mode 120000
index 0000000..1ab772d
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_1_update.attrs
@@ -0,0 +1 @@
+../sql/acct_1_update.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_1_update.unlang b/src/tests/modules/sql_sqlite/acct_1_update.unlang
new file mode 120000
index 0000000..b69ff9b
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_1_update.unlang
@@ -0,0 +1 @@
+../sql/acct_1_update.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_2_stop.attrs b/src/tests/modules/sql_sqlite/acct_2_stop.attrs
new file mode 120000
index 0000000..ea73931
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_2_stop.attrs
@@ -0,0 +1 @@
+../sql/acct_2_stop.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_2_stop.unlang b/src/tests/modules/sql_sqlite/acct_2_stop.unlang
new file mode 120000
index 0000000..ea0be56
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_2_stop.unlang
@@ -0,0 +1 @@
+../sql/acct_2_stop.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_start_conflict.attrs b/src/tests/modules/sql_sqlite/acct_start_conflict.attrs
new file mode 120000
index 0000000..117a505
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_start_conflict.attrs
@@ -0,0 +1 @@
+../sql/acct_start_conflict.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_start_conflict.unlang b/src/tests/modules/sql_sqlite/acct_start_conflict.unlang
new file mode 120000
index 0000000..da35798
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_start_conflict.unlang
@@ -0,0 +1 @@
+../sql/acct_start_conflict.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_update_no_start.attrs b/src/tests/modules/sql_sqlite/acct_update_no_start.attrs
new file mode 120000
index 0000000..328867f
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_update_no_start.attrs
@@ -0,0 +1 @@
+../sql/acct_update_no_start.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/acct_update_no_start.unlang b/src/tests/modules/sql_sqlite/acct_update_no_start.unlang
new file mode 120000
index 0000000..6837977
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/acct_update_no_start.unlang
@@ -0,0 +1 @@
+../sql/acct_update_no_start.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/all.mk b/src/tests/modules/sql_sqlite/all.mk
new file mode 100644
index 0000000..a7907f1
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the sqlite module
+#
diff --git a/src/tests/modules/sql_sqlite/auth.attrs b/src/tests/modules/sql_sqlite/auth.attrs
new file mode 120000
index 0000000..6b30b6b
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/auth.attrs
@@ -0,0 +1 @@
+../sql/auth.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/auth.unlang b/src/tests/modules/sql_sqlite/auth.unlang
new file mode 120000
index 0000000..3ccd80e
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/auth.unlang
@@ -0,0 +1 @@
+../sql/auth.unlang \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/module.conf b/src/tests/modules/sql_sqlite/module.conf
new file mode 100644
index 0000000..1d8ac74
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/module.conf
@@ -0,0 +1,52 @@
+sql {
+ driver = "rlm_sql_sqlite"
+ dialect = "sqlite"
+ sqlite {
+ # Path to the sqlite database
+ filename = "$ENV{MODULE_TEST_DIR}/sql_sqlite/rlm_sql_sqlite.db"
+
+ # If the file above does not exist and bootstrap is set
+ # a new database file will be created, and the SQL statements
+ # contained within the file will be executed.
+ bootstrap = "${modconfdir}/${..:name}/main/${..dialect}/schema.sql"
+ }
+ radius_db = "radius"
+
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+ postauth_table = "radpostauth"
+ authcheck_table = "radcheck"
+ groupcheck_table = "radgroupcheck"
+ authreply_table = "radreply"
+ groupreply_table = "radgroupreply"
+ usergroup_table = "radusergroup"
+ read_groups = yes
+ read_profiles = yes
+
+ # Remove stale session if checkrad does not see a double login
+ delete_stale_sessions = yes
+
+ pool {
+ start = 1
+ min = 0
+ max = 1
+ spare = 3
+ uses = 2
+ lifetime = 1
+ idle_timeout = 60
+ retry_delay = 1
+ }
+
+ # Set to 'yes' to read radius clients from the database ('nas' table)
+ # Clients will ONLY be read on server startup.
+# read_clients = yes
+
+ # Table to keep radius client info
+ client_table = "nas"
+
+ # The group attribute specific to this instance of rlm_sql
+ group_attribute = "SQL-Group"
+
+ # Read database-specific queries
+ $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+}
diff --git a/src/tests/modules/sql_sqlite/reject.attrs b/src/tests/modules/sql_sqlite/reject.attrs
new file mode 120000
index 0000000..71a187f
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/reject.attrs
@@ -0,0 +1 @@
+../sql/reject.attrs \ No newline at end of file
diff --git a/src/tests/modules/sql_sqlite/reject.unlang b/src/tests/modules/sql_sqlite/reject.unlang
new file mode 120000
index 0000000..379839f
--- /dev/null
+++ b/src/tests/modules/sql_sqlite/reject.unlang
@@ -0,0 +1 @@
+../sql/reject.unlang \ No newline at end of file
diff --git a/src/tests/modules/test.mk b/src/tests/modules/test.mk
new file mode 100644
index 0000000..b217ff7
--- /dev/null
+++ b/src/tests/modules/test.mk
@@ -0,0 +1,165 @@
+#
+# Add the module tests to the overall dependencies
+#
+
+TESTS.MODULES_FILES :=
+
+# If module requires test server, make sure TEST_SERVER of <MODULE>_TEST_SERVER variables are defined
+# If TEST_SERVER is defined, define <MODULE>_TEST_SERVER for all modules that have CHECK_MODULE_TEST_CAN_BE_RUN
+define CHECK_MODULE_TEST_CAN_BE_RUN
+ ifndef ${1}_require_test_server
+ tests.modules: ${1}.test
+ else
+ ifdef TEST_SERVER
+ tests.modules: ${1}.test
+ export $(shell echo ${1} | tr a-z A-Z)_TEST_SERVER := $(TEST_SERVER)
+ endif
+ ifdef $(shell echo ${1} | tr a-z A-Z)_TEST_SERVER
+ tests.modules: ${1}.test
+ endif
+ endif
+endef
+$(foreach x,$(TEST_BUILT) $(TEST_SUBBUILT),$(eval $(call CHECK_MODULE_TEST_CAN_BE_RUN,$x)))
+
+######################################################################
+#
+# And now more makefile magic to automatically run the tests
+# for each module.
+#
+
+define DEFAULT_ATTRS
+ifeq "$(wildcard ${1}.attrs)"
+${1}.attrs
+else
+src/tests/modules/default-input.attrs
+endif
+endef
+
+#
+# Files in the output dir depend on the unit tests
+#
+# src/tests/$(MODULE_DIR)/FOO.unlang unlang for the test
+# src/tests/$(MODULE_DIR)/FOO.attrs input RADIUS and output filter
+# build/tests/$(MODULE_DIR)/FOO.out updated if the test succeeds
+# build/tests/$(MODULE_DIR)/FOO.log debug output for the test
+#
+# If the test fails, then look for ERROR in the input. No error
+# means it's unexpected, so we die.
+#
+# Otherwise, check the log file for a parse error which matches the
+# ERROR line in the input.
+#
+$(BUILD_DIR)/tests/modules/%: src/tests/modules/%.unlang $(BUILD_DIR)/tests/modules/%.attrs $(TESTBINDIR)/unittest | build.raddb
+ @mkdir -p $(dir $@)
+ @echo MODULE-TEST $(lastword $(subst /, ,$(dir $@))) $(basename $(notdir $@))
+ @if ! MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TESTBIN)/unittest -D share -d src/tests/modules/ -i $@.attrs -f $@.attrs -xxx > $@.log 2>&1; then \
+ if ! grep ERROR $< 2>&1 > /dev/null; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TESTBIN)/unittest -D share -d src/tests/modules/ -i $@.attrs -f $@.attrs -xx; \
+ exit 1; \
+ fi; \
+ FOUND=$$(grep ^$< $@.log | head -1 | sed 's/:.*//;s/.*\[//;s/\].*//'); \
+ EXPECTED=$$(grep -n ERROR $< | sed 's/:.*//'); \
+ if [ "$$EXPECTED" != "$$FOUND" ]; then \
+ cat $@.log; \
+ echo "# $@.log"; \
+ echo MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TESTBIN)/unittest -D share -d src/tests/modules/ -i $@.attrs -f $@.attrs -xx; \
+ exit 1; \
+ fi \
+ fi
+ @touch $@
+
+#
+# Sometimes we have a default input. So use that. Otherwise, use
+# the input specific to the test.
+#
+MODULE_UNLANG := $(wildcard src/tests/modules/*/*.unlang src/tests/modules/*/*/*.unlang)
+MODULE_ATTRS_REQUIRES := $(patsubst %.unlang,%.attrs,$(MODULE_UNLANG))
+MODULE_ATTRS_EXISTS := $(wildcard src/tests/modules/*/*.attrs src/tests/modules/*/*/*.attrs)
+MODULE_ATTRS_NEEDS := $(filter-out $(MODULE_ATTRS_EXISTS),$(MODULE_ATTRS_REQUIRES))
+
+MODULE_CONF_REQUIRES := $(patsubst %.unlang,%.conf,$(MODULE_UNLANG))
+MODULE_CONF_EXISTS := $(wildcard src/tests/modules/*/*.conf src/tests/modules/*/*/*.attrs)
+MODULE_CONF_NEEDS := $(filter-out $(MODULE_CONF_EXISTS),$(MODULE_CONF_REQUIRES))
+
+#
+# The complete list of tests which are to be run
+#
+MODULE_TESTS := $(patsubst src/tests/modules/%/all.mk,%,$(wildcard src/tests/modules/*/all.mk))
+
+
+#
+# Target-specific rules
+#
+define MODULE_COPY_FILE
+$(BUILD_DIR)/${1}: src/${1}
+ @mkdir -p $$(@D)
+ @cp $$< $$@
+
+endef
+
+#
+# Default rules
+#
+define MODULE_COPY_ATTR
+$(BUILD_DIR)/${1}: src/tests/modules/default-input.attrs
+ @mkdir -p $$(@D)
+ @cp $$< $$@
+endef
+
+#
+# FIXME: get this working
+#
+define MODULE_COPY_CONF
+$(BUILD_DIR)/${1}: src/tests/modules/${2}/module.conf
+ @mkdir -p $$(@D)
+ @cp $$< $$@
+endef
+
+define MODULE_FILE_TARGET
+$(BUILD_DIR)/${1}: src/${1}.unlang $(BUILD_DIR)/${1}.attrs
+
+endef
+
+define MODULE_TEST_TARGET
+${1}.test: $(patsubst %.unlang,%,$(subst src,$(BUILD_DIR),$(filter src/tests/modules/${1}/%,$(MODULE_UNLANG))))
+
+TESTS.MODULES_FILES += $(patsubst %.unlang,%,$(subst src,$(BUILD_DIR),$(filter src/tests/modules/${1}/%,$(MODULE_UNLANG))))
+endef
+
+#
+# Create the rules from the list of input files
+#
+$(foreach x,$(MODULE_ATTRS_EXISTS),$(eval $(call MODULE_COPY_FILE,$(subst src/,,$x))))
+$(foreach x,$(MODULE_CONF_EXISTS),$(eval $(call MODULE_COPY_FILE,$(subst src/,,$x))))
+
+$(foreach x,$(MODULE_ATTRS_NEEDS),$(eval $(call MODULE_COPY_ATTR,$(subst src/,,$x))))
+# FIXME: copy src/tests/modules/*/module.conf to the right place, too
+
+$(foreach x,$(MODULE_UNLANG),$(eval $(call MODULE_FILE_TARGET,$(patsubst %.unlang,%,$(subst src/,,$x)))))
+$(foreach x,$(MODULE_TESTS),$(eval $(call MODULE_TEST_TARGET,$x)))
+
+$(TESTS.MODULES_FILES): $(TESTS.AUTH_FILES)
+
+.PHONY: clean.modules.test
+clean.modules.test:
+ @rm -rf $(BUILD_DIR)/tests/modules/
+
+#
+# For each file, look for precursor test.
+# Ensure that each test depends on its precursors.
+#
+-include $(BUILD_DIR)/tests/modules/depends.mk
+
+$(BUILD_DIR)/tests/modules/depends.mk: $(MODULE_UNLANG) | $(BUILD_DIR)/tests/modules
+ @rm -f $@
+ @for x in $^; do \
+ y=`grep PRE $$x | awk '{ print $$3 }'`; \
+ if [ "$$y" != "" ]; then \
+ z=`echo $$x | sed 's,src/,$(BUILD_DIR)/', | sed 's/.unlang//'`; \
+ d=$$(basename $$(dirname $$x)); \
+ echo "$$z: $(BUILD_DIR)/tests/modules/$$d/$$y" >> $@; \
+ echo "" >> $@; \
+ fi \
+ done
diff --git a/src/tests/modules/unbound/all.mk b/src/tests/modules/unbound/all.mk
new file mode 100644
index 0000000..d64039f
--- /dev/null
+++ b/src/tests/modules/unbound/all.mk
@@ -0,0 +1,3 @@
+#
+# Test the "unbound" module
+#
diff --git a/src/tests/modules/unbound/dns.attrs b/src/tests/modules/unbound/dns.attrs
new file mode 100644
index 0000000..1cce1c5
--- /dev/null
+++ b/src/tests/modules/unbound/dns.attrs
@@ -0,0 +1,11 @@
+#
+# Input packet
+#
+Packet-Type = Access-Request
+User-Name = "bob"
+User-Password = "hello"
+
+#
+# Expected answer
+#
+Response-Packet-Type == Access-Accept
diff --git a/src/tests/modules/unbound/dns.unlang b/src/tests/modules/unbound/dns.unlang
new file mode 100644
index 0000000..d53e433
--- /dev/null
+++ b/src/tests/modules/unbound/dns.unlang
@@ -0,0 +1,53 @@
+# Use builtin "local" zone
+update request {
+ &Tmp-IP-Address-0 := "%{dns-a:localhost}"
+}
+
+if (&Tmp-IP-Address-0 != 127.0.0.1) {
+ test_fail
+}
+
+update request {
+ &Tmp-String-0 := "%{dns-aaaa:localhost}"
+}
+
+if (&Tmp-String-0 != "::1") {
+ test_fail
+}
+
+update request {
+ &Tmp-String-1 := "%{dns-ptr:1.0.0.127.in-addr.arpa}"
+}
+
+if (&Tmp-String-1 != "localhost") {
+ test_fail
+}
+
+# Use local data in module config to allow for dotted names
+update request {
+ &Tmp-IP-Address-0 := "%{dns-a:www.example.com}"
+}
+
+if (&Tmp-IP-Address-0 != 192.168.1.1) {
+ test_fail
+}
+
+update request {
+ &Tmp-String-0 := "%{dns-ptr:1.1.168.192.in-addr.arpa}"
+}
+
+if (&Tmp-String-0 != "www.example.com") {
+ test_fail
+}
+
+# Try a real, known, network response
+# Temporarily disabled while there is a bug in unbound
+#update request {
+# &Tmp-String-0 := "%{dns-ptr:8.8.8.8.in-addr.arpa}"
+#}
+
+#if (&Tmp-String-0 != "dns.google") {
+# test_fail
+#}
+
+test_pass \ No newline at end of file
diff --git a/src/tests/modules/unbound/module.conf b/src/tests/modules/unbound/module.conf
new file mode 100644
index 0000000..c0430d2
--- /dev/null
+++ b/src/tests/modules/unbound/module.conf
@@ -0,0 +1,4 @@
+unbound dns {
+ filename = "$ENV{MODULE_TEST_DIR}/unbound.conf"
+ timeout = 3000
+}
diff --git a/src/tests/modules/unbound/unbound.conf b/src/tests/modules/unbound/unbound.conf
new file mode 100644
index 0000000..33fc461
--- /dev/null
+++ b/src/tests/modules/unbound/unbound.conf
@@ -0,0 +1,6 @@
+server:
+ num-threads: 2
+ local-data: 'www.example.com. A 192.168.1.1'
+ local-data: 'example.com. MX 10 mail.example.com'
+ local-data: 'example.com. MX 20 mail2.example.com'
+ local-data-ptr: '192.168.1.1 www.example.com'
diff --git a/src/tests/mschapv1 b/src/tests/mschapv1
new file mode 100644
index 0000000..338bf8a
--- /dev/null
+++ b/src/tests/mschapv1
@@ -0,0 +1,16 @@
+#
+# bob Cleartext-Password := "bob"
+#
+# TESTS 1
+#
+# SHOULD get:
+#
+# MS-CHAP-MPPE-Keys = 0x4318b176c3d8e3de9a936faf344359a0f1e3c9b5585b9f1f0000000000000000
+# MS-MPPE-Encryption-Policy = 0x00000001
+# MS-MPPE-Encryption-Types = 0x00000006
+#
+# NT Hash hash = 0x9a936faf344359a0f1e3c9b5585b9f1f
+#
+User-Name = "bob",
+MS-CHAP-Challenge = 0xb9634adc358b2ab3,
+MS-CHAP-Response = 0xb9010000000000000000000000000000000000000000000000007a42408782f745ef90a86fd21b0d9294132750f4af66a419
diff --git a/src/tests/panic.gdb b/src/tests/panic.gdb
new file mode 100644
index 0000000..3ae253a
--- /dev/null
+++ b/src/tests/panic.gdb
@@ -0,0 +1,4 @@
+info locals
+info args
+thread apply all bt full
+quit
diff --git a/src/tests/peap-client-mschapv2.conf b/src/tests/peap-client-mschapv2.conf
new file mode 100644
index 0000000..1c60933
--- /dev/null
+++ b/src/tests/peap-client-mschapv2.conf
@@ -0,0 +1,18 @@
+#
+# ./eapol_test -c peap-mschapv2.conf -s testing123
+#
+network={
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="bob"
+ phase2="auth=MSCHAPV2"
+ phase1="peapver=0"
+
+ ca_cert="../../raddb/certs/ca.pem"
+ client_cert="../../raddb/certs/client.crt"
+ private_key="../../raddb/certs/client.key"
+ private_key_passwd="whatever"
+}
diff --git a/src/tests/peap-eap-tls.conf b/src/tests/peap-eap-tls.conf
new file mode 100644
index 0000000..ef5cd3d
--- /dev/null
+++ b/src/tests/peap-eap-tls.conf
@@ -0,0 +1,14 @@
+network={
+ key_mgmt=IEEE8021X
+ eap=PEAP
+ identity="user@example.org"
+ phase1=""
+ phase2="auth=TLS"
+
+ ca_cert="../../raddb/certs/ca.pem"
+
+ ca_cert2="../../raddb/certs/ca.pem"
+ client_cert2="../../raddb/certs/client.crt"
+ private_key2="../../raddb/certs/client.key"
+ private_key2_passwd="whatever"
+}
diff --git a/src/tests/peap-mschapv2.conf b/src/tests/peap-mschapv2.conf
new file mode 100644
index 0000000..ec9df68
--- /dev/null
+++ b/src/tests/peap-mschapv2.conf
@@ -0,0 +1,13 @@
+#
+# ./eapol_test -c peap-mschapv2.conf -s testing123
+#
+network={
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="bob"
+ anonymous_identity="anonymous"
+ password="bob"
+ phase1="peapver=0"
+ phase2="auth=MSCHAPV2"
+}
diff --git a/src/tests/proxy.conf b/src/tests/proxy.conf
new file mode 100644
index 0000000..a6536e7
--- /dev/null
+++ b/src/tests/proxy.conf
@@ -0,0 +1,61 @@
+#
+# This is a LOCAL realm
+#
+realm example.com {
+ nostrip
+}
+
+#
+# And another one, where we strip the realm
+#
+realm stripped.example.com {
+
+}
+
+#
+# Some home servers, server pools, and realms. This tests that
+# the server can load them. Functionality is in another test.
+#
+home_server auth_one {
+ type = auth
+ ipaddr = 127.0.0.1
+ port = 12360
+ secret = testing123
+}
+
+home_server auth_two {
+ type = auth
+ ipaddr = 127.0.0.1
+ port = 12370
+ secret = testing123
+}
+
+server_pool fail-over {
+ type = fail-over
+ home_server = auth_one
+ home_server = auth_two
+}
+
+server_pool load-balance {
+ type = load-balance
+ home_server = auth_one
+ home_server = auth_two
+}
+
+server_pool client-balance {
+ type = client-balance
+ home_server = auth_one
+ home_server = auth_two
+}
+
+realm fail-over {
+ auth_pool = fail-over
+}
+
+realm load-balance {
+ auth_pool = load-balance
+}
+
+realm client-balance {
+ auth_pool = client-balance
+}
diff --git a/src/tests/radiusd.mk b/src/tests/radiusd.mk
new file mode 100644
index 0000000..eed4c79
--- /dev/null
+++ b/src/tests/radiusd.mk
@@ -0,0 +1,115 @@
+#
+# The "RADIUSD_SERVICE" macro is charged to start/stop the radiusd instances
+# from the mostly test targets. It expects the below variables.
+#
+# - Already defined by scripts/boiler.mk
+#
+# DIR = src/tests/$target
+# BUILD_DIR = build/
+#
+# - Defined by the target
+#
+# PORT := Run the service
+# TEST := test.$target
+#
+# - Parameter
+#
+# ${1} config-name found in $(DIR)/config, e.g: src/tests/$target/config/${config-name}.conf
+# ${2} output directory
+#
+# - How to use
+#
+# 1. $(eval $(call RADIUSD_SERVICE,myconfig,directory/path/))
+#
+# 2. It will defined the targets.
+#
+# $(TEST).radiusd_kill and $(TEST).radiusd_start
+#
+# 3. The target 'radiusd_start' define the variable $(RADIUSD_RUN) with the
+# exactly command used to start the service.
+#
+# 4. You could use the 'RADIUSD_BIN' to set such path to the "radiusd" binary
+# that you want to against the tests.
+#
+# e.g:
+#
+# make RADIUSD_BIN=/path/to/my/radiusd test
+#
+include Make.inc
+
+define RADIUSD_SERVICE
+$$(eval RADIUSD_BIN := $(JLIBTOOL) --silent --mode=execute $$(TESTBIN)/radiusd)
+
+#
+# Kill it. We don't care if it failed or not. However, we do care
+# if we can't kill it.
+#
+.PHONY: $(TEST).radiusd_kill
+$(TEST).radiusd_kill: | ${2}
+ ${Q}if [ -f ${2}/radiusd.pid ]; then \
+ if ! ps `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+ rm -f ${2}/radiusd.pid; \
+ echo "FreeRADIUS terminated during test called by $(TEST).radiusd_kill"; \
+ echo "GDB output was:"; \
+ cat "${2}/gdb.log" 2> /dev/null; \
+ echo "--------------------------------------------------"; \
+ echo "Last entries in server log (${2}/radiusd.log):"; \
+ tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+ exit 0; \
+ fi; \
+ if ! kill -9 `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+ exit 1; \
+ fi; \
+ rm -f ${2}/radiusd.pid; \
+ exit 0; \
+ fi
+
+#
+# Stop it politely.
+#
+.PHONY: $(TEST).radiusd_stop
+$(TEST).radiusd_stop: | ${2}
+ ${Q}if [ -f ${2}/radiusd.pid ]; then \
+ if ! ps `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+ rm -f ${2}/radiusd.pid; \
+ echo "FreeRADIUS terminated during test called by $(TEST).radiusd_stop"; \
+ echo "GDB output was:"; \
+ cat "${2}/gdb.log" 2> /dev/null; \
+ echo "--------------------------------------------------"; \
+ echo "Last entries in server log (${2}/radiusd.log):"; \
+ tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+ exit 1; \
+ fi; \
+ if ! kill -TERM `cat ${2}/radiusd.pid` >/dev/null 2>&1; then \
+ exit 1; \
+ fi; \
+ rm -f ${2}/radiusd.pid; \
+ exit 0; \
+ fi
+
+#
+# Start radiusd instance
+#
+${2}/radiusd.pid: ${2}
+ $$(eval RADIUSD_RUN := TOP_SRCDIR=$(top_srcdir) TESTDIR=$(DIR) OUTPUT=$(OUTPUT) TEST_PORT=$(PORT) $$(RADIUSD_BIN) -Pxxx -d $(DIR)/config -n ${1} -D $(DICT_PATH) -l ${2}/radiusd.log)
+ ${Q}rm -f ${2}/radiusd.log
+ ${Q}if ! $$(RADIUSD_RUN); then \
+ echo "FAILED STARTING RADIUSD"; \
+ grep 'Error :' "${2}/radiusd.log"; \
+ echo "Last entries in server log (${2}/radiusd.log):"; \
+ tail -n 100 "${2}/radiusd.log" 2> /dev/null; \
+ echo "RADIUSD_RUN: $$(RADIUSD_RUN)"; \
+ fi
+
+.PHONY: $(TEST).radiusd_start
+$(TEST).radiusd_start: ${2}/radiusd.pid
+
+#
+# If this test framework needs radiusd to be started / stopped, then ensure that
+# the output files depend on the radiusd binary.
+#
+ifneq "$(FILES.$(TEST))" ""
+$(foreach x, $(FILES.$(TEST)), $(eval $x: $(TESTBINDIR)/radiusd $(TESTBINDIR)/$(CLIENT) $(top_srcdir)/src/tests/$(subst test.,,$(TEST))/config/${1}.conf))
+endif
+
+endef
diff --git a/src/tests/radsec/.gitignore b/src/tests/radsec/.gitignore
new file mode 100644
index 0000000..9daa835
--- /dev/null
+++ b/src/tests/radsec/.gitignore
@@ -0,0 +1,6 @@
+dictionary
+radiusd.conf
+sites-enabled
+mods-enabled
+radrelay.conf
+test.conf
diff --git a/src/tests/radsec/1.basic-auth.reply b/src/tests/radsec/1.basic-auth.reply
new file mode 100644
index 0000000..77aa6b1
--- /dev/null
+++ b/src/tests/radsec/1.basic-auth.reply
@@ -0,0 +1,2 @@
+Received Access-Accept
+
diff --git a/src/tests/radsec/1.basic-auth.request b/src/tests/radsec/1.basic-auth.request
new file mode 100644
index 0000000..a6ddb8e
--- /dev/null
+++ b/src/tests/radsec/1.basic-auth.request
@@ -0,0 +1,3 @@
+User-Name = "bob",
+NAS-IP-Address = "1.2.3.4",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/2.ipaddrudp-coa.reply b/src/tests/radsec/2.ipaddrudp-coa.reply
new file mode 100644
index 0000000..8ea0bfd
--- /dev/null
+++ b/src/tests/radsec/2.ipaddrudp-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "coa-buffered-reader:pre-proxy" "proxy-tls-default:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "proxy-tls-default:send-coa" "coa-buffered-reader:post-proxy"$
+
diff --git a/src/tests/radsec/2.ipaddrudp-coa.request b/src/tests/radsec/2.ipaddrudp-coa.request
new file mode 100644
index 0000000..9d3f5eb
--- /dev/null
+++ b/src/tests/radsec/2.ipaddrudp-coa.request
@@ -0,0 +1,3 @@
+User-Name = "IpAddress",
+NAS-IP-Address = "127.0.0.1",
+Called-Station-Id = "12341",
diff --git a/src/tests/radsec/3.homepooludp-coa.reply b/src/tests/radsec/3.homepooludp-coa.reply
new file mode 100644
index 0000000..ab9f0a1
--- /dev/null
+++ b/src/tests/radsec/3.homepooludp-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "home-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "home-originate-coa-relay:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/3.homepooludp-coa.request b/src/tests/radsec/3.homepooludp-coa.request
new file mode 100644
index 0000000..e3bff09
--- /dev/null
+++ b/src/tests/radsec/3.homepooludp-coa.request
@@ -0,0 +1,2 @@
+User-Name = "HomePoolCoA",
+Called-Station-Id = "coa-nas"
diff --git a/src/tests/radsec/4.homepooltls-coa.reply b/src/tests/radsec/4.homepooltls-coa.reply
new file mode 100644
index 0000000..4666894
--- /dev/null
+++ b/src/tests/radsec/4.homepooltls-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "home-originate-coa-relay:pre-proxy" "proxy-tls-default:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "proxy-tls-default:send-coa" "home-originate-coa-relay:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/4.homepooltls-coa.request b/src/tests/radsec/4.homepooltls-coa.request
new file mode 100644
index 0000000..7038e25
--- /dev/null
+++ b/src/tests/radsec/4.homepooltls-coa.request
@@ -0,0 +1,2 @@
+User-Name = "HomePoolCoA",
+Called-Station-Id = "coa-nas-tls"
diff --git a/src/tests/radsec/5.singletunnel_proxy-coa.reply b/src/tests/radsec/5.singletunnel_proxy-coa.reply
new file mode 100644
index 0000000..81a4173
--- /dev/null
+++ b/src/tests/radsec/5.singletunnel_proxy-coa.reply
@@ -0,0 +1,6 @@
+# We don't need delay since proxy flow will be finished
+# just after final CoA home server will return response.
+#delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/5.singletunnel_proxy-coa.request b/src/tests/radsec/5.singletunnel_proxy-coa.request
new file mode 100644
index 0000000..72ace4d
--- /dev/null
+++ b/src/tests/radsec/5.singletunnel_proxy-coa.request
@@ -0,0 +1,2 @@
+User-Name = "TcpSessionKey-Proxy",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/6.singletunnel_originate-coa.reply b/src/tests/radsec/6.singletunnel_originate-coa.reply
new file mode 100644
index 0000000..6a242b0
--- /dev/null
+++ b/src/tests/radsec/6.singletunnel_originate-coa.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received CoA-ACK
+Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"
+
diff --git a/src/tests/radsec/6.singletunnel_originate-coa.request b/src/tests/radsec/6.singletunnel_originate-coa.request
new file mode 100644
index 0000000..a838730
--- /dev/null
+++ b/src/tests/radsec/6.singletunnel_originate-coa.request
@@ -0,0 +1,2 @@
+User-Name = "TcpSessionKey",
+Called-Station-Id = "key0"
diff --git a/src/tests/radsec/7.coareply-auth.reply b/src/tests/radsec/7.coareply-auth.reply
new file mode 100644
index 0000000..62e680e
--- /dev/null
+++ b/src/tests/radsec/7.coareply-auth.reply
@@ -0,0 +1,4 @@
+delay 2.5
+Received Access-Accept
+Acct-Session-Id = "default:post-auth" "default:pre-proxy" "coa_tls:recv-coa" "proxy-originate-coa-relay:pre-proxy" "coa:recv-coa" "coa:send-coa" "proxy-originate-coa-relay:post-proxy-coa-ack" "coa_tls:send-coa" "default:post-proxy-coa-ack"$
+
diff --git a/src/tests/radsec/7.coareply-auth.request b/src/tests/radsec/7.coareply-auth.request
new file mode 100644
index 0000000..bd2e2b4
--- /dev/null
+++ b/src/tests/radsec/7.coareply-auth.request
@@ -0,0 +1,2 @@
+User-Name = "PostAuthCoA",
+Called-Station-Id = "key0",
diff --git a/src/tests/radsec/Makefile b/src/tests/radsec/Makefile
new file mode 100644
index 0000000..d732b29
--- /dev/null
+++ b/src/tests/radsec/Makefile
@@ -0,0 +1,10 @@
+include ../../../Make.inc
+
+all: tests.radsec
+ @echo "All tests done"
+
+include all.mk
+
+
+.PHONY: clean
+clean: clean.tests.radsec \ No newline at end of file
diff --git a/src/tests/radsec/README.rst b/src/tests/radsec/README.rst
new file mode 100644
index 0000000..a016a02
--- /dev/null
+++ b/src/tests/radsec/README.rst
@@ -0,0 +1,103 @@
+=======================
+Tests for radsec flows.
+=======================
+
+ RADIUS CoA
+ ┌─────────────────────────────────────────────────────────────┐
+ │ │
+┌──────▼───────┐ ┌────────────────┐ ┌───────┴────────┐
+│ │ │ │ RADSEC CoA │ │
+│ radiusd │ RADIUS CoA │ radiusd ◄──────────────┤ radiusd │
+│ ◄─────────────┤ │ RADSEC Auth │ │
+│ CoA Server │ │ Proxy Server ├──────────────► Home Server │
+│ │ │ │ │ │
+└──────────────┘ └───────▲────────┘ └───────▲────────┘
+ │ │
+ │ RADIUS │ RADIUS
+ │ Auth │ CoA
+ ┌───────┴────────┐ ┌───────┴────────┐
+ │ radclient │ │ radclient │
+ └────────────────┘ └────────────────┘
+
+
+FreeRADIUS common configuration is located (obviously) in
+src/tests/radsec/radddb directory. Specific configurations for separate radiusd
+instances are located under their respective directories: config-coa,
+config-proxy, config-home.
+
+Each test is a pair of two files ending with \*.request and \*.reply.
+
+To run these tests separately, make sure you run 'make test' from the root
+directory beforehand.
+
+Request files.
+==============
+
+\*.request file specifies attributes to be sent.
+
+The name of the file (the part after the dash) specifies the type of the request
+to be sent.
+
+For example 1.basic-auth.request sends an auth request and 2.basic-coa.request
+sends coa.
+
+* Authentication requests.
+--------------------------
+Radclient sends plain RADIUS Access-Request to Proxy Server. Proxy Server then
+proxies this authentication request with RADSEC to Home Server. An opened TLS
+tunnel is used later to accept CoA requests from Home Server.
+
+* CoA requests.
+---------------
+Radclient sends plain RADIUS CoA request to Home Server. Depending on the
+attributes Home Server does one of the following:
+
+- Originates CoA request to Proxy Server with RADSEC - original flow. This is
+the regular flow where Proxy Server acts as a TCP server and Home Server (as
+a TCP client) first needs to establish a connection to it.
+
+- Originates CoA request to Proxy Server with RADSEC - 'single tunnel flow'.
+This is the new flow where Proxy Server can accept CoA requests from Home Server
+within the same tunnel that it has opened for Access-Request. In this case, the
+Proxy Server is still a TCP client yet in terms of RADIUS protocol it acts as
+a CoA Server.
+
+In both of these two cases, the Proxy Server forwards a CoA request to CoA
+Server to complete the flow. As an example CoA Server responds with CoA-ACK,
+then in turn Proxy Server responds with CoA-ACK to Home Server and the flow
+completes.
+
+- Originates CoA request directly to CoA Server. Although this is not a RADSEC
+flow, that is also good to check.
+
+
+Reply files.
+============
+
+\*.reply file specify a result to be expected for the corresponding \*.request
+file.
+
+
+For each such pair of \*.request \*.reply files runtest.sh is run.
+
+This shell script sends a request with radclient.
+
+Several freeRADIUS instances process requests and add attributes to be checked.
+In the end of the flow all cumulative attributes are written to the detail_test
+file for later checking.
+
+The runtest.sh checks the result following a \*.reply file.
+
+After test is performed a new directory is created with name "$TEST_NAME.result"
+where all intermediate files realted to the test are located, an example of the
+directory structure is like follows:
+
+ok - status file: either ok or fail
+detail_test - helper file to save attributes by freeRADIUS
+2.ipaddrtls-coa.reply.tmp - reply file w/o internal commands (e.g delay)
+fr-home-2.ipaddrtls-coa.log - a part of freeRADIUS logs related to the test
+fr-coa-2.ipaddrtls-coa.log - the same just for radiusd CoA Server
+fr-proxy-2.ipaddrtls-coa.log - the same just for radiusd Proxy Server
+radclient.log - logs for radclient
+result-2.ipaddrtls-coa.log - combined and aggregated radclient.log and
+ - detail_test to be checked against \*.reply file
diff --git a/src/tests/radsec/all.mk b/src/tests/radsec/all.mk
new file mode 100644
index 0000000..1d6140e
--- /dev/null
+++ b/src/tests/radsec/all.mk
@@ -0,0 +1,150 @@
+BUILD_PATH := $(top_builddir)/build
+TEST_PATH := $(top_builddir)/src/tests/radsec
+BIN_PATH := $(BUILD_PATH)/bin/local
+LIB_PATH := $(BUILD_PATH)/lib/.libs/
+RADDB_PATH := $(top_builddir)/raddb
+
+# Naming convention for ports is like follows: port-<owner>-<description>.
+# Owner may be either CoA Server, Proxy Server or Home Server
+port-proxy-auth = 12340
+port-proxy-coa = 12341
+port-home-auth = 12342
+port-home-coa = 12343
+port-coa = 12344
+
+# Port difines for request types: auth or coa
+auth-port = $(port-proxy-auth)
+coa-port = $(port-home-coa)
+
+
+#
+# You can watch what it's doing by:
+#
+# $ VERBOSE=1 make ... args ...
+#
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+raddb:
+ ${Q}echo "Setting up raddb directory"
+ ${Q}cp -r $(top_builddir)/raddb $(TEST_PATH)
+ ${Q}rm -rf $(TEST_PATH)/raddb/sites-enabled/* # we have per server config
+ ${Q}echo 'detail detail_test {' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo ' filename = $${radacctdir}/detail_test' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo '}' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo 'detail detail_coa {' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo ' filename = $${radacctdir}/detail_coa' >> $(TEST_PATH)/raddb/mods-enabled/detail
+ ${Q}echo '}' >> $(TEST_PATH)/raddb/mods-enabled/detail
+
+ ${Q}$(MAKE) -C $(TEST_PATH)/raddb/certs
+
+dictionary:
+ ${Q}echo "# test dictionary not install. Delete at any time." > $(TEST_PATH)/dictionary
+ ${Q}echo '$$INCLUDE ' $(top_builddir)/share/dictionary >> $(TEST_PATH)/dictionary
+
+
+define TEST_CONF
+ ${Q}printf "Configuring radiusd $(1) -> "
+ ${Q}echo "# radiusd test configuration file. Do not install. Delete at any time." > $(TEST_PATH)/test-$(1).conf
+ ${Q}echo "libdir =" $(LIB_PATH) >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo "testdir =" $(TEST_PATH) >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'logdir = $${testdir}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'maindir = ${TEST_PATH}/raddb/' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'radacctdir = $${testdir}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'pidfile = $${testdir}/radiusd-$(1).pid' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'panic_action = "gdb -batch -x $${testdir}/panic.gdb %e %p > $${testdir}/gdb-$(1).log 2>&1; cat $${testdir}/gdb-$(1).log"' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'security {' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo ' allow_vulnerable_openssl = yes' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '}' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'modconfdir = $${maindir}mods-config' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'certdir = $${maindir}/certs' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo 'cadir = $${maindir}/certs' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '$$INCLUDE $${testdir}/config-$(1)/main.conf' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}echo '$$INCLUDE $${maindir}/radiusd.conf' >> $(TEST_PATH)/test-$(1).conf
+ ${Q}rm -f $(TEST_PATH)/gdb-$(1).log $(TEST_PATH)/fr-$(1).log
+endef
+
+define START_SERVER
+ ${Q}printf "Starting $(1) server... "
+ ${Q}if ! $(BIN_PATH)/radiusd -Pxxxxml $(TEST_PATH)/fr-$(1).log -d $(TEST_PATH) -n test-$(1) -D $(TEST_PATH); then \
+ echo "failed"; \
+ echo "Last log entries were:"; \
+ tail -n 20 "$(TEST_PATH)/fr-$(1).log"; \
+ else \
+ echo "ok"; \
+ fi
+endef
+
+define PID_SERVER
+ ${Q}sed 's/$${{port-proxy-auth}}/$(port-proxy-auth)/g; \
+ s/$${{port-proxy-coa}}/$(port-proxy-coa)/g; \
+ s/$${{port-home-auth}}/$(port-home-auth)/g; \
+ s/$${{port-home-coa}}/$(port-home-coa)/g; \
+ s/$${{port-coa}}/$(port-coa)/g' \
+ $(TEST_PATH)/config-$(1)/main.conf > $(TEST_PATH)/config-$(1)/main.conf
+ $(call TEST_CONF,$(1))
+ $(call START_SERVER,$(1))
+endef
+
+radiusd.pid: raddb dictionary
+ $(call PID_SERVER,coa)
+ $(call PID_SERVER,home)
+ $(call PID_SERVER,proxy)
+
+define KILL_SERVER
+ ${Q}if [ -f $(TEST_PATH)/radiusd-$(1).pid ]; then \
+ if ! ps `cat $(TEST_PATH)/radiusd-$(1).pid` >/dev/null 2>&1; then \
+ rm -f $(TEST_PATH)/radiusd-$(1).pid; \
+ echo "FreeRADIUS terminated during test"; \
+ echo "GDB output was:"; \
+ cat "$(TEST_PATH)/gdb-$(1).log"; \
+ echo "Last log entries were:"; \
+ tail -n 20 $(TEST_PATH)/fr-$(1).log; \
+ fi; \
+ if ! kill -TERM `cat $(TEST_PATH)/radiusd-$(1).pid` >/dev/null 2>&1; then \
+ echo "Cannot kill $(TEST_PATH)/radiusd-$(1).pid"; \
+ fi; \
+ fi
+ ${Q}rm -f $(TEST_PATH)/radiusd-$(1).pid $(TEST_PATH)/config-$(1)/*.conf
+endef
+
+radiusd-proxy.kill:
+ $(call KILL_SERVER,proxy)
+radiusd-home.kill:
+ $(call KILL_SERVER,home)
+radiusd-coa.kill:
+ $(call KILL_SERVER,coa)
+
+radiusd.kill: radiusd-proxy.kill radiusd-home.kill radiusd-coa.kill
+
+# E.g: basis-auth.request -> TEST_NAME=basic-auth TYPE=auth, PORT=$(auth-port)
+%.request.test:
+ ${Q}printf "RADSEC-TEST $@... "
+ ${Q}if ! TEST_NAME=$(patsubst %.request.test,%,$@) \
+ TYPE=$(word 2, $(subst -, ,$(patsubst %.request.test,%,$@))) \
+ PORT=$($(word 2, $(subst -, ,$(patsubst %.request.test,%,$@)))-port) \
+ TEST_PATH=$(TEST_PATH) $(TEST_PATH)/runtest.sh 2>&1 > /dev/null; then \
+ echo "failed"; \
+ else \
+ echo "ok"; \
+ fi
+
+# kill the server (if it's running)
+# start the server
+# run the tests
+# kill the server
+#TEST_FILES = 2.basic-coa.request.test
+TEST_FILES = $(sort $(addsuffix .test,$(notdir $(wildcard $(TEST_PATH)/*.request))))
+tests.radsec: radiusd.kill radiusd.pid $(TEST_FILES)
+ ${Q}$(MAKE) radiusd.kill
+
+.PHONY: clean.tests.radsec
+clean.tests.radsec: radiusd.kill
+ ${Q}cd $(TEST_PATH) && rm -rf raddb/ detail_coa detail_test *.result *.conf dictionary *.ok *.log *.tmp
+
+
+.PHONY: radiusd.kill radiusd-proxy.kill radiusd-home.kill radiusd-coa.kill dictionary raddb
diff --git a/src/tests/radsec/config-coa/main.conf.template b/src/tests/radsec/config-coa/main.conf.template
new file mode 100644
index 0000000..5baf4b7
--- /dev/null
+++ b/src/tests/radsec/config-coa/main.conf.template
@@ -0,0 +1,37 @@
+listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}}
+ virtual_server = coa
+}
+
+server coa {
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ recv-coa {
+ update request {
+ &Acct-Session-Id += "coa:recv-coa"
+ }
+ }
+
+ send-coa {
+ update reply {
+ &reply: += request:[*]
+ &reply:Acct-Session-Id += "coa:send-coa"
+ }
+ }
+}
+
diff --git a/src/tests/radsec/config-home/main.conf b/src/tests/radsec/config-home/main.conf
new file mode 100644
index 0000000..98966fd
--- /dev/null
+++ b/src/tests/radsec/config-home/main.conf
@@ -0,0 +1,322 @@
+listen {
+
+ ipaddr = 127.0.0.1
+ port = ${{port-home-auth}}
+ type = auth+coa
+ proto = tcp
+
+ virtual_server = default
+
+ clients = radsec
+
+ tls {
+ tls_max_version="1.2"
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ cipher_server_preference = no
+
+ cache {
+ enable = no
+ lifetime = 24 # hours
+ }
+
+ require_client_cert = yes
+ }
+
+ # Specify the CoA retransmit parameters for CoA single tunnel
+ coa {
+ irt = 1
+ mrt = 16
+ mrc = 0
+ mrd = 5
+ }
+}
+
+clients radsec {
+ client localhost {
+ ipaddr = 127.0.0.1
+ secret = radsec
+ proto = tls
+
+ limit {
+ max_connections = 16
+ lifetime = 0 # do not close connection
+ idle_timeout = 0 # do not close connection even after an idle period
+ }
+ }
+}
+
+server default {
+ authorize {
+ update control {
+ Originating-Realm-Key := &Called-Station-Id
+ Auth-Type := Accept
+ }
+ }
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ post-auth {
+ if(User-Name && User-Name == "PostAuthCoA") {
+ update coa {
+ &Acct-Session-Id += "default:post-auth"
+ &Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ }
+ }
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "default:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update proxy-reply {
+ &Acct-Session-Id += "default:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ # If there was no response at all
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+
+ detail_test.post-proxy
+ }
+}
+
+#
+# CoA Relay
+#
+listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-home-coa}}
+ virtual_server = coa
+}
+
+server coa {
+ recv-coa {
+
+ update request {
+ COA-Packet-Type := "%{Packet-Type}"
+ }
+
+ if(&User-Name == "TcpSessionKey-Proxy") {
+ # Proxying CoA
+ update control {
+ &Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ } else {
+ # Originating CoA
+ detail_coa.accounting
+ }
+ }
+}
+
+server coa-buffered-reader {
+ listen {
+ type = detail
+ filename = "${radacctdir}/detail_coa"
+ load_factor = 90
+ track = yes
+ }
+
+ accounting {
+ switch &User-Name {
+ case "IpAddress" {
+ update {
+ coa:Packet-DST-IP-Address := &NAS-IP-Address
+ coa:Packet-DST-Port:= &Called-Station-Id
+ }
+ }
+ case "IpAddressSingleTunnel" {
+ update {
+ coa:Packet-DST-IP-Address := &NAS-IP-Address
+ }
+ }
+ case "HomePoolCoA" {
+ update {
+ coa:Home-Server-Pool := &Called-Station-Id
+ }
+ }
+ case "TcpSessionKey"{
+ update {
+ coa:Proxy-To-Originating-Realm := &Called-Station-Id
+ }
+ }
+ }
+
+ switch &COA-Packet-Type {
+ case "Disconnect-Request" {
+ update {
+ # Include given attributes
+ &disconnect: += request:[*]
+ &disconnect:Packet-DST-IP-Address := &COA-Packet-DST-IP-Address
+ &disconnect:Packet-DST-Port := &COA-Packet-DST-Port
+ &disconnect:Acct-Session-Id := &COA-Acct-Session-Id
+ &disconnect:Acct-Delay-Time !* ANY
+ }
+ }
+
+ case "CoA-Request" {
+ update {
+ &coa:Acct-Session-Id = "coa-buffered-reader:accounting:coa-request"
+ }
+ }
+ }
+ ok
+ } # accounting
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "coa-buffered-reader:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ update {
+ &proxy-reply:Acct-Session-Id += "coa-buffered-reader:post-proxy"
+ }
+ detail_test.post-proxy
+ }
+}
+
+server home-originate-coa-relay {
+
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "home-originate-coa-relay:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "home-originate-coa-relay:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ # If there was no response at all
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+
+ detail_test.post-proxy
+ }
+}
+
+home_server coa-nas {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas {
+ type = fail-over
+ home_server = coa-nas
+ virtual_server = home-originate-coa-relay
+}
+
+home_server coa-nas-tls {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas-tls {
+ type = fail-over
+ home_server = coa-nas-tls
+ virtual_server = home-originate-coa-relay
+}
diff --git a/src/tests/radsec/config-proxy/main.conf.template b/src/tests/radsec/config-proxy/main.conf.template
new file mode 100644
index 0000000..aa77835
--- /dev/null
+++ b/src/tests/radsec/config-proxy/main.conf.template
@@ -0,0 +1,207 @@
+server proxy-default {
+
+ listen {
+ type = auth+acct
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-auth}}
+ }
+
+ authorize {
+ update control {
+ &Proxy-To-Realm := "tls"
+ }
+ }
+
+ authenticate {
+ Auth-Type PAP {
+ pap
+ }
+
+ Auth-Type MS-CHAP {
+ mschap
+ }
+
+ Auth-Type EAP {
+ eap
+ }
+ }
+
+ pre-proxy {
+ update {
+ &Acct-Session-Id += "proxy-default:pre-proxy"
+ }
+ }
+
+ post-proxy {
+ update {
+ &Acct-Session-Id += "proxy-default:post-proxy"
+ }
+ detail_test.recv-coa
+ }
+
+ recv-coa {
+ update {
+ &Acct-Session-Id += "proxy-default:recv-coa"
+ }
+ detail_test.recv-coa
+ }
+
+ send-coa {
+ update {
+ &Acct-Session-Id += "proxy-default:send-coa"
+ }
+ }
+}
+
+server proxy-tls-default {
+
+ listen {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-proxy-coa}}
+ }
+
+ recv-coa {
+ update {
+ &control:Home-Server-Pool := coa-nas
+ &request:Acct-Session-Id += "proxy-tls-default:recv-coa"
+ }
+ }
+
+ send-coa {
+ update {
+ &reply:Acct-Session-Id += "proxy-tls-default:send-coa"
+ }
+ }
+}
+
+#
+# Proxy To CoA server
+#
+server proxy-originate-coa-relay {
+ pre-proxy {
+ update {
+ &proxy-request:Acct-Session-Id += "proxy-originate-coa-relay:pre-proxy"
+ }
+ }
+ post-proxy {
+ switch &proxy-reply:Packet-Type {
+ case CoA-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-coa-ack"
+ }
+ }
+
+ case CoA-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-coa-nak"
+ }
+ }
+
+ case Disconnect-ACK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-disconnect-ack"
+ }
+ }
+
+ case Disconnect-NAK {
+ update {
+ &proxy-reply:Acct-Session-Id += "proxy-originate-coa-relay:post-proxy-disconnect-nak"
+ }
+ }
+
+ case {
+ fail
+ }
+ }
+
+ Post-Proxy-Type Fail-CoA {
+ ok
+ }
+
+ Post-Proxy-Type Fail-Disconnect {
+ ok
+ }
+ }
+}
+
+home_server coa-nas {
+ type = coa
+ ipaddr = 127.0.0.1
+ port = ${{port-coa}} # A placeholder to be set in test makefile
+ secret = testing123
+
+ coa {
+ irt = 2
+ mrt = 16
+ mrc = 5
+ mrd = 30
+ }
+}
+
+home_server_pool coa-nas {
+ type = fail-over
+ home_server = coa-nas
+ virtual_server = proxy-originate-coa-relay
+}
+
+
+#
+# Proxy To RADSEC Home server
+#
+server coa_tls {
+ recv-coa {
+ update control {
+ &request:Acct-Session-Id += "coa_tls:recv-coa"
+ &Home-Server-Pool := coa-nas
+ }
+ }
+
+ # When a packet is sent, it is processed through the
+ # send-coa section. This applies to *both* CoA-Request and
+ # Disconnect-Request packets.
+ send-coa {
+ update control {
+ &reply:Acct-Session-Id += "coa_tls:send-coa"
+ }
+ }
+
+ # You can use pre-proxy and post-proxy sections here, too.
+ # They will be processed for sending && receiving proxy packets.
+}
+
+home_server tls {
+ ipaddr = 127.0.0.1
+ port = ${{port-home-auth}} # A placeholder to be set in test makefile
+ type = auth+acct+coa
+ secret = radsec
+ proto = tcp
+ status_check = none
+
+ tls {
+ tls_max_version="1.2"
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.key
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${certdir}/ca.pem
+ random_file = /dev/urandom
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ }
+
+ recv_coa {
+ virtual_server = coa_tls
+ }
+}
+
+home_server_pool tls {
+ type = fail-over
+ home_server = tls
+ virtual_server = coa_tls
+}
+
+realm tls {
+ auth_pool = tls
+}
+
diff --git a/src/tests/radsec/runtest.sh b/src/tests/radsec/runtest.sh
new file mode 100755
index 0000000..811f6bb
--- /dev/null
+++ b/src/tests/radsec/runtest.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+#set -x
+
+: ${TYPE=auth}
+: ${TEST_NAME=1.basic-auth}
+: ${PORT=12340}
+: ${SECRET=testing123}
+
+cd $TEST_PATH
+
+BIN_PATH=../../../build/bin/local
+OUTPUT=radclient.log
+
+RES=result-$TEST_NAME.log
+
+clean() {
+ kill $tailcoa $tailhome $tailproxy 2>&1 > /dev/null
+ wait $tailcoa $tailhome $tailproxy 2>&1 > /dev/null # suppress terminated messages
+ echo "" > detail_test
+ rm ./$TEST_NAME.reply.tmp fr-*-$TEST_NAME.log fail ok $RES radclient.log 2>&1 > /dev/null
+}
+
+# Combine a list of several repeated attributes to a single attribute with delimeter:
+# This:
+# Acct-Session-Id = "coa-buffered-reader:accounting:coa-request"
+# Acct-Session-Id = "default:send-coa"
+# Become:
+# Acct-Session-Id = "coa-buffered-reader:accounting:coa-request" "default:send-coa"
+aggregate() {
+ sort -s -t= -k1,1 ./detail_test | awk -F= '
+ prev!=$1 && prev{
+ print prev FS val;
+ prev=val=""}
+ {
+ val=val?val OFS $2:$2;
+ prev=$1
+ }
+ END{
+ if(val){
+ print prev FS val}
+ }' >> $RES
+}
+
+echo "Running test: $TEST_NAME for port: $PORT type: $TYPE"
+
+clean
+
+tail -f fr-coa.log 2> /dev/null > fr-coa-$TEST_NAME.log &
+tailcoa=$(echo $!)
+tail -f fr-home.log 2> /dev/null > fr-home-$TEST_NAME.log &
+tailhome=$(echo $!)
+tail -f fr-proxy.log 2> /dev/null > fr-proxy-$TEST_NAME.log &
+tailproxy=$(echo $!)
+
+$BIN_PATH/radclient -f $TEST_NAME.request -xF -D ./ 127.0.0.1:$PORT $TYPE $SECRET 1> $OUTPUT
+
+# skip comments
+sed '/^\s*#/d' $TEST_NAME.reply > $TEST_NAME.reply.tmp
+
+# wait if needed
+delay=$(grep delay $TEST_NAME.reply.tmp | awk '{print $2}')
+sed '/delay/d' $TEST_NAME.reply.tmp > $TEST_NAME.reply.tmp
+sleep $delay 2>&1 > /dev/null
+
+cat radclient.log > $RES
+aggregate
+
+while read -r line; do
+ if ! grep "$line" $RES >/dev/null 2>&1; then
+ echo "This test failed!" >> fail
+ echo "Testing $TEST_NAME failed. Cannot find $line in $RES." > fail
+ fi
+done < $TEST_NAME.reply.tmp
+
+if [ ! -f fail ]; then echo "This test succeded!" >> ok; fi
+
+mkdir $TEST_NAME.result 2>&1 > /dev/null
+cp ./$TEST_NAME.reply.tmp fr-*-$TEST_NAME.log fail ok \
+ $RES radclient.log detail_test $TEST_NAME.result 2>&1 > /dev/null
+
+clean
+
+test -f $TEST_NAME.result/ok # exit with the status code
diff --git a/src/tests/rbmonkey.c b/src/tests/rbmonkey.c
new file mode 100644
index 0000000..dd58ff0
--- /dev/null
+++ b/src/tests/rbmonkey.c
@@ -0,0 +1,250 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <assert.h>
+
+#include <freeradius-devel/libradius.h>
+
+/*
+ * We need knowlege of the internal structures.
+ * This needs to be kept in lockstep with rbtree.c
+ */
+
+/* RED-BLACK tree description */
+typedef enum {
+ BLACK,
+ RED
+} node_colour_t;
+
+struct rbnode_t {
+ rbnode_t *left; //!< left child
+ rbnode_t *right; //!< right child
+ rbnode_t *parent; //!< Parent
+ node_colour_t colour; //!< Node colour (BLACK, RED)
+ void *data; //!< data stored in node
+};
+
+struct rbtree_t {
+#ifndef NDEBUG
+ uint32_t magic;
+#endif
+ rbnode_t *root;
+ int num_elements;
+ rb_comparator_t compare;
+ rb_free_t free;
+ bool replace;
+#ifdef HAVE_PTHREAD_H
+ bool lock;
+ pthread_mutex_t mutex;
+#endif
+};
+
+/* Storage for the NIL pointer. */
+static rbnode_t *NIL;
+
+static int comp(void const *a, void const *b)
+{
+ if (*(uint32_t const *)a > *(uint32_t const *)b) {
+ return -1;
+ }
+
+ if (*(uint32_t const *)a < *(uint32_t const *)b) {
+ return 1;
+ }
+ return 0;
+}
+
+#if 0
+static int print_cb(UNUSED void *ctx, void *i)
+{
+ fprintf(stderr, "%i\n", *(int*)i);
+ return 0;
+}
+#endif
+
+#define MAXSIZE 1024
+
+static int r = 0;
+static uint32_t rvals[MAXSIZE];
+
+static int store_cb(UNUSED void *ctx, void *i)
+{
+ rvals[r++] = *(int const *)i;
+ return 0;
+}
+
+static uint32_t mask;
+
+static int filter_cb(void *ctx, void *i)
+{
+ if ((*(uint32_t *)i & mask) == (*(uint32_t *)ctx & mask)) {
+ return 2;
+ }
+ return 0;
+}
+
+/*
+ * Returns the count of BLACK nodes from root to child leaves, or a
+ * negative number indicating which RED-BLACK rule was broken.
+ */
+static int rbcount(rbtree_t *t)
+{
+ rbnode_t *n;
+ int count, count_expect;
+
+ count_expect = -1;
+ n = t->root;
+ if (!n || n == NIL) {
+ return 0;
+ }
+ if (n->colour != BLACK) {
+ return -2; /* root not BLACK */
+ }
+ count = 0;
+descend:
+ while (n->left != NIL) {
+ if (n->colour == RED) {
+ if (n->left->colour != BLACK || n->right->colour != BLACK) {
+ return -4; /* Children of RED nodes must be BLACK */
+ }
+ }
+ else {
+ count++;
+ }
+ n = n->left;
+ }
+ if (n->right != NIL) {
+ if (n->colour == RED) {
+ if (n->left->colour != BLACK || n->right->colour != BLACK) {
+ return -4; /* Children of RED nodes must be BLACK */
+ }
+ }
+ else {
+ count++;
+ }
+ n = n->right;
+ }
+ if (n->left != NIL || n->right != NIL) {
+ goto descend;
+ }
+ if (count_expect < 0) {
+ count_expect = count + (n->colour == BLACK);
+ }
+ else {
+ if (count_expect != count + (n->colour == BLACK)) {
+ fprintf(stderr,"Expected %i got %i\n", count_expect, count);
+ return -5; /* All paths must traverse the same number of BLACK nodes. */
+ }
+ }
+ascend:
+ if (n->parent != NIL) return count_expect;
+ while (n->parent->right == n) {
+ n = n->parent;
+ if (!n->parent) return count_expect;
+ if (n->colour == BLACK) {
+ count--;
+ }
+ }
+ if (n->parent->left == n) {
+ if (n->parent->right != NIL) {
+ n = n->parent->right;
+ goto descend;
+ }
+ n = n->parent;
+ if (!n->parent) return count_expect;
+ if (n->colour == BLACK) {
+ count--;
+ }
+ }
+ goto ascend;
+}
+
+#define REPS 10
+
+int main(UNUSED int argc, UNUSED char *argv[])
+{
+ rbtree_t *t;
+ int i, j;
+ uint32_t thresh;
+ int n, rep;
+ uint32_t vals[MAXSIZE];
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ /* TODO: make starting seed and repetitions a CLI option */
+ rep = REPS;
+
+again:
+ if (!--rep) return 0;
+
+ thresh = fr_rand();
+ mask = 0xff >> (fr_rand() & 7);
+ thresh &= mask;
+ n = (fr_rand() % MAXSIZE) + 1;
+
+ fprintf(stderr, "filter = %x mask = %x n= %i\n",
+ thresh, mask, n);
+
+ t = rbtree_create(NULL, comp, free, RBTREE_FLAG_LOCK);
+ /* Find out the value of the NIL node */
+ assert(t->root != NULL);
+ assert(t->root->parent == t->root);
+ NIL = t->root;
+
+ for (i = 0; i < n; i++) {
+ int *p;
+ p = malloc(sizeof(*p));
+ *p = fr_rand();
+ vals[i] = *p;
+ rbtree_insert(t, p);
+ }
+
+ i = rbcount(t);
+ fprintf(stderr,"After insert rbcount is %i.\n", i);
+ if (i < 0) { return i; }
+
+ qsort(vals, n, sizeof(int), comp);
+
+ /*
+ * For testing deletebydata instead
+
+ for (i = 0; i < n; i++) {
+ if (filter_cb(&vals[i], &thresh) == 2) {
+ rbtree_deletebydata(t, &vals[i]);
+ }
+ }
+
+ *
+ */
+ (void) rbtree_walk(t, RBTREE_DELETE_ORDER, filter_cb, &thresh);
+ i = rbcount(t);
+ fprintf(stderr,"After delete rbcount is %i.\n", i);
+ if (i < 0) { return i; }
+
+ r = 0;
+ rbtree_walk(t, RBTREE_IN_ORDER, &store_cb, NULL);
+
+ for (j = i = 0; i < n; i++) {
+ if (i && vals[i-1] == vals[i]) continue;
+ if (!filter_cb(&thresh, &vals[i])) {
+ if (vals[i] != rvals[j]) goto bad;
+ j++;
+ }
+ }
+ fprintf(stderr,"matched OK\n");
+ rbtree_free(t);
+ goto again;
+
+bad:
+ for (j = i = 0; i < n; i++) {
+ if (i && vals[i-1] == vals[i]) continue;
+ if (!filter_cb(&thresh, &vals[i])) {
+ fprintf(stderr, "%i: %x %x\n", j, vals[i], rvals[j]);
+ j++;
+ } else {
+ fprintf(stderr, "skipped %x\n", vals[i]);
+ }
+ }
+ return -1;
+}
+
diff --git a/src/tests/rbmonkey.mk b/src/tests/rbmonkey.mk
new file mode 100644
index 0000000..ecf5e06
--- /dev/null
+++ b/src/tests/rbmonkey.mk
@@ -0,0 +1,7 @@
+TARGET := rbmonkey
+
+SOURCES := rbmonkey.c
+
+TGT_PREREQS := libfreeradius-radius.a
+TGT_LDLIBS := $(LIBS)
+TGT_INSTALLDIR :=
diff --git a/src/tests/runtests.sh b/src/tests/runtests.sh
new file mode 100755
index 0000000..cc403c6
--- /dev/null
+++ b/src/tests/runtests.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+: ${BIN_PATH=./}
+: ${PORT=12340}
+: ${HOME_PORT=12350}
+: ${SECRET=testing123}
+
+rm -f verbose.log
+RCODE=0
+
+echo "Running tests:"
+for NAME in $@
+do
+ TOTAL=`grep TESTS $NAME | sed 's/.*TESTS//'`
+
+ #
+ # Each test may have multiple variants.
+ #
+ for NUMBER in `echo $TOTAL`
+ do
+ cp $NAME .request
+ BASE=`echo $NAME | sed 's,.*/,,'`
+
+ #
+ # Add the name of the test, and the variant to the request
+ #
+ echo "Test-Name = \"$BASE\"," >> .request
+ echo 'Test-Number = ' $NUMBER >> .request
+
+ rm ./radclient.log > /dev/null 2>&1
+ $BIN_PATH/radclient -f .request -xF -D ./ 127.0.0.1:$PORT auth $SECRET 1> ./radclient.log
+ if [ "$?" = "0" ]; then
+ echo "${BASE}_${NUMBER} : Success"
+ else
+ echo "${BASE}_${NUMBER} : FAILED"
+ cat ./radclient.log
+ RCODE=1
+ fi
+ done
+done
+
+
+if [ "$RCODE" = "0" ]
+then
+ rm -f radiusd.log radclient.log
+ echo "All tests succeeded"
+else
+ echo "See radclient.log for more details"
+fi
+
+exit $RCODE
diff --git a/src/tests/salt-test-server/.gitignore b/src/tests/salt-test-server/.gitignore
new file mode 100644
index 0000000..e3aa327
--- /dev/null
+++ b/src/tests/salt-test-server/.gitignore
@@ -0,0 +1,8 @@
+# Local files
+*.swp
+.DS_Store
+*.md5
+
+# Salt runtime directories
+tmp
+cache
diff --git a/src/tests/salt-test-server/README b/src/tests/salt-test-server/README
new file mode 100644
index 0000000..8265f46
--- /dev/null
+++ b/src/tests/salt-test-server/README
@@ -0,0 +1,3 @@
+Salt script to build the test VM required for running the ldap, mysql & postgres tests.
+
+See http://docs.saltstack.com/en/latest/index.html
diff --git a/src/tests/salt-test-server/build.sh b/src/tests/salt-test-server/build.sh
new file mode 100755
index 0000000..ad1873b
--- /dev/null
+++ b/src/tests/salt-test-server/build.sh
@@ -0,0 +1 @@
+salt-ssh --config-dir=salt_config -l quiet "test-server" state.highstate
diff --git a/src/tests/salt-test-server/salt/iptable.sls b/src/tests/salt-test-server/salt/iptable.sls
new file mode 100644
index 0000000..7aefdd1
--- /dev/null
+++ b/src/tests/salt-test-server/salt/iptable.sls
@@ -0,0 +1,13 @@
+{% if grains['os'] == 'CentOS' %}
+update_firewall:
+ file.managed:
+ - name: /etc/sysconfig/iptables
+ - source: salt://iptables
+
+reload_iptables:
+ cmd.wait:
+ - cwd: /
+ - name: service iptables reload
+ - watch:
+ - file: /etc/sysconfig/iptables
+{% endif %}
diff --git a/src/tests/salt-test-server/salt/iptables b/src/tests/salt-test-server/salt/iptables
new file mode 100644
index 0000000..2e2d4a2
--- /dev/null
+++ b/src/tests/salt-test-server/salt/iptables
@@ -0,0 +1,15 @@
+# Generated by iptables-save v1.4.7 on Thu Feb 19 13:41:09 2015
+*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
+-A INPUT -p tcp -m state --state NEW -m tcp --dport 5432 -j ACCEPT
+-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
+-A INPUT -p icmp -j ACCEPT
+-A INPUT -i lo -j ACCEPT
+-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
+-A INPUT -j REJECT --reject-with icmp-host-prohibited
+-A FORWARD -j REJECT --reject-with icmp-host-prohibited
+COMMIT
+# Completed on Thu Feb 19 13:41:09 2015
diff --git a/src/tests/salt-test-server/salt/ldap.sls b/src/tests/salt-test-server/salt/ldap.sls
new file mode 100644
index 0000000..006abf8
--- /dev/null
+++ b/src/tests/salt-test-server/salt/ldap.sls
@@ -0,0 +1,41 @@
+{% if grains['os'] == 'Ubuntu' %}
+
+# In Ubuntu 14.10, openldap comes with a broken AppArmor profile (can't connect through socket)
+# Disable AppArmor alltogether
+/etc/init.d/apparmor teardown:
+ cmd.run
+
+update-rc.d -f apparmor remove:
+ cmd.run
+
+{% endif %}
+
+slapd:
+ pkg.installed
+
+ldap-utils:
+ pkg.installed
+
+# Copy ldif file for base structure
+/root/base.ldif:
+ file.managed:
+ - source: salt://ldap/base.ldif
+
+# Copy ldif file for FreeRADIUS schema
+/root/schema_freeradius.ldif:
+ file.managed:
+ - source: salt://ldap/schema_freeradius.ldif
+
+# Add FreeRADIUS schema
+add_fr_schema:
+ cmd.run:
+ - name: "ldapadd -Y EXTERNAL -H ldapi:/// -f /root/schema_freeradius.ldif"
+ - cwd: /root/
+ - unless: "/usr/bin/ldapsearch -Y EXTERNAL -H ldapi:/// -b cn={4}radius,cn=schema,cn=config -s base"
+
+# Create base structure in LDAP
+build_base_structure:
+ cmd.run:
+ - name: "/usr/bin/ldapadd -Y EXTERNAL -H ldapi:/// -f /root/base.ldif"
+ - cwd: /root/
+ - unless: "/usr/bin/ldapsearch -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com -s base"
diff --git a/src/tests/salt-test-server/salt/ldap/base.ldif b/src/tests/salt-test-server/salt/ldap/base.ldif
new file mode 100644
index 0000000..7a7a1eb
--- /dev/null
+++ b/src/tests/salt-test-server/salt/ldap/base.ldif
@@ -0,0 +1,80 @@
+# Database settings
+dn: olcDatabase=mdb,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcMdbConfig
+olcDatabase: {1}mdb
+olcSuffix: dc=example,dc=com
+olcDbDirectory: /tmp/ldap/db
+olcRootDN: cn=admin,dc=example,dc=com
+olcRootPW: {SSHA}SgCZuAcGQA5HlgKi+g5xwVyI2NhXRFYh
+olcDbIndex: objectClass eq
+olcLastMod: TRUE
+olcDbCheckpoint: 512 30
+olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
+olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by dn="cn=admin,cn=config" manage
+olcAccess: to attrs=shadowLastChange by self write by * read
+olcAccess: to dn.base="" by * read
+olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read
+
+# Create top-level object in domain
+dn: dc=example,dc=com
+objectClass: top
+objectClass: dcObject
+objectclass: organization
+o: Example Organization
+dc: Example
+description: LDAP Example
+
+dn: ou=people,dc=example,dc=com
+objectClass: organizationalUnit
+ou: people
+
+dn: ou=groups,dc=example,dc=com
+objectClass: organizationalUnit
+ou: groups
+
+# foo, groups, example.com
+dn: cn=foo,ou=groups,dc=example,dc=com
+cn: foo
+objectClass: groupOfNames
+objectClass: top
+member: uid=john,ou=people,dc=example,dc=com
+
+dn: ou=profiles,dc=example,dc=com
+objectClass: organizationalUnit
+ou: profiles
+
+dn: cn=radprofile,ou=profiles,dc=example,dc=com
+objectClass: radiusObjectProfile
+objectClass: radiusprofile
+cn: radprofile
+radiusFramedIPNetmask: 255.255.255.0
+
+dn: cn=profile1,ou=profiles,dc=example,dc=com
+objectClass: radiusObjectProfile
+objectClass: radiusprofile
+cn: profile1
+radiusReplyAttribute: Framed-IP-Netmask := 255.255.0.0
+radiusReplyAttribute: Acct-Interim-Interval := 1800
+radiusRequestAttribute: Service-Type := Framed-User
+radiusControlAttribute: Framed-IP-Address == 1.2.3.4
+radiusControlAttribute: Reply-Message == "Hello world"
+
+dn: uid=john,ou=people,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: posixAccount
+objectClass: shadowAccount
+objectClass: radiusprofile
+uid: john
+sn: Doe
+givenName: John
+cn: John Doe
+displayName: John Doe
+userPassword: {cleartext}password
+uidNumber: 100
+gidNumber: 100
+homeDirectory: /home/john
+radiusIdleTimeout: 3600
+radiusAttribute: reply:Session-Timeout := 7200
+radiusAttribute: control:NAS-IP-Address := 1.2.3.4
+radiusProfileDN: cn=profile1,ou=profiles,dc=example,dc=com
diff --git a/src/tests/salt-test-server/salt/ldap/base2.ldif b/src/tests/salt-test-server/salt/ldap/base2.ldif
new file mode 100644
index 0000000..4ae6b07
--- /dev/null
+++ b/src/tests/salt-test-server/salt/ldap/base2.ldif
@@ -0,0 +1,81 @@
+# Database settings
+dn: olcDatabase=mdb,cn=config
+objectClass: olcDatabaseConfig
+objectClass: olcMdbConfig
+olcDatabase: {1}mdb
+olcSuffix: dc=example,dc=com
+olcDbDirectory: /tmp/ldap2/db
+olcRootDN: cn=admin,dc=example,dc=com
+olcRootPW: {SSHA}SgCZuAcGQA5HlgKi+g5xwVyI2NhXRFYh
+olcDbIndex: objectClass eq
+olcLastMod: TRUE
+olcDbCheckpoint: 512 30
+olcAccess: to attrs=userPassword by dn="cn=admin,dc=example,dc=com" write by anonymous auth by self write by * none
+olcAccess: to * by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage by dn="cn=admin,cn=config" manage
+olcAccess: to attrs=shadowLastChange by self write by * read
+olcAccess: to dn.base="" by * read
+olcAccess: to * by dn="cn=admin,dc=example,dc=com" write by * read
+
+# Create top-level object in domain
+dn: dc=example,dc=com
+objectClass: top
+objectClass: dcObject
+objectclass: organization
+o: Example Organization
+dc: Example
+description: LDAP Example Two
+
+dn: dc=subdept,dc=example,dc=com
+objectClass: organization
+objectClass: dcObject
+o: Sub org
+dc: subdept
+
+dn: ou=people,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: people
+
+dn: ou=groups,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: groups
+
+dn: ou=profiles,dc=subdept,dc=example,dc=com
+objectClass: organizationalUnit
+ou: profiles
+
+dn: cn=radprofile,ou=profiles,dc=subdept,dc=example,dc=com
+objectClass: radiusObjectProfile
+objectClass: radiusprofile
+cn: radprofile
+radiusFramedIPNetmask: 255.255.255.0
+
+dn: uid=fred,ou=people,dc=subdept,dc=example,dc=com
+objectClass: inetOrgPerson
+objectClass: posixAccount
+objectClass: shadowAccount
+objectClass: radiusprofile
+uid: fred
+sn: Jones
+givenName: Fred
+cn: Fred Jones
+displayName: Fred Jones
+userPassword: password
+uidNumber: 100
+gidNumber: 100
+homeDirectory: /home/fred
+radiusIdleTimeout: 3600
+radiusAttribute: reply.Session-Timeout := 7200
+radiusAttribute: control.NAS-IP-Address := 1.2.3.4
+radiusProfileDN: cn=radprofile,ou=profiles,ou=subdept,dc=example,dc=com
+
+dn: ou=offsite,dc=subdept,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: offsite
+ref: ldap://127.0.0.1:3890/dc=example,dc=com??sub
+
+dn: ou=bounce1,dc=subdept,dc=example,dc=com
+objectClass: referral
+objectClass: extensibleObject
+ou: bounce1
+ref: ldap://127.0.0.1:3890/ou=bounce2,dc=example,dc=com??sub
diff --git a/src/tests/salt-test-server/salt/ldap/schema_freeradius.ldif b/src/tests/salt-test-server/salt/ldap/schema_freeradius.ldif
new file mode 100644
index 0000000..44d2cb9
--- /dev/null
+++ b/src/tests/salt-test-server/salt/ldap/schema_freeradius.ldif
@@ -0,0 +1,76 @@
+dn: cn=radius,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: radius
+olcAttributeTypes: {0}( 1.3.6.1.4.1.11344.4.3.1.1 NAME 'radiusArapFeatures' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {1}( 1.3.6.1.4.1.11344.4.3.1.2 NAME 'radiusArapSecurity' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {2}( 1.3.6.1.4.1.11344.4.3.1.3 NAME 'radiusArapZoneAccess' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {3}( 1.3.6.1.4.1.11344.4.3.1.44 NAME 'radiusAuthType' DESC 'controlItem: Auth-Type' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {4}( 1.3.6.1.4.1.11344.4.3.1.4 NAME 'radiusCallbackId' DESC 'replyItem: Callback-Id' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {5}( 1.3.6.1.4.1.11344.4.3.1.5 NAME 'radiusCallbackNumber' DESC 'replyItem: Callback-Number' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {6}( 1.3.6.1.4.1.11344.4.3.1.6 NAME 'radiusCalledStationId' DESC 'controlItem: Called-Station-Id' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {7}( 1.3.6.1.4.1.11344.4.3.1.7 NAME 'radiusCallingStationId' DESC 'controlItem: Calling-Station-Id' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {8}( 1.3.6.1.4.1.11344.4.3.1.8 NAME 'radiusClass' DESC 'replyItem: Class' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {9}( 1.3.6.1.4.1.11344.4.3.1.45 NAME 'radiusClientIPAddress' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {10}( 1.3.6.1.4.1.11344.4.3.1.9 NAME 'radiusFilterId' DESC 'replyItem: Filter-Id' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {11}( 1.3.6.1.4.1.11344.4.3.1.10 NAME 'radiusFramedAppleTalkLink' DESC 'replyItem: Framed-AppleTalk-Link' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {12}( 1.3.6.1.4.1.11344.4.3.1.11 NAME 'radiusFramedAppleTalkNetwork' DESC 'replyItem: Framed-AppleTalk-Network' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {13}( 1.3.6.1.4.1.11344.4.3.1.12 NAME 'radiusFramedAppleTalkZone' DESC 'replyItem: Framed-AppleTalk-Zone' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {14}( 1.3.6.1.4.1.11344.4.3.1.13 NAME 'radiusFramedCompression' DESC 'replyItem: Framed-Compression' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {15}( 1.3.6.1.4.1.11344.4.3.1.14 NAME 'radiusFramedIPAddress' DESC 'replyItem: Framed-IP-Address' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {16}( 1.3.6.1.4.1.11344.4.3.1.15 NAME 'radiusFramedIPNetmask' DESC 'replyItem: Framed-IP-Netmask' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {17}( 1.3.6.1.4.1.11344.4.3.1.16 NAME 'radiusFramedIPXNetwork' DESC 'replyItem: Framed-IPX-Network' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {18}( 1.3.6.1.4.1.11344.4.3.1.17 NAME 'radiusFramedMTU' DESC' replyItem: Framed-MTU' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {19}( 1.3.6.1.4.1.11344.4.3.1.18 NAME 'radiusFramedProtocol'DESC 'replyItem: Framed-Protocol' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {20}( 1.3.6.1.4.1.11344.4.3.1.19 NAME 'radiusFramedRoute' DESC 'replyItem: Framed-Route' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {21}( 1.3.6.1.4.1.11344.4.3.1.20 NAME 'radiusFramedRouting' DESC 'replyItem: Framed-Routing' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {22}( 1.3.6.1.4.1.11344.4.3.1.46 NAME 'radiusGroupName' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {23}( 1.3.6.1.4.1.11344.4.3.1.47 NAME 'radiusHint' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {24}( 1.3.6.1.4.1.11344.4.3.1.48 NAME 'radiusHuntgroupName' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {25}( 1.3.6.1.4.1.11344.4.3.1.21 NAME 'radiusIdleTimeout' DESC 'replyItem: Idle-Timeout' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {26}( 1.3.6.1.4.1.11344.4.3.1.22 NAME 'radiusLoginIPHost' DESC 'replyItem: Login-IP-Host' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {27}( 1.3.6.1.4.1.11344.4.3.1.23 NAME 'radiusLoginLATGroup' DESC 'replyItem: Login-LAT-Group' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {28}( 1.3.6.1.4.1.11344.4.3.1.24 NAME 'radiusLoginLATNode' DESC 'replyItem: Login-LAT-Node' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {29}( 1.3.6.1.4.1.11344.4.3.1.25 NAME 'radiusLoginLATPort' DESC 'replyItem: Login-LAT-Port' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {30}( 1.3.6.1.4.1.11344.4.3.1.26 NAME 'radiusLoginLATService' DESC 'replyItem: Login-LAT-Service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {31}( 1.3.6.1.4.1.11344.4.3.1.27 NAME 'radiusLoginService' DESC 'replyItem: Login-Service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {32}( 1.3.6.1.4.1.11344.4.3.1.28 NAME 'radiusLoginTCPPort' DESC 'replyItem: Login-TCP-Port' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {33}( 1.3.6.1.4.1.11344.4.3.1.29 NAME 'radiusPasswordRetry' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {34}( 1.3.6.1.4.1.11344.4.3.1.30 NAME 'radiusPortLimit' DESC 'replyItem: Port-Limit' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {35}( 1.3.6.1.4.1.11344.4.3.1.49 NAME 'radiusProfileDN' DESC '' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
+olcAttributeTypes: {36}( 1.3.6.1.4.1.11344.4.3.1.31 NAME 'radiusPrompt' DESC ''EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {37}( 1.3.6.1.4.1.11344.4.3.1.50 NAME 'radiusProxyToRealm' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {38}( 1.3.6.1.4.1.11344.4.3.1.51 NAME 'radiusReplicateToRealm' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {39}( 1.3.6.1.4.1.11344.4.3.1.52 NAME 'radiusRealm' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE)
+olcAttributeTypes: {40}( 1.3.6.1.4.1.11344.4.3.1.32 NAME 'radiusServiceType' DESC 'replyItem: Service-Type' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {41}( 1.3.6.1.4.1.11344.4.3.1.33 NAME 'radiusSessionTimeout'DESC 'replyItem: Session-Timeout' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {42}( 1.3.6.1.4.1.11344.4.3.1.34 NAME 'radiusTerminationAction' DESC 'replyItem: Termination-Action' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {43}( 1.3.6.1.4.1.11344.4.3.1.35 NAME 'radiusTunnelAssignmentId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
+olcAttributeTypes: {44}( 1.3.6.1.4.1.11344.4.3.1.36 NAME 'radiusTunnelMediumType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {45}( 1.3.6.1.4.1.11344.4.3.1.37 NAME 'radiusTunnelPassword' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {46}( 1.3.6.1.4.1.11344.4.3.1.38 NAME 'radiusTunnelPreference' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {47}( 1.3.6.1.4.1.11344.4.3.1.39 NAME 'radiusTunnelPrivateGroupId' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {48}( 1.3.6.1.4.1.11344.4.3.1.40 NAME 'radiusTunnelServerEndpoint' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {49}( 1.3.6.1.4.1.11344.4.3.1.41 NAME 'radiusTunnelType' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {50}( 1.3.6.1.4.1.11344.4.3.1.42 NAME 'radiusVSA' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {51}( 1.3.6.1.4.1.11344.4.3.1.43 NAME 'radiusTunnelClientEndpoint' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {52}( 1.3.6.1.4.1.11344.4.3.1.53 NAME 'radiusSimultaneousUse' DESC 'controlItem: Simultaneous-Use' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {53}( 1.3.6.1.4.1.11344.4.3.1.54 NAME 'radiusLoginTime' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {54}( 1.3.6.1.4.1.11344.4.3.1.55 NAME 'radiusUserCategory' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {55}( 1.3.6.1.4.1.11344.4.3.1.56 NAME 'radiusStripUserName' DESC '' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+olcAttributeTypes: {56}( 1.3.6.1.4.1.11344.4.3.1.57 NAME 'dialupAccess' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {57}( 1.3.6.1.4.1.11344.4.3.1.58 NAME 'radiusExpiration' DESC 'controlItem: Expiration' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {58}( 1.3.6.1.4.1.11344.4.3.1.59 NAME 'radiusAttribute' DESC 'controlItem: $GENERIC$' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {59}( 1.3.6.1.4.1.11344.4.3.1.61 NAME 'radiusNASIpAddress' DESC '' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {60}( 1.3.6.1.4.1.11344.4.3.1.62 NAME 'radiusReplyMessage' DESC 'replyItem: Reply-Message' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {61}( 1.3.6.1.4.1.11344.4.3.1.63 NAME 'radiusControlAttribute' DESC 'controlItem: $GENERIC$' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {62}( 1.3.6.1.4.1.11344.4.3.1.64 NAME 'radiusReplyAttribute' DESC 'replyItem: $GENERIC$' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {63}( 1.3.6.1.4.1.11344.4.3.1.65 NAME 'radiusRequestAttribute' DESC 'requestItem: $GENERIC$' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcObjectClasses: {0}( 1.3.6.1.4.1.11344.4.3.2.1 NAME 'radiusprofile' DESC '' SUP top AUXILIARY MAY ( radiusArapFeatures $ radiusArapSecurity $ radiusArapZoneAccess $ radiusAuthType $
+ radiusCallbackId $ radiusCallbackNumber $radiusCalledStationId $ radiusCallingStationId $ radiusClass $ radiusClientIPAddress $ radiusFilterId $ radiusFramedAppleTalkLink $ radiusFramedAppleTalkNetwork $
+ radiusFramedAppleTalkZone $ radiusFramedCompression $ radiusFramedIPAddress $ radiusFramedIPNetmask $ radiusFramedIPXNetwork $ radiusFramedMTU $radiusFramedProtocol $ radiusAttribute $
+ radiusFramedRoute $ radiusFramedRouting $ radiusIdleTimeout $ radiusGroupName $ radiusHint $ radiusHuntgroupName $ radiusLoginIPHost $ radiusLoginLATGroup $ radiusLoginLATNode $ radiusLoginLATPort $
+ radiusLoginLATService $ radiusLoginService $ radiusLoginTCPPort $ radiusLoginTime $ radiusPasswordRetry $ radiusPortLimit $ radiusPrompt $ radiusProxyToRealm $ radiusRealm $ radiusReplicateToRealm $
+ radiusServiceType $ radiusSessionTimeout $ radiusStripUserName $ radiusTerminationAction $ radiusTunnelClientEndpoint $ radiusProfileDN $ radiusSimultaneousUse $ radiusTunnelAssignmentId $
+ radiusTunnelMediumType $ radiusTunnelPassword $ radiusTunnelPreference $ radiusTunnelPrivateGroupId $ radiusTunnelServerEndpoint $ radiusTunnelType $ radiusUserCategory $ radiusVSA $ radiusExpiration $
+ dialupAccess $ radiusNASIpAddress $ radiusReplyMessage $ radiusControlAttribute $ radiusReplyAttribute $ radiusRequestAttribute ) )
+olcObjectClasses: {1}( 1.3.6.1.4.1.11344.4.3.2.2 NAME 'radiusObjectProfile' DESC 'A Container Objectclass to be used for creating radius profile object' SUP top STRUCTURAL MUST cn MAY ( uid $ userPassword $ description ) )
diff --git a/src/tests/salt-test-server/salt/mysql.sls b/src/tests/salt-test-server/salt/mysql.sls
new file mode 100644
index 0000000..df1ea00
--- /dev/null
+++ b/src/tests/salt-test-server/salt/mysql.sls
@@ -0,0 +1,74 @@
+mysql-server:
+ pkg.installed
+
+# On Ubuntu, the default MySQL install only listens on localhost
+/etc/mysql/my.cnf:
+{% if grains['os'] == 'Ubuntu' %}
+ file.sed:
+ - before: 127.0.0.1
+ - after: 0.0.0.0
+ - limit: ^bind-address\s+=
+ - require:
+ - pkg: mysql-server
+{% else %}
+ file.exists
+{% endif %}
+
+mysql_daemon:
+ service:
+{% if grains['os'] == 'CentOS' %}
+ - name: mysqld
+{% elif grains['os'] == 'Ubuntu' or grains['os'] == 'Debian' %}
+ - name: mysql
+{% endif %}
+ - running
+ - enable: True
+ - watch:
+ - file: /etc/mysql/my.cnf
+ - require:
+ - pkg: mysql-server
+
+## FW rules don't work well with CentOS < 7
+# Insert is run each time
+#
+# iptables.insert:
+# - position: 1
+# - table: filter
+# - chain: INPUT
+# - j: ACCEPT # Use 'j' instead of 'jump' because iptables-save outputs 'j' flag.
+# - match: state
+# - connstate: NEW
+# - dport: 3306
+# - proto: tcp
+# - save: True
+
+# Copy DB schema file
+/salt/mysql/schema.sql:
+ file.managed:
+ - source: salt://mysql/schema.sql
+ - makedirs: true
+
+# Copy DB setup script
+/salt/mysql/setup.sql:
+ file.managed:
+ - source: salt://mysql/setup.sql
+ - makedirs: true
+
+# Create DB
+echo "CREATE DATABASE radius" | mysql:
+ cmd.run:
+ - creates: /var/lib/mysql/radius/db.opt
+
+# Create FreeRADIUS schema
+mysql radius < /salt/mysql/schema.sql:
+ cmd.run:
+ - unless: "echo 'desc radacct' | mysql radius"
+ - require:
+ - file: /salt/mysql/schema.sql
+
+# Setup DB access
+mysql radius < /salt/mysql/setup.sql:
+ cmd.run:
+ - unless: "echo \"show grants for 'radius';\" | mysql"
+ - require:
+ - file: /salt/mysql/setup.sql
diff --git a/src/tests/salt-test-server/salt/mysql/schema.sql b/src/tests/salt-test-server/salt/mysql/schema.sql
new file mode 100644
index 0000000..7761a62
--- /dev/null
+++ b/src/tests/salt-test-server/salt/mysql/schema.sql
@@ -0,0 +1,150 @@
+###########################################################################
+# $Id$ #
+# #
+# schema.sql rlm_sql - FreeRADIUS SQL Module #
+# #
+# Database schema for MySQL rlm_sql module #
+# #
+# To load: #
+# mysql -uroot -prootpass radius < schema.sql #
+# #
+# Mike Machado <mike@innercite.com> #
+###########################################################################
+#
+# Table structure for table 'radacct'
+#
+
+CREATE TABLE radacct (
+ radacctid bigint(21) NOT NULL auto_increment,
+ acctsessionid varchar(64) NOT NULL default '',
+ acctuniqueid varchar(32) NOT NULL default '',
+ username varchar(64) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ realm varchar(64) default '',
+ nasipaddress varchar(15) NOT NULL default '',
+ nasportid varchar(50) default NULL,
+ nasporttype varchar(32) default NULL,
+ acctstarttime datetime NULL default NULL,
+ acctupdatetime datetime NULL default NULL,
+ acctstoptime datetime NULL default NULL,
+ acctinterval int(12) default NULL,
+ acctsessiontime int(12) unsigned default NULL,
+ acctauthentic varchar(32) default NULL,
+ connectinfo_start varchar(50) default NULL,
+ connectinfo_stop varchar(50) default NULL,
+ acctinputoctets bigint(20) default NULL,
+ acctoutputoctets bigint(20) default NULL,
+ calledstationid varchar(50) NOT NULL default '',
+ callingstationid varchar(50) NOT NULL default '',
+ acctterminatecause varchar(32) NOT NULL default '',
+ servicetype varchar(32) default NULL,
+ framedprotocol varchar(32) default NULL,
+ framedipaddress varchar(15) NOT NULL default '',
+ PRIMARY KEY (radacctid),
+ UNIQUE KEY acctuniqueid (acctuniqueid),
+ KEY username (username),
+ KEY framedipaddress (framedipaddress),
+ KEY acctsessionid (acctsessionid),
+ KEY acctsessiontime (acctsessiontime),
+ KEY acctstarttime (acctstarttime),
+ KEY acctinterval (acctinterval),
+ KEY acctstoptime (acctstoptime),
+ KEY nasipaddress (nasipaddress)
+) ENGINE = INNODB;
+
+#
+# Table structure for table 'radcheck'
+#
+
+CREATE TABLE radcheck (
+ id int(11) unsigned NOT NULL auto_increment,
+ username varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '==',
+ value varchar(253) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY username (username(32))
+);
+
+#
+# Table structure for table 'radgroupcheck'
+#
+
+CREATE TABLE radgroupcheck (
+ id int(11) unsigned NOT NULL auto_increment,
+ groupname varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '==',
+ value varchar(253) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY groupname (groupname(32))
+);
+
+#
+# Table structure for table 'radgroupreply'
+#
+
+CREATE TABLE radgroupreply (
+ id int(11) unsigned NOT NULL auto_increment,
+ groupname varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY groupname (groupname(32))
+);
+
+#
+# Table structure for table 'radreply'
+#
+
+CREATE TABLE radreply (
+ id int(11) unsigned NOT NULL auto_increment,
+ username varchar(64) NOT NULL default '',
+ attribute varchar(64) NOT NULL default '',
+ op char(2) NOT NULL DEFAULT '=',
+ value varchar(253) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY username (username(32))
+);
+
+
+#
+# Table structure for table 'radusergroup'
+#
+
+CREATE TABLE radusergroup (
+ username varchar(64) NOT NULL default '',
+ groupname varchar(64) NOT NULL default '',
+ priority int(11) NOT NULL default '1',
+ KEY username (username(32))
+);
+
+#
+# Table structure for table 'radpostauth'
+#
+CREATE TABLE radpostauth (
+ id int(11) NOT NULL auto_increment,
+ username varchar(64) NOT NULL default '',
+ pass varchar(64) NOT NULL default '',
+ reply varchar(32) NOT NULL default '',
+ authdate timestamp NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE = INNODB;
+
+#
+# Table structure for table 'nas'
+#
+CREATE TABLE nas (
+ id int(10) NOT NULL auto_increment,
+ nasname varchar(128) NOT NULL,
+ shortname varchar(32),
+ type varchar(30) DEFAULT 'other',
+ ports int(5),
+ secret varchar(60) DEFAULT 'secret' NOT NULL,
+ server varchar(64),
+ community varchar(50),
+ description varchar(200) DEFAULT 'RADIUS Client',
+ PRIMARY KEY (id),
+ KEY nasname (nasname)
+);
diff --git a/src/tests/salt-test-server/salt/mysql/setup.sql b/src/tests/salt-test-server/salt/mysql/setup.sql
new file mode 100644
index 0000000..3b9ec54
--- /dev/null
+++ b/src/tests/salt-test-server/salt/mysql/setup.sql
@@ -0,0 +1,18 @@
+# -*- text -*-
+##
+## admin.sql -- MySQL commands for creating the RADIUS user.
+##
+## WARNING: You should change 'localhost' and 'radpass'
+## to something else. Also update raddb/sql.conf
+## with the new RADIUS password.
+##
+## $Id$
+
+#
+# Create default administrator for RADIUS
+#
+CREATE USER 'radius';
+SET PASSWORD FOR 'radius' = PASSWORD('radpass');
+
+# Need to read when running RADIUS and delete for cleanup
+GRANT ALL ON radius.* TO 'radius';
diff --git a/src/tests/salt-test-server/salt/ntp.sls b/src/tests/salt-test-server/salt/ntp.sls
new file mode 100644
index 0000000..66434ff
--- /dev/null
+++ b/src/tests/salt-test-server/salt/ntp.sls
@@ -0,0 +1,22 @@
+UTC:
+ timezone.system
+
+ntp_daemon:
+ # Make sure ntp is installed and running
+ pkg:
+{% if grains['os'] == 'CentOS' or grains['os'] == 'Ubuntu' or grains['os'] == 'Debian' %}
+ - name: ntp
+{% elif grains['os'] == 'FreeBSD' %}
+ - name: openntpd
+{% endif %}
+ - installed
+
+# Make sure ntpd is running and enabled (start on boot)
+{% if grains['os'] == 'CentOS' or grains['os'] == 'FreeBSD' %}
+ntpd:
+{% elif grains['os'] == 'Ubuntu' or grains['os'] == 'Debian' %}
+ntp:
+{% endif %}
+ service:
+ - running
+ - enable: True
diff --git a/src/tests/salt-test-server/salt/postgres.sls b/src/tests/salt-test-server/salt/postgres.sls
new file mode 100644
index 0000000..26fc4e6
--- /dev/null
+++ b/src/tests/salt-test-server/salt/postgres.sls
@@ -0,0 +1,71 @@
+postgresql:
+ # Install postgres and make sure it is running and starts on boot
+ pkg:
+ - installed
+ # Only try to start service after DB has been initialized (will fail otherwise)
+ service:
+ - name: postgresql
+ - running
+ - enable: True
+
+postgres_set_interface:
+ file.sed:
+ - name: /etc/postgresql/9.4/main/postgresql.conf
+ - before: ^\#listen_addresses = 'localhost'
+ - after: listen_addresses = '*'
+
+postgres_password_auth:
+ # Add authentication from anywhere
+ file.append:
+ - name: /etc/postgresql/9.4/main/pg_hba.conf
+ - text:
+ - host radius radius 0.0.0.0/0 md5
+
+postgres_restart:
+ # Restart postgres after changes to the config file (reload isn't enough)
+ cmd.wait:
+ - cwd: /
+ - name: service postgresql restart
+ - require:
+ - pkg: postgresql
+ - file: postgres_password_auth
+ - file: postgres_set_interface
+ - watch:
+ - file: /etc/postgresql/9.4/main/postgresql.conf
+ - file: /etc/postgresql/9.4/main/pg_hba.conf
+
+# Copy DB schema file
+/salt/postgres/schema.sql:
+ file.managed:
+ - source: salt://postgres/schema.sql
+ - makedirs: true
+
+# Copy DB setup script
+/salt/postgres/setup.sql:
+ file.managed:
+ - source: salt://postgres/setup.sql
+ - makedirs: true
+
+# Create DB
+create_db:
+ cmd.run:
+ - cwd: /
+ - name: createdb radius
+ - user: postgres
+ - unless: psql --list | grep radius
+
+# Create FreeRADIUS schema
+psql radius < /salt/postgres/schema.sql:
+ cmd.run:
+ - user: postgres
+ - unless: "echo '\\dt public.*' | psql radius | grep radacct;"
+ - require:
+ - file: /salt/postgres/schema.sql
+
+# Setup DB access
+psql radius < /salt/postgres/setup.sql:
+ cmd.run:
+ - user: postgres
+ - unless: "echo '\\du' | psql radius | grep radius"
+ - require:
+ - file: /salt/postgres/setup.sql
diff --git a/src/tests/salt-test-server/salt/postgres/schema.sql b/src/tests/salt-test-server/salt/postgres/schema.sql
new file mode 100644
index 0000000..c94ee9e
--- /dev/null
+++ b/src/tests/salt-test-server/salt/postgres/schema.sql
@@ -0,0 +1,183 @@
+/*
+ * $Id$
+ *
+ * Postgresql schema for FreeRADIUS
+ *
+ * All field lengths need checking as some are still suboptimal. -pnixon 2003-07-13
+ *
+ */
+
+/*
+ * Table structure for table 'radacct'
+ *
+ * Note: Column type bigserial does not exist prior to Postgres 7.2
+ * If you run an older version you need to change this to serial
+ */
+CREATE TABLE radacct (
+ RadAcctId bigserial PRIMARY KEY,
+ AcctSessionId text NOT NULL,
+ AcctUniqueId text NOT NULL UNIQUE,
+ UserName text,
+ GroupName text,
+ Realm text,
+ NASIPAddress inet NOT NULL,
+ NASPortId text,
+ NASPortType text,
+ AcctStartTime timestamp with time zone,
+ AcctUpdateTime timestamp with time zone,
+ AcctStopTime timestamp with time zone,
+ AcctInterval bigint,
+ AcctSessionTime bigint,
+ AcctAuthentic text,
+ ConnectInfo_start text,
+ ConnectInfo_stop text,
+ AcctInputOctets bigint,
+ AcctOutputOctets bigint,
+ CalledStationId text,
+ CallingStationId text,
+ AcctTerminateCause text,
+ ServiceType text,
+ FramedProtocol text,
+ FramedIPAddress inet
+);
+-- This index may be useful..
+-- CREATE UNIQUE INDEX radacct_whoson on radacct (AcctStartTime, nasipaddress);
+
+-- For use by update-, stop- and simul_* queries
+CREATE INDEX radacct_active_session_idx ON radacct (AcctUniqueId) WHERE AcctStopTime IS NULL;
+
+-- Add if you you regularly have to replay packets
+-- CREATE INDEX radacct_session_idx ON radacct (AcctUniqueId);
+
+-- For backwards compatibility
+-- CREATE INDEX radacct_active_user_idx ON radacct (AcctSessionId, UserName, NASIPAddress) WHERE AcctStopTime IS NULL;
+
+-- For use by onoff-
+CREATE INDEX radacct_bulk_close ON radacct (NASIPAddress, AcctStartTime) WHERE AcctStopTime IS NULL;
+
+-- and for common statistic queries:
+CREATE INDEX radacct_start_user_idx ON radacct (AcctStartTime, UserName);
+-- and, optionally
+-- CREATE INDEX radacct_stop_user_idx ON radacct (acctStopTime, UserName);
+
+/*
+ * There was WAAAY too many indexes previously. This combo index
+ * should take care of the most common searches.
+ * I have commented out all the old indexes, but left them in case
+ * someone wants them. I don't recomend anywone use them all at once
+ * as they will slow down your DB too much.
+ * - pnixon 2003-07-13
+ */
+
+/*
+ * create index radacct_UserName on radacct (UserName);
+ * create index radacct_AcctSessionId on radacct (AcctSessionId);
+ * create index radacct_AcctUniqueId on radacct (AcctUniqueId);
+ * create index radacct_FramedIPAddress on radacct (FramedIPAddress);
+ * create index radacct_NASIPAddress on radacct (NASIPAddress);
+ * create index radacct_AcctStartTime on radacct (AcctStartTime);
+ * create index radacct_AcctStopTime on radacct (AcctStopTime);
+*/
+
+
+
+/*
+ * Table structure for table 'radcheck'
+ */
+CREATE TABLE radcheck (
+ id serial PRIMARY KEY,
+ UserName text NOT NULL DEFAULT '',
+ Attribute text NOT NULL DEFAULT '',
+ op VARCHAR(2) NOT NULL DEFAULT '==',
+ Value text NOT NULL DEFAULT ''
+);
+create index radcheck_UserName on radcheck (UserName,Attribute);
+/*
+ * Use this index if you use case insensitive queries
+ */
+-- create index radcheck_UserName_lower on radcheck (lower(UserName),Attribute);
+
+/*
+ * Table structure for table 'radgroupcheck'
+ */
+CREATE TABLE radgroupcheck (
+ id serial PRIMARY KEY,
+ GroupName text NOT NULL DEFAULT '',
+ Attribute text NOT NULL DEFAULT '',
+ op VARCHAR(2) NOT NULL DEFAULT '==',
+ Value text NOT NULL DEFAULT ''
+);
+create index radgroupcheck_GroupName on radgroupcheck (GroupName,Attribute);
+
+/*
+ * Table structure for table 'radgroupreply'
+ */
+CREATE TABLE radgroupreply (
+ id serial PRIMARY KEY,
+ GroupName text NOT NULL DEFAULT '',
+ Attribute text NOT NULL DEFAULT '',
+ op VARCHAR(2) NOT NULL DEFAULT '=',
+ Value text NOT NULL DEFAULT ''
+);
+create index radgroupreply_GroupName on radgroupreply (GroupName,Attribute);
+
+/*
+ * Table structure for table 'radreply'
+ */
+CREATE TABLE radreply (
+ id serial PRIMARY KEY,
+ UserName text NOT NULL DEFAULT '',
+ Attribute text NOT NULL DEFAULT '',
+ op VARCHAR(2) NOT NULL DEFAULT '=',
+ Value text NOT NULL DEFAULT ''
+);
+create index radreply_UserName on radreply (UserName,Attribute);
+/*
+ * Use this index if you use case insensitive queries
+ */
+-- create index radreply_UserName_lower on radreply (lower(UserName),Attribute);
+
+/*
+ * Table structure for table 'radusergroup'
+ */
+CREATE TABLE radusergroup (
+ id serial PRIMARY KEY,
+ UserName text NOT NULL DEFAULT '',
+ GroupName text NOT NULL DEFAULT '',
+ priority integer NOT NULL DEFAULT 0
+);
+create index radusergroup_UserName on radusergroup (UserName);
+/*
+ * Use this index if you use case insensitive queries
+ */
+-- create index radusergroup_UserName_lower on radusergroup (lower(UserName));
+
+--
+-- Table structure for table 'radpostauth'
+--
+
+CREATE TABLE radpostauth (
+ id bigserial PRIMARY KEY,
+ username text NOT NULL,
+ pass text,
+ reply text,
+ CalledStationId text,
+ CallingStationId text,
+ authdate timestamp with time zone NOT NULL default now()
+);
+
+/*
+ * Table structure for table 'nas'
+ */
+CREATE TABLE nas (
+ id serial PRIMARY KEY,
+ nasname text NOT NULL,
+ shortname text NOT NULL,
+ type text NOT NULL DEFAULT 'other',
+ ports integer,
+ secret text NOT NULL,
+ server text,
+ community text,
+ description text
+);
+create index nas_nasname on nas (nasname);
diff --git a/src/tests/salt-test-server/salt/postgres/setup.sql b/src/tests/salt-test-server/salt/postgres/setup.sql
new file mode 100644
index 0000000..6b41aa1
--- /dev/null
+++ b/src/tests/salt-test-server/salt/postgres/setup.sql
@@ -0,0 +1,21 @@
+/*
+ * admin.sql -- PostgreSQL commands for creating the RADIUS user.
+ *
+ * WARNING: You should change 'localhost' and 'radpass'
+ * to something else. Also update raddb/sql.conf
+ * with the new RADIUS password.
+ *
+ * WARNING: This example file is untested. Use at your own risk.
+ * Please send any bug fixes to the mailing list.
+ *
+ * $Id$
+ */
+
+/*
+ * Create default administrator for RADIUS
+ */
+CREATE USER radius WITH PASSWORD 'radpass';
+
+/* radius user needs ti clean tables in test env */
+GRANT ALL ON ALL TABLES IN SCHEMA public TO radius;
+GRANT SELECT, USAGE ON ALL SEQUENCES IN schema public TO radius;
diff --git a/src/tests/salt-test-server/salt/top.sls b/src/tests/salt-test-server/salt/top.sls
new file mode 100644
index 0000000..efba703
--- /dev/null
+++ b/src/tests/salt-test-server/salt/top.sls
@@ -0,0 +1,7 @@
+base:
+ 'test-server':
+ - ntp
+ - mysql
+ - postgres
+ - ldap
+ - iptable
diff --git a/src/tests/salt-test-server/salt_config/master b/src/tests/salt-test-server/salt_config/master
new file mode 100644
index 0000000..257396a
--- /dev/null
+++ b/src/tests/salt-test-server/salt_config/master
@@ -0,0 +1,12 @@
+root_dir: .
+# pki_dir and cachedir are prefixed with root_dir
+pki_dir: /tmp/
+cachedir: /cache/
+file_roots:
+ base:
+ # salt directory in current working directory
+ - salt
+pillar_roots:
+ base:
+ # pillar directory in current working directory
+ - pillar
diff --git a/src/tests/salt-test-server/salt_config/roster b/src/tests/salt-test-server/salt_config/roster
new file mode 100644
index 0000000..8958bd1
--- /dev/null
+++ b/src/tests/salt-test-server/salt_config/roster
@@ -0,0 +1,4 @@
+test-server:
+ host: 192.168.2.132
+ user: root
+ passwd: root
diff --git a/src/tests/sql_nas_table/all.mk b/src/tests/sql_nas_table/all.mk
new file mode 100644
index 0000000..311e93c
--- /dev/null
+++ b/src/tests/sql_nas_table/all.mk
@@ -0,0 +1,78 @@
+#
+# Unit tests validating the SQL 'nas' table clients
+#
+
+#
+# Test name
+#
+TEST := test.sql_nas_table
+FILES := $(subst $(DIR)/,,$(wildcard $(DIR)/*.txt))
+
+#
+# If we have rlm_sql_sqlite and sqlite3
+#
+ifneq "$(findstring rlm_sql_sqlite,$(ALL_TGTS))" ""
+SQLITE3 := $(shell which sqlite3)
+endif
+
+ifneq "$(SQLITE3)" ""
+
+#
+# Run the full tests
+#
+$(eval $(call TEST_BOOTSTRAP))
+
+#
+# Config settings
+#
+SQL_NASTABLE_BUILD_DIR := $(BUILD_DIR)/tests/sql_nas_table
+SQL_NASTABLE_RADIUS_LOG := $(SQL_NASTABLE_BUILD_DIR)/radiusd.log
+SQL_NASTABLE_GDB_LOG := $(SQL_NASTABLE_BUILD_DIR)/gdb.log
+SQL_NASTABLE_DB := $(SQL_NASTABLE_BUILD_DIR)/sql_nas_table.db
+
+# Used by src/tests/sql_nas_table/config/radiusd.conf
+export SQL_NASTABLE_DB
+
+#
+# Generic rules to start / stop the radius service.
+#
+include src/tests/radiusd.mk
+$(eval $(call RADIUSD_SERVICE,radiusd,$(OUTPUT)))
+
+.PHONY: sql_nas_table_bootstrap
+sql_nas_table_bootstrap:
+ ${Q}rm -f $(SQL_NASTABLE_DB)
+ ${Q}mkdir -p $(SQL_NASTABLE_BUILD_DIR)
+ ${Q}sqlite3 $(SQL_NASTABLE_DB) < ./raddb/mods-config/sql/main/sqlite/schema.sql
+ ${Q}sqlite3 $(SQL_NASTABLE_DB) < ./src/tests/sql_nas_table/clients.sql
+
+#
+# Run the radclient commands against the radiusd.
+#
+$(OUTPUT)/%: $(DIR)/% | $(TEST).radiusd_kill sql_nas_table_bootstrap $(TEST).radiusd_start
+ ${Q}echo "SQL_NASTABLE-TEST"
+ ${Q}mkdir -p $(dir $@)
+ ${Q}[ -f $(dir $@)/radiusd.pid ] || exit 1
+ ${Q}if ! $(TESTBIN)/radclient $(ARGV) -xf src/tests/sql_nas_table/auth.txt -D share/ 127.0.0.1:$(PORT) auth $(SECRET) 1> $(SQL_NASTABLE_BUILD_DIR)/radclient.log 2>&1; then \
+ echo "FAILED"; \
+ rm -f $(BUILD_DIR)/tests/test.sql_nas_table; \
+ $(MAKE) --no-print-directory test.sql_nas_table.radiusd_kill; \
+ echo ==============================; \
+ tail -10 $(SQL_NASTABLE_BUILD_DIR)/radclient.log; \
+ echo ==============================; \
+ echo "RADIUSD: $(RADIUSD_RUN)"; \
+ echo "SQL_NASTABLE: $(TESTBIN)/radclient $(ARGV) -f $< -xF -d src/tests/sql_nas_table/config -D share/ 127.0.0.1:$(PORT) auth $(SECRET)"; \
+ exit 1; \
+ fi
+
+ ${Q}touch $@
+
+$(TEST):
+ ${Q}$(MAKE) --no-print-directory $@.radiusd_stop
+ @touch $(BUILD_DIR)/tests/$@
+else
+#
+# No sqlite3 command, don't do anything.
+#
+$(TEST):
+endif
diff --git a/src/tests/sql_nas_table/auth.txt b/src/tests/sql_nas_table/auth.txt
new file mode 100644
index 0000000..c1b0a1d
--- /dev/null
+++ b/src/tests/sql_nas_table/auth.txt
@@ -0,0 +1,2 @@
+User-Name = bob
+Cleartext-Password = hello
diff --git a/src/tests/sql_nas_table/clients.sql b/src/tests/sql_nas_table/clients.sql
new file mode 100644
index 0000000..d631b7f
--- /dev/null
+++ b/src/tests/sql_nas_table/clients.sql
@@ -0,0 +1 @@
+INSERT INTO nas (nasname,shortname,type,ports,secret,server,community,description) VALUES ('127.0.0.1', 'test', 'test', '123', 'testing123', 'extra', '', 'RADIUS Client');
diff --git a/src/tests/sql_nas_table/config/radiusd.conf b/src/tests/sql_nas_table/config/radiusd.conf
new file mode 100644
index 0000000..16513bb
--- /dev/null
+++ b/src/tests/sql_nas_table/config/radiusd.conf
@@ -0,0 +1,143 @@
+# -*- text -*-
+#
+# test configuration file. Do not install.
+#
+# $Id$
+#
+
+#
+# Minimal radiusd.conf for testing
+#
+top_srcdir = $ENV{TOP_SRCDIR}
+testdir = $ENV{TESTDIR}
+output = ${top_srcdir}/$ENV{OUTPUT}
+run_dir = ${output}
+raddb = raddb
+pidfile = ${run_dir}/radiusd.pid
+panic_action = "gdb -batch -x src/tests/panic.gdb %e %p > ${run_dir}/gdb.log 2>&1; cat ${run_dir}/gdb.log"
+
+maindir = ${raddb}
+radacctdir = ${run_dir}/radacct
+modconfdir = ${maindir}/mods-config
+certdir = ${maindir}/certs
+cadir = ${maindir}/certs
+test_port = $ENV{TEST_PORT}
+
+client docnet {
+ ipaddr = 192.0.2.1
+ secret = testing123123
+}
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+policy {
+ files.authorize {
+ if (&User-Name == "bob") {
+ update control {
+ &Password.Cleartext := "hello"
+ }
+ }
+ }
+ $INCLUDE ${maindir}/policy.d/
+}
+
+modules {
+ expr {
+
+ }
+
+ sql {
+ driver = "rlm_sql_sqlite"
+ dialect = "sqlite"
+ sqlite {
+ # Path to the sqlite database
+ filename = "$ENV{SQL_NASTABLE_DB}"
+
+ # How long to wait for write locks on the database to be
+ # released (in ms) before giving up.
+ busy_timeout = 200
+
+ # The bootstrap is handled by src/tests/sql_nas_table/all.mk
+ }
+
+ radius_db = "radius"
+
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+ postauth_table = "radpostauth"
+ authcheck_table = "radcheck"
+ groupcheck_table = "radgroupcheck"
+ authreply_table = "radreply"
+ groupreply_table = "radgroupreply"
+ usergroup_table = "radusergroup"
+ read_groups = yes
+ read_profiles = yes
+
+ # Set to 'yes' to read radius clients from the database ('nas' table)
+ # Clients will ONLY be read on server startup.
+ read_clients = yes
+
+ # Table to keep radius client info
+ client_table = "nas"
+
+ # The group attribute specific to this instance of rlm_sql
+ group_attribute = "SQL-Group"
+
+ # Read database-specific queries
+ $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf
+ }
+
+ always reject {
+ rcode = reject
+ }
+ always fail {
+ rcode = fail
+ }
+ always ok {
+ rcode = ok
+ }
+ always handled {
+ rcode = handled
+ }
+ always invalid {
+ rcode = invalid
+ }
+ always notfound {
+ rcode = notfound
+ }
+ always noop {
+ rcode = noop
+ }
+ always updated {
+ rcode = updated
+ }
+}
+
+#
+# This virtual server is chosen for processing requests when using:
+#
+# radiusd -Xd src/tests/ -i 127.0.0.1 -p 12340 -n test
+#
+server extra {
+ listen {
+ ipaddr = 127.0.0.1
+ port = ${test_port}
+ type = auth
+ }
+
+ authorize {
+ if (&User-Name == "bob") {
+ accept
+ } else {
+ reject
+ }
+ }
+
+ authenticate {
+
+ }
+}
diff --git a/src/tests/stripped.example.com b/src/tests/stripped.example.com
new file mode 100644
index 0000000..8f4baa3
--- /dev/null
+++ b/src/tests/stripped.example.com
@@ -0,0 +1,5 @@
+#
+# TESTS 1
+#
+User-Name = "bob@stripped.example.com",
+User-Password = "bob"
diff --git a/src/tests/test.example.com b/src/tests/test.example.com
new file mode 100644
index 0000000..56d1960
--- /dev/null
+++ b/src/tests/test.example.com
@@ -0,0 +1,7 @@
+#
+# Tests for clear-text password
+#
+# TESTS 1
+#
+User-Name = "bob@test.example.com"
+User-Password = "bob"
diff --git a/src/tests/tests.gdb b/src/tests/tests.gdb
new file mode 100644
index 0000000..1ff2c91
--- /dev/null
+++ b/src/tests/tests.gdb
@@ -0,0 +1,9 @@
+define hook-stop
+ list
+ info locals
+ info args
+ thread apply all bt full
+end
+handle SIGTERM stop pass noprint
+run
+quit
diff --git a/src/tests/tls/README.md b/src/tests/tls/README.md
new file mode 100644
index 0000000..e0cb686
--- /dev/null
+++ b/src/tests/tls/README.md
@@ -0,0 +1,40 @@
+# Tests for TLS
+
+You will need at least 3 terminal windows:
+
+1. Home Server
+
+```
+./radiusd-home.sh
+```
+
+This server receives Access-Request packets over TLS, and sends Access-Accept.
+
+2. Proxy server
+
+```
+./radiusd-proxy.sh
+```
+
+This server receives Access-Request packets over UDP, and proxies them to the home server.
+
+3. Client(s)
+
+Send one packet:
+
+```
+./radclient.sh
+```
+
+Send 500,000 packets:
+
+```
+./radclient.sh -c 500000
+```
+
+You can also send accounting packets:
+
+```
+./radacct.sh
+```
+
diff --git a/src/tests/tls/acct b/src/tests/tls/acct
new file mode 100644
index 0000000..c246714
--- /dev/null
+++ b/src/tests/tls/acct
@@ -0,0 +1,7 @@
+User-Name = "bob"
+Acct-Session-Id := "0000"
+Acct-Status-Type = Start
+Called-Station-Id := "00:01:02:03"
+Calling-Station-Id := "04:05:06:07"
+Message-Authenticator = 0x00
+Framed-IP-Address = 127.0.0.1
diff --git a/src/tests/tls/block.sh b/src/tests/tls/block.sh
new file mode 100755
index 0000000..20d8bab
--- /dev/null
+++ b/src/tests/tls/block.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Simple script blocking requests from proxy to home server
+#
+# This works only on Linux. It can be used to create random networking issues.
+
+if [ $UID -ne 0 ]; then
+ echo "Only 'root' can modify 'iptables' rules"
+ exit 1
+fi
+
+# avoid keep the server blocked
+function trap_ctrlc ()
+{
+ echo "Ctrl-C caught...performing clean up"
+
+ iptables -D INPUT -p tcp --dport 2083 -j REJECT 1> /dev/null 2>&1
+ exit 0
+}
+
+trap "trap_ctrlc" 2
+
+MAXWAIT=5
+while true; do
+ _wait="$((RANDOM % MAXWAIT))"
+
+ echo "(*) Blocking the port 2083 for ${_wait}s"
+ iptables -A INPUT -p tcp --dport 2083 -j REJECT
+ sleep $_wait
+
+ echo "(*) Allowing the port 2083 for ${_wait}s"
+ iptables -D INPUT -p tcp --dport 2083 -j REJECT
+ sleep $_wait
+done
diff --git a/src/tests/tls/common.sh b/src/tests/tls/common.sh
new file mode 100644
index 0000000..020345b
--- /dev/null
+++ b/src/tests/tls/common.sh
@@ -0,0 +1,12 @@
+#
+# Common definitions.
+#
+DIR=$(dirname $0)/../../..
+PROGRAM=$(basename $0)
+
+export RADDB=$DIR/raddb
+export FR_LOCAL_PREFIX=`cat prefix 2>/dev/null`
+export TEST_PATH=$(dirname $0)/
+export LIB_PATH=$DIR/build/lib/local/
+export FR_LIBRARY_PATH=$DIR/build/lib/local/.libs/
+
diff --git a/src/tests/tls/home/radiusd.conf b/src/tests/tls/home/radiusd.conf
new file mode 100644
index 0000000..69d44f7
--- /dev/null
+++ b/src/tests/tls/home/radiusd.conf
@@ -0,0 +1,105 @@
+#
+# Minimal radiusd.conf for testing
+#
+raddb = $ENV{RADDB}
+modconfdir = ${raddb}/mods-config
+testdir = $ENV{TEST_PATH}
+pidfile = ${testdir}/radiusd.pid
+panic_action = "gdb -batch -x ${raddb}/panic.gdb %e %p > ${testdir}/gdb-radiusd.log 2>&1; cat ${testdir}/gdb-radiusd.log"
+certdir = ${raddb}/certs
+cadir = ${raddb}/certs
+libdir = $ENV{LIB_PATH}
+
+max_requests = 1048576
+
+thread pool {
+ start_servers = 5
+ max_servers = 32
+ min_spare_servers = 3
+ max_spare_servers = 10
+ max_requests_per_server = 0
+ cleanup_delay = 5
+ max_queue_size = 65536
+ auto_limit_acct = no
+}
+
+#
+# Referenced by some modules for default thread pool configuration
+#
+modules {
+
+$INCLUDE ${raddb}/mods-available/always
+}
+
+clients radsec {
+ client home {
+ ipaddr = 127.0.0.1
+ proto = tls
+ }
+}
+
+listen {
+ type = auth
+
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}2083
+ proto = tcp
+
+ clients = radsec
+
+ virtual_server = default
+
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ tls_min_version = "1.2"
+ tls_max_version = "1.2"
+ }
+}
+
+listen {
+ type = acct
+
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}2084
+ proto = tcp
+
+ clients = radsec
+
+ virtual_server = default
+
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/server.pem
+ certificate_file = ${certdir}/server.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ tls_min_version = "1.3"
+ tls_max_version = "1.3"
+ }
+}
+
+server default {
+ authorize {
+ update control {
+ Auth-Type := accept
+ }
+ }
+
+ preacct {
+ update control {
+ Response-Packet-Type := Accounting-Response
+ }
+ }
+
+ acct {
+ ok
+ }
+}
diff --git a/src/tests/tls/proxy/proxy.conf b/src/tests/tls/proxy/proxy.conf
new file mode 100644
index 0000000..e2631c4
--- /dev/null
+++ b/src/tests/tls/proxy/proxy.conf
@@ -0,0 +1,59 @@
+home_server home {
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}2083
+ type = auth
+ secret = radsec
+ proto = tcp
+ status_check = none
+
+ nonblock = yes
+
+ revive_interval = 10
+
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.pem
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ tls_min_version = "1.2"
+ tls_max_version = "1.2"
+ }
+}
+
+home_server_pool home {
+ type = fail-over
+ home_server = home
+}
+
+home_server home_acct {
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}2084
+ type = acct
+ secret = radsec
+ proto = tcp
+ status_check = none
+
+# nonblock = yes
+
+ revive_interval = 10
+
+ tls {
+ private_key_password = whatever
+ private_key_file = ${certdir}/client.pem
+ certificate_file = ${certdir}/client.pem
+ ca_file = ${cadir}/ca.pem
+ fragment_size = 8192
+ ca_path = ${cadir}
+ cipher_list = "DEFAULT"
+ tls_min_version = "1.3"
+ tls_max_version = "1.3"
+ }
+}
+
+home_server_pool home_acct {
+ type = fail-over
+ home_server = home_acct
+}
diff --git a/src/tests/tls/proxy/radiusd.conf b/src/tests/tls/proxy/radiusd.conf
new file mode 100644
index 0000000..8e0577d
--- /dev/null
+++ b/src/tests/tls/proxy/radiusd.conf
@@ -0,0 +1,63 @@
+raddb = $ENV{RADDB}
+modconfdir = ${raddb}/mods-config
+testdir = $ENV{TEST_PATH}/proxy
+pidfile = ${testdir}/radiusd.pid
+panic_action = "gdb -batch -x ${raddb}/panic.gdb %e %p > ${testdir}/gdb-radiusd.log 2>&1; cat ${testdir}/gdb-radiusd.log"
+certdir = ${raddb}/certs
+cadir = ${raddb}/certs
+libdir = $ENV{LIB_PATH}
+
+max_requests = 1048576
+
+thread pool {
+ start_servers = 5
+ max_servers = 32
+ min_spare_servers = 3
+ max_spare_servers = 10
+ max_requests_per_server = 0
+ cleanup_delay = 5
+ max_queue_size = 65536
+ auto_limit_acct = no
+}
+
+#
+# Minimum configuration for Proxy Server -> SRADIUSD
+#
+$INCLUDE ${testdir}/proxy.conf
+
+client local_test {
+ ipaddr = 127.0.0.1
+ secret = testing123
+ proto = *
+}
+
+listen {
+ type = auth
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}1812
+ proto = udp
+ virtual_server = default
+}
+
+listen {
+ type = acct
+ ipaddr = 127.0.0.1
+ port = $ENV{FR_LOCAL_PREFIX}1813
+ proto = udp
+ virtual_server = default
+}
+
+
+server default {
+ authorize {
+ update control {
+ &Home-Server-Pool = "home"
+ }
+ }
+
+ preacct {
+ update control {
+ &Home-Server-Pool = "home_acct"
+ }
+ }
+}
diff --git a/src/tests/tls/radacct.sh b/src/tests/tls/radacct.sh
new file mode 100755
index 0000000..0469727
--- /dev/null
+++ b/src/tests/tls/radacct.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+. $(dirname $0)/common.sh
+
+#
+# Run radclient acct
+#
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/radclient -d $(dirname $0)/home -D $DIR/share/ -f acct $@ localhost:${FR_LOCAL_PREFIX}1813 acct testing123
diff --git a/src/tests/tls/radclient.sh b/src/tests/tls/radclient.sh
new file mode 100755
index 0000000..e82386e
--- /dev/null
+++ b/src/tests/tls/radclient.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+. $(dirname $0)/common.sh
+
+#
+# Run radclient auth
+#
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/radclient -d $(dirname $0)/home -D $DIR/share/ -f user_password $@ localhost:${FR_LOCAL_PREFIX}1812 auth testing123
diff --git a/src/tests/tls/radiusd-home.sh b/src/tests/tls/radiusd-home.sh
new file mode 100755
index 0000000..ea2e694
--- /dev/null
+++ b/src/tests/tls/radiusd-home.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+. $(dirname $0)/common.sh
+
+#
+# Run the home server.
+#
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/radiusd -d $(dirname $0)/home -D $DIR/share/ -fxx -l stdout $@
diff --git a/src/tests/tls/radiusd-proxy.sh b/src/tests/tls/radiusd-proxy.sh
new file mode 100755
index 0000000..65f8066
--- /dev/null
+++ b/src/tests/tls/radiusd-proxy.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+. $(dirname $0)/common.sh
+
+#
+# Run the proxy server.
+#
+exec $DIR/build/make/jlibtool --mode=execute $FR_DEBUGGER $DIR/build/bin/local/radiusd -d $(dirname $0)/proxy -D $DIR/share/ -fxx -l stdout $@
diff --git a/src/tests/tls/user_password b/src/tests/tls/user_password
new file mode 100644
index 0000000..9d0a12c
--- /dev/null
+++ b/src/tests/tls/user_password
@@ -0,0 +1,3 @@
+User-Name = "bob"
+User-Password = "bob"
+Message-Authenticator = 0x00
diff --git a/src/tests/unit/all.mk b/src/tests/unit/all.mk
new file mode 100644
index 0000000..f8cef43
--- /dev/null
+++ b/src/tests/unit/all.mk
@@ -0,0 +1,53 @@
+#
+# Unit tests for individual pieces of functionality.
+#
+
+#
+# The files are put here in order. Later tests need
+# functionality from earlier tests.
+#
+FILES := rfc.txt errors.txt extended.txt lucent.txt wimax.txt \
+ escape.txt condition.txt xlat.txt vendor.txt dhcp.txt ascend.txt \
+ rfc4849.txt eapol_key_msg.txt
+
+#
+# Create the output directory
+#
+.PHONY: $(BUILD_DIR)/tests/unit
+$(BUILD_DIR)/tests/unit:
+ @mkdir -p $@
+
+.PHONY: $(BUILD_DIR)/share
+$(BUILD_DIR)/share:
+ @mkdir -p $@
+
+#
+# We need $INCLUDE in the output file, so we pass 2 parameters to 'echo'
+# No idea how portable that is...
+#
+$(BUILD_DIR)/share/dictionary: $(top_srcdir)/share/dictionary $(top_srcdir)/share/dictionary.dhcp | $(BUILD_DIR)/share
+ @rm -f $@
+ @for x in $^; do \
+ echo '$$INCLUDE ' "$$x" >> $@; \
+ done
+
+#
+# Files in the output dir depend on the unit tests
+#
+$(BUILD_DIR)/tests/unit/%: $(DIR)/% $(BUILD_DIR)/bin/radattr $(TESTBINDIR)/radattr $(BUILD_DIR)/share/dictionary | $(BUILD_DIR)/tests/unit
+ @echo UNIT-TEST $(notdir $@)
+ @if ! $(TESTBIN)/radattr -D $(BUILD_DIR)/share $<; then \
+ echo "$(TESTBIN)/radattr -D $(BUILD_DIR)/share $<"; \
+ exit 1; \
+ fi
+ @touch $@
+
+#
+# Get all of the unit test output files
+#
+TESTS.UNIT_FILES := $(addprefix $(BUILD_DIR)/tests/unit/,$(FILES))
+
+#
+# Depend on the output files, and create the directory first.
+#
+tests.unit: $(TESTS.UNIT_FILES)
diff --git a/src/tests/unit/ascend.txt b/src/tests/unit/ascend.txt
new file mode 100644
index 0000000..4acb223
--- /dev/null
+++ b/src/tests/unit/ascend.txt
@@ -0,0 +1,5 @@
+#
+# Ascend data filters
+#
+encode Ascend-Data-Filter = "ip in drop tcp dstport > 1023"
+data 1a 28 00 00 02 11 f2 22 01 00 01 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 03 ff 00 03 00 00 00 00 00 00 00 00 00 00
diff --git a/src/tests/unit/condition.txt b/src/tests/unit/condition.txt
new file mode 100644
index 0000000..bbe24d2
--- /dev/null
+++ b/src/tests/unit/condition.txt
@@ -0,0 +1,679 @@
+#
+# Tests for parsing conditional expressions.
+#
+# $Id$
+#
+
+#
+# A bunch of errors, in the order that the error strings
+# appear in parser.c
+#
+
+
+# All IP address literals should be parsed as prefixes
+condition ("foo\
+data ERROR offset 6 End of string after escape
+
+condition ("foo
+data ERROR offset 2 Unterminated string
+
+condition ()
+data ERROR offset 1 Empty string is invalid
+
+condition (!)
+data ERROR offset 2 Empty string is invalid
+
+condition (foo == bar
+data ERROR offset 11 No closing brace at end of string
+
+condition (|| b)
+data ERROR offset 1 Empty string is invalid
+
+condition ((ok || handled) foo)
+data ERROR offset 17 Unexpected text after condition
+
+# escapes in names are illegal
+condition (ok\ foo || handled)
+data ERROR offset 3 Unexpected escape
+
+condition (ok FOO handled)
+data ERROR offset 4 Invalid text. Expected comparison operator
+
+condition (ok !x handled)
+data ERROR offset 4 Invalid operator
+
+condition (ok =x handled)
+data ERROR offset 4 Invalid operator
+
+condition (ok =~ handled)
+data ERROR offset 7 Expected regular expression
+
+condition (ok == /foo/)
+data ERROR offset 7 Unexpected regular expression
+
+condition (ok == handled"foo")
+data ERROR offset 14 Unexpected start of string
+
+# And now we have a bunch of VALID conditions we want to parse.
+
+# sillyness is OK
+condition ((((((ok))))))
+data ok
+
+#
+# Extra braces get squashed
+#
+condition (&User-Name == &User-Password)
+data &User-Name == &User-Password
+
+condition (!ok)
+data !ok
+
+condition !(ok)
+data !ok
+
+condition !!ok
+data ERROR offset 1 Double negation is invalid
+
+condition !(!ok)
+data ok
+
+#
+# These next two are identical after normalization
+#
+condition (&User-Name == &User-Password || &Filter-Id == &Reply-Message)
+data &User-Name == &User-Password || &Filter-Id == &Reply-Message
+
+condition ((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data &User-Name == &User-Password || &Filter-Id == &Reply-Message
+
+condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data !&User-Name == &User-Password || &Filter-Id == &Reply-Message
+
+# different from the previous ones.
+condition (!((&User-Name == &User-Password) || (&Filter-Id == &Reply-Message)))
+data !(&User-Name == &User-Password || &Filter-Id == &Reply-Message)
+
+condition (!(&User-Name == &User-Password) || (&Filter-Id == &Reply-Message))
+data !&User-Name == &User-Password || &Filter-Id == &Reply-Message
+
+condition ((a == b) || (c == d)))
+data ERROR offset 22 Unexpected closing brace
+
+condition (handled && (Response-Packet-Type == Access-Challenge))
+data handled && &Response-Packet-Type == Access-Challenge
+
+# This is OK, without the braces
+condition handled && &Response-Packet-Type == Access-Challenge
+data handled && &Response-Packet-Type == Access-Challenge
+
+# and this, though it's not a good idea.
+condition handled &&&Response-Packet-Type == Access-Challenge
+data handled && &Response-Packet-Type == Access-Challenge
+
+condition /foo/ =~ bar
+data ERROR offset 0 Conditional check cannot begin with a regular expression
+
+condition reply == request
+data ERROR offset 0 Cannot use list references in condition
+
+condition reply == "hello"
+data ERROR offset 0 Cannot use list references in condition
+
+condition "hello" == reply
+data ERROR offset 0 Cannot use list references in condition
+
+condition request:User-Name == reply:User-Name
+data &User-Name == &reply:User-Name
+
+#
+# Convert !~ to !(COND) for regex
+#
+condition foo =~ /bar/
+data foo =~ /bar/
+
+condition foo !~ /bar/
+data !foo =~ /bar/
+
+condition !foo !~ /bar/
+data foo =~ /bar/
+
+#
+# Convert != to !(COND) for normal checks
+#
+condition &User-Name == &User-Password
+data &User-Name == &User-Password
+
+condition &User-Name != &User-Password
+data !&User-Name == &User-Password
+
+condition !&User-Name != &User-Password
+data &User-Name == &User-Password
+
+condition <ipv6addr>foo
+data ERROR offset 0 Cannot do cast for existence check
+
+condition <ipaddr>Filter-Id == &Framed-IP-Address
+data <ipaddr>&Filter-Id == &Framed-IP-Address
+
+condition <ipaddr>Filter-Id == <ipaddr>&Framed-IP-Address
+data ERROR offset 21 Unnecessary cast
+
+condition <ipaddr>Filter-Id == <integer>&Framed-IP-Address
+data ERROR offset 21 Cannot cast to a different data type
+
+condition <ipaddr>Filter-Id == <blerg>&Framed-IP-Address
+data ERROR offset 22 Invalid data type in cast
+
+#
+# Normalize things
+#
+condition <ipaddr>Filter-Id == "127.0.0.1"
+data <ipaddr>&Filter-Id == '127.0.0.1'
+
+condition <ipaddr>127.0.0.1 < &Framed-IP-Address
+data &Framed-IP-Address > 127.0.0.1
+
+# =* and !* are only for attrs / lists
+condition "foo" !* bar
+data ERROR offset 6 Cannot use !* on a string
+
+condition "foo" =* bar
+data ERROR offset 6 Cannot use =* on a string
+
+# existence checks don't need the RHS
+condition User-Name =* bar
+data &User-Name
+
+condition User-Name !* bar
+data !&User-Name
+
+condition !User-Name =* bar
+data !&User-Name
+
+condition !User-Name !* bar
+data &User-Name
+
+# redundant casts get squashed
+condition <ipaddr>Framed-IP-Address == 127.0.0.1
+data &Framed-IP-Address == 127.0.0.1
+
+condition <cidr>Framed-IP-Address <= 192.168.0.0/16
+data <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
+
+# All IP address literals should be parsed as prefixes
+condition Framed-IP-Address <= 192.168.0.0/16
+data <ipv4prefix>&Framed-IP-Address <= 192.168.0.0/16
+
+# string attributes must be string
+condition User-Name == "bob"
+data &User-Name == "bob"
+
+condition User-Name == `bob`
+data &User-Name == `bob`
+
+condition User-Name == 'bob'
+data &User-Name == 'bob'
+
+condition User-Name == bob
+data ERROR offset 13 Must have string as value for attribute
+
+# Integer (etc.) types must be "bare"
+condition Session-Timeout == 10
+data &Session-Timeout == 10
+
+condition Session-Timeout == '10'
+data ERROR offset 19 Value must be an unquoted string
+
+# Except for dates, which can be humanly readable!
+# This one is be an expansion, so it's left as-is.
+condition Event-Timestamp == "January 1, 2012 %{blah}"
+data &Event-Timestamp == "January 1, 2012 %{blah}"
+
+# This one is NOT an expansion, so it's parsed into normal form
+condition Event-Timestamp == 'January 1, 2012'
+#data &Event-Timestamp == 'Jan 1 2012 00:00:00 EST'
+
+# literals are parsed when the conditions are parsed
+condition <integer>X == 1
+data ERROR offset 9 Failed to parse field
+
+condition NAS-Port == X
+data ERROR offset 12 Failed to parse value for attribute
+
+#
+# The RHS is a static string, so this gets mashed to a literal,
+# and then statically evaluated.
+#
+condition <ipaddr>127.0.0.1 == "127.0.0.1"
+data true
+
+condition <ipaddr>127.0.0.1 == "%{sql: 127.0.0.1}"
+data <ipaddr>127.0.0.1 == "%{sql: 127.0.0.1}"
+
+condition <ether> 00:11:22:33:44:55 == "00:11:22:33:44:55"
+data true
+
+condition <ether> 00:11:22:33:44:55 == "ff:11:22:33:44:55"
+data false
+
+condition <ether> 00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}"
+data <ether>00:11:22:33:44:55 == "%{sql:00:11:22:33:44:55}"
+
+condition <ether> 00:XX:22:33:44:55 == 00:11:22:33:44:55
+data ERROR offset 8 Failed to parse field
+
+#
+# Tests for boolean data types.
+#
+condition true
+data true
+
+condition 1
+data true
+
+condition false
+data false
+
+condition 0
+data false
+
+condition true && (User-Name == "bob")
+data &User-Name == "bob"
+
+condition false && (User-Name == "bob")
+data false
+
+condition false || (User-Name == "bob")
+data &User-Name == "bob"
+
+condition true || (User-Name == "bob")
+data true
+
+#
+# Both sides static data with a cast: evaluate at parse time.
+#
+condition <integer>20 < 100
+data true
+
+#
+# Both sides literal: evaluate at parse time
+#
+condition ('foo' == 'bar')
+data false
+
+condition ('foo' < 'bar')
+data false
+
+condition ('foo' > 'bar')
+data true
+
+condition ('foo' == 'foo')
+data true
+
+#
+# Double-quotes strings without expansions are literals
+#
+condition ("foo" == "%{sql: foo}")
+data foo == "%{sql: foo}"
+
+condition ("foo bar" == "%{sql: foo}")
+data "foo bar" == "%{sql: foo}"
+
+condition ("foo" == "bar")
+data false
+
+condition ("foo" == 'bar')
+data false
+
+#
+# The RHS gets parsed as a VPT_TYPE_DATA, which is
+# a double-quoted string. Except that there's no '%'
+# in it, so it reverts back to a literal.
+#
+condition (&User-Name == "bob")
+data &User-Name == "bob"
+
+condition (&User-Name == "%{sql: blah}")
+data &User-Name == "%{sql: blah}"
+
+condition <ipaddr>127.0.0.1 == 2130706433
+data true
+
+# /32 suffix should be trimmed for this type
+condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+data true
+
+condition <ipaddr>127.0.0.1/327 == 127.0.0.1
+data ERROR offset 8 Failed to parse field
+
+condition <ipaddr>127.0.0.1/32 == 127.0.0.1
+data true
+
+condition (/foo/)
+data ERROR offset 1 Conditional check cannot begin with a regular expression
+
+#
+# Tests for (FOO).
+#
+condition (1)
+data true
+
+condition (0)
+data false
+
+condition (true)
+data true
+
+condition (false)
+data false
+
+condition ('')
+data false
+
+condition ("")
+data false
+
+#
+# Integers are true, as are non-zero strings
+#
+condition (4)
+data true
+
+condition ('a')
+data true
+
+condition (a)
+data ERROR offset 1 Expected a module return code
+
+#
+# Module return codes are OK
+#
+condition (ok)
+data ok
+
+condition (handled)
+data handled
+
+condition (fail)
+data fail
+
+condition ("a")
+data true
+
+condition (`a`)
+data `a`
+
+condition (User-name)
+data &User-Name
+
+#
+# Forbidden data types in cast
+#
+condition (<vsa>"foo" == &User-Name)
+data ERROR offset 2 Forbidden data type in cast
+
+#
+# Must have attribute references on the LHS of a condition.
+#
+condition ("foo" == &User-Name)
+data ERROR offset 1 Cannot use attribute reference on right side of condition
+
+#
+# If the LHS is a cast to a type, and the RHS is an attribute
+# of the same type, then re-write it so that the attribute
+# is on the LHS of the condition.
+#
+condition <string>"foo" == &User-Name
+data &User-Name == "foo"
+
+condition <integer>"%{expr: 1 + 1}" < &NAS-Port
+data &NAS-Port > "%{expr: 1 + 1}"
+
+condition &Filter-Id == &Framed-IP-Address
+data ERROR offset 0 Attribute comparisons must be of the same data type
+
+condition <ipaddr>127.0.0.1 == &Filter-Id
+data ERROR offset 0 Attribute comparisons must be of the same data type
+
+condition &Tmp-Integer64-0 == &request:Foo-Stuff-Bar
+data &Tmp-Integer64-0 == &Foo-Stuff-Bar
+
+condition &Tmp-Integer64-0 == &reply:Foo-Stuff-Bar
+data &Tmp-Integer64-0 == &reply:Foo-Stuff-Bar
+
+#
+# Casting attributes of different size
+#
+condition <ipaddr>&Tmp-Integer64-0 == &Framed-IP-Address
+data ERROR offset 0 Cannot cast to attribute of incompatible size
+
+condition <ipaddr>&PMIP6-Home-IPv4-HoA == &Framed-IP-Address
+data ERROR offset 0 Cannot cast to attribute of incompatible size
+
+# but these are allowed
+condition <ether>&Tmp-Integer64-0 == "%{module: foo}"
+data <ether>&Tmp-Integer64-0 == "%{module: foo}"
+
+condition <ipaddr>&Filter-Id == &Framed-IP-Address
+data <ipaddr>&Filter-Id == &Framed-IP-Address
+
+condition <ipaddr>&Class == &Framed-IP-Address
+data <ipaddr>&Class == &Framed-IP-Address
+
+#
+# Tags of zero mean restrict to attributes with no tag
+#
+condition &Tunnel-Password:0 == "Hello"
+data &Tunnel-Password:0 == "Hello"
+
+condition &Tunnel-Password:1 == "Hello"
+data &Tunnel-Password:1 == "Hello"
+
+#
+# Single quoted strings are left as-is
+#
+condition &Tunnel-Password:1 == 'Hello'
+data &Tunnel-Password:1 == 'Hello'
+
+#
+# zero offset into arrays get parsed and ignored
+#
+condition &User-Name[0] == "bob"
+data &User-Name[0] == "bob"
+
+condition &User-Name[1] == "bob"
+data &User-Name[1] == "bob"
+
+condition &User-Name[n] == "bob"
+data &User-Name[n] == "bob"
+
+condition &Tunnel-Password:1[0] == "Hello"
+data &Tunnel-Password:1[0] == "Hello"
+
+condition &Tunnel-Password:1[3] == "Hello"
+data &Tunnel-Password:1[3] == "Hello"
+
+#
+# This is allowed for pass2-fixups. Foo-Bar MAY be an attribute.
+# If so allow it so that pass2 can fix it up. Until then,
+# it's an unknown attribute
+#
+condition &Foo-Bar
+data &Foo-Bar
+
+# Same types are optimized
+#
+# FIXME: the tests don't currently run the "pass2" checks.
+# This test should really be:
+#
+# data &Acct-Input-Octets > &Session-Timeout
+#
+condition &Acct-Input-Octets > "%{Session-Timeout}"
+data &Acct-Input-Octets > "%{Session-Timeout}"
+
+# Separate types aren't optimized
+condition &Acct-Input-Octets-64 > "%{Session-Timeout}"
+data &Acct-Input-Octets-64 > "%{Session-Timeout}"
+
+#
+# Parse OIDs into known attributes, where possible.
+#
+condition &Attr-26.24757.84.9.5.4 == 0x1a99
+data &WiMAX-PFDv2-Src-Port == 6809
+
+#
+# This OID is known, but the data is malformed.
+# This is disallowed. Fix the configuration so that
+# it works.
+#
+condition &Attr-26.24757.84.9.5.7 == 0x1a99
+data ERROR offset 27 Failed to parse value for attribute
+
+# This one is really unknown
+condition &Attr-26.24757.84.9.5.15 == 0x1a99
+data &Attr-26.24757.84.9.5.15 == 0x1a99
+
+#
+# Invalid array references.
+#
+condition &User-Name[a] == 'bob'
+data ERROR offset 11 Array index is not an integer
+
+condition &User-Name == &Filter-Id[a]
+data ERROR offset 25 Array index is not an integer
+
+#
+# This one is still wrong.
+#
+condition User-Name[a] == 'bob'
+data false
+
+#
+# Bounds checks...
+#
+condition &User-Name[1001] == 'bob'
+data ERROR offset 11 Invalid array reference '1001' (should be between 0-1000)
+
+condition &User-Name[-1] == 'bob'
+data ERROR offset 11 Invalid array reference '-1' (should be between 0-1000)
+
+#
+# Tags
+#
+condition &Tunnel-Private-Group-Id:10 == 'test'
+data &Tunnel-Private-Group-Id:10 == 'test'
+
+condition &User-Name:10 == 'test'
+data ERROR offset 10 Attribute 'User-Name' cannot have a tag
+
+#
+# Tags are always wrong for attributes which aren't tagged.
+#
+condition &User-Name:0 == 'test'
+data ERROR offset 10 Attribute 'User-Name' cannot have a tag
+
+#
+# Bounds checks...
+#
+condition &Tunnel-Private-Group-Id:32 == 'test'
+data ERROR offset 25 Invalid tag value '32' (should be between 0-31)
+
+condition &request:Tunnel-Private-Group-Id:-1 == 'test'
+data ERROR offset 33 Invalid tag value '-1' (should be between 0-31)
+
+#
+# Sometimes the attribute/condition parser needs to fallback to bare words
+#
+condition request:Foo == 'request:Foo'
+data true
+
+condition request:Foo+Bar == request:Foo+Bar
+data true
+
+condition &request:Foo+Bar == 'request:Foo+Bar'
+data ERROR offset 12 Unexpected text after unknown attr
+
+condition 'request:Foo+d' == &request:Foo+Bar
+data ERROR offset 31 Unexpected text after unknown attr
+
+# Attribute tags are not allowed for unknown attributes
+condition &request:FooBar:0 == &request:FooBar
+data ERROR offset 15 Unexpected text after unknown attr
+
+condition &not-a-list:User-Name == &not-a-list:User-Name
+data ERROR offset 1 Invalid list qualifier
+
+# . is a valid dictionary name attribute, so we can't error out in pass1
+condition &not-a-packet.User-Name == &not-a-packet.User-Name
+data &not-a-packet.User-Name == &not-a-packet.User-Name
+
+#
+# The LHS is a string with ASCII 5C 30 30 30 inside of it.
+#
+condition ('i have scary embedded things\000 inside me' == "i have scary embedded things\000 inside me")
+data false
+
+#
+# 'Unknown' attributes which are defined in the main dictionary
+# should be resolved to their real names.
+condition &Attr-1 == 'bar'
+data &User-Name == 'bar'
+
+condition &Vendor-11344-Attr-1 == 127.0.0.1
+data &FreeRADIUS-Proxied-To == 127.0.0.1
+
+condition &FreeRADIUS-Attr-1 == 127.0.0.1
+data &FreeRADIUS-Proxied-To == 127.0.0.1
+
+#
+# Escape the backslashes correctly
+# And print them correctly
+#
+condition &User-Name =~ /@|\\/
+data &User-Name =~ /@|\\/
+
+condition &User-Name == '\\'
+data &User-Name == '\\'
+
+condition &User-Name !~ /^foo\nbar$/
+data !&User-Name =~ /^foo\nbar$/
+
+condition &User-Name == "@|\\"
+data &User-Name == "@|\\"
+
+condition &User-Name != "foo\nbar"
+data !&User-Name == "foo\nbar"
+
+condition User-Name =~ /^([^\\]*)\\(.*)$/
+data &User-Name =~ /^([^\\]*)\\(.*)$/
+
+#
+# We require explicit casts
+#
+condition 192.168.0.0/16 > 192.168.1.2
+data false
+
+condition <ipv4prefix>192.168.0.0/16 > 192.168.1.2
+data true
+
+condition <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
+data <ipv4prefix>&NAS-IP-Address == 192.168.0.0/24
+
+condition <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
+data <ipv4prefix>192.168.0.0/24 > &NAS-IP-Address
+
+#
+# We add casts to the LHS if necessary
+#
+condition &NAS-IP-Address < &PMIP6-Home-IPv4-HoA
+data <ipv4prefix>&NAS-IP-Address < &PMIP6-Home-IPv4-HoA
+
+condition &NAS-IP-Address < 192.168/16
+data <ipv4prefix>&NAS-IP-Address < 192.168.0.0/16
+
+condition &NAS-IP-Address < "%{echo: 192.168/16}"
+data <ipv4prefix>&NAS-IP-Address < "%{echo: 192.168/16}"
+
+condition &NAS-IP-Address < `/bin/echo 192.168/16`
+data <ipv4prefix>&NAS-IP-Address < `/bin/echo 192.168/16`
diff --git a/src/tests/unit/dhcp.txt b/src/tests/unit/dhcp.txt
new file mode 100644
index 0000000..db7eae2
--- /dev/null
+++ b/src/tests/unit/dhcp.txt
@@ -0,0 +1,44 @@
+#
+# Test vectors for DHCP attributes
+#
+
+encode-dhcp DHCP-Subnet-Mask = 255.255.0.0
+data 01 04 ff ff 00 00
+
+decode-dhcp -
+data DHCP-Subnet-Mask = 255.255.0.0
+
+#
+# A long one... with a weird DHCP-specific vendor ID.
+#
+decode-dhcp 3501013d0701001ceaadac1e37070103060f2c2e2f3c094d5346545f495054565232011c4c41424f4c54322065746820312f312f30312f30312f31302f312f3209120000197f0d050b4c4142373336304f4c5432
+data DHCP-Message-Type = DHCP-Discover, DHCP-Client-Identifier = 0x01001ceaadac1e, DHCP-Parameter-Request-List = DHCP-Subnet-Mask, DHCP-Parameter-Request-List = DHCP-Router-Address, DHCP-Parameter-Request-List = DHCP-Domain-Name-Server, DHCP-Parameter-Request-List = DHCP-Domain-Name, DHCP-Parameter-Request-List = DHCP-NETBIOS-Name-Servers, DHCP-Parameter-Request-List = DHCP-NETBIOS-Node-Type, DHCP-Parameter-Request-List = DHCP-NETBIOS, DHCP-Vendor-Class-Identifier = 0x4d5346545f49505456, DHCP-Relay-Circuit-Id = 0x4c41424f4c54322065746820312f312f30312f30312f31302f312f32, DHCP-Vendor-Specific-Information = 0x0000197f0d050b4c4142373336304f4c5432
+
+
+encode-dhcp DHCP-Agent-Circuit-Id = 0xabcdef, DHCP-Relay-Remote-Id = 0x010203040506
+data 52 0d 01 03 ab cd ef 02 06 01 02 03 04 05 06
+
+decode-dhcp -
+data DHCP-Relay-Circuit-Id = 0xabcdef, DHCP-Relay-Remote-Id = 0x010203040506
+
+# 35 01 01
+# 3d 06 00 a0 bd 11 22 33
+# 37 05 2b 29 01 03 06
+# 3c 09 76 69 61 73 61 74 31 2e 30
+# 52 31
+# 06 1f 30 30 41 30 42 44 31 31 32 32 33 33 40 73 62 32 2e 72 65 73 2e 76 69 61 73 61 74 2e 63 6f 6d
+# 02 06 00 a0 bc 6c 7d 3a
+# 01 06 00 a0 bc 33 22 11
+# 39 02 05 dc
+# 7d 1e
+# 00 00 0d e9 19
+# 01 06 30 30 30 31 39 46
+# 02 0a 52 4e 56 35 30 34 35 39 34 34
+# 03 03 41 54 41
+# ff 00
+
+decode-dhcp 7d 1e 00 00 0d e9 19 01 06 30 30 30 31 39 46 02 0a 52 4e 56 35 30 34 35 39 34 34 03 03 41 54 41
+data ADSL-Forum-Device-Manufacturer-OUI = 0x303030313946, ADSL-Forum-Device-Serial-Number = "RNV5045944", ADSL-Forum-Device-Product-Class = "ATA"
+
+encode-dhcp -
+data 7d 1e 00 00 0d e9 19 01 06 30 30 30 31 39 46 02 0a 52 4e 56 35 30 34 35 39 34 34 03 03 41 54 41
diff --git a/src/tests/unit/eapol_key_msg.txt b/src/tests/unit/eapol_key_msg.txt
new file mode 100644
index 0000000..c6f83ab
--- /dev/null
+++ b/src/tests/unit/eapol_key_msg.txt
@@ -0,0 +1,14 @@
+#
+# For sending EAPoL key messages in RADIUS.
+#
+encode FreeRADIUS-802.1X-Anonce = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+data f5 29 1a 00 00 00 2c 50 01 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
+
+decode -
+data FreeRADIUS-802.1X-Anonce = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+encode FreeRADIUS-802.1X-EAPoL-Key-Msg = 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+data f5 ff 1a 80 00 00 2c 50 02 bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa f5 08 1a 00 aa aa aa aa
+
+decode -
+data FreeRADIUS-802.1X-EAPoL-Key-Msg = 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/src/tests/unit/errors.txt b/src/tests/unit/errors.txt
new file mode 100644
index 0000000..801b501
--- /dev/null
+++ b/src/tests/unit/errors.txt
@@ -0,0 +1,17 @@
+#
+# Bad attributes
+#
+decode 01 04 00
+data rad_attr2vp: Insufficient data
+
+decode 01 01 00
+data rad_attr2vp: Insufficient data
+
+encode Attr-26.1.256 = 0x00000001
+data Number '256' out of allowed range in attribute identifier
+
+encode Attr-240.1 = 0x01
+data Standard attributes cannot use OIDs
+
+encode Attr-26.1.1 = 0x01
+data 1a 09 00 00 00 01 01 03 01
diff --git a/src/tests/unit/escape.txt b/src/tests/unit/escape.txt
new file mode 100644
index 0000000..b65e1b7
--- /dev/null
+++ b/src/tests/unit/escape.txt
@@ -0,0 +1,74 @@
+#
+# Like the conditional tests, but tests for escape sequences
+#
+condition "bob" == 0x626f62
+data true
+
+condition 0x == '0x'
+data ERROR offset 2 Empty octet string is invalid
+
+condition 'foo' == 0x
+data ERROR offset 9 Empty octet string is invalid
+
+# \n gets escaped in double quoted strings
+condition "\n" == 0x0a
+data true
+
+# but not in single quoted strings
+condition '\n' == 0x5c6e
+data true
+
+condition '\'' == 0x27
+data true
+
+condition "'" == 0x27
+data true
+
+condition "\"" == 0x22
+data true
+
+condition 0x22 == '"'
+data true
+
+condition '\'' == "'"
+data true
+
+condition '\\' == "\\"
+data true
+
+#
+# The first string is \ + x
+#
+condition '\x' == "x"
+data false
+
+# embedded zeros are OK
+condition "a\000a" == 0x610061
+data true
+
+condition "aa\000" == 0x616100
+data true
+
+condition 'aa\000' == 0x61615c303030
+data true
+
+condition 'aa\000' == "aa\000"
+data false
+
+condition 'a\n' == "a\n"
+data false
+
+condition 0x626f62 == 'bob'
+data true
+
+condition 0x626f62 == "bob"
+data true
+
+condition 0x626f62 == bob
+data true
+
+condition \n == 0x0a
+data ERROR offset 1 Unexpected escape
+
+condition a\n == 0x610a
+data ERROR offset 2 Unexpected escape
diff --git a/src/tests/unit/extended.txt b/src/tests/unit/extended.txt
new file mode 100644
index 0000000..9810b19
--- /dev/null
+++ b/src/tests/unit/extended.txt
@@ -0,0 +1,103 @@
+# Example attributes as used in the "extended attributes" draft.
+raw 241.1 "bob"
+data f1 06 01 62 6f 62
+
+raw 241.2 {1 23 45 }
+data f1 07 02 01 04 23 45
+
+raw 241.2 {1 23 45 } { 2 67 89 }
+data f1 0b 02 01 04 23 45 02 04 67 89
+
+raw 241.2 {1 23 45 } { 3 { 1 ab cd } }
+data f1 0d 02 01 04 23 45 03 06 01 04 ab cd
+
+raw 241.2 {1 23 45 } { 3 { 1 ab cd } {2 "foo" } }
+data f1 12 02 01 04 23 45 03 0b 01 04 ab cd 02 05 66 6f 6f
+
+raw 241.1 {1 { 2 { 3 { 4 { 5 cd ef } } } } }
+data f1 0f 01 01 0c 02 0a 03 08 04 06 05 04 cd ef
+
+raw 241.26.1.4 "test"
+data f1 0c 1a 00 00 00 01 04 74 65 73 74
+
+raw 241.26.1.5 { 3 "test" }
+data f1 0e 1a 00 00 00 01 05 03 06 74 65 73 74
+
+# More examples.
+raw 245.1 "bob"
+data f5 07 01 00 62 6f 62
+
+raw 245.2 {1 23 45 }
+data f5 08 02 00 01 04 23 45
+
+raw 245.2 {1 23 45 } { 2 67 89 }
+data f5 0c 02 00 01 04 23 45 02 04 67 89
+
+raw 245.2 {1 23 45 } { 3 { 1 ab cd } }
+data f5 0e 02 00 01 04 23 45 03 06 01 04 ab cd
+
+raw 245.2 {1 23 45 } { 3 { 1 ab cd } {2 "foo" } }
+data f5 13 02 00 01 04 23 45 03 0b 01 04 ab cd 02 05 66 6f 6f
+
+raw 245.1 {1 { 2 { 3 { 4 { 5 cd ef } } } } }
+data f5 10 01 00 01 0c 02 0a 03 08 04 06 05 04 cd ef
+
+raw 245.26.1.4 "test"
+data f5 0d 1a 00 00 00 00 01 04 74 65 73 74
+
+raw 245.26.1.5 { 3 "test" }
+data f5 0f 1a 00 00 00 00 01 05 03 06 74 65 73 74
+
+raw 245.4 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccc
+data f5 ff 04 80 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 13 04 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc
+
+#
+# 256 copies of 'x'
+#
+raw 245.1 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+data f5 ff 01 80 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 f5 09 01 00 78 78 78 78 78
+
+#
+# And it decodes to an attribute with 256 x's
+#
+decode f5 ff 01 80 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 f5 09 01 00 78 78 78 78 79
+data Attr-245.1 = 0x78787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787879
+
+#
+# A VSA which has lots of data
+#
+raw 245.26.1.6 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc13456789
+data f5 ff 1a 80 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 17 1a 00 bb bb bb bb bb cc cc cc cc cc cc cc cc cc cc 13 45 67 89
+
+decode f5 ff 1a 80 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 17 1a 00 bb bb bb bb bb cc cc cc cc cc cc cc cc cc cc 13 45 67 89
+data Attr-245.26.1.6 = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccc13456789
+
+# Same as above, but the first attribute doesn't have
+# the "continuation" bit set.
+decode f5 ff 1a 00 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb f5 17 1a 00 bb bb bb bb bb cc cc cc cc cc cc cc cc cc cc 13 45 67 89
+data Attr-245.26.1.6 = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, Attr-245.26 = 0xbbbbbbbbbbcccccccccccccccccccc13456789
+
+
+# again, but the second one attr is not an extended attr
+decode f5 ff 1a 80 00 00 00 01 06 aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa ab bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb 01 05 62 6f 62
+data Attr-245 = 0x1a800000000106aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, User-Name = "bob"
+
+# No data means that the attribute is an "invalid attribute"
+decode f5 04 01 00
+data Attr-245 = 0x0100
+
+# No "flags" field means it's an invalid attribute.
+decode f5 03 01
+data Attr-245 = 0x01
+
+decode f5 09 1a 00 00 00 00 01 06
+data Attr-245.26 = 0x0000000106
+
+decode f5 0a 1a 00 00 00 00 01 06 01
+data Attr-245.26.1.6 = 0x01
+
+decode f5 09 1a 80 00 00 00 01 06 f5 05 1a 80 01
+data Attr-245.26.1.6 = 0x01
+
+decode f5 0a 1a 80 00 00 00 01 06 01 f5 05 1a 80 01
+data Attr-245.26.1.6 = 0x0101
diff --git a/src/tests/unit/lucent.txt b/src/tests/unit/lucent.txt
new file mode 100644
index 0000000..e21d03c
--- /dev/null
+++ b/src/tests/unit/lucent.txt
@@ -0,0 +1,11 @@
+encode Lucent-Max-Shared-Users = 1
+data 1a 0d 00 00 12 ee 00 02 07 00 00 00 01
+
+decode -
+data Lucent-Max-Shared-Users = 1
+
+decode 1a 0d 00 00 12 ee ff 02 07 00 00 00 01
+data Attr-26.4846.65282 = 0x00000001
+
+encode -
+data 1a 0d 00 00 12 ee ff 02 07 00 00 00 01
diff --git a/src/tests/unit/rfc.txt b/src/tests/unit/rfc.txt
new file mode 100644
index 0000000..8e95526
--- /dev/null
+++ b/src/tests/unit/rfc.txt
@@ -0,0 +1,204 @@
+# All attribute lengths are implicit, and are calculated automatically
+#
+# Input is of the form:
+#
+# WORD ...
+#
+# The WORD is a keyword which indicates the format of the following text.
+# WORD is one of:
+#
+# raw - read the grammar defined below, and encode an attribute.
+# The grammar supports a trivial way of describing RADIUS
+# attributes, without reference to dictionaries or fancy
+# parsers
+#
+# encode - reads "Attribute-Name = value", encodes it, and prints
+# the result as text.
+# use "-" to encode the output of the last command
+#
+# decode - reads hex, and decodes it "Attribute-Name = value"
+# use "-" to decode the output of the last command
+#
+# data - the expected output of the previous command, in ASCII form.
+# if the actual command output is different, an error message
+# is produced, and the program terminates.
+#
+#
+# The "raw" input satisfies the following grammar:
+#
+# Identifier = 1*DIGIT *( "." 1*DIGIT )
+#
+# HEXCHAR = HEXDIG HEXDIG
+#
+# STRING = DQUOTE *CHAR DQUOTE
+#
+# TLV = "{" 1*DIGIT DATA "}"
+#
+# DATA = 1*HEXCHAR / 1*TLV / STRING
+#
+# LINE = Identifier DATA
+#
+# The "Identifier" is a RADIUS attribute identifier, as given in the draft.
+#
+# e.g. 1 for User-Name
+# 26.9.1 Vendor-Specific, Cisco, Cisco-AVPAir
+# 241.1 Extended Attribute, number 1
+# 241.2.3 Extended Attribute 2, data type TLV, TLV type 3
+# etc.
+#
+# The "DATA" portion is the contents of the RADIUS Attribute.
+#
+# 123456789abcdef hex string
+# 12 34 56 ab with spaces for clarity
+# "hello" Text string
+# { 1 abcdef } TLV, TLV-Type 1, data "abcdef"
+#
+# TLVs can be nested:
+#
+# { tlv-type { tlv-type data } } { 3 { 4 01020304 } }
+#
+# TLVs can be concatencated
+#
+# {tlv-type data } { tlv-type data} { 3 040506 } { 8 aabbcc }
+#
+# The "raw" data is encoded without reference to dictionaries. Any
+# valid string is parsed to a RADIUS attribute. The resulting RADIUS
+# attribute *may not* be correctly formatted to the relevant RADIUS
+# specifications. i.e. you can use this tool to create attribute 1
+# (User-Name), which is encoded as a series of TLVs. That's up to you.
+#
+# The purpose of the "raw" command is to have a simple way of encoding
+# attributes which is independent of any dictionaries or packet processing
+# routines.
+#
+# The output data is the hex version of the encoded attribute.
+#
+
+encode User-Name = "bob"
+data 01 05 62 6f 62
+
+decode -
+data User-Name = "bob"
+
+decode 01 05 62 6f 62
+data User-Name = "bob"
+
+#
+# The Type/Length is OK, but the attribute data is of the wrong size.
+#
+decode 04 04 ab cd
+data Attr-4 = 0xabcd
+
+# Zero-length attributes
+decode 01 02
+data
+
+# don't encode zero-length attributes
+encode User-Name = ""
+data
+
+# except for CUI. Thank you, WiMAX!
+decode 59 02
+data Chargeable-User-Identity = 0x
+
+# Hah! Thought you had it figured out, didn't you?
+encode -
+data 59 02
+
+attribute Framed-IP-Address = 127.0.0.1/32
+data Framed-IP-Address = 127.0.0.1
+
+attribute Framed-IP-Address = 127.0.0.1/323
+data Invalid IPv4 mask length "/323". Should be between 0-32
+
+attribute Framed-IP-Address = 127.0.0.1/30
+data Invalid IPv4 mask length "/30". Only "/32" permitted for non-prefix types
+
+attribute Framed-IP-Address = *
+data Framed-IP-Address = 0.0.0.0
+
+attribute Framed-IP-Address = 127
+data Framed-IP-Address = 0.0.0.127
+
+attribute Framed-IP-Address = 127.0
+data Framed-IP-Address = 127.0.0.0
+
+attribute Framed-IPv6-Prefix = ::1
+data Framed-IPv6-Prefix = ::1/128
+
+attribute Framed-IPv6-Prefix = ::1/200
+data Invalid IPv6 mask length "/200". Should be between 0-128
+
+attribute Framed-IPv6-Prefix = ::1/200
+data Invalid IPv6 mask length "/200". Should be between 0-128
+
+attribute Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128
+data Framed-IPv6-Prefix = 11:22:33:44:55:66:77:88/128
+
+attribute Framed-IPv6-Prefix = *
+data Framed-IPv6-Prefix = ::/128
+
+attribute PMIP6-Home-IPv4-HoA = 127/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+attribute PMIP6-Home-IPv4-HoA = 127/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+#
+# Octets outside of the mask are OK, but
+# are mashed to zero.
+#
+attribute PMIP6-Home-IPv4-HoA = 127.63/8
+data PMIP6-Home-IPv4-HoA = 127.0.0.0/8
+
+#
+# Unless you give a good mask.
+#
+attribute PMIP6-Home-IPv4-HoA = 127.63/16
+data PMIP6-Home-IPv4-HoA = 127.63.0.0/16
+
+attribute PMIP6-Home-IPv4-HoA = 127.999/16
+data Failed to parse IPv4 address string "127.999/16"
+
+attribute PMIP6-Home-IPv4-HoA = 127.bob/16
+data Failed to parse IPv4 address string "127.bob/16"
+
+attribute PMIP6-Home-IPv4-HoA = 127.63/15
+data PMIP6-Home-IPv4-HoA = 127.62.0.0/15
+
+attribute PMIP6-Home-IPv4-HoA = 127.63.1/24
+data PMIP6-Home-IPv4-HoA = 127.63.1.0/24
+
+attribute PMIP6-Home-IPv4-HoA = 127.63.1.6
+data PMIP6-Home-IPv4-HoA = 127.63.1.6/32
+
+attribute PMIP6-Home-IPv4-HoA = 256/8
+data Failed to parse IPv4 address string "256/8"
+
+attribute PMIP6-Home-IPv4-HoA = bob/8
+data Failed to parse IPv4 address string "bob/8"
+
+#
+# A "concat" attribute, with no data
+#
+decode 89 02
+data PKM-SS-Cert = 0x
+
+#
+# The configuration can use the old names, but they
+# get automatically converted to the new names.
+#
+attribute User-Service-Type = 1
+data Service-Type = Login-User
+
+#
+# Or with weirdly formatted data
+#
+decode 89 03 ff 89 02 89 03 fe
+data PKM-SS-Cert = 0xfffe
+
+$INCLUDE tunnel.txt
+$INCLUDE errors.txt
+$INCLUDE extended.txt
+$INCLUDE lucent.txt
+$INCLUDE wimax.txt
diff --git a/src/tests/unit/rfc4849.txt b/src/tests/unit/rfc4849.txt
new file mode 100644
index 0000000..957a9e9
--- /dev/null
+++ b/src/tests/unit/rfc4849.txt
@@ -0,0 +1,49 @@
+#
+# RFC 4849 NAS-Filter-Rule
+#
+# Individual rules are packed together as with EAP-Message,
+# but the rules are separated by a 0x00 byte.
+#
+encode NAS-Filter-Rule = "hello"
+data 5c 07 68 65 6c 6c 6f
+
+decode -
+data NAS-Filter-Rule = "hello"
+
+
+encode NAS-Filter-Rule = "hello", NAS-Filter-Rule += "bob"
+data 5c 0b 68 65 6c 6c 6f 00 62 6f 62
+
+decode -
+data NAS-Filter-Rule = "hello", NAS-Filter-Rule = "bob"
+
+encode NAS-Filter-Rule = "hello", NAS-Filter-Rule += "bob", NAS-Filter-Rule += "stuff"
+data 5c 11 68 65 6c 6c 6f 00 62 6f 62 00 73 74 75 66 66
+
+decode -
+data NAS-Filter-Rule = "hello", NAS-Filter-Rule = "bob", NAS-Filter-Rule = "stuff"
+
+#
+# And large amounts of data
+#
+
+# 250x and then space (to tell where the 'x' ends
+encode NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule += "bob"
+data 5c ff 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 20 00 62 5c 04 6f 62
+
+decode -
+data NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule = "bob"
+
+# 251x + ' '
+encode NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule += "bob"
+data 5c ff 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 20 00 5c 05 62 6f 62
+
+decode -
+data NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule = "bob"
+
+# 252x + ' '
+encode NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule += "bob"
+data 5c ff 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 20 5c 06 00 62 6f 62
+
+decode -
+data NAS-Filter-Rule = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", NAS-Filter-Rule = "bob"
diff --git a/src/tests/unit/tunnel.txt b/src/tests/unit/tunnel.txt
new file mode 100644
index 0000000..da0cb31
--- /dev/null
+++ b/src/tests/unit/tunnel.txt
@@ -0,0 +1,87 @@
+#
+# We can't look at the data here, because the encoded Tunnel-Password has a 2 byte
+# random salt
+#
+encode Tunnel-Password:0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxabc"
+decode -
+data Tunnel-Password:0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxabc"
+
+encode Tunnel-Password:0 = "0"
+decode -
+data Tunnel-Password:0 = "0"
+
+encode Tunnel-Password:0 = "01"
+decode -
+data Tunnel-Password:0 = "01"
+
+encode Tunnel-Password:0 = "012"
+decode -
+data Tunnel-Password:0 = "012"
+
+encode Tunnel-Password:0 = "0123"
+decode -
+data Tunnel-Password:0 = "0123"
+
+encode Tunnel-Password:0 = "01234"
+decode -
+data Tunnel-Password:0 = "01234"
+
+encode Tunnel-Password:0 = "012345"
+decode -
+data Tunnel-Password:0 = "012345"
+
+encode Tunnel-Password:0 = "0123456"
+decode -
+data Tunnel-Password:0 = "0123456"
+
+encode Tunnel-Password:0 = "01234567"
+decode -
+data Tunnel-Password:0 = "01234567"
+
+encode Tunnel-Password:0 = "012345678"
+decode -
+data Tunnel-Password:0 = "012345678"
+
+encode Tunnel-Password:0 = "0123456789"
+decode -
+data Tunnel-Password:0 = "0123456789"
+
+encode Tunnel-Password:0 = "0123456789a"
+decode -
+data Tunnel-Password:0 = "0123456789a"
+
+encode Tunnel-Password:0 = "0123456789ab"
+decode -
+data Tunnel-Password:0 = "0123456789ab"
+
+encode Tunnel-Password:0 = "0123456789abc"
+decode -
+data Tunnel-Password:0 = "0123456789abc"
+
+encode Tunnel-Password:0 = "0123456789abcd"
+decode -
+data Tunnel-Password:0 = "0123456789abcd"
+
+encode Tunnel-Password:0 = "0123456789abcde"
+decode -
+data Tunnel-Password:0 = "0123456789abcde"
+
+encode Tunnel-Password:0 = "0123456789abcdef"
+decode -
+data Tunnel-Password:0 = "0123456789abcdef"
+
+#
+# We can't look at the data here, because the encoded Tunnel-Password has a 2 byte
+# random salt
+#
+encode Tunnel-Password:0 := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+decode -
+data Tunnel-Password:0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+#
+# 1 octet for the tag. 2 octets for salt. One octet for encrypted length.
+# 249 octets left for real data.
+#
+encode Tunnel-Password:0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789ab"
+decode -
+data Tunnel-Password:0 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx123456789"
diff --git a/src/tests/unit/vendor.txt b/src/tests/unit/vendor.txt
new file mode 100644
index 0000000..1325f49
--- /dev/null
+++ b/src/tests/unit/vendor.txt
@@ -0,0 +1,48 @@
+encode SN-VPN-Name = "foo"
+data 1a 0d 00 00 1f e4 00 02 00 07 66 6f 6f
+
+decode 1a 0d 00 00 1f e4 00 02 00 07 66 6f 6f
+data SN-VPN-Name = "foo"
+
+encode USR-Event-Id = 1234
+data 1a 0e 00 00 01 ad 00 00 bf be 00 00 04 d2
+
+decode 1a 0e 00 00 01 ad 00 00 bf be 00 00 04 d2
+data USR-Event-Id = 1234
+
+decode 1a 15 00 00 4e 20 01 0f 6c 69 74 68 69 61 73 70 72 69 6e 67 73
+data Attr-26.20000.1 = 0x6c6974686961737072696e6773
+
+decode 1a 2e 00 00 00 2b 1c 02 01 06 00 00 00 00 3c 20 31 35 35 2e 34 2e 31 32 2e 31 30 30 20 30 30 3a 30 30 3a 30 30 3a 30 30 3a 30 30 3a 30 30
+data 3Com-User-Access-Level = 3Com-Visitor, 3Com-Ip-Host-Addr = "155.4.12.100 00:00:00:00:00:00"
+
+decode 1a 2c 00 00 00 2b 01 06 00 00 00 00 3c 20 31 35 35 2e 34 2e 31 32 2e 31 30 30 20 30 30 3a 30 30 3a 30 30 3a 30 30 3a 30 30 3a 30 30
+data 3Com-User-Access-Level = 3Com-Visitor, 3Com-Ip-Host-Addr = "155.4.12.100 00:00:00:00:00:00"
+
+encode Vendor-Specific = 0xabcdef
+data Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'
+
+encode Attr-26 = 0x00000009abcdef
+data 1a 09 00 00 00 09 ab cd ef
+
+attribute Attr-26 = 0x00000009abcdef
+data Attr-26 = 0x00000009abcdef
+attribute Ascend-Data-Filter = 0x01010100010203040a0b0c0d05200600000504d2020200000000000000000000
+data Ascend-Data-Filter = "ip in forward srcip 1.2.3.4/5 dstip 10.11.12.13/32 tcp srcport = 5 dstport = 1234"
+
+encode -
+data 1a 28 00 00 02 11 f2 22 01 01 01 00 01 02 03 04 0a 0b 0c 0d 05 20 06 00 00 05 04 d2 02 02 00 00 00 00 00 00 00 00 00 00
+
+decode 1a2800000211f22201010100010203040a0b0c0d05200600000504d2020200000000000000000000
+data Ascend-Data-Filter = "ip in forward srcip 1.2.3.4/5 dstip 10.11.12.13/32 tcp srcport = 5 dstport = 1234"
+
+# this untagged tunnel encrypted VSA is valid in both access accepts and CoA requests
+encode ERX-LI-Action = off
+decode -
+data ERX-LI-Action = off
+
+packet coa_request
+original null
+encode ERX-LI-Action = off
+decode -
+data ERX-LI-Action = off
diff --git a/src/tests/unit/wimax.txt b/src/tests/unit/wimax.txt
new file mode 100644
index 0000000..0917097
--- /dev/null
+++ b/src/tests/unit/wimax.txt
@@ -0,0 +1,171 @@
+#
+# Test vectors for WiMAX attributes.
+#
+encode WiMAX-Release = "1.0"
+data 1a 0e 00 00 60 b5 01 08 00 01 05 31 2e 30
+
+decode -
+data WiMAX-Release = "1.0"
+
+decode 1a 08 00 00 60 b5 01 02
+data Attr-26 = 0x000060b50102
+
+decode 1a 0a 00 00 60 b5 01 04 00 01
+data Attr-26.24757.1 = 0x01
+
+encode WiMAX-Accounting-Capabilities = 1
+data 1a 0c 00 00 60 b5 01 06 00 02 03 01
+
+decode -
+data WiMAX-Accounting-Capabilities = IP-Session-Based
+
+encode WiMAX-Release = "1.0", WiMAX-Accounting-Capabilities = 1
+data 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 03 01
+
+decode -
+data WiMAX-Release = "1.0", WiMAX-Accounting-Capabilities = IP-Session-Based
+
+encode -
+data 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 03 01
+
+encode WiMAX-PFDv2-Classifier-Direction = 1
+data 1a 0e 00 00 60 b5 54 08 00 09 05 04 03 01
+
+encode WiMAX-PFDv2-Classifier-Direction = 1, WiMAX-PFDv2-Src-Port = 6809
+data 1a 14 00 00 60 b5 54 0e 00 09 0b 04 03 01 05 06 04 04 1a 99
+
+decode -
+data WiMAX-PFDv2-Classifier-Direction = 1, WiMAX-PFDv2-Src-Port = 6809
+
+decode 1a 11 00 00 60 b5 54 0b 00 09 08 05 06 04 04 1a 99
+data WiMAX-PFDv2-Src-Port = 6809
+
+# 26.24757.89.9.4 has the correct length.
+# 26.24757.89.9.5 has the correct length.
+# 26.24757.89.9.5.4 has the wrong length.
+decode 1a 14 00 00 60 b5 54 0e 00 09 0b 04 03 01 05 06 04 05 1a 99
+data WiMAX-PFDv2-Classifier-Direction = 1, Attr-26.24757.84.9.5 = 0x04051a99
+
+# The 26.24757.1 has the wrong length
+decode 1a 11 00 00 60 b5 01 0a 00 01 05 31 2e 30 02 03 01
+data Attr-26 = 0x000060b5010a000105312e30020301
+
+encode -
+data 1a 11 00 00 60 b5 01 0a 00 01 05 31 2e 30 02 03 01
+
+decode 1a 11 00 00 60 b5 01 0c 00 01 05 31 2e 30 02 03 01
+data Attr-26 = 0x000060b5010c000105312e30020301
+
+encode -
+data 1a 11 00 00 60 b5 01 0c 00 01 05 31 2e 30 02 03 01
+
+# 26.24757.1.1 has the wrong length
+decode 1a 11 00 00 60 b5 01 0b 00 01 04 31 2e 30 02 03 01
+data Attr-26.24757.1 = 0x0104312e30020301
+
+decode 1a 11 00 00 60 b5 01 0b 00 01 06 31 2e 30 02 03 01
+data Attr-26.24757.1 = 0x0106312e30020301
+
+encode -
+data 1a 11 00 00 60 b5 01 0b 00 01 06 31 2e 30 02 03 01
+
+
+# 26.24757.1.2 has the wrong length
+decode 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 02 01
+data Attr-26.24757.1 = 0x0105312e30020201
+
+encode -
+data 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 02 01
+
+# 26.24757.1.1 has the correct length
+# 26.24757.1.2 has the wrong length
+# This means that 26.24757.1 is invalid, and we create a raw attribute.
+decode 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 04 01
+data Attr-26.24757.1 = 0x0105312e30020401
+
+encode -
+data 1a 11 00 00 60 b5 01 0b 00 01 05 31 2e 30 02 04 01
+
+encode WiMAX-PFDv2-Eth-Priority-Range-Low = 55
+data 1a 12 00 00 60 b5 54 0c 00 09 09 09 07 03 05 01 03 37
+
+encode WiMAX-PFDv2-Eth-Priority-Range-Low = 55, WiMAX-PFDv2-Eth-Priority-Range-High = 84
+data 1a 15 00 00 60 b5 54 0f 00 09 0c 09 0a 03 08 01 03 37 02 03 54
+
+decode -
+data WiMAX-PFDv2-Eth-Priority-Range-Low = 55, WiMAX-PFDv2-Eth-Priority-Range-High = 84
+
+# A less efficient encoding of the above data
+decode 1a 17 00 00 60 b5 54 11 00 09 0e 09 0c 03 05 01 03 37 03 05 02 03 54
+data WiMAX-PFDv2-Eth-Priority-Range-Low = 55, WiMAX-PFDv2-Eth-Priority-Range-High = 84
+
+# 26.24757.84.9.9.3.1 has the wrong length
+decode 1a 15 00 00 60 b5 54 0f 00 09 0c 09 0a 03 08 01 04 37 02 03 54
+data Attr-26.24757.84.9.9.3 = 0x010437020354
+
+# 26.24757.84.9.9.3.2 has the wrong length
+decode 1a 15 00 00 60 b5 54 0f 00 09 0c 09 0a 03 08 01 03 37 02 04 54
+data Attr-26.24757.84.9.9.3 = 0x010337020454
+
+# 26.24757.84.9.9.3.2 has the wrong length
+# This means that the SECOND 26.24757.84.9.9.3 is invalid.
+decode 1a 17 00 00 60 b5 54 11 00 09 0e 09 0c 03 05 01 03 37 03 05 02 04 54
+data WiMAX-PFDv2-Eth-Priority-Range-Low = 55, Attr-26.24757.84.9.9.3 = 0x020454
+
+# 26.24757.84.9.9.3.1 has the wrong length
+# This means that 26.24757.84.9.9.3 is invalid.
+decode 1a 17 00 00 60 b5 54 11 00 09 0e 09 0c 03 05 01 02 37 03 05 02 03 54
+data Attr-26.24757.84.9.9.3 = 0x010237, WiMAX-PFDv2-Eth-Priority-Range-High = 84
+
+#
+# Simple test for continued attributes
+#
+decode 1a 0e 00 00 60 b5 01 08 80 01 05 31 2e 30 1a 0c 00 00 60 b5 01 06 00 02 03 00
+data WiMAX-Release = "1.0", WiMAX-Accounting-Capabilities = No-Accounting
+
+#
+# See if encoding multiple attributes works
+#
+encode WiMAX-Packet-Data-Flow-Id := 32, WiMAX-Service-Data-Flow-ID := 32, WiMAX-Service-Profile-ID := 32
+data 1a 17 00 00 60 b5 1c 11 00 01 04 00 20 02 04 00 20 03 06 00 00 00 20
+
+encode WiMAX-Packet-Data-Flow-Id := 33, WiMAX-Service-Data-Flow-ID := 33, WiMAX-Service-Profile-ID := 33
+data 1a 17 00 00 60 b5 1c 11 00 01 04 00 21 02 04 00 21 03 06 00 00 00 21
+
+encode WiMAX-Packet-Data-Flow-Id := 32, WiMAX-Service-Data-Flow-ID := 32, WiMAX-Service-Profile-ID := 32, WiMAX-Packet-Data-Flow-Id := 33, WiMAX-Service-Data-Flow-ID := 33, WiMAX-Service-Profile-ID := 33
+data 1a 25 00 00 60 b5 1c 1f 00 01 04 00 20 02 04 00 20 03 06 00 00 00 20 01 04 00 21 02 04 00 21 03 06 00 00 00 21
+
+encode WiMAX-Packet-Data-Flow-Id := 32, WiMAX-Service-Data-Flow-ID := 32, WiMAX-Service-Profile-ID := 32, WiMAX-Packet-Data-Flow-Id := 33, WiMAX-Service-Data-Flow-ID := 33, WiMAX-Service-Profile-ID := 33, Session-Timeout := 7200
+data 1a 25 00 00 60 b5 1c 1f 00 01 04 00 20 02 04 00 20 03 06 00 00 00 20 01 04 00 21 02 04 00 21 03 06 00 00 00 21 1b 06 00 00 1c 20
+
+encode Acct-Interim-Interval := 3600, WiMAX-Packet-Data-Flow-Id := 32, WiMAX-Service-Data-Flow-ID := 32, WiMAX-Service-Profile-ID := 32, WiMAX-Packet-Data-Flow-Id := 33, WiMAX-Service-Data-Flow-ID := 33, WiMAX-Service-Profile-ID := 33, Session-Timeout := 7200
+data 55 06 00 00 0e 10 1a 25 00 00 60 b5 1c 1f 00 01 04 00 20 02 04 00 20 03 06 00 00 00 20 01 04 00 21 02 04 00 21 03 06 00 00 00 21 1b 06 00 00 1c 20
+
+encode WiMAX-Packet-Data-Flow-Id := 32, WiMAX-Service-Data-Flow-ID := 32, WiMAX-Service-Profile-ID := 32, Session-Timeout := 7200, WiMAX-Packet-Data-Flow-Id := 33, WiMAX-Service-Data-Flow-ID := 33, WiMAX-Service-Profile-ID := 33
+data 1a 17 00 00 60 b5 1c 11 00 01 04 00 20 02 04 00 20 03 06 00 00 00 20 1b 06 00 00 1c 20 1a 17 00 00 60 b5 1c 11 00 01 04 00 21 02 04 00 21 03 06 00 00 00 21
+
+encode WiMAX-Capability = 0x01ff45454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545040301
+data 1a ff 00 00 60 b5 01 f9 80 01 ff 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 1a 15 00 00 60 b5 01 0f 00 45 45 45 45 45 45 45 45 45 04 03 01
+
+decode -
+data WiMAX-Release = "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", WiMAX-Idle-Mode-Notification-Cap = Supported
+
+#
+# Continuation is set, but there's no continued data.
+decode 1a 0b 00 00 60 b5 31 05 80 00 00
+data Attr-26 = 0x000060b53105800000
+
+encode WiMAX-GMT-Timezone-offset = -1
+data 1a 0d 00 00 60 b5 03 07 00 ff ff ff ff
+
+decode -
+data WiMAX-GMT-Timezone-offset = -1
+
+#
+# It's like a disease which keeps spreading.
+#
+encode Telrad-Reference-QOS-Profile-Name = "garbage"
+data 1a 14 00 00 14 cb 01 0e 00 03 0b 04 09 67 61 72 62 61 67 65
+
+decode -
+data Telrad-Reference-QOS-Profile-Name = "garbage"
diff --git a/src/tests/unit/xlat.txt b/src/tests/unit/xlat.txt
new file mode 100644
index 0000000..5dc4893
--- /dev/null
+++ b/src/tests/unit/xlat.txt
@@ -0,0 +1,142 @@
+#
+# Tests for xlat expansion
+#
+
+xlat %{foo: bar}
+data ERROR offset 2 'Unknown module'
+
+xlat %{test:bar}
+data %{test:bar}
+
+xlat %{1}
+data %{1}
+
+xlat %{33}
+data ERROR offset 2 'Invalid regex reference. Must be in range 0-32'
+
+xlat %{%{foo}:-%{bar}}
+data ERROR offset 4 'Unknown attribute'
+
+xlat %{%{User-Name}:-%{bar}}
+data ERROR offset 18 'Unknown attribute'
+
+xlat %{%{User-Name}:-bar}
+data %{%{User-Name}:-bar}
+
+xlat %{%{test:bar}:-%{User-Name}}
+data %{%{test:bar}:-%{User-Name}}
+
+xlat %{%{test:bar}:-%{%{User-Name}:-bar}}
+data %{%{test:bar}:-%{%{User-Name}:-bar}}
+
+xlat %{Tunnel-Password}
+data %{Tunnel-Password}
+
+xlat %{Tunnel-Password:1}
+data %{Tunnel-Password:1}
+
+xlat %{Tunnel-Password:1[3]}
+data %{Tunnel-Password:1[3]}
+
+xlat %{Tunnel-Password:1[*]}
+data %{Tunnel-Password:1[*]}
+
+xlat %{Tunnel-Password:1[#]}
+data %{Tunnel-Password:1[#]}
+
+xlat %{reply:Tunnel-Password}
+data %{reply:Tunnel-Password}
+
+xlat %{reply:Tunnel-Password:1}
+data %{reply:Tunnel-Password:1}
+
+xlat %{reply:Tunnel-Password:1[3]}
+data %{reply:Tunnel-Password:1[3]}
+
+xlat %{reply:Tunnel-Password:1[*]}
+data %{reply:Tunnel-Password:1[*]}
+
+xlat %{reply:Tunnel-Password:1[#]}
+data %{reply:Tunnel-Password:1[#]}
+
+xlat %{User-Name[3]}
+data %{User-Name[3]}
+
+xlat %{User-Name[*]}
+data %{User-Name[*]}
+
+xlat %{User-Name[#]}
+data %{User-Name[#]}
+
+xlat %{request:User-Name[3]}
+data %{User-Name[3]}
+
+xlat %{request:User-Name[*]}
+data %{User-Name[*]}
+
+xlat %{request:User-Name[#]}
+data %{User-Name[#]}
+
+xlat %{coa:User-Name[#]}
+data %{coa:User-Name[#]}
+
+xlat %{coaX:User-Name[#]}
+data ERROR offset 2 'Unknown module'
+
+xlat %{3GPP-SGSN-Address}
+data %{3GPP-SGSN-Address}
+
+xlat %{%{Operator-Name}:-}
+data %{%{Operator-Name}:-}
+
+xlat %{%{}:-}
+data ERROR offset 4 'Empty expression is invalid'
+
+xlat %{%{}:-foo}
+data ERROR offset 4 'Empty expression is invalid'
+
+xlat %{}
+data ERROR offset 2 'Empty expression is invalid'
+
+xlat %{ }
+data ERROR offset 2 'Invalid attribute name'
+
+xlat %{%{User-Name}:-}
+data %{%{User-Name}:-}
+
+xlat "Hello %S goo"
+data "Hello %S goo"
+
+xlat "%{Foreach-Variable-0}"
+data "%{Foreach-Variable-0}"
+
+#
+# 3GPP stuff, to distinguish "list:3GPP" from
+# "attribute:tag"
+#
+xlat "%{request:3GPP-IMSI}"
+data "%{3GPP-IMSI}"
+
+xlat "%{reply:3GPP-IMSI}"
+data "%{reply:3GPP-IMSI}"
+
+xlat "%{reply:3GPP-IMSI[2]}"
+data "%{reply:3GPP-IMSI[2]}"
+
+xlat /([A-Z0-9\-]*)_%{Calling-Station-Id}/
+data /([A-Z0-9\-]*)_%{Calling-Station-Id}/
+
+xlat %{length:1 + 2
+data ERROR offset 14 'Missing closing brace at end of string'
+
+xlat "%t\tfoo"
+data "%t\tfoo"
+
+xlat "%t\t%{Client-IP-Address}"
+data "%t\t%{Client-IP-Address}"
+
+xlat "foo %{test}"
+data ERROR offset 11 'Missing content in expansion'
+
+xlat "foo %{test:foo}"
+data "foo %{test:foo}"
diff --git a/src/tests/xlat/all.mk b/src/tests/xlat/all.mk
new file mode 100644
index 0000000..190a1ed
--- /dev/null
+++ b/src/tests/xlat/all.mk
@@ -0,0 +1,57 @@
+#
+# Unit tests for dynamic xlat expansions
+#
+
+#
+# The test files are files without extensions.
+# The list is unordered. The order is added in the next step by looking
+# at precursors.
+#
+XLAT_FILES := $(subst $(DIR)/,,$(wildcard $(DIR)/*.txt))
+
+#
+# Create the output directory
+#
+.PHONY: $(BUILD_DIR)/tests/xlat
+$(BUILD_DIR)/tests/xlat:
+ @mkdir -p $@
+
+#
+# Files in the output dir depend on the unit tests
+#
+# src/tests/xlat/FOO input file
+# build/tests/xlat/FOO updated if the test succeeds
+# build/tests/xlat/FOO.log debug output for the test
+#
+# Auto-depend on modules via $(shell grep INCLUDE $(DIR)/radiusd.conf | grep mods-enabled | sed 's/.*}/raddb/'))
+#
+# If the test fails, then look for ERROR in the input. No error
+# means it's unexpected, so we die.
+#
+# Otherwise, check the log file for a parse error which matches the
+# ERROR line in the input.
+#
+$(BUILD_DIR)/tests/xlat/%: $(DIR)/% $(TESTBINDIR)/unittest | $(BUILD_DIR)/tests/xlat build.raddb
+ @echo XLAT-TEST $(notdir $@)
+ @if ! $(TESTBIN)/unittest -D share -d src/tests/xlat/ -i $< -xx -O xlat_only > $@.log 2>&1; then \
+ cat $@.log; \
+ echo "./$(TESTBIN)/unittest -D share -d src/tests/xlat/ -i $< -xx -O xlat_only"; \
+ exit 1; \
+ fi
+ @touch $@
+
+#
+# Get all of the unit test output files
+#
+TESTS.XLAT_FILES := $(addprefix $(BUILD_DIR)/tests/xlat/,$(XLAT_FILES))
+
+#
+# Depend on the output files, and create the directory first.
+#
+tests.xlat: $(TESTS.XLAT_FILES)
+
+$(TESTS.XLAT_FILES): $(TESTS.UNIT_FILES)
+
+.PHONY: clean.tests.xlat
+clean.tests.xlat:
+ @rm -rf $(BUILD_DIR)/tests/xlat/
diff --git a/src/tests/xlat/expr.txt b/src/tests/xlat/expr.txt
new file mode 100644
index 0000000..e2d9f10
--- /dev/null
+++ b/src/tests/xlat/expr.txt
@@ -0,0 +1,20 @@
+xlat %{md5:This is a string\n}
+data 9ac4dbbc3c0ad2429e61d0df5dc28add
+
+xlat %{expr: 1 + 2 + 3 + 4}
+data 10
+
+xlat %{expr: 1 & ~1}
+data 0
+
+xlat %{expr: 2 - -1}
+data 3
+
+xlat %{expr: -1 * 2}
+data -2
+
+xlat %{expr: 1 << 2 | 1}
+data 5
+
+xlat %{expr: 6 + -(1 + 3)}
+data 2
diff --git a/src/tests/xlat/radiusd.conf b/src/tests/xlat/radiusd.conf
new file mode 100644
index 0000000..89e7f24
--- /dev/null
+++ b/src/tests/xlat/radiusd.conf
@@ -0,0 +1,37 @@
+#
+# Minimal radiusd.conf for testing keywords
+#
+
+raddb = raddb
+
+modconfdir = ${raddb}/mods-config
+
+correct_escapes = true
+
+# Only for testing!
+# Setting this on a production system is a BAD IDEA.
+security {
+ allow_vulnerable_openssl = yes
+}
+
+modules {
+ $INCLUDE ${raddb}/mods-enabled/always
+
+ $INCLUDE ${raddb}/mods-enabled/pap
+
+ $INCLUDE ${raddb}/mods-enabled/expr
+}
+
+server default {
+ authorize {
+ update control {
+ Cleartext-Password := 'hello'
+ }
+
+ pap
+ }
+
+ authenticate {
+ pap
+ }
+}